Commit bd277dab authored by Martin Thomson's avatar Martin Thomson

Bug 1386191 - ClientHello callback for applications, r=ekr

--HG--
branch : NSS_TLS13_DRAFT19_BRANCH
extra : rebase_source : 76555bc5a80d7f5808ba1ca143611c7c0d1fd75c
extra : amend_source : 42a3fae051f45d3c50d6ee94f7041550ae22a9ab
parent 0115a134
......@@ -49,6 +49,7 @@ const uint8_t kTlsAlertIllegalParameter = 47;
const uint8_t kTlsAlertDecodeError = 50;
const uint8_t kTlsAlertDecryptError = 51;
const uint8_t kTlsAlertProtocolVersion = 70;
const uint8_t kTlsAlertInternalError = 80;
const uint8_t kTlsAlertInappropriateFallback = 86;
const uint8_t kTlsAlertMissingExtension = 109;
const uint8_t kTlsAlertUnsupportedExtension = 110;
......
This diff is collapsed.
......@@ -519,3 +519,9 @@ ER3(SSL_ERROR_RX_MALFORMED_END_OF_EARLY_DATA, (SSL_ERROR_BASE + 163),
ER3(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API, (SSL_ERROR_BASE + 164),
"An experimental API was called, but not supported.")
ER3(SSL_ERROR_APPLICATION_ABORT, (SSL_ERROR_BASE + 165),
"SSL handshake aborted by the application.")
ER3(SSL_ERROR_APP_CALLBACK_ERROR, (SSL_ERROR_BASE + 166),
"An application callback produced an invalid response.")
......@@ -8444,6 +8444,10 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
#endif
if (ssl3_FindExtension(ss, ssl_tls13_cookie_xtn)) {
ss->ssl3.hs.helloRetry = PR_TRUE;
}
/* Now parse the rest of the extensions. */
rv = ssl3_HandleParsedExtensions(ss, ssl_hs_client_hello);
if (rv != SECSuccess) {
......
......@@ -178,7 +178,7 @@ static const struct {
{ ssl_tls13_pre_shared_key_xtn, ssl_ext_native_only },
{ ssl_tls13_early_data_xtn, ssl_ext_native_only },
{ ssl_tls13_supported_versions_xtn, ssl_ext_native_only },
{ ssl_tls13_cookie_xtn, ssl_ext_native },
{ ssl_tls13_cookie_xtn, ssl_ext_native_only },
{ ssl_tls13_psk_key_exchange_modes_xtn, ssl_ext_native_only },
{ ssl_tls13_ticket_early_data_info_xtn, ssl_ext_native_only },
{ ssl_next_proto_nego_xtn, ssl_ext_none },
......@@ -946,6 +946,7 @@ ssl3_DestroyExtensionData(TLSExtensionData *xtnData)
SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
tls13_DestroyKeyShares(&xtnData->remoteKeyShares);
SECITEM_FreeItem(&xtnData->certReqContext, PR_FALSE);
SECITEM_FreeItem(&xtnData->applicationToken, PR_FALSE);
if (xtnData->certReqAuthorities.arena) {
PORT_FreeArena(xtnData->certReqAuthorities.arena, PR_FALSE);
xtnData->certReqAuthorities.arena = NULL;
......
......@@ -95,6 +95,9 @@ struct TLSExtensionDataStr {
PRUint32 ticketAge; /* Used to accept early data. */
SECItem cookie; /* HRR Cookie. */
const sslNamedGroupDef *selectedGroup; /* For HRR. */
/* The application token contains a value that was passed to the client via
* a session ticket, or the cookie in a HelloRetryRequest. */
SECItem applicationToken;
};
typedef struct TLSExtensionStr {
......
......@@ -1304,10 +1304,12 @@ loser:
/* Generic ticket processing code, common to all TLS versions. */
SECStatus
ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
SECItem *appToken)
{
SECItem decryptedTicket = { siBuffer, NULL, 0 };
SessionTicket parsedTicket;
sslSessionID *sid = NULL;
SECStatus rv;
if (ss->sec.ci.sid != NULL) {
......@@ -1316,12 +1318,12 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
ss->sec.ci.sid = NULL;
}
if (!SECITEM_AllocItem(NULL, &decryptedTicket, data->len)) {
if (!SECITEM_AllocItem(NULL, &decryptedTicket, ticket->len)) {
return SECFailure;
}
/* Decrypt the ticket. */
rv = ssl_SelfEncryptUnprotect(ss, data->data, data->len,
rv = ssl_SelfEncryptUnprotect(ss, ticket->data, ticket->len,
decryptedTicket.data,
&decryptedTicket.len,
decryptedTicket.len);
......@@ -1353,12 +1355,19 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
/* Use the ticket if it is valid and unexpired. */
if (parsedTicket.timestamp + ssl_ticket_lifetime * PR_USEC_PER_SEC >
ssl_TimeUsec()) {
sslSessionID *sid;
rv = ssl_CreateSIDFromTicket(ss, data, &parsedTicket, &sid);
rv = ssl_CreateSIDFromTicket(ss, ticket, &parsedTicket, &sid);
if (rv != SECSuccess) {
goto loser; /* code already set */
}
if (appToken && parsedTicket.applicationToken.len) {
rv = SECITEM_CopyItem(NULL, appToken,
&parsedTicket.applicationToken);
if (rv != SECSuccess) {
goto loser; /* code already set */
}
}
ss->statelessResume = PR_TRUE;
ss->sec.ci.sid = sid;
......@@ -1373,6 +1382,9 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data)
return SECSuccess;
loser:
if (sid) {
ssl_FreeSID(sid);
}
SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE);
PORT_Memset(&parsedTicket, 0, sizeof(parsedTicket));
return SECFailure;
......@@ -1406,7 +1418,8 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData
return SECSuccess;
}
return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data);
return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data,
NULL);
}
/* Extension format:
......
......@@ -89,7 +89,8 @@ SECStatus ssl3_SendExtendedMasterSecretXtn(const sslSocket *ss,
SECStatus ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
SECItem *data);
SECStatus ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data);
SECStatus ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
/* out */ SECItem *appToken);
SECStatus ssl3_ClientSendServerNameXtn(const sslSocket *ss,
TLSExtensionData *xtnData,
sslBuffer *buf, PRBool *added);
......
......@@ -110,7 +110,7 @@ sslBuffer_Clear(sslBuffer *b)
}
SECStatus
ssl3_AppendToItem(SECItem *item, const unsigned char *buf, unsigned int size)
ssl3_AppendToItem(SECItem *item, const PRUint8 *buf, unsigned int size)
{
if (size > item->len) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
......@@ -135,7 +135,7 @@ ssl3_AppendNumberToItem(SECItem *item, PRUint64 num, unsigned int size)
}
SECStatus
ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, unsigned int size)
ssl3_ConsumeFromItem(SECItem *item, PRUint8 **buf, unsigned int size)
{
if (size > item->len) {
PORT_SetError(SEC_ERROR_BAD_DATA);
......
......@@ -33,11 +33,11 @@ void sslBuffer_Clear(sslBuffer *b);
/* All of these functions modify the underlying SECItem, and so should
* be performed on a shallow copy.*/
SECStatus ssl3_AppendToItem(SECItem *item,
const unsigned char *buf, PRUint32 bytes);
const PRUint8 *buf, PRUint32 bytes);
SECStatus ssl3_AppendNumberToItem(SECItem *item,
PRUint64 num, unsigned int size);
SECStatus ssl3_ConsumeFromItem(SECItem *item,
unsigned char **buf, unsigned int size);
PRUint8 **buf, unsigned int size);
SECStatus ssl3_ConsumeNumberFromItem(SECItem *item,
PRUint32 *num, unsigned int size);
......
......@@ -252,6 +252,9 @@ typedef enum {
SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API = (SSL_ERROR_BASE + 164),
SSL_ERROR_APPLICATION_ABORT = (SSL_ERROR_BASE + 165),
SSL_ERROR_APP_CALLBACK_ERROR = (SSL_ERROR_BASE + 166),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */
......
......@@ -242,6 +242,102 @@ typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
unsigned int _appTokenLen), \
(fd, appToken, appTokenLen))
/*
* A stateless retry handler gives an application some control over NSS handling
* of ClientHello messages.
*
* SSL_HelloRetryRequestCallback() installs a callback that allows an
* application to control how NSS sends HelloRetryRequest messages. This
* handler is only used on servers and will only be called if the server selects
* TLS 1.3. Support for older TLS versions could be added in other releases.
*
* The SSLHelloRetryRequestCallback is invoked during the processing of a
* TLS 1.3 ClientHello message. It takes the following arguments:
*
* - |firstHello| indicates if the NSS believes that this is an initial
* ClientHello. An initial ClientHello will never include a cookie extension,
* though it may contain a session ticket.
*
* - |clientToken| includes a token previously provided by the application. If
* |clientTokenLen| is 0, then |clientToken| may be NULL.
*
* - If |firstHello| is PR_FALSE, the value that was provided in the
* |retryToken| outparam of previous invocations of this callback will be
* present here.
*
* - If |firstHello| is PR_TRUE, and the handshake is resuming a session, then
* this will contain any value that was passed in the |token| parameter of
* SSL_SendNewSessionTicket() method (see below). If this is not resuming a
* session, then the token will be empty (and this value could be NULL).
*
* - |clientTokenLen| is the length of |clientToken|.
*
* - |retryToken| is an item that callback can write to. This provides NSS with
* a token. This token is encrypted and integrity protected and embedded in
* the cookie extension of a HelloRetryRequest. The value of this field is
* only used if the handler returns ssl_stateless_retry_check. NSS allocates
* space for this value.
*
* - |retryTokenLen| is an outparam for the length of the token. If this value
* is not set, or set to 0, an empty token will be sent.
*
* - |retryTokenMax| is the size of the space allocated for retryToken. An
* application cannot write more than this many bytes to retryToken.
*
* - |arg| is the same value that was passed to
* SSL_InstallStatelessRetryHandler().
*
* The handler can validate any the value of |clientToken|, query the socket
* status (using SSL_GetPreliminaryChannelInfo() for example) and decide how to
* proceed:
*
* - Returning ssl_hello_retry_fail causes the handshake to fail. This might be
* used if the token is invalid or the application wishes to abort the
* handshake.
*
* - Returning ssl_hello_retry_accept causes the handshake to proceed.
*
* - Returning ssl_hello_retry_request causes NSS to send a HelloRetryRequest
* message and request a second ClientHello. NSS generates a cookie extension
* and embeds the value of |retryToken|. The value of |retryToken| value may
* be left empty if the application does not require any additional context to
* validate a second ClientHello attempt. This return code cannot be used to
* reject a second ClientHello (i.e., when firstHello is PR_FALSE); NSS will
* abort the handshake if this value is returned from a second call.
*
* An application that chooses to perform a stateless retry can discard the
* server socket. All necessary state to continue the TLS handshake will be
* included in the cookie extension. This makes it possible to use a new socket
* to handle the remainder of the handshake. The existing socket can be safely
* discarded. [TODO: see Bug 1386096]
*
* If the same socket is retained, the information in the cookie will be checked
* for consistency against the existing state of the socket. Any discrepancy
* will result in the connection being closed.
*
* Tokens should be kept as small as possible. NSS sets a limit on the size of
* tokens, which it passes in |retryTokenMax|. Depending on circumstances,
* observing a smaller limit might be desirable or even necessary. For
* instance, having HelloRetryRequest and ClientHello fit in a single packet has
* significant performance benefits.
*/
typedef enum {
ssl_hello_retry_fail,
ssl_hello_retry_accept,
ssl_hello_retry_request
} SSLHelloRetryRequestAction;
typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
PRBool firstHello, const PRUint8 *clientToken, unsigned int clientTokenLen,
PRUint8 *retryToken, unsigned int *retryTokenLen, unsigned int retryTokMax,
void *arg);
#define SSL_HelloRetryRequestCallback(fd, cb, arg) \
SSL_EXPERIMENTAL_API("SSL_HelloRetryRequestCallback", \
(PRFileDesc * _fd, \
SSLHelloRetryRequestCallback _cb, void *_arg), \
(fd, cb, arg))
SEC_END_PROTOS
#endif /* __sslexp_h_ */
......@@ -19,6 +19,7 @@
#include "secport.h"
#include "secerr.h"
#include "sslerr.h"
#include "sslexp.h"
#include "ssl3prot.h"
#include "hasht.h"
#include "nssilock.h"
......@@ -1144,6 +1145,8 @@ struct sslSocketStr {
void *pkcs11PinArg;
SSLNextProtoCallback nextProtoCallback;
void *nextProtoArg;
SSLHelloRetryRequestCallback hrrCallback;
void *hrrCallbackArg;
PRCList extensionHooks;
PRIntervalTime rTimeout; /* timeout for NSPR I/O */
......
......@@ -3903,6 +3903,7 @@ struct {
} ssl_experimental_functions[] = {
#ifndef SSL_DISABLE_EXPERIMENTAL_API
EXP(GetExtensionSupport),
EXP(HelloRetryRequestCallback),
EXP(InstallExtensionHooks),
EXP(SendSessionTicket),
EXP(SetupAntiReplay),
......
......@@ -56,8 +56,9 @@ static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss);
static void tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group);
static SECStatus tls13_HandleClientKeyShare(sslSocket *ss,
TLS13KeyShareEntry *peerShare);
static SECStatus tls13_SendHelloRetryRequest(sslSocket *ss,
const sslNamedGroupDef *selectedGroup);
static SECStatus tls13_SendHelloRetryRequest(
sslSocket *ss, const sslNamedGroupDef *selectedGroup,
const PRUint8 *token, unsigned int tokenLen);
static SECStatus tls13_HandleServerKeyShare(sslSocket *ss);
static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b,
......@@ -1074,7 +1075,9 @@ tls13_FindKeyShareEntry(sslSocket *ss, const sslNamedGroupDef *group)
}
static SECStatus
tls13_NegotiateKeyExchange(sslSocket *ss, TLS13KeyShareEntry **clientShare)
tls13_NegotiateKeyExchange(sslSocket *ss,
const sslNamedGroupDef **requestedGroup,
TLS13KeyShareEntry **clientShare)
{
unsigned int index;
TLS13KeyShareEntry *entry = NULL;
......@@ -1154,13 +1157,16 @@ tls13_NegotiateKeyExchange(sslSocket *ss, TLS13KeyShareEntry **clientShare)
SSL_TRC(3, ("%d: TLS13[%d]: group = %d", SSL_GETPID(), ss->fd,
preferredGroup->name));
if (!entry) {
return tls13_SendHelloRetryRequest(ss, preferredGroup);
/* Either provide a share, or provide a group that should be requested in a
* HelloRetryRequest, but not both. */
if (entry) {
PORT_Assert(preferredGroup == entry->group);
*clientShare = entry;
*requestedGroup = NULL;
} else {
*clientShare = NULL;
*requestedGroup = preferredGroup;
}
PORT_Assert(preferredGroup == entry->group);
*clientShare = entry;
return SECSuccess;
}
......@@ -1236,6 +1242,68 @@ tls13_SelectServerCert(sslSocket *ss)
return SECFailure;
}
/* Note: |requestedGroup| is non-NULL when we send a key_share extension. */
static SECStatus
tls13_MaybeSendHelloRetry(sslSocket *ss, const sslNamedGroupDef *requestedGroup,
PRBool *hrrSent)
{
SSLHelloRetryRequestAction action = ssl_hello_retry_accept;
PRUint8 token[256] = { 0 };
unsigned int tokenLen = 0;
SECStatus rv;
/* We asked already, but didn't get a share. */
if (requestedGroup && ss->ssl3.hs.helloRetry) {
FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
if (ss->hrrCallback) {
action = ss->hrrCallback(!ss->ssl3.hs.helloRetry,
ss->xtnData.applicationToken.data,
ss->xtnData.applicationToken.len,
token, &tokenLen, sizeof(token),
ss->hrrCallbackArg);
}
/* These use SSL3_SendAlert directly to avoid an assertion in
* tls13_FatalError(), which is ordinarily OK. */
if (action == ssl_hello_retry_request && ss->ssl3.hs.helloRetry) {
(void)SSL3_SendAlert(ss, alert_fatal, internal_error);
PORT_SetError(SSL_ERROR_APP_CALLBACK_ERROR);
return SECFailure;
}
if (action != ssl_hello_retry_request && tokenLen) {
(void)SSL3_SendAlert(ss, alert_fatal, internal_error);
PORT_SetError(SSL_ERROR_APP_CALLBACK_ERROR);
return SECFailure;
}
if (tokenLen > sizeof(token)) {
(void)SSL3_SendAlert(ss, alert_fatal, internal_error);
PORT_SetError(SSL_ERROR_APP_CALLBACK_ERROR);
return SECFailure;
}
if (action == ssl_hello_retry_fail) {
FATAL_ERROR(ss, SSL_ERROR_APPLICATION_ABORT, handshake_failure);
return SECFailure;
}
if (!requestedGroup && action != ssl_hello_retry_request) {
return SECSuccess;
}
rv = tls13_SendHelloRetryRequest(ss, requestedGroup, token, tokenLen);
if (rv != SECSuccess) {
return SECFailure; /* Code already set. */
}
*hrrSent = PR_TRUE;
return SECSuccess;
}
static SECStatus
tls13_NegotiateAuthentication(sslSocket *ss)
{
......@@ -1271,8 +1339,9 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
{
SECStatus rv;
SSL3Statistics *ssl3stats = SSL_GetStatistics();
const sslNamedGroupDef *requestedGroup = NULL;
TLS13KeyShareEntry *clientShare = NULL;
int j;
PRBool hrr = PR_FALSE;
ssl3CipherSuite previousCipherSuite;
if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) {
......@@ -1281,8 +1350,8 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
#ifndef PARANOID
/* Look for a matching cipher suite. */
j = ssl3_config_match_init(ss);
if (j <= 0) { /* no ciphers are working/supported by PK11 */
if (ssl3_config_match_init(ss) <= 0) {
/* no ciphers are working/supported by PK11 */
FATAL_ERROR(ss, PORT_GetError(), internal_error);
goto loser;
}
......@@ -1353,13 +1422,19 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
}
/* Select key exchange. */
rv = tls13_NegotiateKeyExchange(ss, &clientShare);
rv = tls13_NegotiateKeyExchange(ss, &requestedGroup, &clientShare);
if (rv != SECSuccess) {
goto loser;
}
/* We should get either one of these, but not both. */
PORT_Assert((requestedGroup && !clientShare) ||
(!requestedGroup && clientShare));
/* If we didn't find a client key share, we have to retry. */
if (!clientShare) {
rv = tls13_MaybeSendHelloRetry(ss, requestedGroup, &hrr);
if (rv != SECSuccess) {
goto loser;
}
if (hrr) {
if (sid) { /* Free the sid. */
ss->sec.uncache(sid);
ssl_FreeSID(sid);
......@@ -1517,6 +1592,20 @@ loser:
return SECFailure;
}
SECStatus
SSLExp_HelloRetryRequestCallback(PRFileDesc *fd,
SSLHelloRetryRequestCallback cb, void *arg)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
return SECFailure; /* Code already set. */
}
ss->hrrCallback = cb;
ss->hrrCallbackArg = arg;
return SECSuccess;
}
/*
* struct {
* ProtocolVersion server_version;
......@@ -1579,7 +1668,9 @@ loser:
}
static SECStatus
tls13_SendHelloRetryRequest(sslSocket *ss, const sslNamedGroupDef *selectedGroup)
tls13_SendHelloRetryRequest(sslSocket *ss,
const sslNamedGroupDef *requestedGroup,
const PRUint8 *appToken, unsigned int appTokenLen)
{
SECStatus rv;
unsigned int cookieLen;
......@@ -1591,14 +1682,9 @@ tls13_SendHelloRetryRequest(sslSocket *ss, const sslNamedGroupDef *selectedGroup
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
/* We asked already, but made no progress. */
if (ss->ssl3.hs.helloRetry) {
FATAL_ERROR(ss, SSL_ERROR_BAD_2ND_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* Compute the cookie we are going to need. */
rv = tls13_MakeHrrCookie(ss, selectedGroup,
rv = tls13_MakeHrrCookie(ss, requestedGroup,
appToken, appTokenLen,
cookie, &cookieLen, sizeof(cookie));
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
......@@ -1606,7 +1692,7 @@ tls13_SendHelloRetryRequest(sslSocket *ss, const sslNamedGroupDef *selectedGroup
}
/* Now build the body of the message. */
rv = tls13_ConstructHelloRetryRequest(ss, selectedGroup,
rv = tls13_ConstructHelloRetryRequest(ss, requestedGroup,
cookie, cookieLen, &messageBuf);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
......
......@@ -9,6 +9,8 @@
#ifndef __tls13con_h_
#define __tls13con_h_
#include "sslexp.h"
typedef enum {
StaticSharedSecret,
EphemeralSharedSecret
......@@ -106,4 +108,8 @@ void tls13_AntiReplayRollover(PRTime now);
SECStatus SSLExp_SetupAntiReplay(PRTime window, unsigned int k,
unsigned int bits);
SECStatus SSLExp_HelloRetryRequestCallback(PRFileDesc *fd,
SSLHelloRetryRequestCallback cb,
void *arg);
#endif /* __tls13con_h_ */
......@@ -458,6 +458,7 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData
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));
......@@ -467,9 +468,19 @@ 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;
}
......@@ -495,7 +506,7 @@ 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);
CONST_CAST(sslSocket, ss), &label, appToken);
/* This only happens if we have an internal error, not
* a malformed ticket. Bogus tickets just don't resume
* and return SECSuccess. */
......@@ -987,10 +998,6 @@ tls13_ServerSendHrrKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
/* In future, we may want to send HRRs w/o key_share but we don't
* currently do that. At that time, this assert can simply be
* removed. */
PORT_Assert(xtnData->selectedGroup != NULL);
if (!xtnData->selectedGroup) {
return SECSuccess;
}
......
......@@ -21,14 +21,16 @@
* inner value being.
*
* struct {
* uint8 indicator = 0xff; // To disambiguate from tickets.
* uint16 cipherSuite; // Selected cipher suite.
* uint16 keyShare; // Key share we requested (0 if none)
* opaque ch_hash[rest_of_buffer]; // H(ClientHello)
* uint8 indicator = 0xff; // To disambiguate from tickets.
* uint16 cipherSuite; // Selected cipher suite.
* uint16 keyShare; // Requested key share group (0=none)
* opaque applicationToken<0..65535>; // Application token
* opaque ch_hash[rest_of_buffer]; // H(ClientHello)
* } CookieInner;
*/
SECStatus
tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
const PRUint8 *appToken, unsigned int appTokenLen,
PRUint8 *buf, unsigned int *len, unsigned int maxlen)
{
SECStatus rv;
......@@ -52,6 +54,16 @@ tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
return SECFailure;
}
/* Application token. */
rv = ssl3_AppendNumberToItem(&cookieItem, appTokenLen, 2);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl3_AppendToItem(&cookieItem, appToken, appTokenLen);
if (rv != SECSuccess) {
return SECFailure;
}
/* Encode the hash state */
rv = tls13_ComputeHandshakeHashes(ss, &hashes);
if (rv != SECSuccess) {
......@@ -87,6 +99,8 @@ tls13_RecoverHashState(sslSocket *ss,
PRUint32 cipherSuite;
PRUint32 group;
const sslNamedGroupDef *selectedGroup;
PRUint32 appTokenLen;
PRUint8 *appToken;
rv = ssl_SelfEncryptUnprotect(ss, cookie, cookieLen,
ptItem.data, &ptItem.len, sizeof(plaintext));
......@@ -114,11 +128,26 @@ tls13_RecoverHashState(sslSocket *ss,
return SECFailure;
}
selectedGroup = ssl_LookupNamedGroup(group);
PORT_Assert(selectedGroup);
if (selectedGroup == NULL) {
/* Application token. */
PORT_Assert(ss->xtnData.applicationToken.len == 0);
rv = ssl3_ConsumeNumberFromItem(&ptItem, &appTokenLen, 2);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
if (SECITEM_AllocItem(NULL, &ss->xtnData.applicationToken,
appTokenLen) == NULL) {
FATAL_ERROR(ss, PORT_GetError(), internal_error);
return SECFailure;
}
ss->xtnData.applicationToken.len = appTokenLen;
rv = ssl3_ConsumeFromItem(&ptItem, &appToken, appTokenLen);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
PORT_Memcpy(ss->xtnData.applicationToken.data, appToken, appTokenLen);
/* The remainder is the hash. */
if (ptItem.len != tls13_GetHashSize(ss)) {
......
......@@ -14,6 +14,7 @@
#include "sslimpl.h"
SECStatus tls13_MakeHrrCookie(sslSocket *ss, const sslNamedGroupDef *selectedGroup,
const PRUint8 *appToken, unsigned int appTokenLen,
PRUint8 *buf, unsigned int *len, unsigned int maxlen);
SECStatus tls13_GetHrrCookieLength(sslSocket *ss, unsigned int *length);
SECStatus tls13_RecoverHashState(sslSocket *ss,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment