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