• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //! An adapter that converts between generated protobuf types and native Rust types.
16 
17 use crypto_provider::elliptic_curve::EcdhProvider;
18 use crypto_provider::p256::{P256EcdhProvider, P256PublicKey, P256};
19 use crypto_provider::CryptoProvider;
20 use derive_getters::Getters;
21 use ukey2_proto::ukey2_all_proto::{securemessage, ukey};
22 
23 /// For generated proto types for UKEY2 messages
24 trait WithMessageType: ukey2_proto::protobuf::Message {
msg_type() -> ukey::ukey2message::Type25     fn msg_type() -> ukey::ukey2message::Type;
26 }
27 
28 pub(crate) trait ToWrappedMessage {
29     /// Wrap `self` in a `Ukey2Message`. Creates a new `Ukey2Message` with `message_type` set to
30     /// [`msg_type`][WithMessageType::msg_type] and `message_data` set to the serialized bytes for
31     /// the `self` proto.
to_wrapped_msg(self) -> ukey::Ukey2Message32     fn to_wrapped_msg(self) -> ukey::Ukey2Message;
33 }
34 
35 impl<M: WithMessageType> ToWrappedMessage for M {
to_wrapped_msg(self) -> ukey::Ukey2Message36     fn to_wrapped_msg(self) -> ukey::Ukey2Message {
37         ukey::Ukey2Message {
38             message_type: Some(Self::msg_type().into()),
39             message_data: self.write_to_bytes().ok(),
40             ..Default::default()
41         }
42     }
43 }
44 
45 impl WithMessageType for ukey::Ukey2Alert {
msg_type() -> ukey::ukey2message::Type46     fn msg_type() -> ukey::ukey2message::Type {
47         ukey::ukey2message::Type::ALERT
48     }
49 }
50 
51 impl WithMessageType for ukey::Ukey2ServerInit {
msg_type() -> ukey::ukey2message::Type52     fn msg_type() -> ukey::ukey2message::Type {
53         ukey::ukey2message::Type::SERVER_INIT
54     }
55 }
56 
57 impl WithMessageType for ukey::Ukey2ClientFinished {
msg_type() -> ukey::ukey2message::Type58     fn msg_type() -> ukey::ukey2message::Type {
59         ukey::ukey2message::Type::CLIENT_FINISH
60     }
61 }
62 
63 impl WithMessageType for ukey::Ukey2ClientInit {
msg_type() -> ukey::ukey2message::Type64     fn msg_type() -> ukey::ukey2message::Type {
65         ukey::ukey2message::Type::CLIENT_INIT
66     }
67 }
68 
69 /// Convert a generated proto type into our custom adapter type.
70 pub(crate) trait IntoAdapter<A> {
71     /// Convert `self` into the adapter type.
into_adapter(self) -> Result<A, ukey::ukey2alert::AlertType>72     fn into_adapter(self) -> Result<A, ukey::ukey2alert::AlertType>;
73 }
74 
75 #[derive(Debug, PartialEq, Eq)]
76 pub(crate) enum MessageType {
77     ClientInit,
78     ServerInit,
79     ClientFinish,
80 }
81 
82 #[derive(Getters)]
83 pub(crate) struct ClientInit {
84     version: i32,
85     commitments: Vec<CipherCommitment>,
86     next_protocol: String,
87 }
88 
89 #[allow(dead_code)]
90 #[derive(Getters)]
91 pub(crate) struct ServerInit {
92     version: i32,
93     random: [u8; 32],
94     handshake_cipher: HandshakeCipher,
95     #[getter(skip)]
96     pub(crate) public_key: Vec<u8>,
97 }
98 
99 pub(crate) struct ClientFinished {
100     pub(crate) public_key: Vec<u8>,
101 }
102 
103 /// The handshake cipher used for UKEY2 handshake. Corresponds to the proto message
104 /// `ukey::Ukey2HandshakeCipher`.
105 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
106 pub enum HandshakeCipher {
107     /// NIST P-256 used for ECDH, SHA512 used for commitment
108     P256Sha512,
109     /// Curve 25519 used for ECDH, SHA512 used for commitment
110     Curve25519Sha512,
111 }
112 
113 impl HandshakeCipher {
as_proto(&self) -> ukey::Ukey2HandshakeCipher114     pub(crate) fn as_proto(&self) -> ukey::Ukey2HandshakeCipher {
115         match self {
116             HandshakeCipher::P256Sha512 => ukey::Ukey2HandshakeCipher::P256_SHA512,
117             HandshakeCipher::Curve25519Sha512 => ukey::Ukey2HandshakeCipher::CURVE25519_SHA512,
118         }
119     }
120 }
121 
122 #[derive(Clone, Getters)]
123 pub(crate) struct CipherCommitment {
124     cipher: HandshakeCipher,
125     commitment: Vec<u8>,
126 }
127 
128 pub(crate) enum GenericPublicKey<C: CryptoProvider> {
129     Ec256(<C::P256 as EcdhProvider<P256>>::PublicKey),
130     // Other public key types are not supported
131 }
132 
133 impl IntoAdapter<MessageType> for ukey::ukey2message::Type {
into_adapter(self) -> Result<MessageType, ukey::ukey2alert::AlertType>134     fn into_adapter(self) -> Result<MessageType, ukey::ukey2alert::AlertType> {
135         match self {
136             ukey::ukey2message::Type::CLIENT_INIT => Ok(MessageType::ClientInit),
137             ukey::ukey2message::Type::SERVER_INIT => Ok(MessageType::ServerInit),
138             ukey::ukey2message::Type::CLIENT_FINISH => Ok(MessageType::ClientFinish),
139             _ => Err(ukey::ukey2alert::AlertType::BAD_MESSAGE_TYPE),
140         }
141     }
142 }
143 
144 impl IntoAdapter<HandshakeCipher> for i32 {
into_adapter(self) -> Result<HandshakeCipher, ukey::ukey2alert::AlertType>145     fn into_adapter(self) -> Result<HandshakeCipher, ukey::ukey2alert::AlertType> {
146         const P256_CODE: i32 = ukey::Ukey2HandshakeCipher::P256_SHA512 as i32;
147         const CURVE25519_CODE: i32 = ukey::Ukey2HandshakeCipher::CURVE25519_SHA512 as i32;
148         match self {
149             P256_CODE => Ok(HandshakeCipher::P256Sha512),
150             CURVE25519_CODE => Ok(HandshakeCipher::Curve25519Sha512),
151             _ => Err(ukey::ukey2alert::AlertType::BAD_HANDSHAKE_CIPHER),
152         }
153     }
154 }
155 
156 impl IntoAdapter<CipherCommitment> for ukey::ukey2client_init::CipherCommitment {
into_adapter(self) -> Result<CipherCommitment, ukey::ukey2alert::AlertType>157     fn into_adapter(self) -> Result<CipherCommitment, ukey::ukey2alert::AlertType> {
158         let handshake_cipher: HandshakeCipher = self
159             .handshake_cipher
160             .ok_or(ukey::ukey2alert::AlertType::BAD_HANDSHAKE_CIPHER)
161             .and_then(|code| code.value().into_adapter())?;
162         // no bad commitment so this is best-effort
163         let commitment = self
164             .commitment
165             .filter(|c| !c.is_empty())
166             .ok_or(ukey::ukey2alert::AlertType::BAD_HANDSHAKE_CIPHER)?;
167         Ok(CipherCommitment {
168             commitment,
169             cipher: handshake_cipher,
170         })
171     }
172 }
173 
174 impl IntoAdapter<ClientInit> for ukey::Ukey2ClientInit {
into_adapter(self) -> Result<ClientInit, ukey::ukey2alert::AlertType>175     fn into_adapter(self) -> Result<ClientInit, ukey::ukey2alert::AlertType> {
176         if self.random().len() != 32 {
177             return Err(ukey::ukey2alert::AlertType::BAD_RANDOM);
178         }
179         let version: i32 = self
180             .version
181             .ok_or(ukey::ukey2alert::AlertType::BAD_VERSION)?;
182         let next_protocol = self
183             .next_protocol
184             .filter(|n| !n.is_empty())
185             .ok_or(ukey::ukey2alert::AlertType::BAD_NEXT_PROTOCOL)?;
186         Ok(ClientInit {
187             next_protocol,
188             version,
189             commitments: self
190                 .cipher_commitments
191                 .into_iter()
192                 .map(|c| c.into_adapter())
193                 .collect::<Result<Vec<_>, _>>()?,
194         })
195     }
196 }
197 
198 impl IntoAdapter<ServerInit> for ukey::Ukey2ServerInit {
into_adapter(self) -> Result<ServerInit, ukey::ukey2alert::AlertType>199     fn into_adapter(self) -> Result<ServerInit, ukey::ukey2alert::AlertType> {
200         let version: i32 = self
201             .version
202             .ok_or(ukey::ukey2alert::AlertType::BAD_VERSION)?;
203         let random: [u8; 32] = self
204             .random
205             .and_then(|r| r.try_into().ok())
206             .ok_or(ukey::ukey2alert::AlertType::BAD_RANDOM)?;
207         let handshake_cipher = self
208             .handshake_cipher
209             .ok_or(ukey::ukey2alert::AlertType::BAD_HANDSHAKE_CIPHER)
210             .and_then(|code| code.value().into_adapter())?;
211         // We will be handling bad pubkeys in the layers above
212         let public_key: Vec<u8> = self
213             .public_key
214             .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
215         Ok(ServerInit {
216             handshake_cipher,
217             version,
218             public_key,
219             random,
220         })
221     }
222 }
223 
224 impl IntoAdapter<ClientFinished> for ukey::Ukey2ClientFinished {
into_adapter(self) -> Result<ClientFinished, ukey::ukey2alert::AlertType>225     fn into_adapter(self) -> Result<ClientFinished, ukey::ukey2alert::AlertType> {
226         let public_key: Vec<u8> = self
227             .public_key
228             .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
229         Ok(ClientFinished { public_key })
230     }
231 }
232 
233 impl<C: CryptoProvider> IntoAdapter<GenericPublicKey<C>> for securemessage::GenericPublicKey {
into_adapter(self) -> Result<GenericPublicKey<C>, ukey::ukey2alert::AlertType>234     fn into_adapter(self) -> Result<GenericPublicKey<C>, ukey::ukey2alert::AlertType> {
235         let key_type = self
236             .type_
237             .and_then(|t| t.enum_value().ok())
238             .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
239         match key_type {
240             securemessage::PublicKeyType::EC_P256 => {
241                 let (key_x, key_y) = self
242                     .ec_p256_public_key
243                     .into_option()
244                     .and_then(|pk| pk.x.zip(pk.y))
245                     .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
246                 let key_x_bytes: [u8; 32] = positive_twos_complement_to_32_byte_unsigned(&key_x)
247                     .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
248                 let key_y_bytes: [u8; 32] = positive_twos_complement_to_32_byte_unsigned(&key_y)
249                     .ok_or(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)?;
250                 <C::P256 as P256EcdhProvider>::PublicKey::from_affine_coordinates(
251                     &key_x_bytes,
252                     &key_y_bytes,
253                 )
254                 .map(GenericPublicKey::Ec256)
255                 .map_err(|_| ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)
256             }
257             securemessage::PublicKeyType::RSA2048 => {
258                 // We don't support RSA keys
259                 Err(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)
260             }
261             securemessage::PublicKeyType::DH2048_MODP => {
262                 // We don't support DH2048 keys, only ECDH.
263                 Err(ukey::ukey2alert::AlertType::BAD_PUBLIC_KEY)
264             }
265         }
266     }
267 }
268 
269 /// Turns a big endian two's complement integer representation into big endian unsigned
270 /// representation. If the input byte array is not positive or cannot be fit into 32 byte unsigned
271 /// int range, then `None` is returned.
positive_twos_complement_to_32_byte_unsigned(twos_complement: &[u8]) -> Option<[u8; 32]>272 fn positive_twos_complement_to_32_byte_unsigned(twos_complement: &[u8]) -> Option<[u8; 32]> {
273     if !twos_complement.is_empty() && (twos_complement[0] & 0x80) == 0 {
274         let mut twos_complement_iter = twos_complement.iter().rev();
275         let mut result = [0_u8; 32];
276         for (dst, src) in result.iter_mut().rev().zip(&mut twos_complement_iter) {
277             *dst = *src;
278         }
279         if twos_complement_iter.any(|x| *x != 0) {
280             // If any remaining elements are non-zero, the input cannot be fit into the 32 byte
281             // unsigned range
282             return None;
283         }
284         // No conversion needed since positive two's complement is the same as unsigned
285         Some(result)
286     } else {
287         None
288     }
289 }
290 
291 #[cfg(test)]
292 mod test {
293     #[test]
test_positive_twos_complement_to_32_byte_unsigned()294     fn test_positive_twos_complement_to_32_byte_unsigned() {
295         assert_eq!(
296             super::positive_twos_complement_to_32_byte_unsigned(&[]), // Empty input
297             None
298         );
299         assert_eq!(
300             super::positive_twos_complement_to_32_byte_unsigned(&[0xff, 0x05, 0x05]), // Negative
301             None
302         );
303         assert_eq!(
304             super::positive_twos_complement_to_32_byte_unsigned(&[0xff; 32]), // Negative
305             None
306         );
307         assert_eq!(
308             super::positive_twos_complement_to_32_byte_unsigned(&[0x05; 34]), // Too long
309             None
310         );
311         assert_eq!(
312             super::positive_twos_complement_to_32_byte_unsigned(&[0x05, 0xff]),
313             Some([
314                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316                 0x00, 0x00, 0x05, 0xff
317             ])
318         );
319         assert_eq!(
320             super::positive_twos_complement_to_32_byte_unsigned(&[0x05, 0x05, 0x05]),
321             Some([
322                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324                 0x00, 0x05, 0x05, 0x05
325             ])
326         );
327         assert_eq!(
328             super::positive_twos_complement_to_32_byte_unsigned(&[0x05; 32]),
329             Some([0x05; 32])
330         );
331         let mut input_33_bytes = [0xff_u8; 33];
332         assert_eq!(
333             super::positive_twos_complement_to_32_byte_unsigned(&input_33_bytes),
334             None // Negative input
335         );
336         input_33_bytes[0] = 0;
337         assert_eq!(
338             super::positive_twos_complement_to_32_byte_unsigned(&input_33_bytes),
339             Some([0xff; 32])
340         );
341     }
342 }
343