1 // Copyright 2022, The Android Open Source Project
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 //! Functionality related to elliptic curve support.
16 
17 use super::{CurveType, KeyMaterial, OpaqueOr};
18 use crate::{der_err, km_err, try_to_vec, vec_try, Error, FallibleAllocExt};
19 use alloc::vec::Vec;
20 use der::{asn1::BitStringRef, AnyRef, Decode, Encode, Sequence};
21 use kmr_wire::{coset, keymint::EcCurve, rpc, KeySizeInBits};
22 use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo, SubjectPublicKeyInfoRef};
23 use zeroize::ZeroizeOnDrop;
24 
25 /// Size (in bytes) of a curve 25519 private key.
26 pub const CURVE25519_PRIV_KEY_LEN: usize = 32;
27 
28 /// Maximum message size for Ed25519 Signing operations.
29 pub const MAX_ED25519_MSG_SIZE: usize = 16 * 1024;
30 
31 /// Marker value used to indicate that a public key is for RKP test mode.
32 pub const RKP_TEST_KEY_CBOR_MARKER: i64 = -70000;
33 
34 /// Initial byte of SEC1 public key encoding that indicates an uncompressed point.
35 pub const SEC1_UNCOMPRESSED_PREFIX: u8 = 0x04;
36 
37 /// OID value for general-use NIST EC keys held in PKCS#8 and X.509; see RFC 5480 s2.1.1.
38 pub const X509_NIST_OID: pkcs8::ObjectIdentifier =
39     pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.2.1");
40 
41 /// OID value for Ed25519 keys held in PKCS#8 and X.509; see RFC 8410 s3.
42 pub const X509_ED25519_OID: pkcs8::ObjectIdentifier =
43     pkcs8::ObjectIdentifier::new_unwrap("1.3.101.112");
44 
45 /// OID value for X25519 keys held in PKCS#8 and X.509; see RFC 8410 s3.
46 pub const X509_X25519_OID: pkcs8::ObjectIdentifier =
47     pkcs8::ObjectIdentifier::new_unwrap("1.3.101.110");
48 
49 /// OID value for PKCS#1 signature with SHA-256 and ECDSA, see RFC 5758 s3.2.
50 pub const ECDSA_SHA256_SIGNATURE_OID: pkcs8::ObjectIdentifier =
51     pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.2");
52 
53 /// OID value in `AlgorithmIdentifier.parameters` for P-224; see RFC 5480 s2.1.1.1.
54 pub const ALGO_PARAM_P224_OID: pkcs8::ObjectIdentifier =
55     pkcs8::ObjectIdentifier::new_unwrap("1.3.132.0.33");
56 
57 /// OID value in `AlgorithmIdentifier.parameters` for P-256; see RFC 5480 s2.1.1.1.
58 pub const ALGO_PARAM_P256_OID: pkcs8::ObjectIdentifier =
59     pkcs8::ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7");
60 
61 /// OID value in `AlgorithmIdentifier.parameters` for P-384; see RFC 5480 s2.1.1.1.
62 pub const ALGO_PARAM_P384_OID: pkcs8::ObjectIdentifier =
63     pkcs8::ObjectIdentifier::new_unwrap("1.3.132.0.34");
64 
65 /// OID value in `AlgorithmIdentifier.parameters` for P-521; see RFC 5480 s2.1.1.1.
66 pub const ALGO_PARAM_P521_OID: pkcs8::ObjectIdentifier =
67     pkcs8::ObjectIdentifier::new_unwrap("1.3.132.0.35");
68 
69 /// Subset of `EcCurve` values that are NIST curves.
70 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
71 #[repr(i32)]
72 pub enum NistCurve {
73     /// P-224
74     P224 = 0,
75     /// P-256
76     P256 = 1,
77     /// P-384
78     P384 = 2,
79     /// P-521
80     P521 = 3,
81 }
82 
83 impl NistCurve {
84     /// Curve coordinate size in bytes.
coord_len(&self) -> usize85     pub fn coord_len(&self) -> usize {
86         match self {
87             NistCurve::P224 => 28,
88             NistCurve::P256 => 32,
89             NistCurve::P384 => 48,
90             NistCurve::P521 => 66,
91         }
92     }
93 }
94 
95 impl From<NistCurve> for EcCurve {
from(nist: NistCurve) -> EcCurve96     fn from(nist: NistCurve) -> EcCurve {
97         match nist {
98             NistCurve::P224 => EcCurve::P224,
99             NistCurve::P256 => EcCurve::P256,
100             NistCurve::P384 => EcCurve::P384,
101             NistCurve::P521 => EcCurve::P521,
102         }
103     }
104 }
105 
106 impl TryFrom<EcCurve> for NistCurve {
107     type Error = Error;
try_from(curve: EcCurve) -> Result<NistCurve, Error>108     fn try_from(curve: EcCurve) -> Result<NistCurve, Error> {
109         match curve {
110             EcCurve::P224 => Ok(NistCurve::P224),
111             EcCurve::P256 => Ok(NistCurve::P256),
112             EcCurve::P384 => Ok(NistCurve::P384),
113             EcCurve::P521 => Ok(NistCurve::P521),
114             EcCurve::Curve25519 => Err(km_err!(InvalidArgument, "curve 25519 is not a NIST curve")),
115         }
116     }
117 }
118 
119 impl OpaqueOr<Key> {
120     /// Encode into `buf` the public key information as an ASN.1 DER encodable
121     /// `SubjectPublicKeyInfo`, as described in RFC 5280 section 4.1.
122     ///
123     /// ```asn1
124     /// SubjectPublicKeyInfo  ::=  SEQUENCE  {
125     ///    algorithm            AlgorithmIdentifier,
126     ///    subjectPublicKey     BIT STRING  }
127     ///
128     /// AlgorithmIdentifier  ::=  SEQUENCE  {
129     ///    algorithm               OBJECT IDENTIFIER,
130     ///    parameters              ANY DEFINED BY algorithm OPTIONAL  }
131     /// ```
132     ///
133     /// For NIST curve EC keys, the contents are described in RFC 5480 section 2.1.
134     /// - The `AlgorithmIdentifier` has an `algorithm` OID of 1.2.840.10045.2.1.
135     /// - The `AlgorithmIdentifier` has `parameters` that hold an OID identifying the curve, here
136     ///   one of:
137     ///    - P-224: 1.3.132.0.33
138     ///    - P-256: 1.2.840.10045.3.1.7
139     ///    - P-384: 1.3.132.0.34
140     ///    - P-521: 1.3.132.0.35
141     /// - The `subjectPublicKey` bit string holds an ASN.1 DER-encoded `OCTET STRING` that contains
142     ///   a SEC-1 encoded public key.  The first byte indicates the format:
143     ///    - 0x04: uncompressed, followed by x || y coordinates
144     ///    - 0x03: compressed, followed by x coordinate (and with a odd y coordinate)
145     ///    - 0x02: compressed, followed by x coordinate (and with a even y coordinate)
146     ///
147     /// For Ed25519 keys, the contents of the `AlgorithmIdentifier` are described in RFC 8410
148     /// section 3.
149     /// - The `algorithm` has an OID of 1.3.101.112.
150     /// - The `parameters` are absent.
151     ///
152     /// The `subjectPublicKey` holds the raw key bytes.
153     ///
154     /// For X25519 keys, the contents of the `AlgorithmIdentifier` are described in RFC 8410
155     /// section 3.
156     /// - The `algorithm` has an OID of 1.3.101.110.
157     /// - The `parameters` are absent.
158     ///
159     /// The `subjectPublicKey` holds the raw key bytes.
subject_public_key_info<'a>( &'a self, buf: &'a mut Vec<u8>, ec: &dyn super::Ec, curve: &EcCurve, curve_type: &CurveType, ) -> Result<SubjectPublicKeyInfoRef<'a>, Error>160     pub fn subject_public_key_info<'a>(
161         &'a self,
162         buf: &'a mut Vec<u8>,
163         ec: &dyn super::Ec,
164         curve: &EcCurve,
165         curve_type: &CurveType,
166     ) -> Result<SubjectPublicKeyInfoRef<'a>, Error> {
167         buf.try_extend_from_slice(&ec.subject_public_key(self)?)?;
168         let (oid, parameters) = match curve_type {
169             CurveType::Nist => {
170                 let nist_curve: NistCurve = (*curve).try_into()?;
171                 let params_oid = match nist_curve {
172                     NistCurve::P224 => &ALGO_PARAM_P224_OID,
173                     NistCurve::P256 => &ALGO_PARAM_P256_OID,
174                     NistCurve::P384 => &ALGO_PARAM_P384_OID,
175                     NistCurve::P521 => &ALGO_PARAM_P521_OID,
176                 };
177                 (X509_NIST_OID, Some(AnyRef::from(params_oid)))
178             }
179             CurveType::EdDsa => (X509_ED25519_OID, None),
180             CurveType::Xdh => (X509_X25519_OID, None),
181         };
182         Ok(SubjectPublicKeyInfo {
183             algorithm: AlgorithmIdentifier { oid, parameters },
184             subject_public_key: BitStringRef::from_bytes(buf).unwrap(),
185         })
186     }
187 
188     /// Generate a `COSE_Key` for the public key.
public_cose_key( &self, ec: &dyn super::Ec, curve: EcCurve, curve_type: CurveType, purpose: CoseKeyPurpose, key_id: Option<Vec<u8>>, test_mode: rpc::TestMode, ) -> Result<coset::CoseKey, Error>189     pub fn public_cose_key(
190         &self,
191         ec: &dyn super::Ec,
192         curve: EcCurve,
193         curve_type: CurveType,
194         purpose: CoseKeyPurpose,
195         key_id: Option<Vec<u8>>,
196         test_mode: rpc::TestMode,
197     ) -> Result<coset::CoseKey, Error> {
198         let nist_algo = match purpose {
199             CoseKeyPurpose::Agree => coset::iana::Algorithm::ECDH_ES_HKDF_256,
200             CoseKeyPurpose::Sign => coset::iana::Algorithm::ES256,
201         };
202 
203         let pub_key = ec.subject_public_key(self)?;
204         let mut builder = match curve_type {
205             CurveType::Nist => {
206                 let nist_curve: NistCurve = curve.try_into()?;
207                 let (x, y) = coordinates_from_pub_key(pub_key, nist_curve)?;
208                 let cose_nist_curve = match nist_curve {
209                     NistCurve::P224 => {
210                         // P-224 is not supported by COSE: there is no value in the COSE Elliptic
211                         // Curve registry for it.
212                         return Err(km_err!(Unimplemented, "no COSE support for P-224"));
213                     }
214                     NistCurve::P256 => coset::iana::EllipticCurve::P_256,
215                     NistCurve::P384 => coset::iana::EllipticCurve::P_384,
216                     NistCurve::P521 => coset::iana::EllipticCurve::P_521,
217                 };
218                 coset::CoseKeyBuilder::new_ec2_pub_key(cose_nist_curve, x, y).algorithm(nist_algo)
219             }
220             CurveType::EdDsa => coset::CoseKeyBuilder::new_okp_key()
221                 .param(
222                     coset::iana::OkpKeyParameter::Crv as i64,
223                     coset::cbor::value::Value::from(coset::iana::EllipticCurve::Ed25519 as u64),
224                 )
225                 .param(
226                     coset::iana::OkpKeyParameter::X as i64,
227                     coset::cbor::value::Value::from(pub_key),
228                 )
229                 .algorithm(coset::iana::Algorithm::EdDSA),
230             CurveType::Xdh => coset::CoseKeyBuilder::new_okp_key()
231                 .param(
232                     coset::iana::OkpKeyParameter::Crv as i64,
233                     coset::cbor::value::Value::from(coset::iana::EllipticCurve::X25519 as u64),
234                 )
235                 .param(
236                     coset::iana::OkpKeyParameter::X as i64,
237                     coset::cbor::value::Value::from(pub_key),
238                 )
239                 .algorithm(coset::iana::Algorithm::ECDH_ES_HKDF_256),
240         };
241 
242         if let Some(key_id) = key_id {
243             builder = builder.key_id(key_id);
244         }
245         if test_mode == rpc::TestMode(true) {
246             builder = builder.param(RKP_TEST_KEY_CBOR_MARKER, coset::cbor::value::Value::Null);
247         }
248         Ok(builder.build())
249     }
250 }
251 
252 /// Elliptic curve private key material.
253 #[derive(Clone, PartialEq, Eq)]
254 pub enum Key {
255     /// P-224 private key.
256     P224(NistKey),
257     /// P-256 private key.
258     P256(NistKey),
259     /// P-384 private key.
260     P384(NistKey),
261     /// P-521 private key.
262     P521(NistKey),
263     /// Ed25519 private key.
264     Ed25519(Ed25519Key),
265     /// X25519 private key.
266     X25519(X25519Key),
267 }
268 
269 /// Indication of the purpose for a COSE key.
270 pub enum CoseKeyPurpose {
271     /// ECDH key agreement.
272     Agree,
273     /// ECDSA signature generation.
274     Sign,
275 }
276 
277 impl Key {
278     /// Return the private key material.
private_key_bytes(&self) -> &[u8]279     pub fn private_key_bytes(&self) -> &[u8] {
280         match self {
281             Key::P224(key) => &key.0,
282             Key::P256(key) => &key.0,
283             Key::P384(key) => &key.0,
284             Key::P521(key) => &key.0,
285             Key::Ed25519(key) => &key.0,
286             Key::X25519(key) => &key.0,
287         }
288     }
289 
290     /// Return the type of curve.
curve_type(&self) -> CurveType291     pub fn curve_type(&self) -> CurveType {
292         match self {
293             Key::P224(_) | Key::P256(_) | Key::P384(_) | Key::P521(_) => CurveType::Nist,
294             Key::Ed25519(_) => CurveType::EdDsa,
295             Key::X25519(_) => CurveType::Xdh,
296         }
297     }
298 
299     /// Return the curve.
curve(&self) -> EcCurve300     pub fn curve(&self) -> EcCurve {
301         match self {
302             Key::P224(_) => EcCurve::P224,
303             Key::P256(_) => EcCurve::P256,
304             Key::P384(_) => EcCurve::P384,
305             Key::P521(_) => EcCurve::P521,
306             Key::Ed25519(_) => EcCurve::Curve25519,
307             Key::X25519(_) => EcCurve::Curve25519,
308         }
309     }
310 }
311 
312 /// A NIST EC key, in the form of an ASN.1 DER encoding of a `ECPrivateKey` structure,
313 /// as specified by RFC 5915 section 3:
314 ///
315 /// ```asn1
316 /// ECPrivateKey ::= SEQUENCE {
317 ///    version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
318 ///    privateKey     OCTET STRING,
319 ///    parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
320 ///    publicKey  [1] BIT STRING OPTIONAL
321 /// }
322 /// ```
323 #[derive(Clone, PartialEq, Eq, ZeroizeOnDrop)]
324 pub struct NistKey(pub Vec<u8>);
325 
326 /// Helper function to return the (x,y) coordinates, given the public key as a SEC-1 encoded
327 /// uncompressed point. 0x04: uncompressed, followed by x || y coordinates.
coordinates_from_pub_key( pub_key: Vec<u8>, curve: NistCurve, ) -> Result<(Vec<u8>, Vec<u8>), Error>328 pub fn coordinates_from_pub_key(
329     pub_key: Vec<u8>,
330     curve: NistCurve,
331 ) -> Result<(Vec<u8>, Vec<u8>), Error> {
332     let coord_len = curve.coord_len();
333     if pub_key.len() != (1 + 2 * coord_len) {
334         return Err(km_err!(
335             UnsupportedKeySize,
336             "unexpected SEC1 pubkey len of {} for {:?}",
337             pub_key.len(),
338             curve
339         ));
340     }
341     if pub_key[0] != SEC1_UNCOMPRESSED_PREFIX {
342         return Err(km_err!(
343             UnsupportedKeySize,
344             "unexpected SEC1 pubkey initial byte {} for {:?}",
345             pub_key[0],
346             curve
347         ));
348     }
349     Ok((try_to_vec(&pub_key[1..1 + coord_len])?, try_to_vec(&pub_key[1 + coord_len..])?))
350 }
351 
352 /// An Ed25519 private key.
353 #[derive(Clone, PartialEq, Eq, ZeroizeOnDrop)]
354 pub struct Ed25519Key(pub [u8; CURVE25519_PRIV_KEY_LEN]);
355 
356 /// An X25519 private key.
357 #[derive(Clone, PartialEq, Eq, ZeroizeOnDrop)]
358 pub struct X25519Key(pub [u8; CURVE25519_PRIV_KEY_LEN]);
359 
360 /// Return the OID used in an `AlgorithmIdentifier` for signatures produced by this curve.
curve_to_signing_oid(curve: EcCurve) -> pkcs8::ObjectIdentifier361 pub fn curve_to_signing_oid(curve: EcCurve) -> pkcs8::ObjectIdentifier {
362     match curve {
363         EcCurve::P224 | EcCurve::P256 | EcCurve::P384 | EcCurve::P521 => ECDSA_SHA256_SIGNATURE_OID,
364         EcCurve::Curve25519 => X509_ED25519_OID,
365     }
366 }
367 
368 /// Return the key size for a curve.
curve_to_key_size(curve: EcCurve) -> KeySizeInBits369 pub fn curve_to_key_size(curve: EcCurve) -> KeySizeInBits {
370     KeySizeInBits(match curve {
371         EcCurve::P224 => 224,
372         EcCurve::P256 => 256,
373         EcCurve::P384 => 384,
374         EcCurve::P521 => 521,
375         EcCurve::Curve25519 => 256,
376     })
377 }
378 
379 /// Import an NIST EC key in SEC1 ECPrivateKey format.
import_sec1_private_key(data: &[u8]) -> Result<KeyMaterial, Error>380 pub fn import_sec1_private_key(data: &[u8]) -> Result<KeyMaterial, Error> {
381     let ec_key = sec1::EcPrivateKey::from_der(data)
382         .map_err(|e| der_err!(e, "failed to parse ECPrivateKey"))?;
383     let ec_parameters = ec_key.parameters.ok_or_else(|| {
384         km_err!(InvalidArgument, "sec1 formatted EC private key didn't have a parameters field")
385     })?;
386     let parameters_oid = ec_parameters.named_curve().ok_or_else(|| {
387         km_err!(
388             InvalidArgument,
389             "couldn't retrieve parameters oid from sec1 ECPrivateKey formatted ec key parameters"
390         )
391     })?;
392     let algorithm =
393         AlgorithmIdentifier { oid: X509_NIST_OID, parameters: Some(AnyRef::from(&parameters_oid)) };
394     let pkcs8_key = pkcs8::PrivateKeyInfo::new(algorithm, data);
395     import_pkcs8_key_impl(&pkcs8_key)
396 }
397 
398 /// Import an EC key in PKCS#8 format.
import_pkcs8_key(data: &[u8]) -> Result<KeyMaterial, Error>399 pub fn import_pkcs8_key(data: &[u8]) -> Result<KeyMaterial, Error> {
400     let key_info = pkcs8::PrivateKeyInfo::try_from(data)
401         .map_err(|_| km_err!(InvalidArgument, "failed to parse PKCS#8 EC key"))?;
402     import_pkcs8_key_impl(&key_info)
403 }
404 
405 /// Import a `pkcs8::PrivateKeyInfo` EC key.
import_pkcs8_key_impl(key_info: &pkcs8::PrivateKeyInfo) -> Result<KeyMaterial, Error>406 fn import_pkcs8_key_impl(key_info: &pkcs8::PrivateKeyInfo) -> Result<KeyMaterial, Error> {
407     let algo_params = key_info.algorithm.parameters;
408     match key_info.algorithm.oid {
409         X509_NIST_OID => {
410             let algo_params = algo_params.ok_or_else(|| {
411                 km_err!(
412                     InvalidArgument,
413                     "missing PKCS#8 parameters for NIST curve import under OID {:?}",
414                     key_info.algorithm.oid
415                 )
416             })?;
417             let curve_oid = algo_params
418                 .decode_as()
419                 .map_err(|_e| km_err!(InvalidArgument, "imported key has no OID parameter"))?;
420             let (curve, key) = match curve_oid {
421                 ALGO_PARAM_P224_OID => {
422                     (EcCurve::P224, Key::P224(NistKey(try_to_vec(key_info.private_key)?)))
423                 }
424                 ALGO_PARAM_P256_OID => {
425                     (EcCurve::P256, Key::P256(NistKey(try_to_vec(key_info.private_key)?)))
426                 }
427                 ALGO_PARAM_P384_OID => {
428                     (EcCurve::P384, Key::P384(NistKey(try_to_vec(key_info.private_key)?)))
429                 }
430                 ALGO_PARAM_P521_OID => {
431                     (EcCurve::P521, Key::P521(NistKey(try_to_vec(key_info.private_key)?)))
432                 }
433                 oid => {
434                     return Err(km_err!(
435                         ImportParameterMismatch,
436                         "imported key has unknown OID {:?}",
437                         oid,
438                     ))
439                 }
440             };
441             Ok(KeyMaterial::Ec(curve, CurveType::Nist, key.into()))
442         }
443         X509_ED25519_OID => {
444             if algo_params.is_some() {
445                 Err(km_err!(InvalidArgument, "unexpected PKCS#8 parameters for Ed25519 import"))
446             } else {
447                 // For Ed25519 the PKCS#8 `privateKey` field holds a `CurvePrivateKey`
448                 // (RFC 8410 s7) that is an OCTET STRING holding the raw key.  As this is DER,
449                 // this is just a 2 byte prefix (0x04 = OCTET STRING, 0x20 = length of raw key).
450                 if key_info.private_key.len() != 2 + CURVE25519_PRIV_KEY_LEN
451                     || key_info.private_key[0] != 0x04
452                     || key_info.private_key[1] != 0x20
453                 {
454                     return Err(km_err!(InvalidArgument, "unexpected CurvePrivateKey contents"));
455                 }
456                 import_raw_ed25519_key(&key_info.private_key[2..])
457             }
458         }
459         X509_X25519_OID => {
460             if algo_params.is_some() {
461                 Err(km_err!(InvalidArgument, "unexpected PKCS#8 parameters for X25519 import",))
462             } else {
463                 // For X25519 the PKCS#8 `privateKey` field holds a `CurvePrivateKey`
464                 // (RFC 8410 s7) that is an OCTET STRING holding the raw key.  As this is DER,
465                 // this is just a 2 byte prefix (0x04 = OCTET STRING, 0x20 = length of raw key).
466                 if key_info.private_key.len() != 2 + CURVE25519_PRIV_KEY_LEN
467                     || key_info.private_key[0] != 0x04
468                     || key_info.private_key[1] != 0x20
469                 {
470                     return Err(km_err!(InvalidArgument, "unexpected CurvePrivateKey contents"));
471                 }
472                 import_raw_x25519_key(&key_info.private_key[2..])
473             }
474         }
475         _ => Err(km_err!(
476             InvalidArgument,
477             "unexpected OID {:?} for PKCS#8 EC key import",
478             key_info.algorithm.oid,
479         )),
480     }
481 }
482 
483 /// Import a 32-byte raw Ed25519 key.
import_raw_ed25519_key(data: &[u8]) -> Result<KeyMaterial, Error>484 pub fn import_raw_ed25519_key(data: &[u8]) -> Result<KeyMaterial, Error> {
485     let key = data.try_into().map_err(|_e| {
486         km_err!(InvalidInputLength, "import Ed25519 key of incorrect len {}", data.len())
487     })?;
488     Ok(KeyMaterial::Ec(EcCurve::Curve25519, CurveType::EdDsa, Key::Ed25519(Ed25519Key(key)).into()))
489 }
490 
491 /// Import a 32-byte raw X25519 key.
import_raw_x25519_key(data: &[u8]) -> Result<KeyMaterial, Error>492 pub fn import_raw_x25519_key(data: &[u8]) -> Result<KeyMaterial, Error> {
493     let key = data.try_into().map_err(|_e| {
494         km_err!(InvalidInputLength, "import X25519 key of incorrect len {}", data.len())
495     })?;
496     Ok(KeyMaterial::Ec(EcCurve::Curve25519, CurveType::Xdh, Key::X25519(X25519Key(key)).into()))
497 }
498 
499 /// Convert a signature as emitted from the `Ec` trait into the form needed for
500 /// a `COSE_Sign1`.
to_cose_signature(curve: EcCurve, sig: Vec<u8>) -> Result<Vec<u8>, Error>501 pub fn to_cose_signature(curve: EcCurve, sig: Vec<u8>) -> Result<Vec<u8>, Error> {
502     match curve {
503         EcCurve::P224 | EcCurve::P256 | EcCurve::P384 | EcCurve::P521 => {
504             // NIST curve signatures are emitted as a DER-encoded `SEQUENCE`.
505             let der_sig = NistSignature::from_der(&sig)
506                 .map_err(|e| km_err!(EncodingError, "failed to parse DER signature: {:?}", e))?;
507             // COSE expects signature of (r||s) with each value left-padded with zeros to coordinate
508             // size.
509             let nist_curve = NistCurve::try_from(curve)?;
510             let l = nist_curve.coord_len();
511             let mut sig = vec_try![0; 2 * l]?;
512             let r = der_sig.r.as_bytes();
513             let s = der_sig.s.as_bytes();
514             let r_offset = l - r.len();
515             let s_offset = l + l - s.len();
516             sig[r_offset..r_offset + r.len()].copy_from_slice(r);
517             sig[s_offset..s_offset + s.len()].copy_from_slice(s);
518             Ok(sig)
519         }
520         EcCurve::Curve25519 => {
521             // Ed25519 signatures can be used as-is (RFC 8410 section 6)
522             Ok(sig)
523         }
524     }
525 }
526 
527 /// Convert a signature as used in a `COSE_Sign1` into the form needed for the `Ec` trait.
from_cose_signature(curve: EcCurve, sig: &[u8]) -> Result<Vec<u8>, Error>528 pub fn from_cose_signature(curve: EcCurve, sig: &[u8]) -> Result<Vec<u8>, Error> {
529     match curve {
530         EcCurve::P224 | EcCurve::P256 | EcCurve::P384 | EcCurve::P521 => {
531             // COSE signatures are (r||s) with each value left-padded with zeros to coordinate size.
532             let nist_curve = NistCurve::try_from(curve)?;
533             let l = nist_curve.coord_len();
534             if sig.len() != 2 * l {
535                 return Err(km_err!(
536                     EncodingError,
537                     "unexpected len {} for {:?} COSE signature value",
538                     sig.len(),
539                     nist_curve
540                 ));
541             }
542 
543             // NIST curve signatures need to be emitted as a DER-encoded `SEQUENCE`.
544             let der_sig = NistSignature {
545                 r: der::asn1::UintRef::new(&sig[..l])
546                     .map_err(|e| km_err!(EncodingError, "failed to build INTEGER: {:?}", e))?,
547                 s: der::asn1::UintRef::new(&sig[l..])
548                     .map_err(|e| km_err!(EncodingError, "failed to build INTEGER: {:?}", e))?,
549             };
550             der_sig
551                 .to_der()
552                 .map_err(|e| km_err!(EncodingError, "failed to encode signature SEQUENCE: {:?}", e))
553         }
554         EcCurve::Curve25519 => {
555             // Ed25519 signatures can be used as-is (RFC 8410 section 6)
556             try_to_vec(sig)
557         }
558     }
559 }
560 
561 /// DER-encoded signature from a NIST curve (RFC 3279 section 2.2.3):
562 /// ```asn1
563 /// Ecdsa-Sig-Value  ::=  SEQUENCE  {
564 ///      r     INTEGER,
565 ///      s     INTEGER
566 /// }
567 /// ```
568 #[derive(Sequence)]
569 struct NistSignature<'a> {
570     r: der::asn1::UintRef<'a>,
571     s: der::asn1::UintRef<'a>,
572 }
573 
574 #[cfg(test)]
575 mod tests {
576     use super::*;
577     #[test]
test_sig_decode()578     fn test_sig_decode() {
579         let sig_data = hex::decode("3045022001b309d5eeffa5d550bde27630f9fc7f08492e4617bc158da08b913414cf675b022100fcdca2e77d036c33fa78f4a892b98569358d83c047a7d8a74ce6fe12fbf919c6").unwrap();
580         let sig = NistSignature::from_der(&sig_data).expect("sequence should decode");
581         assert_eq!(
582             hex::encode(sig.r.as_bytes()),
583             "01b309d5eeffa5d550bde27630f9fc7f08492e4617bc158da08b913414cf675b"
584         );
585         assert_eq!(
586             hex::encode(sig.s.as_bytes()),
587             "fcdca2e77d036c33fa78f4a892b98569358d83c047a7d8a74ce6fe12fbf919c6"
588         );
589     }
590 
591     #[test]
test_longer_sig_transmute()592     fn test_longer_sig_transmute() {
593         let nist_sig_data = hex::decode(concat!(
594             "30", // SEQUENCE
595             "45", // len
596             "02", // INTEGER
597             "20", // len = 32
598             "01b309d5eeffa5d550bde27630f9fc7f08492e4617bc158da08b913414cf675b",
599             "02", // INTEGER
600             "21", // len = 33 (high bit set so leading zero needed)
601             "00fcdca2e77d036c33fa78f4a892b98569358d83c047a7d8a74ce6fe12fbf919c6"
602         ))
603         .unwrap();
604         let cose_sig_data = to_cose_signature(EcCurve::P256, nist_sig_data.clone()).unwrap();
605         assert_eq!(
606             concat!(
607                 "01b309d5eeffa5d550bde27630f9fc7f08492e4617bc158da08b913414cf675b",
608                 "fcdca2e77d036c33fa78f4a892b98569358d83c047a7d8a74ce6fe12fbf919c6"
609             ),
610             hex::encode(&cose_sig_data),
611         );
612         let got_nist_sig = from_cose_signature(EcCurve::P256, &cose_sig_data).unwrap();
613         assert_eq!(got_nist_sig, nist_sig_data);
614     }
615 
616     #[test]
test_short_sig_transmute()617     fn test_short_sig_transmute() {
618         let nist_sig_data = hex::decode(concat!(
619             "30", // SEQUENCE
620             "43", // len x44
621             "02", // INTEGER
622             "1e", // len = 30
623             "09d5eeffa5d550bde27630f9fc7f08492e4617bc158da08b913414cf675b",
624             "02", // INTEGER
625             "21", // len = 33 (high bit set so leading zero needed)
626             "00fcdca2e77d036c33fa78f4a892b98569358d83c047a7d8a74ce6fe12fbf919c6"
627         ))
628         .unwrap();
629         let cose_sig_data = to_cose_signature(EcCurve::P256, nist_sig_data.clone()).unwrap();
630         assert_eq!(
631             concat!(
632                 "000009d5eeffa5d550bde27630f9fc7f08492e4617bc158da08b913414cf675b",
633                 "fcdca2e77d036c33fa78f4a892b98569358d83c047a7d8a74ce6fe12fbf919c6"
634             ),
635             hex::encode(&cose_sig_data),
636         );
637         let got_nist_sig = from_cose_signature(EcCurve::P256, &cose_sig_data).unwrap();
638         assert_eq!(got_nist_sig, nist_sig_data);
639     }
640 
641     #[test]
test_sec1_ec_import()642     fn test_sec1_ec_import() {
643         // Key data created with:
644         // ```
645         // openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem
646         // ```
647         let key_data = hex::decode(concat!(
648             "3077",   // SEQUENCE len x77 (ECPrivateKey)
649             "020101", // INTEGER 1 = (ecPrivkeyVer1)
650             "0420",   // OCTET STRING len x20 (privateKey)
651             "a6a30ca3dc87b58763736400e7e86260",
652             "9e8311f41e6b89888c33753218168517",
653             "a00a",             // [0] len x0a (parameters)
654             "0608",             // OBJECT IDENTIFIER len 8 (NamedCurve)
655             "2a8648ce3d030107", // 1.2.840.10045.3.1.7=secp256r1
656             "a144",             // [1] len x44 (publicKey)
657             "0342",             // BIT STRING len x42
658             "00",               // no pad bits
659             "0481e4ce20d8be3dd40b940b3a3ba3e8",
660             "cf5a3f2156eceb4debb8fce83cbe4a48",
661             "bd576a03eebf77d329a438fcdc509f37",
662             "1f092cad41e2ecf9f25cd82f31500f33",
663             "8e"
664         ))
665         .unwrap();
666         let key = import_sec1_private_key(&key_data).expect("SEC1 parse failed");
667         if let KeyMaterial::Ec(curve, curve_type, _key) = key {
668             assert_eq!(curve, EcCurve::P256);
669             assert_eq!(curve_type, CurveType::Nist);
670         } else {
671             panic!("unexpected key type");
672         }
673     }
674 }
675