summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl/tls13psk.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--security/nss/lib/ssl/tls13psk.c219
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;
+}