diff options
Diffstat (limited to 'security/nss/lib/ssl/tls13psk.c')
-rw-r--r-- | security/nss/lib/ssl/tls13psk.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/security/nss/lib/ssl/tls13psk.c b/security/nss/lib/ssl/tls13psk.c new file mode 100644 index 0000000000..7343c5a6f1 --- /dev/null +++ b/security/nss/lib/ssl/tls13psk.c @@ -0,0 +1,219 @@ +/* -*- 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 "nss.h" +#include "pk11func.h" +#include "ssl.h" +#include "sslproto.h" +#include "sslimpl.h" +#include "ssl3exthandle.h" +#include "tls13exthandle.h" +#include "tls13hkdf.h" +#include "tls13psk.h" + +SECStatus +SSLExp_AddExternalPsk0Rtt(PRFileDesc *fd, PK11SymKey *key, const PRUint8 *identity, + unsigned int identityLen, SSLHashType hash, + PRUint16 zeroRttSuite, PRUint32 maxEarlyData) +{ + + sslSocket *ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in SSLExp_SetExternalPsk", + SSL_GETPID(), fd)); + return SECFailure; + } + + if (!key || !identity || !identityLen || identityLen > 0xFFFF || + (hash != ssl_hash_sha256 && hash != ssl_hash_sha384)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + SECItem label = { siBuffer, CONST_CAST(unsigned char, identity), identityLen }; + sslPsk *psk = tls13_MakePsk(PK11_ReferenceSymKey(key), ssl_psk_external, + hash, &label); + if (!psk) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + psk->zeroRttSuite = zeroRttSuite; + psk->maxEarlyData = maxEarlyData; + SECStatus rv = SECFailure; + + ssl_Get1stHandshakeLock(ss); + ssl_GetSSL3HandshakeLock(ss); + + if (ss->psk) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + tls13_DestroyPsk(psk); + } else { + ss->psk = psk; + rv = SECSuccess; + tls13_ResetHandshakePsks(ss, &ss->ssl3.hs.psks); + } + + ssl_ReleaseSSL3HandshakeLock(ss); + ssl_Release1stHandshakeLock(ss); + + return rv; +} + +SECStatus +SSLExp_AddExternalPsk(PRFileDesc *fd, PK11SymKey *key, const PRUint8 *identity, + unsigned int identityLen, SSLHashType hash) +{ + return SSLExp_AddExternalPsk0Rtt(fd, key, identity, identityLen, + hash, TLS_NULL_WITH_NULL_NULL, 0); +} + +SECStatus +SSLExp_RemoveExternalPsk(PRFileDesc *fd, const PRUint8 *identity, unsigned int identityLen) +{ + if (!identity || !identityLen) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + sslSocket *ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetPSK", + SSL_GETPID(), fd)); + return SECFailure; + } + + SECItem removeIdentity = { siBuffer, + (unsigned char *)identity, + identityLen }; + + SECStatus rv; + ssl_Get1stHandshakeLock(ss); + ssl_GetSSL3HandshakeLock(ss); + + if (!ss->psk || SECITEM_CompareItem(&ss->psk->label, &removeIdentity) != SECEqual) { + PORT_SetError(SEC_ERROR_NO_KEY); + rv = SECFailure; + } else { + tls13_DestroyPsk(ss->psk); + ss->psk = NULL; + tls13_ResetHandshakePsks(ss, &ss->ssl3.hs.psks); + rv = SECSuccess; + } + + ssl_ReleaseSSL3HandshakeLock(ss); + ssl_Release1stHandshakeLock(ss); + + return rv; +} + +sslPsk * +tls13_CopyPsk(sslPsk *opsk) +{ + if (!opsk || !opsk->key) { + return NULL; + } + + sslPsk *psk = PORT_ZNew(sslPsk); + if (!psk) { + return NULL; + } + + SECStatus rv = SECITEM_CopyItem(NULL, &psk->label, &opsk->label); + if (rv != SECSuccess) { + PORT_Free(psk); + return NULL; + } + /* We should only have the initial key. Binder keys + * are derived during the handshake. */ + PORT_Assert(opsk->type == ssl_psk_external); + PORT_Assert(opsk->key); + PORT_Assert(!opsk->binderKey); + psk->hash = opsk->hash; + psk->type = opsk->type; + psk->key = opsk->key ? PK11_ReferenceSymKey(opsk->key) : NULL; + psk->binderKey = opsk->binderKey ? PK11_ReferenceSymKey(opsk->binderKey) : NULL; + return psk; +} + +void +tls13_DestroyPsk(sslPsk *psk) +{ + if (!psk) { + return; + } + if (psk->key) { + PK11_FreeSymKey(psk->key); + psk->key = NULL; + } + if (psk->binderKey) { + PK11_FreeSymKey(psk->binderKey); + psk->binderKey = NULL; + } + SECITEM_ZfreeItem(&psk->label, PR_FALSE); + PORT_ZFree(psk, sizeof(*psk)); +} + +void +tls13_DestroyPskList(PRCList *list) +{ + PRCList *cur_p; + while (!PR_CLIST_IS_EMPTY(list)) { + cur_p = PR_LIST_TAIL(list); + PR_REMOVE_LINK(cur_p); + tls13_DestroyPsk((sslPsk *)cur_p); + } +} + +sslPsk * +tls13_MakePsk(PK11SymKey *key, SSLPskType pskType, SSLHashType hashType, const SECItem *label) +{ + sslPsk *psk = PORT_ZNew(sslPsk); + if (!psk) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + psk->type = pskType; + psk->hash = hashType; + psk->key = key; + + /* Label is NULL in the resumption case. */ + if (label) { + PORT_Assert(psk->type != ssl_psk_resume); + SECStatus rv = SECITEM_CopyItem(NULL, &psk->label, label); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + tls13_DestroyPsk(psk); + return NULL; + } + } + + return psk; +} + +/* Destroy any existing PSKs in |list| then copy + * in the configured |ss->psk|, if any.*/ +SECStatus +tls13_ResetHandshakePsks(sslSocket *ss, PRCList *list) +{ + tls13_DestroyPskList(list); + PORT_Assert(!ss->xtnData.selectedPsk); + ss->xtnData.selectedPsk = NULL; + if (ss->psk) { + PORT_Assert(ss->psk->type == ssl_psk_external); + PORT_Assert(ss->psk->key); + PORT_Assert(!ss->psk->binderKey); + + sslPsk *epsk = tls13_MakePsk(PK11_ReferenceSymKey(ss->psk->key), + ss->psk->type, ss->psk->hash, &ss->psk->label); + if (!epsk) { + return SECFailure; + } + epsk->zeroRttSuite = ss->psk->zeroRttSuite; + epsk->maxEarlyData = ss->psk->maxEarlyData; + PR_APPEND_LINK(&epsk->link, list); + } + return SECSuccess; +} |