Skip to content

Commit

Permalink
Prepare handshake to deal with bikeshed certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
pohlm01 committed Oct 2, 2024
1 parent fe1253b commit 420d1d1
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 49 deletions.
14 changes: 8 additions & 6 deletions bogo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,10 +468,11 @@ struct FixedSignatureSchemeServerCertResolver {
impl server::ResolvesServerCert for FixedSignatureSchemeServerCertResolver {
fn resolve(&self, client_hello: ClientHello) -> Option<Arc<sign::CertifiedKey>> {
let mut certkey = self.resolver.resolve(client_hello)?;
Arc::make_mut(&mut certkey).key = Arc::new(FixedSignatureSchemeSigningKey {
key: certkey.key.clone(),
let key = certkey.to_key();
Arc::make_mut(&mut certkey).set_key(Arc::new(FixedSignatureSchemeSigningKey {
key,
scheme: self.scheme,
});
}));
Some(certkey)
}
}
Expand All @@ -494,10 +495,11 @@ impl client::ResolvesClientCert for FixedSignatureSchemeClientCertResolver {
let mut certkey = self
.resolver
.resolve(root_hint_subjects, sigschemes)?;
Arc::make_mut(&mut certkey).key = Arc::new(FixedSignatureSchemeSigningKey {
key: certkey.key.clone(),
let key = certkey.to_key();
Arc::make_mut(&mut certkey).set_key(Arc::new(FixedSignatureSchemeSigningKey {
key,
scheme: self.scheme,
});
}));
Some(certkey)
}

Expand Down
2 changes: 1 addition & 1 deletion rustls/src/client/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl ClientAuthDetails {
.collect::<Vec<&[u8]>>();

if let Some(certkey) = resolver.resolve(&acceptable_issuers, sigschemes) {
if let Some(signer) = certkey.key.choose_scheme(sigschemes) {
if let Some(signer) = certkey.key().choose_scheme(sigschemes) {
debug!("Attempting client auth");
return Self::Verify {
certkey,
Expand Down
7 changes: 6 additions & 1 deletion rustls/src/client/tls12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,12 @@ impl State<ClientConnectionData> for ExpectServerDone<'_> {
if let Some(client_auth) = &st.client_auth {
let certs = match client_auth {
ClientAuthDetails::Empty { .. } => CertificateChain::default(),
ClientAuthDetails::Verify { certkey, .. } => CertificateChain(certkey.cert.clone()),
ClientAuthDetails::Verify { certkey, .. } => CertificateChain(
certkey
.x509_cert_chain()
.unwrap_or_default()
.to_vec(),
),
};
emit_certificate(&mut st.transcript, certs, cx.common);
}
Expand Down
23 changes: 17 additions & 6 deletions rustls/src/client/tls13.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1163,8 +1163,14 @@ fn emit_compressed_certificate_tls13(
compressor: &dyn compress::CertCompressor,
config: &ClientConfig,
) {
let mut cert_payload =
CertificatePayloadTls13::from_x509_certificates(certkey.cert.iter(), None);
let mut cert_payload = match certkey {
CertifiedKey::X509 { cert, .. } => {
CertificatePayloadTls13::from_x509_certificates(cert.iter(), None)
}
CertifiedKey::Bikeshed { cert, .. } => {
CertificatePayloadTls13::from_bikeshed_certificate(cert)
}
};
cert_payload.context = PayloadU8::new(auth_context.clone().unwrap_or_default());

let compressed = match config
Expand All @@ -1186,10 +1192,15 @@ fn emit_certificate_tls13(
certkey: Option<&CertifiedKey>,
auth_context: Option<Vec<u8>>,
) {
let certs = certkey
.map(|ck| ck.cert.as_ref())
.unwrap_or(&[][..]);
let mut cert_payload = CertificatePayloadTls13::from_x509_certificates(certs.iter(), None);
let mut cert_payload = match certkey {
Some(CertifiedKey::X509 { cert, .. }) => {
CertificatePayloadTls13::from_x509_certificates(cert.iter(), None)
}
Some(CertifiedKey::Bikeshed { cert, .. }) => {
CertificatePayloadTls13::from_bikeshed_certificate(cert)
}
None => CertificatePayloadTls13::empty(),
};
cert_payload.context = PayloadU8::new(auth_context.unwrap_or_default());

flight.add(HandshakeMessagePayload {
Expand Down
109 changes: 91 additions & 18 deletions rustls/src/crypto/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use alloc::boxed::Box;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::fmt::Debug;

use core::ops::Deref;
use mtc_verifier::Certificate as BikeshedCertificate;
use pki_types::{AlgorithmIdentifier, CertificateDer, SubjectPublicKeyInfoDer};

use crate::enums::{SignatureAlgorithm, SignatureScheme};
Expand Down Expand Up @@ -85,19 +86,38 @@ pub trait Signer: Debug + Send + Sync {
fn scheme(&self) -> SignatureScheme;
}

/// A packaged-together certificate chain, matching `SigningKey` and
/// optional stapled OCSP response.
#[derive(Clone, Debug)]
pub struct CertifiedKey {
/// The certificate chain.
pub cert: Vec<CertificateDer<'static>>,

/// The certified key.
pub key: Arc<dyn SigningKey>,
// /// A packaged-together certificate chain, matching `SigningKey` and
// /// optional stapled OCSP response.
// #[derive(Clone, Debug)]
// pub struct CertifiedKey {
// /// The certificate chain.
// pub cert: Vec<CertificateDer<'static>>,
//
// /// The certified key.
// pub key: Arc<dyn SigningKey>,
//
// /// An optional OCSP response from the certificate issuer,
// /// attesting to its continued validity.
// pub ocsp: Option<Vec<u8>>,
// }

/// An optional OCSP response from the certificate issuer,
/// attesting to its continued validity.
pub ocsp: Option<Vec<u8>>,
#[derive(Clone, Debug)]
pub enum CertifiedKey {
X509 {
/// The certificate chain.
cert: Vec<CertificateDer<'static>>,

/// The certified key.
key: Arc<dyn SigningKey>,

/// An optional OCSP response from the certificate issuer,
/// attesting to its continued validity.
ocsp: Option<Vec<u8>>,
},
Bikeshed {
cert: BikeshedCertificate<'static>,
key: Arc<dyn SigningKey>,
},
}

impl CertifiedKey {
Expand All @@ -106,17 +126,53 @@ impl CertifiedKey {
/// The cert chain must not be empty. The first certificate in the chain
/// must be the end-entity certificate.
pub fn new(cert: Vec<CertificateDer<'static>>, key: Arc<dyn SigningKey>) -> Self {
Self {
Self::X509 {
cert,
key,
ocsp: None,
}
}

pub fn key(&self) -> &dyn SigningKey {
match self {
Self::X509 { key, .. } => key.deref(),
Self::Bikeshed { key, .. } => key.deref(),
}
}

pub fn to_key(&self) -> Arc<dyn SigningKey> {
match self {
Self::X509 { key, .. } => Arc::clone(key),
Self::Bikeshed { key, .. } => Arc::clone(key),
}
}

pub fn set_key(&mut self, new_key: Arc<dyn SigningKey>) {
match self {
Self::X509 { ref mut key, .. } => *key = new_key,
Self::Bikeshed { ref mut key, .. } => *key = new_key,
}
}

pub fn ocsp(&self) -> Option<&[u8]> {
match self {
Self::X509 { ocsp, .. } => ocsp.as_deref(),
Self::Bikeshed { .. } => None,
}
}

pub fn set_ocsp(&mut self, new_ocsp: Vec<u8>) {
match self {
Self::X509 { ref mut ocsp, .. } => *ocsp = Some(new_ocsp),
Self::Bikeshed { .. } => {}
}
}

/// Verify the consistency of this [`CertifiedKey`]'s public and private keys.
/// This is done by performing a comparison of SubjectPublicKeyInfo bytes.
pub fn keys_match(&self) -> Result<(), Error> {
let key_spki = match self.key.public_key() {
let key = self.key();
let key_spki = match key.public_key() {
Some(key) => key,
None => return Err(InconsistentKeys::Unknown.into()),
};
Expand All @@ -128,11 +184,28 @@ impl CertifiedKey {
}
}

pub fn x509_cert_chain(&self) -> Option<&[CertificateDer<'static>]> {
match self {
Self::X509 { cert, .. } => Some(cert),
Self::Bikeshed { .. } => None,
}
}

/// The end-entity certificate.
pub fn end_entity_cert(&self) -> Result<&CertificateDer<'_>, Error> {
self.cert
.first()
.ok_or(Error::NoCertificatesPresented)
match self {
Self::X509 { cert, .. } => cert
.first()
.ok_or(Error::NoCertificatesPresented),
Self::Bikeshed { .. } => Err(Error::WrongCertificateType),
}
}

pub fn bikeshed_certificate(&self) -> Result<&BikeshedCertificate<'_>, Error> {
match self {
Self::X509 { .. } => Err(Error::WrongCertificateType),
Self::Bikeshed { cert, .. } => Ok(cert),
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions rustls/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ pub enum Error {
/// The peer didn't give us any certificates.
NoCertificatesPresented,

/// X509 or Bikeshed certificate got confused
// TODO @max think about error handling
WrongCertificateType,

/// The certificate verifier doesn't support the given type of name.
UnsupportedNameType,

Expand Down Expand Up @@ -595,6 +599,7 @@ impl fmt::Display for Error {
Self::InconsistentKeys(ref why) => {
write!(f, "keys may not be consistent: {:?}", why)
}
Self::WrongCertificateType => write!(f, "wrong certificate type"),
Self::General(ref err) => write!(f, "unexpected error: {}", err),
Self::Other(ref err) => write!(f, "other error: {}", err),
}
Expand Down
9 changes: 8 additions & 1 deletion rustls/src/msgs/handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1730,13 +1730,20 @@ impl<'a> CertificatePayloadTls13<'a> {
}
}

pub(crate) fn from_bikeshed_certificate(cert: BikeshedCertificate<'_>) -> Self {
pub(crate) fn from_bikeshed_certificate(cert: &BikeshedCertificate<'_>) -> Self {
Self {
context: PayloadU8::empty(),
entries: vec![CertificateEntry::new(cert.encode())],
}
}

pub(crate) fn empty() -> Self {
Self {
context: PayloadU8::empty(),
entries: Default::default(),
}
}

pub(crate) fn into_owned(self) -> CertificatePayloadTls13<'static> {
CertificatePayloadTls13 {
context: self.context,
Expand Down
26 changes: 22 additions & 4 deletions rustls/src/server/common.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use mtc_verifier::Certificate as BikeshedCertificate;
use pki_types::CertificateDer;

use crate::sign;
Expand All @@ -8,24 +9,41 @@ pub(super) struct ActiveCertifiedKey<'a> {
ocsp: Option<&'a [u8]>,
}

pub(super) enum Certificate<'a> {
X509(&'a [CertificateDer<'static>]),
Bikeshed(&'a BikeshedCertificate<'static>),
}

impl<'a> Certificate<'a> {
pub(crate) fn into_x509(self) -> Option<&'a [CertificateDer<'static>]> {
match self {
Certificate::X509(chain) => Some(chain),
Certificate::Bikeshed(_) => None,
}
}
}

impl<'a> ActiveCertifiedKey<'a> {
pub(super) fn from_certified_key(key: &sign::CertifiedKey) -> ActiveCertifiedKey<'_> {
ActiveCertifiedKey {
key,
ocsp: key.ocsp.as_deref(),
ocsp: key.ocsp(),
}
}

/// Get the certificate chain
#[inline]
pub(super) fn get_cert(&self) -> &[CertificateDer<'static>] {
&self.key.cert
pub(super) fn get_cert(&self) -> Certificate<'a> {
match self.key {
sign::CertifiedKey::X509 { cert, .. } => Certificate::X509(cert),
sign::CertifiedKey::Bikeshed { cert, .. } => Certificate::Bikeshed(cert),
}
}

/// Get the signing key
#[inline]
pub(super) fn get_key(&self) -> &dyn sign::SigningKey {
&*self.key.key
self.key.key()
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion rustls/src/server/handy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ impl AlwaysResolvesChain {
{
let cert = Arc::make_mut(&mut r.0);
if !ocsp.is_empty() {
cert.ocsp = Some(ocsp);
cert.set_ocsp(ocsp);
}
}

Expand Down
8 changes: 7 additions & 1 deletion rustls/src/server/tls12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,13 @@ mod client_hello {
&self.randoms,
self.extra_exts,
)?;
emit_certificate(&mut flight, server_key.get_cert());
emit_certificate(
&mut flight,
server_key
.get_cert()
.into_x509()
.unwrap_or_default(),
);
if let Some(ocsp_response) = ocsp_response {
emit_cert_status(&mut flight, ocsp_response);
}
Expand Down
Loading

0 comments on commit 420d1d1

Please sign in to comment.