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