• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! This module contains the Endpoint Encryption Keys (EEK) utilities for encrypting
2 //! factory payloads for CSR versions 1 & 2. EEK usage was dropped for CSR v3.
3 //!
4 //! NOTE: Since CSR version 3 drops the encryption requirement, Google is publishing
5 //! the private Google EEKs so that testing on platforms that support CSR versions
6 //! 1 & 2 have diagnostic parity with CSR v3 systems.
7 
8 use anyhow::{bail, Context, Result};
9 use coset::{CborSerializable, CoseKdfContextBuilder, Nonce, PartyInfo, SuppPubInfoBuilder};
10 use openssl::{
11     bn::{BigNum, BigNumContext},
12     derive::Deriver,
13     ec::{EcGroup, EcKey, EcPoint, PointConversionForm},
14     md::Md,
15     nid::Nid,
16     pkey::{HasPublic, Id, PKey, PKeyRef, Private, Public},
17     pkey_ctx::PkeyCtx,
18 };
19 
20 pub const X25519_EEK_ID: &[u8] = b"\xd0\xae\xc1\x15\xca\x2a\xcf\x73\xae\x6b\xcc\xcb\xd1\x96\x1d\x65\xe8\xb1\xdd\xd7\x4a\x1a\x37\xb9\x43\x3a\x97\xd5\x99\xdf\x98\x08";
21 // X25519_EEK_PUBLIC_X: b"\xbe\x85\xe7\x46\xc4\xa3\x42\x5a\x40\xd9\x36\x3a\xa6\x15\xd0\x2c\x58\x7e\x3d\xdc\x33\x02\x32\xd2\xfc\x5e\x1e\x87\x25\x5f\x72\x60";
22 pub const X25519_EEK_PRIVATE: &[u8] = b"\x47\x66\x65\xdb\xaa\xe1\x1d\xdb\xd3\x03\xf7\xad\x68\xbb\xff\x8d\x90\xaf\x8a\x4f\xb8\xbf\x7c\xf3\x39\xc7\xe9\x73\xec\x70\x75\x8c";
23 
24 pub const P256_EEK_ID: &[u8] = b"\x35\x73\xb7\x3f\xa0\x8a\x80\x89\xb1\x26\x67\xe9\xcb\x7c\x75\xa1\xaf\x02\x61\xfc\x6e\x65\x03\x91\x3b\xd3\x4b\x7d\x14\x94\x3e\x46";
25 pub const P256_EEK_PUBLIC_X: &[u8] = b"\xe0\x41\xcf\x2f\x0f\x34\x0f\x1c\x33\x2c\x41\xb0\xcf\xd7\x0c\x30\x55\x35\xd2\x1e\x6a\x47\x13\x4b\x2e\xd1\x48\x96\x7e\x24\x9c\x68";
26 pub const P256_EEK_PUBLIC_Y: &[u8] = b"\x1f\xce\x45\xc5\xfb\x61\xba\x81\x21\xf9\xe5\x05\x9b\x9b\x39\x0e\x76\x86\x86\x47\xb8\x1e\x2f\x45\xf1\xce\xaf\xda\x3f\x80\x68\xdb";
27 pub const P256_EEK_PRIVATE: &[u8] = b"\x00\xd1\x0a\x51\x59\xb2\xa0\x39\x43\xc8\x58\xf1\xdc\x3f\xc4\x0a\x03\x39\x31\x9d\x34\x01\x8f\x30\xa9\xc4\x46\x7e\x64\x61\x35\x6d\xdf";
28 
29 /// Get the well-known P256 GEEK private key.
p256_geek() -> PKey<Private>30 pub fn p256_geek() -> PKey<Private> {
31     let p256 = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
32     let private = BigNum::from_slice(P256_EEK_PRIVATE).unwrap();
33     let mut public_key = EcPoint::new(&p256).unwrap();
34     public_key
35         .set_affine_coordinates_gfp(
36             &p256,
37             &BigNum::from_slice(P256_EEK_PUBLIC_X).unwrap(),
38             &BigNum::from_slice(P256_EEK_PUBLIC_Y).unwrap(),
39             &mut BigNumContext::new().unwrap(),
40         )
41         .unwrap();
42 
43     let ec_key = EcKey::from_private_components(&p256, &private, &public_key).unwrap();
44     PKey::from_ec_key(ec_key).unwrap()
45 }
46 
47 /// Get the well-known X25519 GEEK private key.
x25519_geek() -> PKey<Private>48 pub fn x25519_geek() -> PKey<Private> {
49     PKey::private_key_from_raw_bytes(X25519_EEK_PRIVATE, Id::X25519).unwrap()
50 }
51 
derive_ephemeral_symmetric_key( private: &PKeyRef<Private>, public: &PKeyRef<Public>, ) -> Result<[u8; 32]>52 pub fn derive_ephemeral_symmetric_key(
53     private: &PKeyRef<Private>,
54     public: &PKeyRef<Public>,
55 ) -> Result<[u8; 32]> {
56     let mut deriver = Deriver::new(private)?;
57     deriver.set_peer(public)?;
58     let shared_secret = deriver.derive_to_vec()?;
59 
60     let supp_pub_info = SuppPubInfoBuilder::new().key_data_length(256).build();
61 
62     let context = CoseKdfContextBuilder::new()
63         .algorithm(coset::iana::Algorithm::A256GCM)
64         .party_u_info(kdf_party_info(b"client", public)?)
65         .party_v_info(kdf_party_info(b"server", private)?)
66         .supp_pub_info(supp_pub_info)
67         .build();
68     let hkdf_info = match context.to_vec() {
69         Ok(v) => v,
70         Err(e) => bail!("Error serializing COSE_KDF_Context: {e}"),
71     };
72 
73     let mut kdf = PkeyCtx::new_id(Id::HKDF)?;
74     kdf.derive_init()?;
75     kdf.set_hkdf_key(&shared_secret)?;
76     kdf.set_hkdf_md(Md::sha256())?;
77     kdf.add_hkdf_info(&hkdf_info)?;
78 
79     let mut derived_key = [0; 32];
80     kdf.derive(Some(&mut derived_key))?;
81     Ok(derived_key)
82 }
83 
kdf_party_info<T: HasPublic>(identity: &[u8], key: &PKeyRef<T>) -> Result<PartyInfo>84 fn kdf_party_info<T: HasPublic>(identity: &[u8], key: &PKeyRef<T>) -> Result<PartyInfo> {
85     Ok(PartyInfo {
86         identity: Some(identity.to_vec()),
87         nonce: Some(Nonce::Bytes(vec![])),
88         other: Some(raw_key_bytes(key)?),
89     })
90 }
91 
raw_key_bytes<T: HasPublic>(key: &PKeyRef<T>) -> Result<Vec<u8>>92 fn raw_key_bytes<T: HasPublic>(key: &PKeyRef<T>) -> Result<Vec<u8>> {
93     match key.id() {
94         Id::X25519 => key.raw_public_key().context("Unable to fetch raw public key"),
95         Id::EC => {
96             let ec = key.ec_key()?;
97             let mut ctx = BigNumContext::new()?;
98             let mut uncompressed = ec.public_key().to_bytes(
99                 ec.group(),
100                 PointConversionForm::UNCOMPRESSED,
101                 &mut ctx,
102             )?;
103             // uncompressed format is '04 | X | Y'. For KDF purposes, we just want 'X | Y'
104             uncompressed.remove(0);
105             Ok(uncompressed)
106         }
107         other => bail!("Unsupported public key type {other:?}"),
108     }
109 }
110