blob: e4caf941fc93eccf797024437b6da69aa08440b2 [file] [log] [blame]
// 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();