| // Copyright 2026 The BoringSSL Authors | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| //! PKI definitions for TLS | |
| use core::{ | |
| fmt::{Debug, Formatter, Result as FmtResult}, | |
| marker::PhantomData, | |
| }; | |
| use bssl_crypto::{digest, ec, ecdsa, ed25519, rsa}; | |
| use rustls::pki_types::{ | |
| AlgorithmIdentifier, InvalidSignature, SignatureVerificationAlgorithm, alg_id, | |
| }; | |
| use crate::RsaSignatureDigest; | |
| /// A PKI object with assigned Object Identifier | |
| pub(crate) trait PkiIdentified { | |
| /// The assigned identifier | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier; | |
| } | |
| /// PKI Verification algorithm | |
| pub(crate) trait PkiPublicKeyAlgorithm: PkiIdentified { | |
| /// Public key type that operates based on the identified algorithm. | |
| type PublicKey; | |
| /// Decode a signature public key from a `subjectPublicKey` field. | |
| fn from_der_subject_public_key(spk: &[u8]) -> Option<Self::PublicKey>; | |
| } | |
| /// PKI Verification algorithm | |
| pub(crate) trait PkiSignatureAlgorithm: PkiIdentified { | |
| /// Supported public key, which can be deserialised from a DER-serialised | |
| /// `SubjectPublicKeyInfo` field. | |
| type PublicKeyAlgorithm: PkiPublicKeyAlgorithm; | |
| /// Perform verification of the signature against the deserialised public key | |
| /// and the original message. | |
| fn verify( | |
| public_key: <Self::PublicKeyAlgorithm as PkiPublicKeyAlgorithm>::PublicKey, | |
| message: &[u8], | |
| signature: &[u8], | |
| ) -> bool; | |
| } | |
| /// PKI verification as prescribed in [RFC 3279](https://datatracker.ietf.org/doc/html/rfc3279) | |
| struct PkiSignatureVerification<S>(PhantomData<fn() -> S>); | |
| impl<S> PkiSignatureVerification<S> { | |
| pub(crate) const fn new() -> Self { | |
| Self(PhantomData) | |
| } | |
| } | |
| impl<S> Debug for PkiSignatureVerification<S> { | |
| fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { | |
| f.debug_struct("PkiVerification").finish() | |
| } | |
| } | |
| impl<S: PkiSignatureAlgorithm> SignatureVerificationAlgorithm for PkiSignatureVerification<S> { | |
| fn verify_signature( | |
| &self, | |
| subject_public_key: &[u8], | |
| message: &[u8], | |
| signature: &[u8], | |
| ) -> Result<(), InvalidSignature> { | |
| let public_key = S::PublicKeyAlgorithm::from_der_subject_public_key(subject_public_key) | |
| .ok_or(InvalidSignature)?; | |
| if S::verify(public_key, message, signature) { | |
| Ok(()) | |
| } else { | |
| Err(InvalidSignature) | |
| } | |
| } | |
| fn public_key_alg_id(&self) -> AlgorithmIdentifier { | |
| S::PublicKeyAlgorithm::OBJECT_IDENTIFIER | |
| } | |
| fn signature_alg_id(&self) -> AlgorithmIdentifier { | |
| S::OBJECT_IDENTIFIER | |
| } | |
| } | |
| /// RSA encryption | |
| /// | |
| /// OID: 1.2.840.113549.1.1.1 | |
| struct PkiRsaPublicKey; | |
| impl PkiIdentified for PkiRsaPublicKey { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::RSA_ENCRYPTION; | |
| } | |
| impl PkiPublicKeyAlgorithm for PkiRsaPublicKey { | |
| type PublicKey = rsa::PublicKey; | |
| fn from_der_subject_public_key(spk: &[u8]) -> Option<Self::PublicKey> { | |
| rsa::PublicKey::from_der_rsa_public_key(spk) | |
| } | |
| } | |
| /// Elliptic curve (EC) public key encoded in X9.62 | |
| /// | |
| /// OID: 1.2.840.10045.2.1 | |
| struct PkiEcPublicKey<C> { | |
| pub(crate) _p: PhantomData<fn() -> C>, | |
| } | |
| /// EC public key over curve P-256 | |
| /// | |
| /// OID: 1.2.840.10045.3.1.7 | |
| impl PkiIdentified for PkiEcPublicKey<ec::P256> { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::ECDSA_P256; | |
| } | |
| /// EC public key over curve P-384 | |
| /// | |
| /// OID: 1.3.132.0.34 | |
| impl PkiIdentified for PkiEcPublicKey<ec::P384> { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::ECDSA_P384; | |
| } | |
| impl<C: ec::Curve> PkiPublicKeyAlgorithm for PkiEcPublicKey<C> | |
| where | |
| Self: PkiIdentified, | |
| { | |
| type PublicKey = ecdsa::PublicKey<C>; | |
| fn from_der_subject_public_key(spk: &[u8]) -> Option<Self::PublicKey> { | |
| ecdsa::PublicKey::from_x962_uncompressed(spk) | |
| .or_else(|| ecdsa::PublicKey::from_x962_compressed(spk)) | |
| } | |
| } | |
| /// Ed25519/EdDSA public key | |
| /// | |
| /// OID: 1.3.101.112 | |
| pub(crate) struct PkiEd25519PublicKey; | |
| impl PkiIdentified for PkiEd25519PublicKey { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::ED25519; | |
| } | |
| impl PkiPublicKeyAlgorithm for PkiEd25519PublicKey { | |
| type PublicKey = ed25519::PublicKey; | |
| fn from_der_subject_public_key(spk: &[u8]) -> Option<Self::PublicKey> { | |
| Some(ed25519::PublicKey::from_bytes(spk.try_into().ok()?)) | |
| } | |
| } | |
| /// A family of RSA signature scheme | |
| struct PkiRsaPkcs1SignatureScheme<D> { | |
| pub(crate) _p: PhantomData<fn() -> D>, | |
| } | |
| pub(crate) enum DigestAlgorithm { | |
| Sha256, | |
| Sha384, | |
| Sha512, | |
| } | |
| /// RSA with SHA256 signature scheme | |
| /// | |
| /// OID: 1.2.840.113549.1.1.11 | |
| impl PkiIdentified for PkiRsaPkcs1SignatureScheme<digest::Sha256> { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::RSA_PKCS1_SHA256; | |
| } | |
| /// RSA with SHA384 | |
| /// | |
| /// OID: 1.2.840.113549.1.1.12 | |
| impl PkiIdentified for PkiRsaPkcs1SignatureScheme<digest::Sha384> { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::RSA_PKCS1_SHA384; | |
| } | |
| /// RSA with SHA512 | |
| /// | |
| /// OID: 1.2.840.113549.1.1.13 | |
| impl PkiIdentified for PkiRsaPkcs1SignatureScheme<digest::Sha512> { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::RSA_PKCS1_SHA512; | |
| } | |
| impl<D: RsaSignatureDigest> PkiSignatureAlgorithm for PkiRsaPkcs1SignatureScheme<D> | |
| where | |
| Self: PkiIdentified, | |
| { | |
| type PublicKeyAlgorithm = PkiRsaPublicKey; | |
| fn verify( | |
| public_key: <Self::PublicKeyAlgorithm as PkiPublicKeyAlgorithm>::PublicKey, | |
| message: &[u8], | |
| signature: &[u8], | |
| ) -> bool { | |
| public_key.verify_pkcs1::<D>(message, signature).is_ok() | |
| } | |
| } | |
| /// A family of RSA signature scheme | |
| struct PkiRsaPssSignatureScheme<D> { | |
| pub(crate) _p: PhantomData<fn() -> D>, | |
| } | |
| /// RSA PSS with SHA256 signature scheme | |
| /// | |
| /// OID: 1.2.840.113549.1.1.10 | |
| impl PkiIdentified for PkiRsaPssSignatureScheme<digest::Sha256> { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::RSA_PSS_SHA256; | |
| } | |
| /// RSA PSS with SHA384 | |
| /// | |
| /// OID: 1.2.840.113549.1.1.10 | |
| impl PkiIdentified for PkiRsaPssSignatureScheme<digest::Sha384> { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::RSA_PSS_SHA384; | |
| } | |
| /// RSA PSS with SHA512 | |
| /// | |
| /// OID: 1.2.840.113549.1.1.10 | |
| impl PkiIdentified for PkiRsaPssSignatureScheme<digest::Sha512> { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::RSA_PSS_SHA512; | |
| } | |
| impl<D: RsaSignatureDigest> PkiSignatureAlgorithm for PkiRsaPssSignatureScheme<D> | |
| where | |
| Self: PkiIdentified, | |
| { | |
| type PublicKeyAlgorithm = PkiRsaPublicKey; | |
| fn verify( | |
| public_key: <Self::PublicKeyAlgorithm as PkiPublicKeyAlgorithm>::PublicKey, | |
| message: &[u8], | |
| signature: &[u8], | |
| ) -> bool { | |
| public_key.verify_pss::<D>(message, signature).is_ok() | |
| } | |
| } | |
| struct PkiEcdsaScheme<C> { | |
| pub(crate) _p: PhantomData<fn() -> C>, | |
| } | |
| /// ECDSA with SHA-256 | |
| /// | |
| /// OID: 1.2.840.10045.4.3.2 | |
| impl PkiIdentified for PkiEcdsaScheme<ec::P256> { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::ECDSA_SHA256; | |
| } | |
| /// ECDSA with SHA-384 | |
| /// | |
| /// OID: 1.2.840.10045.4.3.3 | |
| impl PkiIdentified for PkiEcdsaScheme<ec::P384> { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::ECDSA_SHA384; | |
| } | |
| impl<C: ec::Curve> PkiSignatureAlgorithm for PkiEcdsaScheme<C> | |
| where | |
| Self: PkiIdentified, | |
| PkiEcPublicKey<C>: PkiIdentified, | |
| { | |
| type PublicKeyAlgorithm = PkiEcPublicKey<C>; | |
| fn verify( | |
| public_key: <Self::PublicKeyAlgorithm as PkiPublicKeyAlgorithm>::PublicKey, | |
| message: &[u8], | |
| signature: &[u8], | |
| ) -> bool { | |
| // Safety: we would only allow SHA-256 hashing onto P-256 and SHA-384 hashing onto P-384 | |
| public_key.verify(message, signature).is_ok() | |
| } | |
| } | |
| /// Signature algorithm EdDSA | |
| /// | |
| /// OID: 1.3.101.112 | |
| struct PkiEddsa; | |
| impl PkiIdentified for PkiEddsa { | |
| const OBJECT_IDENTIFIER: AlgorithmIdentifier = alg_id::ED25519; | |
| } | |
| impl PkiSignatureAlgorithm for PkiEddsa { | |
| type PublicKeyAlgorithm = PkiEd25519PublicKey; | |
| fn verify( | |
| public_key: <Self::PublicKeyAlgorithm as PkiPublicKeyAlgorithm>::PublicKey, | |
| message: &[u8], | |
| signature: &[u8], | |
| ) -> bool { | |
| let Ok(signature) = signature.try_into() else { | |
| return false; | |
| }; | |
| public_key.verify(message, signature).is_ok() | |
| } | |
| } | |
| /// PKI Signature scheme `ECDSA_NISTP256_SHA256` | |
| pub const ECDSA_NISTP256_SHA256: &'static dyn SignatureVerificationAlgorithm = | |
| &PkiSignatureVerification::<PkiEcdsaScheme<ec::P256>>::new(); | |
| /// PKI Signature scheme `ECDSA_NISTP384_SHA384` | |
| pub const ECDSA_NISTP384_SHA384: &'static dyn SignatureVerificationAlgorithm = | |
| &PkiSignatureVerification::<PkiEcdsaScheme<ec::P384>>::new(); | |
| /// PKI Signature scheme `ED25519` | |
| pub const ED25519: &'static (dyn SignatureVerificationAlgorithm + 'static) = | |
| &PkiSignatureVerification::<PkiEddsa>::new(); | |
| /// PKI Signature scheme `RSA_PKCS1_SHA256` | |
| pub const RSA_PKCS1_SHA256: &'static (dyn SignatureVerificationAlgorithm + 'static) = | |
| &PkiSignatureVerification::<PkiRsaPkcs1SignatureScheme<digest::Sha256>>::new(); | |
| /// PKI Signature scheme `RSA_PKCS1_SHA384` | |
| pub const RSA_PKCS1_SHA384: &'static (dyn SignatureVerificationAlgorithm + 'static) = | |
| &PkiSignatureVerification::<PkiRsaPkcs1SignatureScheme<digest::Sha384>>::new(); | |
| /// PKI Signature scheme `RSA_PKCS1_SHA512` | |
| pub const RSA_PKCS1_SHA512: &'static (dyn SignatureVerificationAlgorithm + 'static) = | |
| &PkiSignatureVerification::<PkiRsaPkcs1SignatureScheme<digest::Sha512>>::new(); | |
| /// PKI Signature scheme `RSA_PSS_SHA256` | |
| pub const RSA_PSS_SHA256: &'static (dyn SignatureVerificationAlgorithm + 'static) = | |
| &PkiSignatureVerification::<PkiRsaPssSignatureScheme<digest::Sha256>>::new(); | |
| /// PKI Signature scheme `RSA_PSS_SHA384` | |
| pub const RSA_PSS_SHA384: &'static (dyn SignatureVerificationAlgorithm + 'static) = | |
| &PkiSignatureVerification::<PkiRsaPssSignatureScheme<digest::Sha384>>::new(); | |
| /// PKI Signature scheme `RSA_PSS_SHA512` | |
| pub const RSA_PSS_SHA512: &'static (dyn SignatureVerificationAlgorithm + 'static) = | |
| &PkiSignatureVerification::<PkiRsaPssSignatureScheme<digest::Sha512>>::new(); |