diff options
Diffstat (limited to 'security/nss/lib/ssl/tls13exthandle.c')
-rw-r--r-- | security/nss/lib/ssl/tls13exthandle.c | 813 |
1 files changed, 471 insertions, 342 deletions
diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c index 899f23827..c2ce390ff 100644 --- a/security/nss/lib/ssl/tls13exthandle.c +++ b/security/nss/lib/ssl/tls13exthandle.c @@ -14,35 +14,50 @@ #include "ssl3exthandle.h" #include "tls13exthandle.h" -SECStatus -tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ServerSendStatusRequestXtn( + const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; const sslServerCert *serverCert = ss->sec.serverCert; const SECItem *item; SECStatus rv; if (!serverCert->certStatusArray || !serverCert->certStatusArray->len) { - return SECSuccess; + return 0; } item = &serverCert->certStatusArray->items[0]; /* Only send the first entry. */ - /* status_type == ocsp */ - rv = sslBuffer_AppendNumber(buf, 1 /*ocsp*/, 1); - if (rv != SECSuccess) { - return SECFailure; + extension_length = 2 + 2 + 1 /* status_type */ + 3 + item->len; + if (maxBytes < (PRUint32)extension_length) { + return 0; } - /* opaque OCSPResponse<1..2^24-1> */ - rv = sslBuffer_AppendVariable(buf, item->data, item->len, 3); - if (rv != SECSuccess) { - return SECFailure; + if (append) { + /* extension_type */ + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_cert_status_xtn, 2); + if (rv != SECSuccess) + return -1; + /* length of extension_data */ + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); + if (rv != SECSuccess) + return -1; + /* status_type == ocsp */ + rv = ssl3_ExtAppendHandshakeNumber(ss, 1 /*ocsp*/, 1); + if (rv != SECSuccess) + return rv; /* err set by AppendHandshake. */ + /* opaque OCSPResponse<1..2^24-1> */ + rv = ssl3_ExtAppendHandshakeVariable(ss, item->data, item->len, 3); + if (rv != SECSuccess) + return rv; /* err set by AppendHandshake. */ } - *added = PR_TRUE; - return SECSuccess; + return extension_length; } /* @@ -86,27 +101,41 @@ tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey) return 0; } +static PRUint32 +tls13_SizeOfClientKeyShareExtension(const sslSocket *ss) +{ + PRCList *cursor; + /* Size is: extension(2) + extension_len(2) + client_shares(2) */ + PRUint32 size = 2 + 2 + 2; + for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs); + cursor != &ss->ephemeralKeyPairs; + cursor = PR_NEXT_LINK(cursor)) { + sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor; + size += tls13_SizeOfKeyShareEntry(keyPair->keys->pubKey); + } + return size; +} + static SECStatus -tls13_EncodeKeyShareEntry(sslBuffer *buf, const sslEphemeralKeyPair *keyPair) +tls13_EncodeKeyShareEntry(const sslSocket *ss, const sslEphemeralKeyPair *keyPair) { SECStatus rv; SECKEYPublicKey *pubKey = keyPair->keys->pubKey; unsigned int size = tls13_SizeOfKeyShareEntry(pubKey); - rv = sslBuffer_AppendNumber(buf, keyPair->group->name, 2); + rv = ssl3_ExtAppendHandshakeNumber(ss, keyPair->group->name, 2); if (rv != SECSuccess) return rv; - rv = sslBuffer_AppendNumber(buf, size - 4, 2); + rv = ssl3_ExtAppendHandshakeNumber(ss, size - 4, 2); if (rv != SECSuccess) return rv; switch (pubKey->keyType) { case ecKey: - rv = sslBuffer_Append(buf, pubKey->u.ec.publicValue.data, - pubKey->u.ec.publicValue.len); + rv = tls13_EncodeECDHEKeyShareKEX(ss, pubKey); break; case dhKey: - rv = ssl_AppendPaddedDHKeyShare(buf, pubKey, PR_FALSE); + rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_FALSE); break; default: PORT_Assert(0); @@ -117,16 +146,14 @@ tls13_EncodeKeyShareEntry(sslBuffer *buf, const sslEphemeralKeyPair *keyPair) return rv; } -SECStatus -tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { - SECStatus rv; - PRCList *cursor; - unsigned int lengthOffset; + PRUint32 extension_length; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; + return 0; } /* Optimistically try to send an ECDHE key using the @@ -134,28 +161,47 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn", SSL_GETPID(), ss->fd)); - /* Save the offset to the length. */ - rv = sslBuffer_Skip(buf, 2, &lengthOffset); - if (rv != SECSuccess) { - return SECFailure; + extension_length = tls13_SizeOfClientKeyShareExtension(ss); + if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; } - for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs); - cursor != &ss->ephemeralKeyPairs; - cursor = PR_NEXT_LINK(cursor)) { - sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor; - rv = tls13_EncodeKeyShareEntry(buf, keyPair); - if (rv != SECSuccess) { - return SECFailure; + if (append) { + SECStatus rv; + PRCList *cursor; + + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2); + if (rv != SECSuccess) + goto loser; + + /* The extension length */ + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); + if (rv != SECSuccess) + goto loser; + + /* The length of KeyShares */ + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 6, 2); + if (rv != SECSuccess) + goto loser; + + for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs); + cursor != &ss->ephemeralKeyPairs; + cursor = PR_NEXT_LINK(cursor)) { + sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor; + rv = tls13_EncodeKeyShareEntry(ss, keyPair); + if (rv != SECSuccess) + goto loser; } - } - rv = sslBuffer_InsertLength(buf, lengthOffset, 2); - if (rv != SECSuccess) { - return SECFailure; + + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_key_share_xtn; } - *added = PR_TRUE; - return SECSuccess; + return extension_length; + +loser: + return -1; } static SECStatus @@ -204,8 +250,7 @@ loser: * |xtnData->remoteKeyShares| for future use. The key * share is processed in tls13_HandleServerKeyShare(). */ SECStatus -tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares)); @@ -236,8 +281,7 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, } SECStatus -tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PRUint32 tmp; @@ -287,8 +331,7 @@ tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, * |xtnData->remoteKeyShares| for future use. The key * share is processed in tls13_HandleClientKeyShare(). */ SECStatus -tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PRUint32 length; @@ -321,6 +364,16 @@ tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, goto loser; } + /* Check that the client only offered one share if this is + * after HRR. */ + if (ss->ssl3.hs.helloRetry) { + if (PR_PREV_LINK(&xtnData->remoteKeyShares) != + PR_NEXT_LINK(&xtnData->remoteKeyShares)) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); + goto loser; + } + } + return SECSuccess; loser: @@ -328,10 +381,12 @@ loser: return SECFailure; } -SECStatus -tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { + PRUint32 extension_length; + PRUint32 entry_length; SECStatus rv; sslEphemeralKeyPair *keyPair; @@ -342,13 +397,31 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); - rv = tls13_EncodeKeyShareEntry(buf, keyPair); - if (rv != SECSuccess) { - return SECFailure; + entry_length = tls13_SizeOfKeyShareEntry(keyPair->keys->pubKey); + extension_length = 2 + 2 + entry_length; /* Type + length + entry_length */ + if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; } - *added = PR_TRUE; - return SECSuccess; + if (append) { + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2); + if (rv != SECSuccess) + goto loser; + + rv = ssl3_ExtAppendHandshakeNumber(ss, entry_length, 2); + if (rv != SECSuccess) + goto loser; + + rv = tls13_EncodeKeyShareEntry(ss, keyPair); + if (rv != SECSuccess) + goto loser; + } + + return extension_length; + +loser: + return -1; } /* Called by clients. @@ -375,83 +448,113 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, * Presently the only way to get a PSK is by resumption, so this is * really a ticket label and there will be at most one. */ -SECStatus +PRInt32 tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) + PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length; + PRInt32 identities_length; + PRInt32 binders_length; NewSessionTicket *session_ticket; - PRTime age; - const static PRUint8 binder[TLS13_MAX_FINISHED_SIZE] = { 0 }; - unsigned int binderLen; - SECStatus rv; /* We only set statelessResume on the client in TLS 1.3 code. */ - if (!ss->statelessResume) { - return SECSuccess; - } - - /* Save where this extension starts so that if we have to add padding, it - * can be inserted before this extension. */ - PORT_Assert(buf->len >= 4); - xtnData->lastXtnOffset = buf->len - 4; + if (!ss->statelessResume) + return 0; PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); - /* Send a single ticket identity. */ + /* The length computations are simplified by the fact that there + * is just one ticket at most. */ session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket; - rv = sslBuffer_AppendNumber(buf, 2 + /* identity length */ - session_ticket->ticket.len + /* ticket */ - 4 /* obfuscated_ticket_age */, - 2); - if (rv != SECSuccess) - goto loser; - rv = sslBuffer_AppendVariable(buf, session_ticket->ticket.data, - session_ticket->ticket.len, 2); - if (rv != SECSuccess) - goto loser; + identities_length = + 2 + /* vector length */ + 2 + session_ticket->ticket.len + /* identity length + ticket len */ + 4; /* obfuscated_ticket_age */ + binders_length = + 2 + /* vector length */ + 1 + tls13_GetHashSizeForHash( + tls13_GetHashForCipherSuite(ss->sec.ci.sid->u.ssl3.cipherSuite)); + extension_length = + 2 + 2 + /* Type + length */ + identities_length + binders_length; + + if (maxBytes < (PRUint32)extension_length) { + PORT_Assert(0); + return 0; + } + + if (append) { + SECStatus rv; + PRTime age; + unsigned int prefixLength; + PRUint8 binder[TLS13_MAX_FINISHED_SIZE]; + unsigned int binderLen; + + /* extension_type */ + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_ExtAppendHandshakeNumber(ss, identities_length - 2, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_ExtAppendHandshakeVariable(ss, session_ticket->ticket.data, + session_ticket->ticket.len, 2); + if (rv != SECSuccess) + goto loser; - /* Obfuscated age. */ - age = ssl_TimeUsec() - session_ticket->received_timestamp; - age /= PR_USEC_PER_MSEC; - age += session_ticket->ticket_age_add; - rv = sslBuffer_AppendNumber(buf, age, 4); - if (rv != SECSuccess) - goto loser; + /* Obfuscated age. */ + age = PR_Now() - session_ticket->received_timestamp; + age /= PR_USEC_PER_MSEC; + age += session_ticket->ticket_age_add; + rv = ssl3_ExtAppendHandshakeNumber(ss, age, 4); + if (rv != SECSuccess) + goto loser; - /* Write out the binder list length. */ - binderLen = tls13_GetHashSize(ss); - rv = sslBuffer_AppendNumber(buf, binderLen + 1, 2); - if (rv != SECSuccess) - goto loser; - /* Write zeroes for the binder for the moment. */ - rv = sslBuffer_AppendVariable(buf, binder, binderLen, 1); - if (rv != SECSuccess) - goto loser; + /* Now the binders. */ + prefixLength = ss->ssl3.hs.messages.len; + rv = tls13_ComputePskBinder(CONST_CAST(sslSocket, ss), PR_TRUE, + prefixLength, binder, &binderLen, + sizeof(binder)); + if (rv != SECSuccess) + goto loser; + PORT_Assert(binderLen == tls13_GetHashSize(ss)); + rv = ssl3_ExtAppendHandshakeNumber(ss, binders_length - 2, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_ExtAppendHandshakeVariable(ss, + binder, binderLen, 1); + if (rv != SECSuccess) + goto loser; - PRINT_BUF(50, (ss, "Sending PreSharedKey value", - session_ticket->ticket.data, - session_ticket->ticket.len)); + PRINT_BUF(50, (ss, "Sending PreSharedKey value", + session_ticket->ticket.data, + session_ticket->ticket.len)); - xtnData->sentSessionTicketInClientHello = PR_TRUE; - *added = PR_TRUE; - return SECSuccess; + xtnData->sentSessionTicketInClientHello = PR_TRUE; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_pre_shared_key_xtn; + } + return extension_length; loser: xtnData->ticketTimestampVerified = PR_FALSE; - return SECFailure; + return -1; } /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs * that contain session tickets. */ SECStatus -tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, +tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECItem inner; SECStatus rv; unsigned int numIdentities = 0; unsigned int numBinders = 0; - SECItem *appToken; SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension", SSL_GETPID(), ss->fd)); @@ -461,26 +564,16 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } - /* The application token is set via the cookie extension if this is the - * second ClientHello. Don't set it twice. The cookie extension handler - * sets |helloRetry| and that will have been called already because this - * extension always comes last. */ - if (!ss->ssl3.hs.helloRetry) { - appToken = &xtnData->applicationToken; - } else { - appToken = NULL; - } - /* Parse the identities list. */ - rv = ssl3_ExtConsumeHandshakeVariable(ss, &inner, 2, - &data->data, &data->len); + rv = ssl3_ExtConsumeHandshakeVariable(ss, + &inner, 2, &data->data, &data->len); if (rv != SECSuccess) { return SECFailure; } while (inner.len) { SECItem label; - PRUint32 obfuscatedAge; + PRUint32 utmp; rv = ssl3_ExtConsumeHandshakeVariable(ss, &label, 2, &inner.data, &inner.len); @@ -490,8 +583,9 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData goto alert_loser; } - rv = ssl3_ExtConsumeHandshakeNumber(ss, &obfuscatedAge, 4, - &inner.data, &inner.len); + /* Read and discard session ticket age. Bug 1295163 */ + rv = ssl3_ExtConsumeHandshake(ss, &utmp, 4, + &inner.data, &inner.len); if (rv != SECSuccess) return rv; @@ -499,29 +593,17 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData PRINT_BUF(50, (ss, "Handling PreSharedKey value", label.data, label.len)); rv = ssl3_ProcessSessionTicketCommon( - CONST_CAST(sslSocket, ss), &label, appToken); + CONST_CAST(sslSocket, ss), &label); /* This only happens if we have an internal error, not * a malformed ticket. Bogus tickets just don't resume * and return SECSuccess. */ if (rv != SECSuccess) return SECFailure; - - if (ss->sec.ci.sid) { - /* xtnData->ticketAge contains the baseline we use for - * calculating the ticket age (i.e., our RTT estimate less the - * value of ticket_age_add). - * - * Add that to the obfuscated ticket age to recover the client's - * view of the ticket age plus the estimated RTT. - * - * See ssl3_EncodeSessionTicket() for details. */ - xtnData->ticketAge += obfuscatedAge; - } } ++numIdentities; } - xtnData->pskBindersLen = data->len; + xtnData->pskBinderPrefixLen = ss->ssl3.hs.messages.len - data->len; /* Parse the binders list. */ rv = ssl3_ExtConsumeHandshakeVariable(ss, @@ -553,7 +635,7 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData /* Keep track of negotiated extensions. Note that this does not * mean we are resuming. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; @@ -563,27 +645,43 @@ alert_loser: return SECFailure; } -SECStatus +PRInt32 tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) + PRBool append, + PRUint32 maxBytes) { + PRInt32 extension_length = + 2 + 2 + 2; /* type + len + index */ SECStatus rv; - /* We only process the first session ticket the client sends, - * so the index is always 0. */ - rv = sslBuffer_AppendNumber(buf, 0, 2); - if (rv != SECSuccess) { - return SECFailure; + if (maxBytes < (PRUint32)extension_length) { + PORT_Assert(0); + return 0; } - *added = PR_TRUE; - return SECSuccess; + if (append) { + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_pre_shared_key_xtn, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeNumber(ss, 2, 2); + if (rv != SECSuccess) + return -1; + + /* We only process the first session ticket the client sends, + * so the index is always 0. */ + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + return -1; + } + + return extension_length; } /* Handle a TLS 1.3 PreSharedKey Extension. We only accept PSKs * that contain session tickets. */ SECStatus -tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, +tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { PRUint32 index; @@ -615,7 +713,7 @@ tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } @@ -623,20 +721,43 @@ tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData /* * struct { } EarlyDataIndication; */ -SECStatus +PRInt32 tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) + PRBool append, + PRUint32 maxBytes) { - if (!tls13_ClientAllow0Rtt(ss, ss->sec.ci.sid)) { - return SECSuccess; + SECStatus rv; + PRInt32 extension_length; + + if (!tls13_ClientAllow0Rtt(ss, ss->sec.ci.sid)) + return 0; + + /* type + length */ + extension_length = 2 + 2; + + if (maxBytes < (PRUint32)extension_length) { + PORT_Assert(0); + return 0; } - *added = PR_TRUE; - return SECSuccess; + if (append) { + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + return -1; + + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_early_data_xtn; + } + + return extension_length; } SECStatus -tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, +tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", @@ -658,14 +779,44 @@ tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, return SECFailure; } - xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_early_data_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } +/* This is only registered if we are sending it. */ +PRInt32 +tls13_ServerSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) +{ + SSL_TRC(3, ("%d: TLS13[%d]: send early_data extension", + SSL_GETPID(), ss->fd)); + + PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted); + if (maxBytes < 4) { + PORT_Assert(0); + return 0; + } + + if (append) { + SECStatus rv; + + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + return -1; + } + + return 4; +} + /* This will only be called if we also offered the extension. */ SECStatus -tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, +tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", @@ -683,19 +834,19 @@ tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_early_data_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } SECStatus -tls13_ClientHandleTicketEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ClientHandleTicketEarlyDataInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, + SECItem *data) { PRUint32 utmp; SECStatus rv; - SSL_TRC(3, ("%d: TLS13[%d]: handle ticket early_data extension", + SSL_TRC(3, ("%d: TLS13[%d]: handle early_data_info extension", SSL_GETPID(), ss->fd)); /* The server must not send this extension when negotiating < TLS 1.3. */ @@ -722,71 +873,59 @@ tls13_ClientHandleTicketEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnD /* * struct { - * select (Handshake.msg_type) { - * case client_hello: * ProtocolVersion versions<2..254>; - * case server_hello: - * ProtocolVersion version; - * }; * } SupportedVersions; */ -SECStatus -tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) { + PRInt32 extensions_len; PRUint16 version; - unsigned int lengthOffset; SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; + return 0; } - SSL_TRC(3, ("%d: TLS13[%d]: client send supported_versions extension", + SSL_TRC(3, ("%d: TLS13[%d]: send supported_versions extension", SSL_GETPID(), ss->fd)); - rv = sslBuffer_Skip(buf, 1, &lengthOffset); - if (rv != SECSuccess) { - return SECFailure; - } + /* Extension type, extension len fiels, vector len field, + * length of the values. */ + extensions_len = 2 + 2 + 1 + + 2 * (ss->vrange.max - ss->vrange.min + 1); - for (version = ss->vrange.max; version >= ss->vrange.min; --version) { - rv = sslBuffer_AppendNumber(buf, tls13_EncodeDraftVersion(version), 2); - if (rv != SECSuccess) { - return SECFailure; - } + if (maxBytes < (PRUint32)extensions_len) { + PORT_Assert(0); + return 0; } - rv = sslBuffer_InsertLength(buf, lengthOffset, 1); - if (rv != SECSuccess) { - return SECFailure; - } - - *added = PR_TRUE; - return SECSuccess; -} + if (append) { + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_supported_versions_xtn, 2); + if (rv != SECSuccess) + return -1; -SECStatus -tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) -{ - SECStatus rv; + rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 4, 2); + if (rv != SECSuccess) + return -1; - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; - } + rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 5, 1); + if (rv != SECSuccess) + return -1; - SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension", - SSL_GETPID(), ss->fd)); + for (version = ss->vrange.max; version >= ss->vrange.min; --version) { + rv = ssl3_ExtAppendHandshakeNumber( + ss, tls13_EncodeDraftVersion(version), 2); + if (rv != SECSuccess) + return -1; + } - rv = sslBuffer_AppendNumber( - buf, tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3), 2); - if (rv != SECSuccess) { - return SECFailure; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_supported_versions_xtn; } - *added = PR_TRUE; - return SECSuccess; + return extensions_len; } /* @@ -795,8 +934,7 @@ tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD * } Cookie; */ SECStatus -tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; @@ -822,57 +960,41 @@ tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, return SECSuccess; } -SECStatus -tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { - SECStatus rv; + PRInt32 extension_len; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 || !ss->ssl3.hs.cookie.len) { - return SECSuccess; + return 0; } SSL_TRC(3, ("%d: TLS13[%d]: send cookie extension", SSL_GETPID(), ss->fd)); - rv = sslBuffer_AppendVariable(buf, ss->ssl3.hs.cookie.data, - ss->ssl3.hs.cookie.len, 2); - if (rv != SECSuccess) { - return SECFailure; - } - - *added = PR_TRUE; - return SECSuccess; -} -SECStatus -tls13_ServerHandleCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) -{ - SECStatus rv; + /* Extension type, length, cookie length, cookie value. */ + extension_len = 2 + 2 + 2 + ss->ssl3.hs.cookie.len; - SSL_TRC(3, ("%d: TLS13[%d]: handle cookie extension", - SSL_GETPID(), ss->fd)); - - rv = ssl3_ExtConsumeHandshakeVariable(ss, &xtnData->cookie, 2, - &data->data, &data->len); - if (rv != SECSuccess) { - return SECFailure; - } - - if (xtnData->cookie.len == 0) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); - return SECFailure; + if (maxBytes < (PRUint32)extension_len) { + PORT_Assert(0); + return 0; } - if (data->len) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_SERVER_HELLO); - return SECFailure; - } + if (append) { + SECStatus rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_cookie_xtn, 2); + if (rv != SECSuccess) + return -1; - /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_cookie_xtn; + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_len - 4, 2); + if (rv != SECSuccess) + return -1; - return SECSuccess; + rv = ssl3_ExtAppendHandshakeVariable(ss, ss->ssl3.hs.cookie.data, + ss->ssl3.hs.cookie.len, 2); + if (rv != SECSuccess) + return -1; + } + return extension_len; } /* @@ -882,33 +1004,54 @@ tls13_ServerHandleCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, * PskKeyExchangeMode ke_modes<1..255>; * } PskKeyExchangeModes; */ -SECStatus -tls13_ClientSendPskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes) { static const PRUint8 ke_modes[] = { tls13_psk_dh_ke }; - SECStatus rv; + static const unsigned long ke_modes_len = sizeof(ke_modes); + PRInt32 extension_len; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 || ss->opt.noCache) { - return SECSuccess; + return 0; } + extension_len = + 2 + 2 + /* Type + length */ + 1 + ke_modes_len; /* key exchange modes vector */ + SSL_TRC(3, ("%d: TLS13[%d]: send psk key exchange modes extension", SSL_GETPID(), ss->fd)); - rv = sslBuffer_AppendVariable(buf, ke_modes, sizeof(ke_modes), 1); - if (rv != SECSuccess) { - return SECFailure; + if (maxBytes < (PRUint32)extension_len) { + PORT_Assert(0); + return 0; } - *added = PR_TRUE; - return SECSuccess; + if (append) { + SECStatus rv = ssl3_ExtAppendHandshakeNumber( + ss, ssl_tls13_psk_key_exchange_modes_xtn, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_len - 4, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeVariable( + ss, ke_modes, ke_modes_len, 1); + if (rv != SECSuccess) + return -1; + } + return extension_len; } SECStatus -tls13_ServerHandlePskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, - SECItem *data) +tls13_ServerHandlePskKeyExchangeModesXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data) { SECStatus rv; @@ -933,126 +1076,112 @@ tls13_ServerHandlePskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, } /* Keep track of negotiated extensions. */ - xtnData->negotiated[xtnData->numNegotiated++] = - ssl_tls13_psk_key_exchange_modes_xtn; + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; } -SECStatus -tls13_SendCertAuthoritiesXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +PRInt32 +tls13_SendShortHeaderXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes) { - unsigned int calen; - const SECItem *name; - unsigned int nnames; - SECStatus rv; + PRUint32 extension_len = 2 + 2; /* Type + length (0). */ - PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - - rv = ssl_GetCertificateRequestCAs(ss, &calen, &name, &nnames); - if (rv != SECSuccess) { - return SECFailure; + if (!ss->opt.enableShortHeaders) { + return 0; } - if (!calen) { - return SECSuccess; + /* Presently this is incompatible with 0-RTT. We will fix if + * it becomes more than an experiment. */ + if (ss->opt.enable0RttData) { + return 0; } - rv = sslBuffer_AppendNumber(buf, calen, 2); - if (rv != SECSuccess) { - return SECFailure; + if (IS_DTLS(ss)) { + return 0; } - while (nnames) { - rv = sslBuffer_AppendVariable(buf, name->data, name->len, 2); - if (rv != SECSuccess) { - return SECFailure; - } - ++name; - --nnames; + /* Don't send this if TLS 1.3 isn't at least possible. */ + if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { + /* This should only happen on the client. */ + PORT_Assert(!ss->sec.isServer); + return 0; } - *added = PR_TRUE; - return SECSuccess; -} - -SECStatus -tls13_ClientHandleCertAuthoritiesXtn(const sslSocket *ss, - TLSExtensionData *xtnData, - SECItem *data) -{ - SECStatus rv; - PLArenaPool *arena; + SSL_TRC(3, ("%d: TLS13[%d]: send short_header extension", + SSL_GETPID(), ss->fd)); - if (!data->len) { - ssl3_ExtSendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST); - return SECFailure; + if (maxBytes < extension_len) { + PORT_Assert(0); + return 0; } - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (!arena) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } + if (append) { + SECStatus rv; - xtnData->certReqAuthorities.arena = arena; - rv = ssl3_ParseCertificateRequestCAs((sslSocket *)ss, - &data->data, &data->len, - &xtnData->certReqAuthorities); - if (rv != SECSuccess) { - goto loser; - } - if (data->len) { - ssl3_ExtSendAlert(ss, alert_fatal, decode_error); - PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_REQUEST); - goto loser; + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_short_header_xtn, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + return -1; + + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_short_header_xtn; } - return SECSuccess; -loser: - PORT_FreeArena(arena, PR_FALSE); - xtnData->certReqAuthorities.arena = NULL; - return SECFailure; + return extension_len; } SECStatus -tls13_ServerSendHrrKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) +tls13_HandleShortHeaderXtn( + const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, + SECItem *data) { - SECStatus rv; + SSL_TRC(3, ("%d: TLS13[%d]: handle short_header extension", + SSL_GETPID(), ss->fd)); - PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); + /* The client might have asked for this, but we didn't negotiate TLS 1.3. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } - if (!xtnData->selectedGroup) { + /* Presently this is incompatible with 0-RTT. We will fix if + * it becomes more than an experiment. */ + if (ss->opt.enable0RttData) { return SECSuccess; } - rv = sslBuffer_AppendNumber(buf, xtnData->selectedGroup->name, 2); - if (rv != SECSuccess) { + if (IS_DTLS(ss)) { + PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); return SECFailure; } - *added = PR_TRUE; - return SECSuccess; -} + if (data->len) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); + return SECFailure; + } -SECStatus -tls13_ServerSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, - sslBuffer *buf, PRBool *added) -{ - SECStatus rv; + if (!ss->opt.enableShortHeaders) { + /* Ignore. */ + return SECSuccess; + } - PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); - PORT_Assert(xtnData->cookie.len > 0); + /* Keep track of negotiated extensions. */ + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; - rv = sslBuffer_AppendVariable(buf, - xtnData->cookie.data, xtnData->cookie.len, 2); - if (rv != SECSuccess) { - return SECFailure; + if (ss->sec.isServer) { + SECStatus rv; + + rv = ssl3_RegisterExtensionSender(ss, xtnData, + ssl_tls13_short_header_xtn, + tls13_SendShortHeaderXtn); + if (rv != SECSuccess) { + return SECFailure; + } } - *added = PR_TRUE; return SECSuccess; } |