Reputation: 121
i have stucked to extract the Auth Data from Webauth api attention into Public Key
for this case i am using coset, openssl, ciborium to extract the public key and cose key
here is how i implement to extract public key from cose
pub(super) fn extract_public_key_from_cose(&self, cose_key_value: ciborium::value::Value) -> Option<Vec<u8>> {
if let ciborium::value::Value::Map(cose_key_map) = cose_key_value {
let mut cose_key_builder: CoseKeyBuilder = CoseKeyBuilder::new();
for (key, value) in cose_key_map {
if let ciborium::value::Value::Integer(param) = key {
if param == Integer::from(1) {
if let ciborium::value::Value::Integer(kty) = value {
cose_key_builder = cose_key_builder.kty(KeyType::Assigned(iana::KeyType::from_i64(kty.try_into().ok()?)?));
}
} else if param == Integer::from(3) {
if let ciborium::value::Value::Integer(alg) = value {
cose_key_builder = cose_key_builder.algorithm(iana::Algorithm::from_i64(alg.try_into().ok()?)?);
}
} else if param == Integer::from(-2) {
if let ciborium::value::Value::Bytes(x) = value {
cose_key_builder = cose_key_builder.param(-2, ciborium::value::Value::Bytes(x));
}
} else if param == Integer::from(-3) {
if let ciborium::value::Value::Bytes(y) = value {
cose_key_builder = cose_key_builder.param(-3, ciborium::value::Value::Bytes(y));
}
}
}
}
let cose_key: CoseKey = cose_key_builder.build();
let cbor_key: Vec<u8> = cose_key.to_cbor_value().unwrap().to_vec().unwrap();
return Some(cbor_key);
}
None
}
and using that extract on this function
pub(super) fn extract_public_key(&self, auth_data: &[u8]) -> Option<Vec<u8>> {
// The length of the authenticator data is at least 37 bytes
if auth_data.len() < 37 {
return None;
}
// The attestedCredentialData starts at byte 37
let attested_credential_data = &auth_data[37..];
// The AAGUID is 16 bytes, and the credential ID length is 2 bytes
let aaguid_length = 16;
let credential_id_length = 2;
// Ensure there is enough data for the AAGUID and credential ID length
if attested_credential_data.len() < aaguid_length + credential_id_length {
return None;
}
// Extract the credential ID length
let credential_id_length = u16::from_be_bytes([
attested_credential_data[aaguid_length],
attested_credential_data[aaguid_length + 1],
]) as usize;
// Ensure there is enough data for the credential ID and public key
let public_key_start = aaguid_length + 2 + credential_id_length;
if attested_credential_data.len() <= public_key_start {
return None;
}
// Extract the public key in COSE format
let public_key_cose = &attested_credential_data[public_key_start..];
// Manually deserialize the COSE key
let mut cursor = Cursor::new(public_key_cose);
let cose_key_value: ciborium::Value = match ciborium::from_reader(&mut cursor) {
Ok(value) => value,
Err(e) => {
println!("Failed to deserialize public_key_cose: {:?}", e);
return None;
}
};
// Extract the public key from the COSE key
self.extract_public_key_from_cose(cose_key_value)
}
and than i did the core thing here
// Extract the public key from authData
let public_key = if let ciborium::Value::Bytes(ref auth_data_bytes) = auth_data {
self.extract_public_key(auth_data_bytes)
} else {
return Err("Invalid authData format".into());
};
let auth_data_bytes = if let ciborium::Value::Bytes(auth_data_bytes) = auth_data {
auth_data_bytes.clone()
} else {
println!("Invalid authData format");
return Err("Invalid authData format".into());
};
let mut signature_base = Vec::new();
signature_base.extend_from_slice(&auth_data_bytes);
signature_base.extend_from_slice(client_data_json);
// Verify the signature using the public key
return self.verify_signature_with_public_key(sig, &signature_base, &public_key.unwrap(), alg);
let public_key = openssl::pkey::PKey::public_key_from_der(public_key)?;
let message_digest = match alg {
-7 => openssl::hash::MessageDigest::sha256(),
-35 => openssl::hash::MessageDigest::sha384(),
-36 => openssl::hash::MessageDigest::sha512(),
_ => return Err("Unsupported algorithm".into()),
};
let mut verifier = openssl::sign::Verifier::new(message_digest, &public_key)?;
verifier.update(data)?;
Ok(verifier.verify(&sig)?)
i got error this
error:068000A8:asn1 encoding routines:asn1_check_tlen:wrong
tag:crypto/asn1/tasn_dec.c:1194:, error:0688010A:asn1 encoding
routines:asn1_item_embed_d2i:nested asn1 error:crypto/asn1/tasn_dec.c:349:Type=X509_PUBKEY
did i wrong implementation ? or how i extract_public_key_from_cose
was wrong to be DER
format ?
the error is from this:
let public_key = openssl::pkey::PKey::public_key_from_der(public_key)?;
Upvotes: 0
Views: 70
Reputation: 1682
I don't know these libraries, but the core seems to be:
let cbor_key: Vec<u8> = cose_key.to_cbor_value().unwrap().to_vec().unwrap();
So it looks like you're parsing a COSE key and then reencoding it in COSE format. public_key_from_der
probably wants a public key in SubjectPublicKeyInfo format.
Perhaps the libraries that you're using offer a way to do that conversion, but if you're dealing only with COSE algorithm -7, then you can check the kty (with key 1) is 2, that the alg (with key 3) is -7, and that the curve (with key -1) is 1. If all that's true then it's algorithm -7 and you can take 32-byte x and y strings from keys -2 and -3. Then the SPKI can be formed by concatenating 3059301306072a8648ce3d020106082a8648ce3d03010703420004
followed by the x and y values.
Upvotes: 0