mirror of https://github.com/ctz/rustls
Support RFC7627 extended master secret
This commit is contained in:
parent
42800fd492
commit
466ed6381a
|
@ -14,8 +14,6 @@
|
|||
"ConflictingVersionNegotiation": "",
|
||||
"ConflictingVersionNegotiation-2": "",
|
||||
"PointFormat-Server-Missing": "we require ecc",
|
||||
"EMS-Forbidden-TLS13": "TODO: unsupported but should be",
|
||||
"ExtendedMasterSecret-*": "",
|
||||
"ECDSAKeyUsage-*": "TODO: we don't do anything with key usages",
|
||||
"CheckRecordVersion-*": "we don't look at record version",
|
||||
"TLS13-WrongOuterRecord": "we're lax on this",
|
||||
|
@ -76,6 +74,7 @@
|
|||
"Renegotiate-Client-*": "no reneg",
|
||||
"Renegotiate-Server-*": "",
|
||||
"SendHalfHelloRequest-*": "",
|
||||
"ExtendedMasterSecret-Renego-*": "",
|
||||
|
||||
"Agree-Digest-SHA1": "the remainder are tests that are UNIMPLEMENTED (ie that need an option the shim doesn't support). including them here makes running the tests quicker under kcov",
|
||||
"Agree-Digest-SHA256": "delete these when doing development of the shim or upgrading bogo!",
|
||||
|
@ -324,8 +323,6 @@
|
|||
"NoCommonAlgorithms": "",
|
||||
"NoCommonAlgorithms-Digests": "",
|
||||
"NoCommonAlgorithms-TLS13": "",
|
||||
"NoExtendedMasterSecret-TLS13-Client": "",
|
||||
"NoExtendedMasterSecret-TLS13-Server": "",
|
||||
"NoFalseStart-DHE_RSA": "",
|
||||
"NoFalseStart-NoAEAD": "",
|
||||
"NoFalseStart-NoALPN": "",
|
||||
|
@ -688,6 +685,10 @@
|
|||
"SendUnsolicitedOCSPOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
|
||||
"SendUnsolicitedSCTOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
|
||||
"SendUnknownExtensionOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:",
|
||||
"LargePlaintext": ":PEER_MISBEHAVIOUR:"
|
||||
"LargePlaintext": ":PEER_MISBEHAVIOUR:",
|
||||
"EMS-Forbidden-TLS13": ":PEER_MISBEHAVIOUR:",
|
||||
"ExtendedMasterSecret-NoToYes-Client": ":PEER_MISBEHAVIOUR:",
|
||||
"ExtendedMasterSecret-YesToNo-Server": ":PEER_MISBEHAVIOUR:",
|
||||
"ExtendedMasterSecret-YesToNo-Client": ":PEER_MISBEHAVIOUR:"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -336,6 +336,7 @@ fn main() {
|
|||
}
|
||||
"-expect-no-session" |
|
||||
"-expect-session-miss" |
|
||||
"-expect-extended-master-secret" |
|
||||
"-expect-ticket-renewal" => {}
|
||||
|
||||
"-select-alpn" => {
|
||||
|
@ -407,7 +408,6 @@ fn main() {
|
|||
"-use-ticket-callback" |
|
||||
"-enable-grease" |
|
||||
"-enable-channel-id" |
|
||||
"-expect-extended-master-secret" |
|
||||
"-expect-resume-curve-id" |
|
||||
"-resumption-delay" |
|
||||
"-expect-early-data-info" |
|
||||
|
|
|
@ -262,6 +262,7 @@ pub struct ClientHandshakeData {
|
|||
pub resuming_session: Option<persist::ClientSessionValue>,
|
||||
pub randoms: SessionRandoms,
|
||||
pub must_issue_new_ticket: bool,
|
||||
pub using_ems: bool,
|
||||
pub new_ticket: Vec<u8>,
|
||||
pub new_ticket_lifetime: u32,
|
||||
pub doing_client_auth: bool,
|
||||
|
@ -285,6 +286,7 @@ impl ClientHandshakeData {
|
|||
resuming_session: None,
|
||||
randoms: SessionRandoms::for_client(),
|
||||
must_issue_new_ticket: false,
|
||||
using_ems: false,
|
||||
new_ticket: Vec::new(),
|
||||
new_ticket_lifetime: 0,
|
||||
doing_client_auth: false,
|
||||
|
|
|
@ -230,6 +230,7 @@ fn emit_client_hello_for_retry(sess: &mut ClientSessionImpl,
|
|||
exts.push(ClientExtension::ECPointFormats(ECPointFormatList::supported()));
|
||||
exts.push(ClientExtension::NamedGroups(NamedGroups::supported()));
|
||||
exts.push(ClientExtension::SignatureAlgorithms(SupportedSignatureSchemes::supported_verify()));
|
||||
exts.push(ClientExtension::ExtendedMasterSecretRequest);
|
||||
|
||||
if support_tls13 {
|
||||
exts.push(ClientExtension::KeyShare(key_shares));
|
||||
|
@ -381,7 +382,8 @@ static ALLOWED_PLAINTEXT_EXTS: &'static [ExtensionType] = &[
|
|||
static DISALLOWED_TLS13_EXTS: &'static [ExtensionType] = &[
|
||||
ExtensionType::ECPointFormats,
|
||||
ExtensionType::SessionTicket,
|
||||
ExtensionType::RenegotiationInfo
|
||||
ExtensionType::RenegotiationInfo,
|
||||
ExtensionType::ExtendedMasterSecret,
|
||||
];
|
||||
|
||||
fn validate_server_hello_tls13(sess: &mut ClientSessionImpl,
|
||||
|
@ -561,6 +563,11 @@ fn handle_server_hello(sess: &mut ClientSessionImpl, m: Message) -> StateResult
|
|||
server_hello.random.write_slice(&mut sess.handshake_data.randoms.server);
|
||||
sess.handshake_data.session_id = server_hello.session_id.clone();
|
||||
|
||||
// Doing EMS?
|
||||
if server_hello.ems_support_acked() {
|
||||
sess.handshake_data.using_ems = true;
|
||||
}
|
||||
|
||||
// Might the server send a ticket?
|
||||
if server_hello.find_extension(ExtensionType::SessionTicket).is_some() {
|
||||
info!("Server supports tickets");
|
||||
|
@ -580,6 +587,12 @@ fn handle_server_hello(sess: &mut ClientSessionImpl, m: Message) -> StateResult
|
|||
return Err(TLSError::PeerMisbehavedError(error_msg));
|
||||
}
|
||||
|
||||
// And about EMS support?
|
||||
if resuming.extended_ms != sess.handshake_data.using_ems {
|
||||
let error_msg = "server varied ems support over resume".to_string();
|
||||
return Err(TLSError::PeerMisbehavedError(error_msg));
|
||||
}
|
||||
|
||||
sess.secrets = Some(SessionSecrets::new_resume(&sess.handshake_data.randoms,
|
||||
scs.unwrap().get_hash(),
|
||||
&resuming.master_secret.0));
|
||||
|
@ -1127,6 +1140,8 @@ fn handle_server_hello_done(sess: &mut ClientSessionImpl,
|
|||
|
||||
// 4b.
|
||||
emit_clientkx(sess, &kxd);
|
||||
// nb. EMS handshake hash only runs up to ClientKeyExchange.
|
||||
let handshake_hash = sess.handshake_data.transcript.get_current_hash();
|
||||
|
||||
// 4c.
|
||||
if sess.handshake_data.doing_client_auth {
|
||||
|
@ -1138,8 +1153,16 @@ fn handle_server_hello_done(sess: &mut ClientSessionImpl,
|
|||
|
||||
// 4e. Now commit secrets.
|
||||
let hashalg = sess.common.get_suite().get_hash();
|
||||
sess.secrets =
|
||||
Some(SessionSecrets::new(&sess.handshake_data.randoms, hashalg, &kxd.premaster_secret));
|
||||
if sess.handshake_data.using_ems {
|
||||
sess.secrets = Some(SessionSecrets::new_ems(&sess.handshake_data.randoms,
|
||||
&handshake_hash,
|
||||
hashalg,
|
||||
&kxd.premaster_secret));
|
||||
} else {
|
||||
sess.secrets = Some(SessionSecrets::new(&sess.handshake_data.randoms,
|
||||
hashalg,
|
||||
&kxd.premaster_secret));
|
||||
}
|
||||
sess.start_encryption_tls12();
|
||||
|
||||
// 5.
|
||||
|
@ -1253,6 +1276,9 @@ fn save_session(sess: &mut ClientSessionImpl) {
|
|||
value.set_times(ticket_timebase(),
|
||||
sess.handshake_data.new_ticket_lifetime,
|
||||
0);
|
||||
if sess.handshake_data.using_ems {
|
||||
value.set_extended_ms_used();
|
||||
}
|
||||
|
||||
let mut persist = sess.config.session_persistence.lock().unwrap();
|
||||
let worked = persist.put(key.get_encoding(), value.get_encoding());
|
||||
|
|
|
@ -555,6 +555,7 @@ pub enum ClientExtension {
|
|||
PresharedKeyModes(PSKKeyExchangeModes),
|
||||
PresharedKey(PresharedKeyOffer),
|
||||
Cookie(PayloadU16),
|
||||
ExtendedMasterSecretRequest,
|
||||
Unknown(UnknownExtension),
|
||||
}
|
||||
|
||||
|
@ -574,6 +575,7 @@ impl ClientExtension {
|
|||
ClientExtension::PresharedKeyModes(_) => ExtensionType::PSKKeyExchangeModes,
|
||||
ClientExtension::PresharedKey(_) => ExtensionType::PreSharedKey,
|
||||
ClientExtension::Cookie(_) => ExtensionType::Cookie,
|
||||
ClientExtension::ExtendedMasterSecretRequest => ExtensionType::ExtendedMasterSecret,
|
||||
ClientExtension::Unknown(ref r) => r.typ,
|
||||
}
|
||||
}
|
||||
|
@ -598,6 +600,7 @@ impl Codec for ClientExtension {
|
|||
ClientExtension::PresharedKeyModes(ref r) => r.encode(&mut sub),
|
||||
ClientExtension::PresharedKey(ref r) => r.encode(&mut sub),
|
||||
ClientExtension::Cookie(ref r) => r.encode(&mut sub),
|
||||
ClientExtension::ExtendedMasterSecretRequest => (),
|
||||
ClientExtension::Unknown(ref r) => r.encode(&mut sub),
|
||||
}
|
||||
|
||||
|
@ -617,8 +620,10 @@ impl Codec for ClientExtension {
|
|||
ExtensionType::EllipticCurves => {
|
||||
ClientExtension::NamedGroups(try_ret!(NamedGroups::read(&mut sub)))
|
||||
}
|
||||
ExtensionType::SignatureAlgorithms =>
|
||||
ClientExtension::SignatureAlgorithms(try_ret!(SupportedSignatureSchemes::read(&mut sub))),
|
||||
ExtensionType::SignatureAlgorithms => {
|
||||
let schemes = try_ret!(SupportedSignatureSchemes::read(&mut sub));
|
||||
ClientExtension::SignatureAlgorithms(schemes)
|
||||
}
|
||||
ExtensionType::Heartbeat => {
|
||||
ClientExtension::Heartbeat(try_ret!(HeartbeatMode::read(&mut sub)))
|
||||
}
|
||||
|
@ -648,6 +653,9 @@ impl Codec for ClientExtension {
|
|||
ClientExtension::PresharedKey(try_ret!(PresharedKeyOffer::read(&mut sub)))
|
||||
}
|
||||
ExtensionType::Cookie => ClientExtension::Cookie(try_ret!(PayloadU16::read(&mut sub))),
|
||||
ExtensionType::ExtendedMasterSecret if !sub.any_left() => {
|
||||
ClientExtension::ExtendedMasterSecretRequest
|
||||
}
|
||||
_ => ClientExtension::Unknown(try_ret!(UnknownExtension::read(typ, &mut sub))),
|
||||
})
|
||||
}
|
||||
|
@ -669,12 +677,13 @@ impl ClientExtension {
|
|||
pub enum ServerExtension {
|
||||
ECPointFormats(ECPointFormatList),
|
||||
Heartbeat(HeartbeatMode),
|
||||
ServerNameAcknowledgement,
|
||||
SessionTicketAcknowledgement,
|
||||
ServerNameAck,
|
||||
SessionTicketAck,
|
||||
RenegotiationInfo(PayloadU8),
|
||||
Protocols(ProtocolNameList),
|
||||
KeyShare(KeyShareEntry),
|
||||
PresharedKey(u16),
|
||||
ExtendedMasterSecretAck,
|
||||
Unknown(UnknownExtension),
|
||||
}
|
||||
|
||||
|
@ -683,12 +692,13 @@ impl ServerExtension {
|
|||
match *self {
|
||||
ServerExtension::ECPointFormats(_) => ExtensionType::ECPointFormats,
|
||||
ServerExtension::Heartbeat(_) => ExtensionType::Heartbeat,
|
||||
ServerExtension::ServerNameAcknowledgement => ExtensionType::ServerName,
|
||||
ServerExtension::SessionTicketAcknowledgement => ExtensionType::SessionTicket,
|
||||
ServerExtension::ServerNameAck => ExtensionType::ServerName,
|
||||
ServerExtension::SessionTicketAck => ExtensionType::SessionTicket,
|
||||
ServerExtension::RenegotiationInfo(_) => ExtensionType::RenegotiationInfo,
|
||||
ServerExtension::Protocols(_) => ExtensionType::ALProtocolNegotiation,
|
||||
ServerExtension::KeyShare(_) => ExtensionType::KeyShare,
|
||||
ServerExtension::PresharedKey(_) => ExtensionType::PreSharedKey,
|
||||
ServerExtension::ExtendedMasterSecretAck => ExtensionType::ExtendedMasterSecret,
|
||||
ServerExtension::Unknown(ref r) => r.typ,
|
||||
}
|
||||
}
|
||||
|
@ -702,12 +712,13 @@ impl Codec for ServerExtension {
|
|||
match *self {
|
||||
ServerExtension::ECPointFormats(ref r) => r.encode(&mut sub),
|
||||
ServerExtension::Heartbeat(ref r) => r.encode(&mut sub),
|
||||
ServerExtension::ServerNameAcknowledgement => (),
|
||||
ServerExtension::SessionTicketAcknowledgement => (),
|
||||
ServerExtension::ServerNameAck => (),
|
||||
ServerExtension::SessionTicketAck => (),
|
||||
ServerExtension::RenegotiationInfo(ref r) => r.encode(&mut sub),
|
||||
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::ExtendedMasterSecretAck => (),
|
||||
ServerExtension::Unknown(ref r) => r.encode(&mut sub),
|
||||
}
|
||||
|
||||
|
@ -727,8 +738,8 @@ impl Codec for ServerExtension {
|
|||
ExtensionType::Heartbeat => {
|
||||
ServerExtension::Heartbeat(try_ret!(HeartbeatMode::read(&mut sub)))
|
||||
}
|
||||
ExtensionType::ServerName => ServerExtension::ServerNameAcknowledgement,
|
||||
ExtensionType::SessionTicket => ServerExtension::SessionTicketAcknowledgement,
|
||||
ExtensionType::ServerName => ServerExtension::ServerNameAck,
|
||||
ExtensionType::SessionTicket => ServerExtension::SessionTicketAck,
|
||||
ExtensionType::RenegotiationInfo => {
|
||||
ServerExtension::RenegotiationInfo(try_ret!(PayloadU8::read(&mut sub)))
|
||||
}
|
||||
|
@ -741,6 +752,7 @@ impl Codec for ServerExtension {
|
|||
ExtensionType::PreSharedKey => {
|
||||
ServerExtension::PresharedKey(try_ret!(codec::read_u16(&mut sub)))
|
||||
}
|
||||
ExtensionType::ExtendedMasterSecret => ServerExtension::ExtendedMasterSecretAck,
|
||||
_ => ServerExtension::Unknown(try_ret!(UnknownExtension::read(typ, &mut sub))),
|
||||
})
|
||||
}
|
||||
|
@ -941,6 +953,11 @@ impl ClientHelloPayload {
|
|||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn ems_support_offered(&self) -> bool {
|
||||
self.find_extension(ExtensionType::ExtendedMasterSecret)
|
||||
.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -1151,6 +1168,11 @@ impl ServerHelloPayload {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ems_support_acked(&self) -> bool {
|
||||
self.find_extension(ExtensionType::ExtendedMasterSecret)
|
||||
.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
pub type ASN1Cert = key::Certificate; // PayloadU24;
|
||||
|
|
|
@ -56,7 +56,8 @@ pub struct ClientSessionValue {
|
|||
pub master_secret: PayloadU8,
|
||||
pub epoch: u64,
|
||||
pub lifetime: u32,
|
||||
pub age_add: u32
|
||||
pub age_add: u32,
|
||||
pub extended_ms: bool,
|
||||
}
|
||||
|
||||
impl Codec for ClientSessionValue {
|
||||
|
@ -69,6 +70,7 @@ impl Codec for ClientSessionValue {
|
|||
codec::encode_u64(self.epoch, bytes);
|
||||
codec::encode_u32(self.lifetime, bytes);
|
||||
codec::encode_u32(self.age_add, bytes);
|
||||
codec::encode_u8(if self.extended_ms { 1u8 } else { 0u8 }, bytes);
|
||||
}
|
||||
|
||||
fn read(r: &mut Reader) -> Option<ClientSessionValue> {
|
||||
|
@ -80,6 +82,7 @@ impl Codec for ClientSessionValue {
|
|||
let epoch = try_ret!(codec::read_u64(r));
|
||||
let lifetime = try_ret!(codec::read_u32(r));
|
||||
let age_add = try_ret!(codec::read_u32(r));
|
||||
let extended_ms = try_ret!(codec::read_u8(r));
|
||||
|
||||
Some(ClientSessionValue {
|
||||
version: v,
|
||||
|
@ -89,7 +92,8 @@ impl Codec for ClientSessionValue {
|
|||
master_secret: ms,
|
||||
epoch: epoch,
|
||||
lifetime: lifetime,
|
||||
age_add: age_add
|
||||
age_add: age_add,
|
||||
extended_ms: extended_ms == 1u8,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -111,10 +115,15 @@ impl ClientSessionValue {
|
|||
master_secret: PayloadU8::new(ms),
|
||||
epoch: 0,
|
||||
lifetime: 0,
|
||||
age_add: 0
|
||||
age_add: 0,
|
||||
extended_ms: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_extended_ms_used(&mut self) {
|
||||
self.extended_ms = true;
|
||||
}
|
||||
|
||||
pub fn set_times(&mut self, receipt_time_secs: u64,
|
||||
lifetime_secs: u32, age_add: u32) {
|
||||
self.epoch = receipt_time_secs;
|
||||
|
@ -147,6 +156,7 @@ pub struct ServerSessionValue {
|
|||
pub version: ProtocolVersion,
|
||||
pub cipher_suite: CipherSuite,
|
||||
pub master_secret: PayloadU8,
|
||||
pub extended_ms: bool,
|
||||
pub client_cert_chain: Option<CertificatePayload>,
|
||||
}
|
||||
|
||||
|
@ -155,6 +165,7 @@ impl Codec for ServerSessionValue {
|
|||
self.version.encode(bytes);
|
||||
self.cipher_suite.encode(bytes);
|
||||
self.master_secret.encode(bytes);
|
||||
codec::encode_u8(if self.extended_ms { 1u8 } else { 0u8 }, bytes);
|
||||
if self.client_cert_chain.is_some() {
|
||||
self.client_cert_chain.as_ref().unwrap().encode(bytes);
|
||||
}
|
||||
|
@ -164,6 +175,7 @@ impl Codec for ServerSessionValue {
|
|||
let v = try_ret!(ProtocolVersion::read(r));
|
||||
let cs = try_ret!(CipherSuite::read(r));
|
||||
let ms = try_ret!(PayloadU8::read(r));
|
||||
let ems = try_ret!(codec::read_u8(r));
|
||||
let ccert = if r.any_left() {
|
||||
CertificatePayload::read(r)
|
||||
} else {
|
||||
|
@ -174,6 +186,7 @@ impl Codec for ServerSessionValue {
|
|||
version: v,
|
||||
cipher_suite: cs,
|
||||
master_secret: ms,
|
||||
extended_ms: ems == 1u8,
|
||||
client_cert_chain: ccert,
|
||||
})
|
||||
}
|
||||
|
@ -189,7 +202,12 @@ impl ServerSessionValue {
|
|||
version: v,
|
||||
cipher_suite: cs,
|
||||
master_secret: PayloadU8::new(ms),
|
||||
extended_ms: false,
|
||||
client_cert_chain: cert_chain.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_extended_ms_used(&mut self) {
|
||||
self.extended_ms = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,6 +319,7 @@ pub struct ServerHandshakeData {
|
|||
pub kx_data: Option<KeyExchange>,
|
||||
pub doing_resume: bool,
|
||||
pub send_ticket: bool,
|
||||
pub using_ems: bool,
|
||||
pub doing_client_auth: bool,
|
||||
pub done_retry: bool,
|
||||
pub valid_client_cert_chain: Option<Vec<key::Certificate>>,
|
||||
|
@ -334,6 +335,7 @@ impl ServerHandshakeData {
|
|||
hash_at_server_fin: vec![],
|
||||
kx_data: None,
|
||||
send_ticket: false,
|
||||
using_ems: false,
|
||||
doing_resume: false,
|
||||
doing_client_auth: false,
|
||||
done_retry: false,
|
||||
|
|
|
@ -87,7 +87,7 @@ fn process_extensions(sess: &mut ServerSessionImpl,
|
|||
|
||||
// SNI
|
||||
if hello.get_sni_extension().is_some() {
|
||||
ret.push(ServerExtension::ServerNameAcknowledgement);
|
||||
ret.push(ServerExtension::ServerNameAck);
|
||||
}
|
||||
|
||||
if !sess.common.is_tls13() {
|
||||
|
@ -107,7 +107,12 @@ fn process_extensions(sess: &mut ServerSessionImpl,
|
|||
if hello.find_extension(ExtensionType::SessionTicket).is_some() &&
|
||||
sess.config.ticketer.enabled() {
|
||||
sess.handshake_data.send_ticket = true;
|
||||
ret.push(ServerExtension::SessionTicketAcknowledgement);
|
||||
ret.push(ServerExtension::SessionTicketAck);
|
||||
}
|
||||
|
||||
// Confirm use of EMS if offered.
|
||||
if sess.handshake_data.using_ems {
|
||||
ret.push(ServerExtension::ExtendedMasterSecretAck);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,8 +275,13 @@ fn can_resume(sess: &ServerSessionImpl,
|
|||
resumedata: &Option<persist::ServerSessionValue>) -> bool {
|
||||
// The RFCs underspecify what happens if we try to resume to
|
||||
// an unoffered/varying suite. We merely don't resume in weird cases.
|
||||
resumedata.is_some() &&
|
||||
resumedata.as_ref().unwrap().cipher_suite == sess.common.get_suite().suite
|
||||
if let Some(ref resume) = *resumedata {
|
||||
resume.cipher_suite == sess.common.get_suite().suite &&
|
||||
(resume.extended_ms == sess.handshake_data.using_ems ||
|
||||
(resume.extended_ms && !sess.handshake_data.using_ems))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn start_resumption(sess: &mut ServerSessionImpl,
|
||||
|
@ -281,6 +291,10 @@ fn start_resumption(sess: &mut ServerSessionImpl,
|
|||
-> StateResult {
|
||||
info!("Resuming session");
|
||||
|
||||
if resumedata.extended_ms && !sess.handshake_data.using_ems {
|
||||
return Err(illegal_param(sess, "refusing to resume without ems"));
|
||||
}
|
||||
|
||||
sess.handshake_data.session_id = id.clone();
|
||||
try!(emit_server_hello(sess, client_hello));
|
||||
|
||||
|
@ -785,6 +799,10 @@ fn handle_client_hello(sess: &mut ServerSessionImpl, m: Message) -> StateResult
|
|||
// Save their Random.
|
||||
client_hello.random.write_slice(&mut sess.handshake_data.randoms.client);
|
||||
|
||||
if client_hello.ems_support_offered() {
|
||||
sess.handshake_data.using_ems = true;
|
||||
}
|
||||
|
||||
let groups_ext = try!(client_hello.get_namedgroups_extension()
|
||||
.ok_or_else(|| incompatible(sess, "client didn't describe groups")));
|
||||
let ecpoints_ext = try!(client_hello.get_ecpoints_extension()
|
||||
|
@ -989,8 +1007,17 @@ fn handle_client_kx(sess: &mut ServerSessionImpl, m: Message) -> StateResult {
|
|||
};
|
||||
|
||||
let hashalg = sess.common.get_suite().get_hash();
|
||||
sess.secrets =
|
||||
Some(SessionSecrets::new(&sess.handshake_data.randoms, hashalg, &kxd.premaster_secret));
|
||||
if sess.handshake_data.using_ems {
|
||||
let handshake_hash = sess.handshake_data.transcript.get_current_hash();
|
||||
sess.secrets = Some(SessionSecrets::new_ems(&sess.handshake_data.randoms,
|
||||
&handshake_hash,
|
||||
hashalg,
|
||||
&kxd.premaster_secret));
|
||||
} else {
|
||||
sess.secrets = Some(SessionSecrets::new(&sess.handshake_data.randoms,
|
||||
hashalg,
|
||||
&kxd.premaster_secret));
|
||||
}
|
||||
sess.start_encryption_tls12();
|
||||
|
||||
if sess.handshake_data.doing_client_auth {
|
||||
|
@ -1171,7 +1198,13 @@ fn get_server_session_value(sess: &ServerSessionImpl) -> persist::ServerSessionV
|
|||
(ProtocolVersion::TLSv1_2, sess.secrets.as_ref().unwrap().get_master_secret())
|
||||
};
|
||||
|
||||
persist::ServerSessionValue::new(version, scs.suite, secret, client_certs)
|
||||
let mut v = persist::ServerSessionValue::new(version, scs.suite, secret, client_certs);
|
||||
|
||||
if sess.handshake_data.using_ems {
|
||||
v.set_extended_ms_used();
|
||||
}
|
||||
|
||||
v
|
||||
}
|
||||
|
||||
fn handle_finished(sess: &mut ServerSessionImpl, m: Message) -> StateResult {
|
||||
|
|
|
@ -150,6 +150,24 @@ impl SessionSecrets {
|
|||
ret
|
||||
}
|
||||
|
||||
pub fn new_ems(randoms: &SessionRandoms,
|
||||
hs_hash: &[u8],
|
||||
hashalg: &'static ring::digest::Algorithm,
|
||||
pms: &[u8]) -> SessionSecrets {
|
||||
let mut ret = SessionSecrets {
|
||||
randoms: randoms.clone(),
|
||||
hash: hashalg,
|
||||
master_secret: [0u8; 48]
|
||||
};
|
||||
|
||||
prf::prf(&mut ret.master_secret,
|
||||
ret.hash,
|
||||
pms,
|
||||
b"extended master secret",
|
||||
hs_hash);
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn new_resume(randoms: &SessionRandoms,
|
||||
hashalg: &'static ring::digest::Algorithm,
|
||||
master_secret: &[u8])
|
||||
|
|
Loading…
Reference in New Issue