mirror of
https://github.com/saymrwulf/anza-cryptography-source.git
synced 2026-09-04 20:24:04 +00:00
Validate SPKI OID/bytes and add pkcs8 tests (#43)
Add strict SPKI validation and tests for PKCS#8 public keys. Introduce OID and ALGORITHM_ID constants and refactor SPKI parsing into verification_key_bytes_from_spki which verifies the algorithm OID, parameters, and key byte length/format, returning appropriate pkcs8::spki::Error values. Update TryFrom/EncodePublicKey/DecodePublicKey implementations to use the new helper and to propagate/mapping errors correctly. Add two tests (behind the pkcs8 feature) to assert rejection of SPKI docs with the wrong algorithm OID and with malformed key bytes.
This commit is contained in:
parent
34a01d5b75
commit
c41adab68f
2 changed files with 76 additions and 10 deletions
|
|
@ -78,6 +78,45 @@ fn decode_der_to_verification_key() {
|
|||
assert_eq!(hex::decode(vk_bytes_string).unwrap(), vk.as_ref());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "pkcs8")]
|
||||
fn reject_public_key_der_with_wrong_algorithm_oid() {
|
||||
let vk = VerificationKey::from_public_key_der(PUBLIC_KEY_DER).unwrap();
|
||||
let oid = pkcs8::ObjectIdentifier::new_unwrap("1.3.101.110"); // X25519
|
||||
let spki = pkcs8::spki::SubjectPublicKeyInfoRef {
|
||||
algorithm: pkcs8::spki::AlgorithmIdentifierRef {
|
||||
oid,
|
||||
parameters: None,
|
||||
},
|
||||
subject_public_key: pkcs8::der::asn1::BitStringRef::from_bytes(vk.as_ref()).unwrap(),
|
||||
};
|
||||
let doc = pkcs8::Document::try_from(spki).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
VerificationKey::from_public_key_der(doc.as_bytes()).unwrap_err(),
|
||||
pkcs8::spki::Error::OidUnknown { oid }
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "pkcs8")]
|
||||
fn reject_public_key_der_with_malformed_key_bytes() {
|
||||
let oid = pkcs8::ObjectIdentifier::new_unwrap("1.3.101.112"); // Ed25519
|
||||
let spki = pkcs8::spki::SubjectPublicKeyInfoRef {
|
||||
algorithm: pkcs8::spki::AlgorithmIdentifierRef {
|
||||
oid,
|
||||
parameters: None,
|
||||
},
|
||||
subject_public_key: pkcs8::der::asn1::BitStringRef::from_bytes(&[0u8; 31]).unwrap(),
|
||||
};
|
||||
let doc = pkcs8::Document::try_from(spki).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
VerificationKey::from_public_key_der(doc.as_bytes()).unwrap_err(),
|
||||
pkcs8::spki::Error::KeyMalformed
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "pem")]
|
||||
fn decode_doc_to_verification_key() {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ use ed25519::{Signature, signature::Verifier};
|
|||
use pkcs8::der::asn1::BitStringRef;
|
||||
#[cfg(feature = "pkcs8")]
|
||||
use pkcs8::spki::{
|
||||
AlgorithmIdentifierRef, DecodePublicKey, EncodePublicKey, SubjectPublicKeyInfoRef,
|
||||
AlgorithmIdentifierRef, DecodePublicKey, EncodePublicKey, Error as SpkiError,
|
||||
SubjectPublicKeyInfoRef,
|
||||
};
|
||||
#[cfg(feature = "pkcs8")]
|
||||
use pkcs8::{Document, ObjectIdentifier};
|
||||
|
|
@ -38,6 +39,14 @@ use super::{Error, scalar_from_sha512};
|
|||
/// The length of an ed25519 `VerificationKey`, in bytes.
|
||||
pub const VERIFICATION_KEY_LENGTH: usize = 32;
|
||||
|
||||
#[cfg(feature = "pkcs8")]
|
||||
const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.101.112"); // RFC 8410
|
||||
#[cfg(feature = "pkcs8")]
|
||||
const ALGORITHM_ID: AlgorithmIdentifierRef<'_> = AlgorithmIdentifierRef {
|
||||
oid: OID,
|
||||
parameters: None,
|
||||
};
|
||||
|
||||
const LEGACY_EXCLUDED_R_ENCODINGS: [[u8; 32]; 11] = [
|
||||
[
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
|
@ -163,10 +172,32 @@ impl<'a> TryFrom<SubjectPublicKeyInfoRef<'a>> for VerificationKeyBytes {
|
|||
type Error = Error;
|
||||
|
||||
fn try_from(spki: SubjectPublicKeyInfoRef<'a>) -> Result<VerificationKeyBytes, Error> {
|
||||
Ok(VerificationKeyBytes::try_from(spki.subject_public_key.as_bytes().unwrap()).unwrap())
|
||||
verification_key_bytes_from_spki(spki).map_err(|_| Error::MalformedPublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "pkcs8")]
|
||||
fn verification_key_bytes_from_spki(
|
||||
spki: SubjectPublicKeyInfoRef<'_>,
|
||||
) -> Result<VerificationKeyBytes, SpkiError> {
|
||||
if spki.algorithm.oid != OID {
|
||||
return Err(SpkiError::OidUnknown {
|
||||
oid: spki.algorithm.oid,
|
||||
});
|
||||
}
|
||||
|
||||
if spki.algorithm != ALGORITHM_ID {
|
||||
return Err(SpkiError::KeyMalformed);
|
||||
}
|
||||
|
||||
let bytes = spki
|
||||
.subject_public_key
|
||||
.as_bytes()
|
||||
.ok_or(SpkiError::KeyMalformed)?;
|
||||
|
||||
VerificationKeyBytes::try_from(bytes).map_err(|_| SpkiError::KeyMalformed)
|
||||
}
|
||||
|
||||
/// A valid Ed25519 verification key.
|
||||
///
|
||||
/// This is also called a public key by other implementations.
|
||||
|
|
@ -262,12 +293,8 @@ impl TryFrom<[u8; 32]> for VerificationKey {
|
|||
impl EncodePublicKey for VerificationKey {
|
||||
/// Serialize [`VerificationKey`] to an ASN.1 DER-encoded document.
|
||||
fn to_public_key_der(&self) -> pkcs8::spki::Result<Document> {
|
||||
let alg_info = AlgorithmIdentifierRef {
|
||||
oid: ObjectIdentifier::new_unwrap("1.3.101.112"), // RFC 8410
|
||||
parameters: None,
|
||||
};
|
||||
SubjectPublicKeyInfoRef {
|
||||
algorithm: alg_info,
|
||||
algorithm: ALGORITHM_ID,
|
||||
subject_public_key: BitStringRef::from_bytes(&self.A_bytes.0[..])?,
|
||||
}
|
||||
.try_into()
|
||||
|
|
@ -278,9 +305,9 @@ impl EncodePublicKey for VerificationKey {
|
|||
impl DecodePublicKey for VerificationKey {
|
||||
/// Deserialize [`VerificationKey`] from ASN.1 DER bytes (32 bytes).
|
||||
fn from_public_key_der(bytes: &[u8]) -> Result<Self, pkcs8::spki::Error> {
|
||||
let spki = SubjectPublicKeyInfoRef::try_from(bytes).unwrap();
|
||||
let pk_bytes = spki.subject_public_key.as_bytes().unwrap();
|
||||
Ok(Self::try_from(pk_bytes).unwrap())
|
||||
let spki = SubjectPublicKeyInfoRef::try_from(bytes)?;
|
||||
let pk_bytes = verification_key_bytes_from_spki(spki)?;
|
||||
Self::try_from(pk_bytes).map_err(|_| SpkiError::KeyMalformed)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue