1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! V1 advertisement section np_ed25519 signature payload
16 //! after the included context bytes, and utilities for
17 //! performing signatures and signature verification.
18 
19 use crate::header::VERSION_HEADER_V1;
20 use crypto_provider::{
21     aes::ctr::AesCtrNonce,
22     ed25519::{Ed25519Provider, PrivateKey, PublicKey, Signature},
23 };
24 use sink::{Sink, SinkWriter};
25 
26 use crate::NP_SVC_UUID;
27 
28 /// A struct representing the necessary contents
29 /// of an v1 advertisement section np_ed25519 signature payload which
30 /// come after the context prefix (shared among all advs).
31 pub(crate) struct SectionSignaturePayload<'a> {
32     /// first 1-2 bytes of format
33     format_bytes: &'a [u8],
34     /// Salt bytes
35     salt_bytes: &'a [u8],
36     /// Nonce for en/decrypting the section
37     nonce: &'a AesCtrNonce,
38     /// plaintext identity token
39     plaintext_identity_token: &'a [u8],
40     /// the len of the rest of the section contents stored as an u8
41     section_payload_len: u8,
42     /// plaintext identity token
43     plaintext_data_elements: &'a [u8],
44 }
45 
46 const ADV_SIGNATURE_CONTEXT: np_ed25519::SignatureContext = {
47     match np_ed25519::SignatureContext::from_string_bytes("Advertisement Signed Section") {
48         Ok(x) => x,
49         Err(_) => panic!(),
50     }
51 };
52 
53 impl<'a> SectionSignaturePayload<'a> {
54     /// Construct a section signature payload with separate section len and
55     /// remaining contents of the section header.
56     ///
57     /// The section header should be in its on-the-wire form.
new( format_bytes: &'a [u8], salt_bytes: &'a [u8], nonce: &'a AesCtrNonce, plaintext_identity_token: &'a [u8], section_payload_len: u8, plaintext_data_elements: &'a [u8], ) -> Self58     pub(crate) fn new(
59         format_bytes: &'a [u8],
60         salt_bytes: &'a [u8],
61         nonce: &'a AesCtrNonce,
62         plaintext_identity_token: &'a [u8],
63         section_payload_len: u8,
64         plaintext_data_elements: &'a [u8],
65     ) -> Self {
66         Self {
67             format_bytes,
68             salt_bytes,
69             nonce,
70             plaintext_identity_token,
71             section_payload_len,
72             plaintext_data_elements,
73         }
74     }
75 
76     /// Generates a signature for this section signing payload using
77     /// the given Ed25519 key-pair.
sign<E: Ed25519Provider>(self, private_key: &PrivateKey) -> Signature78     pub(crate) fn sign<E: Ed25519Provider>(self, private_key: &PrivateKey) -> Signature {
79         np_ed25519::sign_with_context::<E, _>(private_key, &ADV_SIGNATURE_CONTEXT, self)
80             .expect("section signature payloads should fit in signature buffer")
81     }
82 
83     /// Verifies a signature for this section signing payload using
84     /// the given Ed25519 public key.
verify<E: Ed25519Provider>( self, signature: Signature, public_key: &PublicKey, ) -> Result<(), np_ed25519::SignatureVerificationError>85     pub(crate) fn verify<E: Ed25519Provider>(
86         self,
87         signature: Signature,
88         public_key: &PublicKey,
89     ) -> Result<(), np_ed25519::SignatureVerificationError> {
90         np_ed25519::verify_signature_with_context::<E, _>(
91             public_key,
92             &ADV_SIGNATURE_CONTEXT,
93             self,
94             signature,
95         )
96     }
97 }
98 
99 impl<'a> SinkWriter for SectionSignaturePayload<'a> {
100     type DataType = u8;
101 
write_payload<S: Sink<u8> + ?Sized>(self, sink: &mut S) -> Option<()>102     fn write_payload<S: Sink<u8> + ?Sized>(self, sink: &mut S) -> Option<()> {
103         sink.try_extend_from_slice(&NP_SVC_UUID)?;
104         sink.try_push(VERSION_HEADER_V1)?;
105         sink.try_extend_from_slice(self.format_bytes)?;
106         sink.try_extend_from_slice(self.salt_bytes)?;
107         sink.try_extend_from_slice(self.nonce)?;
108         sink.try_extend_from_slice(self.plaintext_identity_token)?;
109         sink.try_push(self.section_payload_len)?;
110         sink.try_extend_from_slice(self.plaintext_data_elements)
111     }
112 }
113