Pass around parts of CertifiedKey separately

This commit is contained in:
Dirkjan Ochtman 2021-03-12 13:17:36 +01:00
parent 452b1b275f
commit 3440410bd4
5 changed files with 50 additions and 74 deletions

View File

@ -388,14 +388,14 @@ impl hs::State for ExpectCertificateRequest {
.client_auth_cert_resolver
.resolve(&canames, &certreq.sigschemes);
if let Some(mut certkey) = maybe_certkey {
if let Some(certkey) = maybe_certkey {
let maybe_signer = certkey
.key
.choose_scheme(&certreq.sigschemes);
if let Some(_) = &maybe_signer {
debug!("Attempting client auth");
client_auth.cert = Some(certkey.take_cert());
client_auth.cert = Some(certkey.cert);
}
client_auth.signer = maybe_signer;
} else {

View File

@ -760,12 +760,12 @@ impl hs::State for ExpectCertificateRequest {
.resolve(&canames, &compat_sigschemes);
let mut client_auth = ClientAuthDetails::new();
if let Some(mut certkey) = maybe_certkey {
if let Some(certkey) = maybe_certkey {
debug!("Attempting client auth");
let maybe_signer = certkey
.key
.choose_scheme(&compat_sigschemes);
client_auth.cert = Some(certkey.take_cert());
client_auth.cert = Some(certkey.cert);
client_auth.signer = maybe_signer;
client_auth.auth_context = Some(certreq.context.0.clone());
} else {

View File

@ -1,4 +1,5 @@
use crate::error::TlsError;
use crate::key::Certificate;
use crate::kx;
#[cfg(feature = "logging")]
use crate::log::{debug, trace};
@ -31,6 +32,8 @@ use webpki;
use crate::server::common::{HandshakeDetails, ServerKXDetails};
use crate::server::{tls12, tls13};
use std::sync::Arc;
pub type NextState = Box<dyn State + Send + Sync>;
pub type NextStateOrError = Result<NextState, TlsError>;
@ -150,7 +153,8 @@ impl ExtensionProcessing {
pub fn process_common(
&mut self,
sess: &mut ServerSessionImpl,
server_key: Option<&mut sign::CertifiedKey>,
ocsp_response: &mut Option<Vec<u8>>,
sct_list: &mut Option<Vec<u8>>,
hello: &ClientHelloPayload,
resumedata: Option<&persist::ServerSessionValue>,
handshake: &HandshakeDetails,
@ -223,7 +227,6 @@ impl ExtensionProcessing {
.push(ServerExtension::ServerNameAck);
}
if let Some(server_key) = server_key {
// Send status_request response if we have one. This is not allowed
// if we're resuming, and is only triggered if we have an OCSP response
// to send.
@ -232,14 +235,14 @@ impl ExtensionProcessing {
.find_extension(ExtensionType::StatusRequest)
.is_some()
{
if server_key.has_ocsp() && !sess.common.is_tls13() {
if ocsp_response.is_some() && !sess.common.is_tls13() {
// Only TLS1.2 sends confirmation in ServerHello
self.exts
.push(ServerExtension::CertificateStatusAck);
}
} else {
// Throw away any OCSP response so we don't try to send it later.
drop(server_key.take_ocsp());
ocsp_response.take();
}
if !for_resume
@ -250,18 +253,14 @@ impl ExtensionProcessing {
if !sess.common.is_tls13() {
// Take the SCT list, if any, so we don't send it later,
// and put it in the legacy extension.
server_key
.take_sct_list()
.map(|sct_list| {
self.exts
.push(ServerExtension::make_sct(sct_list))
});
if let Some(sct_list) = sct_list.take() {
self.exts.push(ServerExtension::make_sct(sct_list));
}
}
} else {
// Throw away any SCT list so we don't send it later.
drop(server_key.take_sct_list());
sct_list.take();
}
}
self.exts
.extend(handshake.extra_exts.iter().cloned());
@ -395,13 +394,14 @@ impl ExpectClientHello {
fn emit_server_hello(
&mut self,
sess: &mut ServerSessionImpl,
server_key: Option<&mut sign::CertifiedKey>,
ocsp_response: &mut Option<Vec<u8>>,
sct_list: &mut Option<Vec<u8>>,
hello: &ClientHelloPayload,
resumedata: Option<&persist::ServerSessionValue>,
randoms: &SessionRandoms,
) -> Result<(), TlsError> {
let mut ep = ExtensionProcessing::new();
ep.process_common(sess, server_key, hello, resumedata, &self.handshake)?;
ep.process_common(sess, ocsp_response, sct_list, hello, resumedata, &self.handshake)?;
ep.process_tls12(sess, hello, self.using_ems);
self.send_ticket = ep.send_ticket;
@ -433,10 +433,8 @@ impl ExpectClientHello {
fn emit_certificate(
&mut self,
sess: &mut ServerSessionImpl,
server_certkey: &mut sign::CertifiedKey,
cert_chain: Vec<Certificate>,
) {
let cert_chain = server_certkey.take_cert();
let c = Message {
typ: ContentType::Handshake,
version: ProtocolVersion::TLSv1_2,
@ -455,13 +453,8 @@ impl ExpectClientHello {
fn emit_cert_status(
&mut self,
sess: &mut ServerSessionImpl,
server_certkey: &mut sign::CertifiedKey,
ocsp: Vec<u8>,
) {
let ocsp = match server_certkey.take_ocsp() {
Some(ocsp) => ocsp,
None => return,
};
let st = CertificateStatus::new(ocsp);
let c = Message {
@ -484,7 +477,7 @@ impl ExpectClientHello {
sess: &mut ServerSessionImpl,
sigschemes: Vec<SignatureScheme>,
skxg: &'static kx::SupportedKxGroup,
server_certkey: &mut sign::CertifiedKey,
signing_key: Arc<Box<dyn sign::SigningKey>>,
randoms: &SessionRandoms,
) -> Result<kx::KeyExchange, TlsError> {
let kx = kx::KeyExchange::start(skxg)
@ -496,7 +489,6 @@ impl ExpectClientHello {
msg.extend(&randoms.server);
secdh.encode(&mut msg);
let signing_key = &server_certkey.key;
let signer = signing_key
.choose_scheme(&sigschemes)
.ok_or_else(|| TlsError::General("incompatible signing key".to_string()))?;
@ -600,7 +592,7 @@ impl ExpectClientHello {
}
self.handshake.session_id = *id;
self.emit_server_hello(sess, None, client_hello, Some(&resumedata), randoms)?;
self.emit_server_hello(sess, &mut None, &mut None, client_hello, Some(&resumedata), randoms)?;
let suite = sess.common.get_suite_assert();
let secrets = SessionSecrets::new_resume(&randoms, suite, &resumedata.master_secret.0);
@ -738,7 +730,7 @@ impl State for ExpectClientHello {
.map(|protos| protos.to_slices());
// Choose a certificate.
let mut certkey = {
let certkey = {
let sni_ref = sni
.as_ref()
.map(webpki::DNSName::as_ref);
@ -943,10 +935,14 @@ impl State for ExpectClientHello {
debug_assert_eq!(ecpoint, ECPointFormat::Uncompressed);
self.emit_server_hello(sess, Some(&mut certkey), client_hello, None, &randoms)?;
self.emit_certificate(sess, &mut certkey);
self.emit_cert_status(sess, &mut certkey);
let kx = self.emit_server_kx(sess, sigschemes, group, &mut certkey, &randoms)?;
let sign::CertifiedKey { cert, key, mut ocsp, mut sct_list } = certkey;
self.emit_server_hello(sess, &mut ocsp, &mut sct_list, client_hello, None, &randoms)?;
self.emit_certificate(sess, cert);
if let Some(ocsp_response) = ocsp {
self.emit_cert_status(sess, ocsp_response);
}
let kx = self.emit_server_kx(sess, sigschemes, group, key, &randoms)?;
let doing_client_auth = self.emit_certificate_req(sess)?;
self.emit_server_hello_done(sess);

View File

@ -1,6 +1,7 @@
use crate::check::check_message;
use crate::{cipher, SupportedCipherSuite};
use crate::error::TlsError;
use crate::key;
use crate::key_schedule::{
KeyScheduleEarly, KeyScheduleHandshake, KeyScheduleNonSecret, KeyScheduleTraffic,
KeyScheduleTrafficWithClientFinishedPending,
@ -48,6 +49,8 @@ use crate::server::hs;
use ring::constant_time;
use std::sync::Arc;
pub struct CompleteClientHelloHandling {
pub handshake: HandshakeDetails,
pub randoms: SessionRandoms,
@ -275,12 +278,13 @@ impl CompleteClientHelloHandling {
fn emit_encrypted_extensions(
&mut self,
sess: &mut ServerSessionImpl,
server_key: &mut sign::CertifiedKey,
ocsp_response: &mut Option<Vec<u8>>,
sct_list: &mut Option<Vec<u8>>,
hello: &ClientHelloPayload,
resumedata: Option<&persist::ServerSessionValue>,
) -> Result<(), TlsError> {
let mut ep = hs::ExtensionProcessing::new();
ep.process_common(sess, Some(server_key), hello, resumedata, &self.handshake)?;
ep.process_common(sess, ocsp_response, sct_list, hello, resumedata, &self.handshake)?;
let ee = Message {
typ: ContentType::Handshake,
@ -355,10 +359,12 @@ impl CompleteClientHelloHandling {
fn emit_certificate_tls13(
&mut self,
sess: &mut ServerSessionImpl,
server_key: &mut sign::CertifiedKey,
server_cert: Vec<key::Certificate>,
ocsp_response: Option<Vec<u8>>,
sct_list: Option<Vec<u8>>,
) {
let mut cert_entries = vec![];
for cert in server_key.take_cert() {
for cert in server_cert {
let entry = CertificateEntry {
cert,
exts: Vec::new(),
@ -370,7 +376,7 @@ impl CompleteClientHelloHandling {
if let Some(end_entity_cert) = cert_entries.first_mut() {
// Apply OCSP response to first certificate (we don't support OCSP
// except for leaf certs).
if let Some(ocsp) = server_key.take_ocsp() {
if let Some(ocsp) = ocsp_response {
let cst = CertificateStatus::new(ocsp);
end_entity_cert
.exts
@ -378,7 +384,7 @@ impl CompleteClientHelloHandling {
}
// Likewise, SCT
if let Some(sct_list) = server_key.take_sct_list() {
if let Some(sct_list) = sct_list {
end_entity_cert
.exts
.push(CertificateExtension::make_sct(sct_list));
@ -405,7 +411,7 @@ impl CompleteClientHelloHandling {
fn emit_certificate_verify_tls13(
&mut self,
sess: &mut ServerSessionImpl,
server_key: &mut sign::CertifiedKey,
signing_key: Arc<Box<dyn sign::SigningKey>>,
schemes: &[SignatureScheme],
) -> Result<(), TlsError> {
let message = verify::construct_tls13_server_verify_message(
@ -415,7 +421,6 @@ impl CompleteClientHelloHandling {
.get_current_hash(),
);
let signing_key = &server_key.key;
let signer = signing_key
.choose_scheme(schemes)
.ok_or_else(|| hs::incompatible(sess, "no overlapping sigschemes"))?;
@ -532,7 +537,7 @@ impl CompleteClientHelloHandling {
mut self,
suite: &'static SupportedCipherSuite,
sess: &mut ServerSessionImpl,
mut server_key: sign::CertifiedKey,
server_key: sign::CertifiedKey,
chm: &Message,
) -> hs::NextStateOrError {
let client_hello = require_handshake_msg!(
@ -669,12 +674,13 @@ impl CompleteClientHelloHandling {
if !self.done_retry {
self.emit_fake_ccs(sess);
}
self.emit_encrypted_extensions(sess, &mut server_key, client_hello, resumedata.as_ref())?;
let sign::CertifiedKey { cert, key, mut ocsp, mut sct_list } = server_key;
self.emit_encrypted_extensions(sess, &mut ocsp, &mut sct_list, client_hello, resumedata.as_ref())?;
let doing_client_auth = if full_handshake {
let client_auth = self.emit_certificate_req_tls13(sess)?;
self.emit_certificate_tls13(sess, &mut server_key);
self.emit_certificate_verify_tls13(sess, &mut server_key, &sigschemes_ext)?;
self.emit_certificate_tls13(sess, cert, ocsp, sct_list);
self.emit_certificate_verify_tls13(sess, key, &sigschemes_ext)?;
client_auth
} else {
false

View File

@ -8,7 +8,6 @@ use ring::{
};
use webpki;
use std::mem;
use std::sync::Arc;
/// An abstract signing key.
@ -66,31 +65,6 @@ impl CertifiedKey {
}
}
/// The end-entity certificate.
pub fn end_entity_cert(&self) -> Result<&key::Certificate, ()> {
self.cert.get(0).ok_or(())
}
/// Steal ownership of the certificate chain.
pub fn take_cert(&mut self) -> Vec<key::Certificate> {
mem::replace(&mut self.cert, Vec::new())
}
/// Return true if there's an OCSP response.
pub fn has_ocsp(&self) -> bool {
self.ocsp.is_some()
}
/// Steal ownership of the OCSP response.
pub fn take_ocsp(&mut self) -> Option<Vec<u8>> {
mem::replace(&mut self.ocsp, None)
}
/// Steal ownership of the SCT list.
pub fn take_sct_list(&mut self) -> Option<Vec<u8>> {
mem::replace(&mut self.sct_list, None)
}
/// Check the certificate chain for validity:
/// - it should be non-empty list
/// - the first certificate should be parsable as a x509v3,
@ -104,7 +78,7 @@ impl CertifiedKey {
name: Option<webpki::DNSNameRef>,
) -> Result<(), TlsError> {
// Always reject an empty certificate chain.
let end_entity_cert = self.end_entity_cert().map_err(|()| {
let end_entity_cert = self.cert.first().ok_or_else(|| {
TlsError::General("No end-entity certificate in certificate chain".to_string())
})?;