Start SCT extension support

This commit is contained in:
Joseph Birr-Pixton 2017-07-05 21:16:49 +01:00
parent a7a36f9f0c
commit df361f832b
6 changed files with 75 additions and 8 deletions

View File

@ -240,6 +240,7 @@ fn emit_client_hello_for_retry(sess: &mut ClientSessionImpl,
exts.push(ClientExtension::SignatureAlgorithms(SupportedSignatureSchemes::supported_verify()));
exts.push(ClientExtension::ExtendedMasterSecretRequest);
exts.push(ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()));
exts.push(ClientExtension::SignedCertificateTimestampRequest);
if support_tls13 {
exts.push(ClientExtension::KeyShare(key_shares));

View File

@ -206,6 +206,7 @@ enum_builder! {@U16
UseSRTP => 0x000e,
Heartbeat => 0x000f,
ALProtocolNegotiation => 0x0010,
SCT => 0x0012,
Padding => 0x0015,
ExtendedMasterSecret => 0x0017,
SessionTicket => 0x0023,

View File

@ -585,6 +585,7 @@ pub enum ClientExtension {
Cookie(PayloadU16),
ExtendedMasterSecretRequest,
CertificateStatusRequest(CertificateStatusRequest),
SignedCertificateTimestampRequest,
Unknown(UnknownExtension),
}
@ -606,6 +607,7 @@ impl ClientExtension {
ClientExtension::Cookie(_) => ExtensionType::Cookie,
ClientExtension::ExtendedMasterSecretRequest => ExtensionType::ExtendedMasterSecret,
ClientExtension::CertificateStatusRequest(_) => ExtensionType::StatusRequest,
ClientExtension::SignedCertificateTimestampRequest => ExtensionType::SCT,
ClientExtension::Unknown(ref r) => r.typ,
}
}
@ -623,7 +625,8 @@ impl Codec for ClientExtension {
ClientExtension::Heartbeat(ref r) => r.encode(&mut sub),
ClientExtension::ServerName(ref r) => r.encode(&mut sub),
ClientExtension::SessionTicketRequest |
ClientExtension::ExtendedMasterSecretRequest => (),
ClientExtension::ExtendedMasterSecretRequest |
ClientExtension::SignedCertificateTimestampRequest => (),
ClientExtension::SessionTicketOffer(ref r) => r.encode(&mut sub),
ClientExtension::Protocols(ref r) => r.encode(&mut sub),
ClientExtension::SupportedVersions(ref r) => r.encode(&mut sub),
@ -691,6 +694,9 @@ impl Codec for ClientExtension {
let csr = try_ret!(CertificateStatusRequest::read(&mut sub));
ClientExtension::CertificateStatusRequest(csr)
}
ExtensionType::SCT if !sub.any_left() => {
ClientExtension::SignedCertificateTimestampRequest
}
_ => ClientExtension::Unknown(try_ret!(UnknownExtension::read(typ, &mut sub))),
})
}
@ -828,6 +834,7 @@ pub enum ServerExtension {
PresharedKey(u16),
ExtendedMasterSecretAck,
CertificateStatusAck,
SignedCertificateTimestamp(Payload),
Unknown(UnknownExtension),
}
@ -844,6 +851,7 @@ impl ServerExtension {
ServerExtension::PresharedKey(_) => ExtensionType::PreSharedKey,
ServerExtension::ExtendedMasterSecretAck => ExtensionType::ExtendedMasterSecret,
ServerExtension::CertificateStatusAck => ExtensionType::StatusRequest,
ServerExtension::SignedCertificateTimestamp(_) => ExtensionType::SCT,
ServerExtension::Unknown(ref r) => r.typ,
}
}
@ -865,6 +873,7 @@ impl Codec for ServerExtension {
ServerExtension::Protocols(ref r) => r.encode(&mut sub),
ServerExtension::KeyShare(ref r) => r.encode(&mut sub),
ServerExtension::PresharedKey(r) => codec::encode_u16(r, &mut sub),
ServerExtension::SignedCertificateTimestamp(ref r) => r.encode(&mut sub),
ServerExtension::Unknown(ref r) => r.encode(&mut sub),
}
@ -900,6 +909,9 @@ impl Codec for ServerExtension {
ServerExtension::PresharedKey(try_ret!(codec::read_u16(&mut sub)))
}
ExtensionType::ExtendedMasterSecret => ServerExtension::ExtendedMasterSecretAck,
ExtensionType::SCT => {
ServerExtension::SignedCertificateTimestamp(try_ret!(Payload::read(&mut sub)))
}
_ => ServerExtension::Unknown(try_ret!(UnknownExtension::read(typ, &mut sub))),
})
}
@ -914,6 +926,10 @@ impl ServerExtension {
let empty = Vec::new();
ServerExtension::RenegotiationInfo(PayloadU8::new(empty))
}
pub fn make_sct(sctl: Vec<u8>) -> ServerExtension {
ServerExtension::SignedCertificateTimestamp(Payload::new(sctl))
}
}
#[derive(Debug)]
@ -1339,6 +1355,7 @@ impl Codec for CertificatePayload {
#[derive(Debug)]
pub enum CertificateExtension {
CertificateStatus(CertificateStatus),
SignedCertificateTimestamp(Payload),
Unknown(UnknownExtension),
}
@ -1346,9 +1363,14 @@ impl CertificateExtension {
pub fn get_type(&self) -> ExtensionType {
match *self {
CertificateExtension::CertificateStatus(_) => ExtensionType::StatusRequest,
CertificateExtension::SignedCertificateTimestamp(_) => ExtensionType::SCT,
CertificateExtension::Unknown(ref r) => r.typ,
}
}
pub fn make_sct(sct_list: Vec<u8>) -> CertificateExtension {
CertificateExtension::SignedCertificateTimestamp(Payload::new(sct_list))
}
}
impl Codec for CertificateExtension {
@ -1358,6 +1380,7 @@ impl Codec for CertificateExtension {
let mut sub: Vec<u8> = Vec::new();
match *self {
CertificateExtension::CertificateStatus(ref r) => r.encode(&mut sub),
CertificateExtension::SignedCertificateTimestamp(ref r) => r.encode(&mut sub),
CertificateExtension::Unknown(ref r) => r.encode(&mut sub),
}
@ -1372,7 +1395,12 @@ impl Codec for CertificateExtension {
Some(match typ {
ExtensionType::StatusRequest => {
CertificateExtension::CertificateStatus(try_ret!(CertificateStatus::read(&mut sub)))
let st = try_ret!(CertificateStatus::read(&mut sub));
CertificateExtension::CertificateStatus(st)
}
ExtensionType::SCT => {
let scts = try_ret!(Payload::read(&mut sub));
CertificateExtension::SignedCertificateTimestamp(scts)
}
_ => CertificateExtension::Unknown(try_ret!(UnknownExtension::read(typ, &mut sub))),
})

View File

@ -397,6 +397,7 @@ pub struct ServerHandshakeData {
pub doing_resume: bool,
pub send_ticket: bool,
pub send_cert_status: bool,
pub send_sct: bool,
pub using_ems: bool,
pub doing_client_auth: bool,
pub done_retry: bool,
@ -414,6 +415,7 @@ impl ServerHandshakeData {
kx_data: None,
send_ticket: false,
send_cert_status: false,
send_sct: false,
using_ems: false,
doing_resume: false,
doing_client_auth: false,

View File

@ -102,6 +102,22 @@ fn process_extensions(sess: &mut ServerSessionImpl,
}
}
if !for_resume &&
hello.find_extension(ExtensionType::SCT).is_some() &&
sess.handshake_data.server_certkey.is_some() &&
sess.handshake_data.server_certkey.as_ref().unwrap().has_sct_list() {
sess.handshake_data.send_sct = true;
if !sess.common.is_tls13() {
let sct_list = sess.handshake_data.server_certkey
.as_mut()
.unwrap()
.take_sct_list()
.unwrap();
ret.push(ServerExtension::make_sct(sct_list));
}
}
if !sess.common.is_tls13() {
// Renegotiation.
// (We don't do reneg at all, but would support the secure version if we did.)
@ -492,9 +508,9 @@ fn emit_certificate_req_tls13(sess: &mut ServerSessionImpl) {
fn emit_certificate_tls13(sess: &mut ServerSessionImpl) {
let mut cert_body = CertificatePayloadTLS13::new();
let (certs, ocsp) = {
let (certs, ocsp, sct_list) = {
let ck = sess.handshake_data.server_certkey.as_mut().unwrap();
(ck.take_cert(), ck.take_ocsp())
(ck.take_cert(), ck.take_ocsp(), ck.take_sct_list())
};
for cert in certs {
@ -516,6 +532,14 @@ fn emit_certificate_tls13(sess: &mut ServerSessionImpl) {
last_entry.exts.push(CertificateExtension::CertificateStatus(cst));
}
// Likewise, SCT
if sess.handshake_data.send_sct &&
sct_list.is_some() &&
!cert_body.list.is_empty() {
let last_entry = cert_body.list.last_mut().unwrap();
last_entry.exts.push(CertificateExtension::make_sct(sct_list.unwrap()));
}
let c = Message {
typ: ContentType::Handshake,
version: ProtocolVersion::TLSv1_3,

View File

@ -47,15 +47,16 @@ pub struct CertifiedKey {
/// attesting to its continued validity.
pub ocsp: Option<Vec<u8>>,
/// An optional SCT response from a CT log, proving the
/// certificate is included on that log.
pub sct: Option<Vec<u8>>,
/// An optional collection of SCTs from CT logs, proving the
/// certificate is included on those logs. This must be
/// a `SignedCertificateTimestampList` encoding; see RFC6962.
pub sct_list: Option<Vec<u8>>,
}
impl CertifiedKey {
/// Make a new CertifiedKey, with the given chain and key.
pub fn new(cert: Vec<key::Certificate>, key: Arc<Box<SigningKey>>) -> CertifiedKey {
CertifiedKey { cert: cert, key: key, ocsp: None, sct: None }
CertifiedKey { cert: cert, key: key, ocsp: None, sct_list: None }
}
/// Steal ownership of the certificate chain.
@ -72,6 +73,16 @@ impl CertifiedKey {
pub fn take_ocsp(&mut self) -> Option<Vec<u8>> {
mem::replace(&mut self.ocsp, None)
}
/// Return true if there's an SCT list.
pub fn has_sct_list(&self) -> bool {
self.sct_list.is_some()
}
/// Steal ownership of the SCT list.
pub fn take_sct_list(&mut self) -> Option<Vec<u8>> {
mem::replace(&mut self.sct_list, None)
}
}
/// A SigningKey for RSA-PKCS1 or RSA-PSS