diff --git a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c index 882e356..396c408 100644 --- a/nss/lib/ssl/ssl3con.c +++ b/nss/lib/ssl/ssl3con.c @@ -7594,6 +7594,33 @@ ssl3_SendClientSecondRound(sslSocket *ss) ssl_ReleaseXmitBufLock(ss); /*******************************/ + if (!ss->ssl3.hs.isResuming && + ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)) { + /* If we are negotiating ChannelID on a full handshake then we record + * the handshake hashes in |sid| at this point. They will be needed in + * the event that we resume this session and use ChannelID on the + * resumption handshake. */ + SSL3Hashes hashes; + SECItem *originalHandshakeHash = + &ss->sec.ci.sid->u.ssl3.originalHandshakeHash; + PORT_Assert(ss->sec.ci.sid->cached == never_cached); + + ssl_GetSpecReadLock(ss); + PORT_Assert(ss->version > SSL_LIBRARY_VERSION_3_0); + rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0); + ssl_ReleaseSpecReadLock(ss); + if (rv != SECSuccess) { + return rv; + } + + PORT_Assert(originalHandshakeHash->len == 0); + originalHandshakeHash->data = PORT_Alloc(hashes.len); + if (!originalHandshakeHash->data) + return SECFailure; + originalHandshakeHash->len = hashes.len; + memcpy(originalHandshakeHash->data, hashes.u.raw, hashes.len); + } + if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) ss->ssl3.hs.ws = wait_new_session_ticket; else @@ -10590,6 +10617,7 @@ static SECStatus ssl3_SendEncryptedExtensions(sslSocket *ss) { static const char CHANNEL_ID_MAGIC[] = "TLS Channel ID signature"; + static const char CHANNEL_ID_RESUMPTION_MAGIC[] = "Resumption"; /* This is the ASN.1 prefix for a P-256 public key. Specifically it's: * SEQUENCE * SEQUENCE @@ -10615,7 +10643,10 @@ ssl3_SendEncryptedExtensions(sslSocket *ss) SECItem *spki = NULL; SSL3Hashes hashes; const unsigned char *pub_bytes; - unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + sizeof(SSL3Hashes)]; + unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + + sizeof(CHANNEL_ID_RESUMPTION_MAGIC) + + sizeof(SSL3Hashes)*2]; + size_t signed_data_len; unsigned char digest[SHA256_LENGTH]; SECItem digest_item; unsigned char signature[64]; @@ -10665,11 +10696,26 @@ ssl3_SendEncryptedExtensions(sslSocket *ss) pub_bytes = spki->data + sizeof(P256_SPKI_PREFIX); - memcpy(signed_data, CHANNEL_ID_MAGIC, sizeof(CHANNEL_ID_MAGIC)); - memcpy(signed_data + sizeof(CHANNEL_ID_MAGIC), hashes.u.raw, hashes.len); + signed_data_len = 0; + memcpy(signed_data + signed_data_len, CHANNEL_ID_MAGIC, + sizeof(CHANNEL_ID_MAGIC)); + signed_data_len += sizeof(CHANNEL_ID_MAGIC); + if (ss->ssl3.hs.isResuming) { + SECItem *originalHandshakeHash = + &ss->sec.ci.sid->u.ssl3.originalHandshakeHash; + PORT_Assert(originalHandshakeHash->len > 0); - rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, - sizeof(CHANNEL_ID_MAGIC) + hashes.len); + memcpy(signed_data + signed_data_len, CHANNEL_ID_RESUMPTION_MAGIC, + sizeof(CHANNEL_ID_RESUMPTION_MAGIC)); + signed_data_len += sizeof(CHANNEL_ID_RESUMPTION_MAGIC); + memcpy(signed_data + signed_data_len, originalHandshakeHash->data, + originalHandshakeHash->len); + signed_data_len += originalHandshakeHash->len; + } + memcpy(signed_data + signed_data_len, hashes.u.raw, hashes.len); + signed_data_len += hashes.len; + + rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, signed_data_len); if (rv != SECSuccess) goto loser; diff --git a/nss/lib/ssl/ssl3ext.c b/nss/lib/ssl/ssl3ext.c index 03cf05c..166022c 100644 --- a/nss/lib/ssl/ssl3ext.c +++ b/nss/lib/ssl/ssl3ext.c @@ -812,6 +812,15 @@ ssl3_ClientSendChannelIDXtn(sslSocket * ss, PRBool append, return 0; } + if (ss->sec.ci.sid->cached != never_cached && + ss->sec.ci.sid->u.ssl3.originalHandshakeHash.len == 0) { + /* We can't do ChannelID on a connection if we're resuming and didn't + * do ChannelID on the original connection: without ChannelID on the + * original connection we didn't record the handshake hashes needed for + * the signature. */ + return 0; + } + if (append) { SECStatus rv; rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); diff --git a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h index 9c789bf..ca68727 100644 --- a/nss/lib/ssl/sslimpl.h +++ b/nss/lib/ssl/sslimpl.h @@ -705,6 +705,14 @@ struct sslSessionIDStr { */ NewSessionTicket sessionTicket; SECItem srvName; + + /* originalHandshakeHash contains the hash of the original, full + * handshake prior to the server's final flow. This is either a + * SHA-1/MD5 combination (for TLS < 1.2) or the TLS PRF hash (for + * TLS 1.2). This is recorded and used only when ChannelID is + * negotiated as it's used to bind the ChannelID signature on the + * resumption handshake to the original handshake. */ + SECItem originalHandshakeHash; } ssl3; } u; }; diff --git a/nss/lib/ssl/sslnonce.c b/nss/lib/ssl/sslnonce.c index a6f7349..eb5004c 100644 --- a/nss/lib/ssl/sslnonce.c +++ b/nss/lib/ssl/sslnonce.c @@ -148,6 +148,9 @@ ssl_DestroySID(sslSessionID *sid) if (sid->u.ssl3.srvName.data) { SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); } + if (sid->u.ssl3.originalHandshakeHash.data) { + SECITEM_FreeItem(&sid->u.ssl3.originalHandshakeHash, PR_FALSE); + } PORT_ZFree(sid, sizeof(sslSessionID)); } diff --git a/nss/lib/ssl/sslt.h b/nss/lib/ssl/sslt.h index e4d188f..b813c04 100644 --- a/nss/lib/ssl/sslt.h +++ b/nss/lib/ssl/sslt.h @@ -204,7 +204,7 @@ typedef enum { ssl_app_layer_protocol_xtn = 16, ssl_session_ticket_xtn = 35, ssl_next_proto_nego_xtn = 13172, - ssl_channel_id_xtn = 30031, + ssl_channel_id_xtn = 30032, ssl_padding_xtn = 35655, ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ } SSLExtensionType;