f6141e59699addb391ff6bfb523f75767e81aa7f
[rust-lightning] / lightning / src / offers / signer.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
8 // licenses.
9
10 //! Utilities for signing offer messages and verifying metadata.
11
12 use bitcoin::hashes::{Hash, HashEngine};
13 use bitcoin::hashes::cmp::fixed_time_eq;
14 use bitcoin::hashes::hmac::{Hmac, HmacEngine};
15 use bitcoin::hashes::sha256::Hash as Sha256;
16 use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey, self};
17 use core::convert::TryFrom;
18 use core::fmt;
19 use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
20 use crate::offers::merkle::TlvRecord;
21 use crate::util::ser::Writeable;
22
23 use crate::prelude::*;
24
25 const DERIVED_METADATA_HMAC_INPUT: &[u8; 16] = &[1; 16];
26 const DERIVED_METADATA_AND_KEYS_HMAC_INPUT: &[u8; 16] = &[2; 16];
27
28 /// Message metadata which possibly is derived from [`MetadataMaterial`] such that it can be
29 /// verified.
30 #[derive(Clone)]
31 pub(super) enum Metadata {
32         /// Metadata as parsed, supplied by the user, or derived from the message contents.
33         Bytes(Vec<u8>),
34
35         /// Metadata to be derived from message contents and given material.
36         Derived(MetadataMaterial),
37
38         /// Metadata and signing pubkey to be derived from message contents and given material.
39         DerivedSigningPubkey(MetadataMaterial),
40 }
41
42 impl Metadata {
43         pub fn as_bytes(&self) -> Option<&Vec<u8>> {
44                 match self {
45                         Metadata::Bytes(bytes) => Some(bytes),
46                         Metadata::Derived(_) => None,
47                         Metadata::DerivedSigningPubkey(_) => None,
48                 }
49         }
50
51         pub fn has_derivation_material(&self) -> bool {
52                 match self {
53                         Metadata::Bytes(_) => false,
54                         Metadata::Derived(_) => true,
55                         Metadata::DerivedSigningPubkey(_) => true,
56                 }
57         }
58
59         pub fn derives_keys(&self) -> bool {
60                 match self {
61                         // Infer whether Metadata::derived_from was called on Metadata::DerivedSigningPubkey to
62                         // produce Metadata::Bytes. This is merely to determine which fields should be included
63                         // when verifying a message. It doesn't necessarily indicate that keys were in fact
64                         // derived, as wouldn't be the case if a Metadata::Bytes with length Nonce::LENGTH had
65                         // been set explicitly.
66                         Metadata::Bytes(bytes) => bytes.len() == Nonce::LENGTH,
67                         Metadata::Derived(_) => false,
68                         Metadata::DerivedSigningPubkey(_) => true,
69                 }
70         }
71
72         pub fn without_keys(self) -> Self {
73                 match self {
74                         Metadata::Bytes(_) => self,
75                         Metadata::Derived(_) => self,
76                         Metadata::DerivedSigningPubkey(material) => Metadata::Derived(material),
77                 }
78         }
79
80         pub fn derive_from<W: Writeable, T: secp256k1::Signing>(
81                 self, tlv_stream: W, secp_ctx: Option<&Secp256k1<T>>
82         ) -> (Self, Option<KeyPair>) {
83                 match self {
84                         Metadata::Bytes(_) => (self, None),
85                         Metadata::Derived(mut metadata_material) => {
86                                 tlv_stream.write(&mut metadata_material.hmac).unwrap();
87                                 (Metadata::Bytes(metadata_material.derive_metadata()), None)
88                         },
89                         Metadata::DerivedSigningPubkey(mut metadata_material) => {
90                                 tlv_stream.write(&mut metadata_material.hmac).unwrap();
91                                 let secp_ctx = secp_ctx.unwrap();
92                                 let (metadata, keys) = metadata_material.derive_metadata_and_keys(secp_ctx);
93                                 (Metadata::Bytes(metadata), Some(keys))
94                         },
95                 }
96         }
97 }
98
99 impl Default for Metadata {
100         fn default() -> Self {
101                 Metadata::Bytes(vec![])
102         }
103 }
104
105 impl fmt::Debug for Metadata {
106         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107                 match self {
108                         Metadata::Bytes(bytes) => bytes.fmt(f),
109                         Metadata::Derived(_) => f.write_str("Derived"),
110                         Metadata::DerivedSigningPubkey(_) => f.write_str("DerivedSigningPubkey"),
111                 }
112         }
113 }
114
115 #[cfg(test)]
116 impl PartialEq for Metadata {
117         fn eq(&self, other: &Self) -> bool {
118                 match self {
119                         Metadata::Bytes(bytes) => if let Metadata::Bytes(other_bytes) = other {
120                                 bytes == other_bytes
121                         } else {
122                                 false
123                         },
124                         Metadata::Derived(_) => false,
125                         Metadata::DerivedSigningPubkey(_) => false,
126                 }
127         }
128 }
129
130 /// Material used to create metadata for a message.
131 #[derive(Clone)]
132 pub(super) struct MetadataMaterial {
133         nonce: Nonce,
134         hmac: HmacEngine<Sha256>,
135 }
136
137 impl MetadataMaterial {
138         pub fn new(nonce: Nonce, expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN]) -> Self {
139                 Self {
140                         nonce,
141                         hmac: expanded_key.hmac_for_offer(nonce, iv_bytes),
142                 }
143         }
144
145         fn derive_metadata(mut self) -> Vec<u8> {
146                 self.hmac.input(DERIVED_METADATA_HMAC_INPUT);
147
148                 let mut bytes = self.nonce.as_slice().to_vec();
149                 bytes.extend_from_slice(&Hmac::from_engine(self.hmac).into_inner());
150                 bytes
151         }
152
153         fn derive_metadata_and_keys<T: secp256k1::Signing>(
154                 mut self, secp_ctx: &Secp256k1<T>
155         ) -> (Vec<u8>, KeyPair) {
156                 self.hmac.input(DERIVED_METADATA_AND_KEYS_HMAC_INPUT);
157
158                 let hmac = Hmac::from_engine(self.hmac);
159                 let privkey = SecretKey::from_slice(hmac.as_inner()).unwrap();
160                 let keys = KeyPair::from_secret_key(secp_ctx, &privkey);
161                 (self.nonce.as_slice().to_vec(), keys)
162         }
163 }
164
165 /// Verifies data given in a TLV stream was used to produce the given metadata, consisting of:
166 /// - a 128-bit [`Nonce`] and possibly
167 /// - a [`Sha256`] hash of the nonce and the TLV records using the [`ExpandedKey`].
168 ///
169 /// If the latter is not included in the metadata, the TLV stream is used to check if the given
170 /// `signing_pubkey` can be derived from it.
171 pub(super) fn verify_metadata<'a, T: secp256k1::Signing>(
172         metadata: &[u8], expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
173         signing_pubkey: PublicKey, tlv_stream: impl core::iter::Iterator<Item = TlvRecord<'a>>,
174         secp_ctx: &Secp256k1<T>
175 ) -> bool {
176         if metadata.len() < Nonce::LENGTH {
177                 return false;
178         }
179
180         let nonce = match Nonce::try_from(&metadata[..Nonce::LENGTH]) {
181                 Ok(nonce) => nonce,
182                 Err(_) => return false,
183         };
184         let mut hmac = expanded_key.hmac_for_offer(nonce, iv_bytes);
185
186         for record in tlv_stream {
187                 hmac.input(record.record_bytes);
188         }
189
190         if metadata.len() == Nonce::LENGTH {
191                 hmac.input(DERIVED_METADATA_AND_KEYS_HMAC_INPUT);
192                 let hmac = Hmac::from_engine(hmac);
193                 let derived_pubkey = SecretKey::from_slice(hmac.as_inner()).unwrap().public_key(&secp_ctx);
194                 fixed_time_eq(&signing_pubkey.serialize(), &derived_pubkey.serialize())
195         } else if metadata[Nonce::LENGTH..].len() == Sha256::LEN {
196                 hmac.input(DERIVED_METADATA_HMAC_INPUT);
197                 fixed_time_eq(&metadata[Nonce::LENGTH..], &Hmac::from_engine(hmac).into_inner())
198         } else {
199                 false
200         }
201 }