use rand_core::{OsRng, RngCore};
#[repr(u16)]
pub enum Kind {
Shared = 1,
Symmetric = 2,
Symmetric32Nonce = 3,
Ed255 = 4,
P256 = 5,
X255 = 6,
}
fn trussed_serialized_key(sensitive: bool, kind: Kind, material: &[u8]) -> Vec<u8> {
let mut buffer = Vec::new();
let mut flags = 0u16;
if sensitive {
flags |= 2;
}
buffer.extend_from_slice(flags.to_be_bytes().as_ref());
buffer.extend_from_slice((kind as u16).to_be_bytes().as_ref());
buffer.extend_from_slice(material);
buffer
}
pub fn generate_selfsigned_fido() -> ([u8; 16], [u8; 36], String, rcgen::Certificate) {
let alg = &rcgen::PKCS_ECDSA_P256_SHA256;
let mut aaguid = [0u8; 16];
OsRng.fill_bytes(&mut aaguid);
let keypair = rcgen::KeyPair::generate(alg).unwrap();
let key_pkcs8 = keypair.serialize_der();
let key_pem = keypair.serialize_pem();
let key_info: p256::pkcs8::PrivateKeyInfo = key_pkcs8.as_slice().try_into().unwrap();
let secret_key: [u8; 32] = p256::SecretKey::try_from(key_info)
.unwrap()
.to_be_bytes()
.try_into()
.unwrap();
let sensitive = true;
let kind = Kind::P256;
let key_trussed: [u8; 36] = trussed_serialized_key(sensitive, kind, secret_key.as_ref())
.try_into()
.unwrap();
let mut tbs = rcgen::CertificateParams::default();
tbs.alg = alg;
tbs.serial_number = Some(OsRng.next_u64());
let now = time::OffsetDateTime::now_utc();
tbs.not_before = now;
tbs.not_after = now + time::Duration::days(50 * 365);
let mut subject = rcgen::DistinguishedName::new();
subject.push(rcgen::DnType::CountryName, "AQ");
subject.push(rcgen::DnType::OrganizationName, "Example Vendor");
subject.push(
rcgen::DnType::OrganizationalUnitName,
"Authenticator Attestation",
);
subject.push(rcgen::DnType::CommonName, "example.com");
tbs.distinguished_name = subject;
tbs.key_pair = Some(keypair);
tbs.is_ca = rcgen::IsCa::NoCa;
tbs.use_authority_key_identifier_extension = true;
let extensions = vec![
rcgen::CustomExtension::from_oid_content(
&[1, 3, 6, 1, 4, 1, 45724, 1, 1, 4],
yasna::construct_der(|writer| writer.write_bytes(aaguid.as_ref())),
),
];
tbs.custom_extensions = extensions;
let cert = rcgen::Certificate::from_params(tbs).unwrap();
(aaguid, key_trussed, key_pem, cert)
}