Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 1381198 - Add nonce to session ticket, r=ekr
--HG--
branch : NSS_TLS13_DRAFT19_BRANCH
extra : rebase_source : 238f3dc95a541921be9401195346579d9b41b59e
  • Loading branch information
martinthomson committed Jul 14, 2017
1 parent 509c356 commit a43c11d
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 42 deletions.
1 change: 0 additions & 1 deletion gtests/ssl_gtest/libssl_internals.c
Expand Up @@ -136,7 +136,6 @@ PRBool SSLInt_CheckSecretsDestroyed(PRFileDesc *fd) {
}

CHECK_SECRET(currentSecret);
CHECK_SECRET(resumptionMasterSecret);
CHECK_SECRET(dheSecret);
CHECK_SECRET(clientEarlyTrafficSecret);
CHECK_SECRET(clientHsTrafficSecret);
Expand Down
3 changes: 3 additions & 0 deletions gtests/ssl_gtest/tls_filter.cc
Expand Up @@ -470,6 +470,9 @@ static bool FindNewSessionTicketExtensions(TlsParser* parser,
if (!parser->Skip(8)) { // lifetime, age add
return false;
}
if (!parser->SkipVariable(1)) { // ticket_nonce
return false;
}
if (!parser->SkipVariable(2)) { // ticket
return false;
}
Expand Down
20 changes: 11 additions & 9 deletions lib/ssl/ssl3con.c
Expand Up @@ -10145,7 +10145,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
SECStatus rv;
NewSessionTicket nticket = { 0 };

rv = ssl3_EncodeSessionTicket(ss, &nticket, &ticket);
rv = ssl3_EncodeSessionTicket(ss, &nticket, &ticket,
ss->ssl3.pwSpec->master_secret);
if (rv != SECSuccess)
goto loser;

Expand Down Expand Up @@ -11229,8 +11230,8 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags)
* Caller holds the Spec read lock.
*/
SECStatus
ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid,
ssl3CipherSpec *spec)
ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid,
PK11SymKey *secret)
{
PK11SymKey *wrappingKey = NULL;
PK11SlotInfo *symKeySlot;
Expand All @@ -11239,7 +11240,7 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid,
PRBool isServer = ss->sec.isServer;
CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;

symKeySlot = PK11_GetSlotFromKey(spec->master_secret);
symKeySlot = PK11_GetSlotFromKey(secret);
if (!isServer) {
int wrapKeyIndex;
int incarnation;
Expand Down Expand Up @@ -11300,7 +11301,7 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid,
wmsItem.data = sid->u.ssl3.keys.wrapped_master_secret;
wmsItem.len = sizeof sid->u.ssl3.keys.wrapped_master_secret;
rv = PK11_WrapSymKey(mechanism, NULL, wrappingKey,
spec->master_secret, &wmsItem);
secret, &wmsItem);
/* rv is examined below. */
sid->u.ssl3.keys.wrapped_master_secret_len = wmsItem.len;
PK11_FreeSymKey(wrappingKey);
Expand Down Expand Up @@ -11450,7 +11451,7 @@ ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length,
}

if (sid->cached == never_cached && !ss->opt.noCache) {
rv = ssl3_FillInCachedSID(ss, sid);
rv = ssl3_FillInCachedSID(ss, sid, ss->ssl3.crSpec->master_secret);

/* If the wrap failed, we don't cache the sid.
* The connection continues normally however.
Expand All @@ -11474,7 +11475,7 @@ ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length,
}

SECStatus
ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid)
ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, PK11SymKey *secret)
{
SECStatus rv;

Expand Down Expand Up @@ -11506,6 +11507,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid)

/* Copy the master secret (wrapped or unwrapped) into the sid */
if (ss->ssl3.crSpec->msItem.len && ss->ssl3.crSpec->msItem.data) {
PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
sid->u.ssl3.keys.wrapped_master_secret_len =
ss->ssl3.crSpec->msItem.len;
memcpy(sid->u.ssl3.keys.wrapped_master_secret,
Expand All @@ -11514,8 +11516,8 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid)
sid->u.ssl3.keys.msIsWrapped = PR_FALSE;
rv = SECSuccess;
} else {
rv = ssl3_CacheWrappedMasterSecret(ss, ss->sec.ci.sid,
ss->ssl3.crSpec);
PORT_Assert(secret);
rv = ssl3_CacheWrappedSecret(ss, ss->sec.ci.sid, secret);
sid->u.ssl3.keys.msIsWrapped = PR_TRUE;
}
ssl_ReleaseSpecReadLock(ss); /*************************************/
Expand Down
19 changes: 8 additions & 11 deletions lib/ssl/ssl3exthandle.c
Expand Up @@ -662,7 +662,7 @@ PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */
SECStatus
ssl3_EncodeSessionTicket(sslSocket *ss,
const NewSessionTicket *ticket,
SECItem *ticket_data)
SECItem *ticket_data, PK11SymKey *secret)
{
SECStatus rv;
SECItem plaintext;
Expand All @@ -677,7 +677,6 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
SECItem *srvName = NULL;
CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value,
* must be >= 0 */
ssl3CipherSpec *spec;
SECItem *alpnSelection = NULL;

SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake",
Expand All @@ -690,22 +689,20 @@ ssl3_EncodeSessionTicket(sslSocket *ss,
cert_length = 2 + ss->sec.ci.sid->peerCert->derCert.len;
}

if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
spec = ss->ssl3.cwSpec;
} else {
spec = ss->ssl3.pwSpec;
}
if (spec->msItem.len && spec->msItem.data) {
if (ss->ssl3.pwSpec->msItem.len && ss->ssl3.pwSpec->msItem.data) {
PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
/* The master secret is available unwrapped. */
ms_item.data = spec->msItem.data;
ms_item.len = spec->msItem.len;
ms_item.data = ss->ssl3.pwSpec->msItem.data;
ms_item.len = ss->ssl3.pwSpec->msItem.len;
ms_is_wrapped = PR_FALSE;
} else {
/* Extract the master secret wrapped. */
sslSessionID sid;

PORT_Memset(&sid, 0, sizeof(sslSessionID));

rv = ssl3_CacheWrappedMasterSecret(ss, &sid, spec);
PORT_Assert(secret);
rv = ssl3_CacheWrappedSecret(ss, &sid, secret);
if (rv == SECSuccess) {
if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms))
goto loser;
Expand Down
9 changes: 5 additions & 4 deletions lib/ssl/sslimpl.h
Expand Up @@ -1683,16 +1683,16 @@ extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash,
SECKEYPrivateKey *key, SECItem *buf);
extern SECStatus ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme,
SSL3Hashes *hash, SECItem *buf);
extern SECStatus ssl3_CacheWrappedMasterSecret(
sslSocket *ss, sslSessionID *sid, ssl3CipherSpec *spec);
extern SECStatus ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid,
PK11SymKey *secret);
extern void ssl3_FreeSniNameArray(TLSExtensionData *xtnData);

/* Hello Extension related routines. */
extern void ssl3_SetSIDSessionTicket(sslSessionID *sid,
/*in/out*/ NewSessionTicket *session_ticket);
SECStatus ssl3_EncodeSessionTicket(sslSocket *ss,
const NewSessionTicket *ticket_input,
SECItem *ticket_data);
SECItem *ticket_data, PK11SymKey *secret);

SECStatus ssl_MaybeSetSelfEncryptKeyPair(const sslKeyPair *keyPair);
SECStatus ssl_GetSelfEncryptKeys(sslSocket *ss, unsigned char *keyName,
Expand Down Expand Up @@ -1813,7 +1813,8 @@ PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss,
PK11SlotInfo *masterSecretSlot,
CK_MECHANISM_TYPE masterWrapMech,
void *pwArg);
SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid);
SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid,
PK11SymKey *secret);
const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
const ssl3BulkCipherDef *
ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_def);
Expand Down
68 changes: 51 additions & 17 deletions lib/ssl/tls13con.c
Expand Up @@ -125,6 +125,7 @@ const char kHkdfLabelApplicationTrafficSecret[] = "ap traffic";
const char kHkdfLabelFinishedSecret[] = "finished";
const char kHkdfLabelResumptionMasterSecret[] = "res master";
const char kHkdfLabelExporterMasterSecret[] = "exp master";
const char kHkdfLabelResumption[] = "resumption";
const char kHkdfPurposeKey[] = "key";
const char kHkdfPurposeIv[] = "iv";

Expand Down Expand Up @@ -791,9 +792,8 @@ tls13_ComputeEarlySecrets(sslSocket *ss)
if (rv != SECSuccess) {
return SECFailure;
}
} else {
PORT_Assert(!ss->ssl3.hs.resumptionMasterSecret);
}
PORT_Assert(!ss->ssl3.hs.resumptionMasterSecret);

return SECSuccess;
}
Expand Down Expand Up @@ -915,30 +915,19 @@ static SECStatus
tls13_ComputeFinalSecrets(sslSocket *ss)
{
SECStatus rv;
PK11SymKey *resumptionMasterSecret = NULL;

PORT_Assert(!ss->ssl3.crSpec->master_secret);
PORT_Assert(!ss->ssl3.cwSpec->master_secret);

rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
NULL, kHkdfLabelResumptionMasterSecret,
&resumptionMasterSecret);
&ss->ssl3.hs.resumptionMasterSecret);
PK11_FreeSymKey(ss->ssl3.hs.currentSecret);
ss->ssl3.hs.currentSecret = NULL;
if (rv != SECSuccess) {
return SECFailure;
}

/* This is pretty gross. TLS 1.3 uses a number of master secrets:
* The master secret to generate the keys and then the resumption
* master secret for future connections. To make this work without
* refactoring too much of the SSLv3 code, we store the RMS in
* |crSpec->master_secret| and |cwSpec->master_secret|.
*/
ss->ssl3.crSpec->master_secret = resumptionMasterSecret;
ss->ssl3.cwSpec->master_secret =
PK11_ReferenceSymKey(ss->ssl3.crSpec->master_secret);

return SECSuccess;
}

Expand Down Expand Up @@ -3849,6 +3838,7 @@ tls13_SendClientSecondRound(sslSocket *ss)
* struct {
* uint32 ticket_lifetime;
* uint32 ticket_age_add;
* opaque ticket_nonce<1..255>;
* opaque ticket<1..2^16-1>;
* TicketExtension extensions<0..2^16-2>;
* } NewSessionTicket;
Expand All @@ -3860,24 +3850,39 @@ SECStatus
tls13_SendNewSessionTicket(sslSocket *ss)
{
PRUint16 message_length;
PK11SymKey *secret;
SECItem ticket_data = { 0, NULL, 0 };
SECStatus rv;
NewSessionTicket ticket = { 0 };
PRUint32 max_early_data_size_len = 0;

ticket.flags = 0;
if (ss->opt.enable0RttData) {
ticket.flags |= ticket_allow_early_data;
max_early_data_size_len = 8; /* type + len + value. */
}
ticket.ticket_lifetime_hint = ssl_ticket_lifetime;

rv = ssl3_EncodeSessionTicket(ss, &ticket, &ticket_data);
rv = tls13_HkdfExpandLabel(ss->ssl3.hs.resumptionMasterSecret,
tls13_GetHash(ss),
NULL, 0,
kHkdfLabelResumption,
strlen(kHkdfLabelResumption),
tls13_GetHkdfMechanism(ss),
tls13_GetHashSize(ss), &secret);
if (rv != SECSuccess) {
goto loser;
}

rv = ssl3_EncodeSessionTicket(ss, &ticket, &ticket_data, secret);
PK11_FreeSymKey(secret);
if (rv != SECSuccess)
goto loser;

message_length =
4 + /* lifetime */
4 + /* ticket_age_add */
1 + /* ticket_nonce length */
2 + max_early_data_size_len + /* max_early_data_size_len */
2 + /* ticket length */
ticket_data.len;
Expand All @@ -3902,6 +3907,11 @@ tls13_SendNewSessionTicket(sslSocket *ss)
if (rv != SECSuccess)
goto loser;

/* An empty nonce. */
rv = ssl3_AppendHandshakeVariable(ss, NULL, 0, 1);
if (rv != SECSuccess)
goto loser;

/* Encode the ticket. */
rv = ssl3_AppendHandshakeVariable(
ss, ticket_data.data, ticket_data.len, 2);
Expand Down Expand Up @@ -3946,6 +3956,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
PRUint32 utmp;
NewSessionTicket ticket = { 0 };
SECItem data;
SECItem ticket_nonce;
SECItem ticket_data;

SSL_TRC(3, ("%d: TLS13[%d]: handle new session ticket message",
Expand Down Expand Up @@ -3980,6 +3991,14 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
ticket.ticket_age_add = PR_ntohl(utmp);

/* The nonce. */
rv = ssl3_ConsumeHandshakeVariable(ss, &ticket_nonce, 1, &b, &length);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET,
decode_error);
return SECFailure;
}

/* Get the ticket value. */
rv = ssl3_ConsumeHandshakeVariable(ss, &ticket_data, 2, &b, &length);
if (rv != SECSuccess || !ticket_data.len) {
Expand Down Expand Up @@ -4009,6 +4028,8 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
}

if (!ss->opt.noCache) {
PK11SymKey *secret;

PORT_Assert(ss->sec.ci.sid);
rv = SECITEM_CopyItem(NULL, &ticket.ticket, &ticket_data);
if (rv != SECSuccess) {
Expand Down Expand Up @@ -4045,9 +4066,22 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
ssl3_SetSIDSessionTicket(ss->sec.ci.sid, &ticket);
PORT_Assert(!ticket.ticket.data);

rv = ssl3_FillInCachedSID(ss, ss->sec.ci.sid);
if (rv != SECSuccess)
rv = tls13_HkdfExpandLabel(ss->ssl3.hs.resumptionMasterSecret,
tls13_GetHash(ss),
ticket_nonce.data, ticket_nonce.len,
kHkdfLabelResumption,
strlen(kHkdfLabelResumption),
tls13_GetHkdfMechanism(ss),
tls13_GetHashSize(ss), &secret);
if (rv != SECSuccess) {
return SECFailure;
}

rv = ssl3_FillInCachedSID(ss, ss->sec.ci.sid, secret);
PK11_FreeSymKey(secret);
if (rv != SECSuccess) {
return SECFailure;
}

/* Cache the session. */
ss->sec.cache(ss->sec.ci.sid);
Expand Down

0 comments on commit a43c11d

Please sign in to comment.