diff options
Diffstat (limited to 'security/nss/lib/ssl/tls13exthandle.c')
-rw-r--r-- | security/nss/lib/ssl/tls13exthandle.c | 1169 |
1 files changed, 1169 insertions, 0 deletions
diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c new file mode 100644 index 000000000..be93b97db --- /dev/null +++ b/security/nss/lib/ssl/tls13exthandle.c @@ -0,0 +1,1169 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nssrenam.h" +#include "nss.h" +#include "ssl.h" +#include "sslproto.h" +#include "sslimpl.h" +#include "pk11pub.h" +#include "ssl3ext.h" +#include "ssl3exthandle.h" +#include "tls13exthandle.h" + +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 0; + } + + item = &serverCert->certStatusArray->items[0]; + + /* Only send the first entry. */ + extension_length = 2 + 2 + 1 /* status_type */ + 3 + item->len; + if (maxBytes < (PRUint32)extension_length) { + return 0; + } + 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. */ + } + + return extension_length; +} + +/* + * [draft-ietf-tls-tls13-11] Section 6.3.2.3. + * + * struct { + * NamedGroup group; + * opaque key_exchange<1..2^16-1>; + * } KeyShareEntry; + * + * struct { + * select (role) { + * case client: + * KeyShareEntry client_shares<4..2^16-1>; + * + * case server: + * KeyShareEntry server_share; + * } + * } KeyShare; + * + * DH is Section 6.3.2.3.1. + * + * opaque dh_Y<1..2^16-1>; + * + * ECDH is Section 6.3.2.3.2. + * + * opaque point <1..2^8-1>; + */ +static PRUint32 +tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey) +{ + /* Size = NamedGroup(2) + length(2) + opaque<?> share */ + switch (pubKey->keyType) { + case ecKey: + return 2 + 2 + pubKey->u.ec.publicValue.len; + case dhKey: + return 2 + 2 + pubKey->u.dh.prime.len; + default: + PORT_Assert(0); + } + 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(const sslSocket *ss, const sslEphemeralKeyPair *keyPair) +{ + SECStatus rv; + SECKEYPublicKey *pubKey = keyPair->keys->pubKey; + unsigned int size = tls13_SizeOfKeyShareEntry(pubKey); + + rv = ssl3_ExtAppendHandshakeNumber(ss, keyPair->group->name, 2); + if (rv != SECSuccess) + return rv; + rv = ssl3_ExtAppendHandshakeNumber(ss, size - 4, 2); + if (rv != SECSuccess) + return rv; + + switch (pubKey->keyType) { + case ecKey: + rv = tls13_EncodeECDHEKeyShareKEX(ss, pubKey); + break; + case dhKey: + rv = ssl_AppendPaddedDHKeyShare(ss, pubKey, PR_FALSE); + break; + default: + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + break; + } + + return rv; +} + +PRInt32 +tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) +{ + PRUint32 extension_length; + + if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { + return 0; + } + + /* Optimistically try to send an ECDHE key using the + * preexisting key (in future will be keys) */ + SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn", + SSL_GETPID(), ss->fd)); + + extension_length = tls13_SizeOfClientKeyShareExtension(ss); + if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; + } + + 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; + } + + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_key_share_xtn; + } + + return extension_length; + +loser: + return -1; +} + +static SECStatus +tls13_HandleKeyShareEntry(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) +{ + SECStatus rv; + PRInt32 group; + const sslNamedGroupDef *groupDef; + TLS13KeyShareEntry *ks = NULL; + SECItem share = { siBuffer, NULL, 0 }; + + group = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len); + if (group < 0) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); + goto loser; + } + groupDef = ssl_LookupNamedGroup(group); + rv = ssl3_ExtConsumeHandshakeVariable(ss, &share, 2, &data->data, + &data->len); + if (rv != SECSuccess) { + goto loser; + } + /* If the group is disabled, continue. */ + if (!groupDef) { + return SECSuccess; + } + + ks = PORT_ZNew(TLS13KeyShareEntry); + if (!ks) + goto loser; + ks->group = groupDef; + + rv = SECITEM_CopyItem(NULL, &ks->key_exchange, &share); + if (rv != SECSuccess) + goto loser; + + PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares); + return SECSuccess; + +loser: + if (ks) + tls13_DestroyKeyShareEntry(ks); + return SECFailure; +} +/* Handle an incoming KeyShare extension at the client and copy to + * |xtnData->remoteKeyShares| for future use. The key + * share is processed in tls13_HandleServerKeyShare(). */ +SECStatus +tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +{ + SECStatus rv; + PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares)); + + PORT_Assert(!ss->sec.isServer); + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + /* This can't happen because the extension processing + * code filters out TLS 1.3 extensions when not in + * TLS 1.3 mode. */ + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension", + SSL_GETPID(), ss->fd)); + + rv = tls13_HandleKeyShareEntry(ss, xtnData, data); + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); + return SECFailure; + } + + if (data->len) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); + return SECFailure; + } + + return SECSuccess; +} + +SECStatus +tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +{ + SECStatus rv; + PRInt32 tmp; + const sslNamedGroupDef *group; + + PORT_Assert(!ss->sec.isServer); + PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); + + SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension in HRR", + SSL_GETPID(), ss->fd)); + + tmp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len); + if (tmp < 0) { + return SECFailure; /* error code already set */ + } + if (data->len) { + ssl3_ExtSendAlert(ss, alert_fatal, decode_error); + PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST); + return SECFailure; + } + + group = ssl_LookupNamedGroup((SSLNamedGroup)tmp); + /* If the group is not enabled, or we already have a share for the + * requested group, abort. */ + if (!ssl_NamedGroupEnabled(ss, group) || + ssl_HaveEphemeralKeyPair(ss, group)) { + ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter); + PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST); + return SECFailure; + } + + /* Now delete all the key shares per [draft-ietf-tls-tls13 S 4.1.2] */ + ssl_FreeEphemeralKeyPairs(CONST_CAST(sslSocket, ss)); + + /* And replace with our new share. */ + rv = tls13_CreateKeyShare(CONST_CAST(sslSocket, ss), group); + if (rv != SECSuccess) { + ssl3_ExtSendAlert(ss, alert_fatal, internal_error); + PORT_SetError(SEC_ERROR_KEYGEN_FAIL); + return SECFailure; + } + + return SECSuccess; +} + +/* Handle an incoming KeyShare extension at the server and copy to + * |xtnData->remoteKeyShares| for future use. The key + * share is processed in tls13_HandleClientKeyShare(). */ +SECStatus +tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +{ + SECStatus rv; + PRInt32 length; + + PORT_Assert(ss->sec.isServer); + PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares)); + + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + + SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension", + SSL_GETPID(), ss->fd)); + + /* Redundant length because of TLS encoding (this vector consumes + * the entire extension.) */ + length = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, + &data->len); + if (length < 0) + goto loser; + if (length != data->len) { + /* Check for consistency */ + PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); + goto loser; + } + + while (data->len) { + rv = tls13_HandleKeyShareEntry(ss, xtnData, data); + if (rv != SECSuccess) + 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: + tls13_DestroyKeyShares(&xtnData->remoteKeyShares); + return SECFailure; +} + +PRInt32 +tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) +{ + PRUint32 extension_length; + PRUint32 entry_length; + SECStatus rv; + sslEphemeralKeyPair *keyPair; + + /* There should be exactly one key share. */ + PORT_Assert(!PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)); + PORT_Assert(PR_PREV_LINK(&ss->ephemeralKeyPairs) == + PR_NEXT_LINK(&ss->ephemeralKeyPairs)); + + keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); + + 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; + } + + 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. + * + * struct { + * opaque identity<0..2^16-1>; + * uint32 obfuscated_ticket_age; + * } PskIdentity; + * + * opaque PskBinderEntry<32..255>; + * + * struct { + * select (Handshake.msg_type) { + * case client_hello: + * PskIdentity identities<6..2^16-1>; + * PskBinderEntry binders<33..2^16-1>; + * + * case server_hello: + * uint16 selected_identity; + * }; + * + * } PreSharedKeyExtension; + + * 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. + */ +PRInt32 +tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) +{ + PRInt32 extension_length; + PRInt32 identities_length; + PRInt32 binders_length; + NewSessionTicket *session_ticket; + + /* We only set statelessResume on the client in TLS 1.3 code. */ + if (!ss->statelessResume) + return 0; + + PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); + + /* 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; + 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; + PRUint32 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_Time() - session_ticket->received_timestamp; + age += session_ticket->ticket_age_add; + rv = ssl3_ExtAppendHandshakeNumber(ss, age, 4); + 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)); + + xtnData->sentSessionTicketInClientHello = PR_TRUE; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_pre_shared_key_xtn; + } + return extension_length; + +loser: + xtnData->ticketTimestampVerified = PR_FALSE; + 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, PRUint16 ex_type, + SECItem *data) +{ + SECItem inner; + SECStatus rv; + unsigned int numIdentities = 0; + unsigned int numBinders = 0; + + SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension", + SSL_GETPID(), ss->fd)); + + /* If we are doing < TLS 1.3, then ignore this. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + + /* Parse the identities list. */ + rv = ssl3_ExtConsumeHandshakeVariable(ss, + &inner, 2, &data->data, &data->len); + if (rv != SECSuccess) { + return SECFailure; + } + + while (inner.len) { + SECItem label; + PRUint32 utmp; + + rv = ssl3_ExtConsumeHandshakeVariable(ss, &label, 2, + &inner.data, &inner.len); + if (rv != SECSuccess) + return rv; + if (!label.len) { + goto alert_loser; + } + + /* Read and discard session ticket age. Bug 1295163 */ + rv = ssl3_ExtConsumeHandshake(ss, &utmp, 4, + &inner.data, &inner.len); + if (rv != SECSuccess) + return rv; + + if (!numIdentities) { + PRINT_BUF(50, (ss, "Handling PreSharedKey value", + label.data, label.len)); + rv = ssl3_ProcessSessionTicketCommon( + 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; + } + ++numIdentities; + } + + xtnData->pskBinderPrefixLen = ss->ssl3.hs.messages.len - data->len; + + /* Parse the binders list. */ + rv = ssl3_ExtConsumeHandshakeVariable(ss, + &inner, 2, &data->data, &data->len); + if (rv != SECSuccess) + return SECFailure; + if (data->len) { + goto alert_loser; + } + + while (inner.len) { + SECItem binder; + rv = ssl3_ExtConsumeHandshakeVariable(ss, &binder, 1, + &inner.data, &inner.len); + if (rv != SECSuccess) + return rv; + if (binder.len < 32) { + goto alert_loser; + } + + if (!numBinders) { + xtnData->pskBinder = binder; + } + ++numBinders; + } + + if (numBinders != numIdentities) + goto alert_loser; + + /* Keep track of negotiated extensions. Note that this does not + * mean we are resuming. */ + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + + return SECSuccess; + +alert_loser: + ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter); + PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY); + return SECFailure; +} + +PRInt32 +tls13_ServerSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) +{ + PRInt32 extension_length = + 2 + 2 + 2; /* type + len + index */ + SECStatus rv; + + if (maxBytes < (PRUint32)extension_length) { + PORT_Assert(0); + return 0; + } + + 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, PRUint16 ex_type, + SECItem *data) +{ + PRInt32 index; + + SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension", + SSL_GETPID(), ss->fd)); + + /* If we are doing < TLS 1.3, then ignore this. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + + index = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len); + if (index < 0) + return SECFailure; + + /* This should be the end of the extension. */ + if (data->len) { + PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY); + return SECFailure; + } + + /* We only sent one PSK label so index must be equal to 0 */ + if (index) { + PORT_SetError(SSL_ERROR_MALFORMED_PRE_SHARED_KEY); + return SECFailure; + } + + /* Keep track of negotiated extensions. */ + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + + return SECSuccess; +} + +/* + * struct { } EarlyDataIndication; + */ +PRInt32 +tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, + PRUint32 maxBytes) +{ + 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; + } + + 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, PRUint16 ex_type, + SECItem *data) +{ + SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", + SSL_GETPID(), ss->fd)); + + /* If we are doing < TLS 1.3, then ignore this. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + + if (data->len) { + PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA); + return SECFailure; + } + + 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, PRUint16 ex_type, + SECItem *data) +{ + SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", + SSL_GETPID(), ss->fd)); + + /* If we are doing < TLS 1.3, then ignore this. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); + return SECFailure; + } + + if (data->len) { + PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA); + return SECFailure; + } + + /* Keep track of negotiated extensions. */ + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + + return SECSuccess; +} + +SECStatus +tls13_ClientHandleTicketEarlyDataInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, + SECItem *data) +{ + PRUint32 utmp; + SECStatus rv; + + SSL_TRC(3, ("%d: TLS13[%d]: handle early_data_info extension", + SSL_GETPID(), ss->fd)); + + /* If we are doing < TLS 1.3, then ignore this. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); + return SECFailure; + } + + rv = ssl3_ExtConsumeHandshake(ss, &utmp, sizeof(utmp), + &data->data, &data->len); + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET); + return SECFailure; + } + if (data->len) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET); + return SECFailure; + } + + xtnData->max_early_data_size = PR_ntohl(utmp); + + return SECSuccess; +} + +/* + * struct { + * ProtocolVersion versions<2..254>; + * } SupportedVersions; + */ +PRInt32 +tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, + PRUint32 maxBytes) +{ + PRInt32 extensions_len; + PRUint16 version; + SECStatus rv; + + if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { + return 0; + } + + SSL_TRC(3, ("%d: TLS13[%d]: send supported_versions extension", + SSL_GETPID(), ss->fd)); + + /* 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); + + if (maxBytes < (PRUint32)extensions_len) { + PORT_Assert(0); + return 0; + } + + if (append) { + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_supported_versions_xtn, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 4, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 5, 1); + if (rv != SECSuccess) + return -1; + + for (version = ss->vrange.max; version >= ss->vrange.min; --version) { + rv = ssl3_ExtAppendHandshakeNumber( + ss, tls13_EncodeDraftVersion(version), 2); + if (rv != SECSuccess) + return -1; + } + } + + return extensions_len; +} + +/* + * struct { + * opaque cookie<1..2^16-1>; + * } Cookie; + */ +SECStatus +tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) +{ + SECStatus rv; + + SSL_TRC(3, ("%d: TLS13[%d]: handle cookie extension", + SSL_GETPID(), ss->fd)); + + PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); + + /* IMPORTANT: this is only valid while the HelloRetryRequest is still valid. */ + rv = ssl3_ExtConsumeHandshakeVariable( + ss, &CONST_CAST(sslSocket, ss)->ssl3.hs.cookie, 2, + &data->data, &data->len); + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST); + return SECFailure; + } + if (!ss->ssl3.hs.cookie.len || data->len) { + ssl3_ExtSendAlert(ss, alert_fatal, decode_error); + PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST); + return SECFailure; + } + + return SECSuccess; +} + +PRInt32 +tls13_ClientSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) +{ + PRInt32 extension_len; + + if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 || + !ss->ssl3.hs.cookie.len) { + return 0; + } + + SSL_TRC(3, ("%d: TLS13[%d]: send cookie extension", SSL_GETPID(), ss->fd)); + + /* Extension type, length, cookie length, cookie value. */ + extension_len = 2 + 2 + 2 + ss->ssl3.hs.cookie.len; + + if (maxBytes < (PRUint32)extension_len) { + PORT_Assert(0); + return 0; + } + + if (append) { + SECStatus rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_cookie_xtn, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeNumber(ss, extension_len - 4, 2); + if (rv != SECSuccess) + return -1; + + rv = ssl3_ExtAppendHandshakeVariable(ss, ss->ssl3.hs.cookie.data, + ss->ssl3.hs.cookie.len, 2); + if (rv != SECSuccess) + return -1; + } + return extension_len; +} + +/* + * enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode; + * + * struct { + * PskKeyExchangeMode ke_modes<1..255>; + * } PskKeyExchangeModes; + */ +PRInt32 +tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes) +{ + static const PRUint8 ke_modes[] = { tls13_psk_dh_ke }; + 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 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)); + + if (maxBytes < (PRUint32)extension_len) { + PORT_Assert(0); + return 0; + } + + 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_ServerHandlePskKeyExchangeModesXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + PRUint16 ex_type, SECItem *data) +{ + SECStatus rv; + + /* If we are doing < TLS 1.3, then ignore this. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + + SSL_TRC(3, ("%d: TLS13[%d]: handle PSK key exchange modes extension", + SSL_GETPID(), ss->fd)); + + /* IMPORTANT: We aren't copying these values, just setting pointers. + * They will only be valid as long as the ClientHello is in memory. */ + rv = ssl3_ExtConsumeHandshakeVariable(ss, + &xtnData->psk_ke_modes, 1, + &data->data, &data->len); + if (rv != SECSuccess) + return rv; + if (!xtnData->psk_ke_modes.len || data->len) { + PORT_SetError(SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES); + return SECFailure; + } + + /* Keep track of negotiated extensions. */ + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + + return SECSuccess; +} + +PRInt32 +tls13_SendShortHeaderXtn(const sslSocket *ss, + TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes) +{ + PRUint32 extension_len = 2 + 2; /* Type + length (0). */ + + if (!ss->opt.enableShortHeaders) { + return 0; + } + + /* Presently this is incompatible with 0-RTT. We will fix if + * it becomes more than an experiment. */ + if (ss->opt.enable0RttData) { + return 0; + } + + if (IS_DTLS(ss)) { + return 0; + } + + SSL_TRC(3, ("%d: TLS13[%d]: send short_header extension", + SSL_GETPID(), ss->fd)); + + if (maxBytes < extension_len) { + PORT_Assert(0); + return 0; + } + + if (append) { + SECStatus rv; + + 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 extension_len; +} + +SECStatus +tls13_HandleShortHeaderXtn( + const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, + SECItem *data) +{ + SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", + SSL_GETPID(), ss->fd)); + + /* If we are doing < TLS 1.3, then ignore this. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + return SECSuccess; + } + + /* Presently this is incompatible with 0-RTT. We will fix if + * it becomes more than an experiment. */ + if (ss->opt.enable0RttData) { + return SECSuccess; + } + + if (IS_DTLS(ss)) { + PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); + return SECFailure; + } + + if (data->len) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); + return SECFailure; + } + + if (!ss->opt.enableShortHeaders) { + /* Ignore. */ + return SECSuccess; + } + + /* Keep track of negotiated extensions. */ + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; + + if (ss->sec.isServer) { + SECStatus rv; + + rv = ssl3_RegisterExtensionSender(ss, xtnData, + ssl_tls13_short_header_xtn, + tls13_SendShortHeaderXtn); + if (rv != SECSuccess) { + return SECFailure; + } + } + + return SECSuccess; +} |