summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Jacobs <kjacobs@mozilla.com>2020-06-10 16:18:39 +0000
committerKevin Jacobs <kjacobs@mozilla.com>2020-06-10 16:18:39 +0000
commit6bd9c7b86e88e13cac6086c62e93ffaade158751 (patch)
treeb8eda0b60ec010e2d293ca0e3a25e033bbc910ea
parent486400ca1c16833569ae2aa7f41d03b5471c947d (diff)
downloadnss-hg-6bd9c7b86e88e13cac6086c62e93ffaade158751.tar.gz
Bug 1603042 - Support external PSKs in tstclnt/selfserv. r=jcj
This patch adds support for TLS 1.3 external PSKs in tstclnt and selfserv with the `-z` option. Command examples: - `selfserv -D -p 4443 -d . -n localhost.localdomain -w nss -V tls1.3: -H 1 -z 0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD[:label] -m` - `tstclnt -h 127.0.0.1 -p 4443 -z 0xAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD[:label] -d . -w nss` For OpenSSL interop: - `openssl s_server -nocert -port 4433 -psk AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD [-psk_identity label]` Note: If the optional label is omitted, both NSS tools and OpenSSL default to "Client_identity". Differential Revision: https://phabricator.services.mozilla.com/D75836
-rw-r--r--cmd/lib/basicutil.c5
-rw-r--r--cmd/lib/secutil.c54
-rw-r--r--cmd/lib/secutil.h2
-rw-r--r--cmd/selfserv/selfserv.c60
-rw-r--r--cmd/tstclnt/tstclnt.c60
-rw-r--r--lib/ssl/tls13psk.c4
6 files changed, 171 insertions, 14 deletions
diff --git a/cmd/lib/basicutil.c b/cmd/lib/basicutil.c
index 345e970ad..476475d90 100644
--- a/cmd/lib/basicutil.c
+++ b/cmd/lib/basicutil.c
@@ -741,7 +741,6 @@ SECU_HexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str)
int byteval = 0;
int tmp = PORT_Strlen(str);
- PORT_Assert(arena);
PORT_Assert(item);
if ((tmp % 2) != 0) {
@@ -762,7 +761,9 @@ SECU_HexString2SECItem(PLArenaPool *arena, SECItem *item, const char *str)
} else if ((str[i] >= 'A') && (str[i] <= 'F')) {
tmp = str[i] - 'A' + 10;
} else {
- /* item is in arena and gets freed by the caller */
+ if (!arena) {
+ SECITEM_FreeItem(item, PR_FALSE);
+ }
return NULL;
}
diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c
index b05dc7938..605139925 100644
--- a/cmd/lib/secutil.c
+++ b/cmd/lib/secutil.c
@@ -4159,3 +4159,57 @@ exportKeyingMaterials(PRFileDesc *fd,
return SECSuccess;
}
+
+SECStatus
+readPSK(const char *arg, SECItem *psk, SECItem *label)
+{
+ SECStatus rv = SECFailure;
+ char *str = PORT_Strdup(arg);
+ if (!str) {
+ goto cleanup;
+ }
+
+ char *pskBytes = strtok(str, ":");
+ if (!pskBytes) {
+ goto cleanup;
+ }
+ if (PORT_Strncasecmp(pskBytes, "0x", 2) != 0) {
+ goto cleanup;
+ }
+
+ psk = SECU_HexString2SECItem(NULL, psk, &pskBytes[2]);
+ if (!psk || !psk->data || psk->len != strlen(&str[2]) / 2) {
+ goto cleanup;
+ }
+
+ SECItem labelItem = { siBuffer, NULL, 0 };
+ char *inLabel = strtok(NULL, ":");
+ if (inLabel) {
+ labelItem.data = (unsigned char *)PORT_Strdup(inLabel);
+ if (!labelItem.data) {
+ goto cleanup;
+ }
+ labelItem.len = strlen(inLabel);
+
+ if (PORT_Strncasecmp(inLabel, "0x", 2) == 0) {
+ rv = SECU_SECItemHexStringToBinary(&labelItem);
+ if (rv != SECSuccess) {
+ SECITEM_FreeItem(&labelItem, PR_FALSE);
+ goto cleanup;
+ }
+ }
+ rv = SECSuccess;
+ } else {
+ const PRUint8 defaultLabel[] = { 'C', 'l', 'i', 'e', 'n', 't', '_',
+ 'i', 'd', 'e', 'n', 't', 'i', 't', 'y' };
+ rv = SECITEM_MakeItem(NULL, &labelItem, defaultLabel,
+ sizeof(defaultLabel));
+ }
+ if (rv == SECSuccess) {
+ *label = labelItem;
+ }
+
+cleanup:
+ PORT_Free(str);
+ return rv;
+}
diff --git a/cmd/lib/secutil.h b/cmd/lib/secutil.h
index c6da961e7..0bdfa9508 100644
--- a/cmd/lib/secutil.h
+++ b/cmd/lib/secutil.h
@@ -424,6 +424,8 @@ SECStatus exportKeyingMaterials(PRFileDesc *fd,
const secuExporter *exporters,
unsigned int exporterCount);
+SECStatus readPSK(const char *arg, SECItem *psk, SECItem *label);
+
/*
*
* Error messaging
diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c
index 0f500d65c..1584d7ee0 100644
--- a/cmd/selfserv/selfserv.c
+++ b/cmd/selfserv/selfserv.c
@@ -138,6 +138,8 @@ static SECItem bigBuf;
static int configureDHE = -1; /* -1: don't configure, 0 disable, >=1 enable*/
static int configureReuseECDHE = -1; /* -1: don't configure, 0 refresh, >=1 reuse*/
static int configureWeakDHE = -1; /* -1: don't configure, 0 disable, >=1 enable*/
+SECItem psk = { siBuffer, NULL, 0 };
+SECItem pskLabel = { siBuffer, NULL, 0 };
static PRThread *acceptorThread;
@@ -167,7 +169,7 @@ PrintUsageHeader(const char *progName)
" [ T <good|revoked|unknown|badsig|corrupted|none|ocsp>] [-A ca]\n"
" [-C SSLCacheEntries] [-S dsa_nickname] [-Q]\n"
" [-I groups] [-J signatureschemes] [-e ec_nickname]\n"
- " -U [0|1] -H [0|1|2] -W [0|1]\n"
+ " -U [0|1] -H [0|1|2] -W [0|1] [-z externalPsk]\n"
"\n",
progName);
}
@@ -241,7 +243,11 @@ PrintParameterUsage()
" LABEL[:OUTPUT-LENGTH[:CONTEXT]]\n"
" where LABEL and CONTEXT can be either a free-form string or\n"
" a hex string if it is preceded by \"0x\"; OUTPUT-LENGTH\n"
- " is a decimal integer.\n",
+ " is a decimal integer.\n"
+ "-z Configure a TLS 1.3 External PSK with the given hex string for a key.\n"
+ " To specify a label, use ':' as a delimiter. For example:\n"
+ " 0xAAAABBBBCCCCDDDD:mylabel. Otherwise, the default label of\n"
+ " 'Client_identity' will be used.\n",
stderr);
}
@@ -1841,6 +1847,32 @@ handshakeCallback(PRFileDesc *fd, void *client_data)
}
}
+static SECStatus
+importPsk(PRFileDesc *model_sock)
+{
+ SECU_PrintAsHex(stdout, &psk, "Using External PSK", 0);
+ PK11SlotInfo *slot = NULL;
+ PK11SymKey *symKey = NULL;
+ slot = PK11_GetInternalSlot();
+ if (!slot) {
+ errWarn("PK11_GetInternalSlot failed");
+ return SECFailure;
+ }
+ symKey = PK11_ImportSymKey(slot, CKM_HKDF_KEY_GEN, PK11_OriginUnwrap,
+ CKA_DERIVE, &psk, NULL);
+ PK11_FreeSlot(slot);
+ if (!symKey) {
+ errWarn("PK11_ImportSymKey failed\n");
+ return SECFailure;
+ }
+
+ SECStatus rv = SSL_AddExternalPsk(model_sock, symKey,
+ (const PRUint8 *)pskLabel.data,
+ pskLabel.len, ssl_hash_sha256);
+ PK11_FreeSymKey(symKey);
+ return rv;
+}
+
void
server_main(
PRFileDesc *listen_sock,
@@ -2050,6 +2082,13 @@ server_main(
}
}
+ if (psk.data) {
+ rv = importPsk(model_sock);
+ if (rv != SECSuccess) {
+ errExit("importPsk failed");
+ }
+ }
+
if (MakeCertOK)
SSL_BadCertHook(model_sock, myBadCertHandler, NULL);
@@ -2291,10 +2330,9 @@ main(int argc, char **argv)
/* please keep this list of options in ASCII collating sequence.
** numbers, then capital letters, then lower case, alphabetical.
** XXX: 'B', and 'q' were used in the past but removed
- ** in 3.28, please leave some time before resuing those.
- ** 'z' was removed in 3.39. */
+ ** in 3.28, please leave some time before resuing those. */
optstate = PL_CreateOptState(argc, argv,
- "2:A:C:DEGH:I:J:L:M:NP:QRS:T:U:V:W:YZa:bc:d:e:f:g:hi:jk:lmn:op:rst:uvw:x:y");
+ "2:A:C:DEGH:I:J:L:M:NP:QRS:T:U:V:W:YZa:bc:d:e:f:g:hi:jk:lmn:op:rst:uvw:x:yz:");
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
++optionsFound;
switch (optstate->option) {
@@ -2516,6 +2554,16 @@ main(int argc, char **argv)
zeroRTT = PR_TRUE;
break;
+ case 'z':
+ rv = readPSK(optstate->value, &psk, &pskLabel);
+ if (rv != SECSuccess) {
+ PL_DestroyOptState(optstate);
+ fprintf(stderr, "Bad PSK specified.\n");
+ Usage(progName);
+ exit(1);
+ }
+ break;
+
case 'Q':
enableALPN = PR_TRUE;
break;
@@ -2871,6 +2919,8 @@ cleanup:
if (antiReplay) {
SSL_ReleaseAntiReplayContext(antiReplay);
}
+ SECITEM_ZfreeItem(&psk, PR_FALSE);
+ SECITEM_ZfreeItem(&pskLabel, PR_FALSE);
if (NSS_Shutdown() != SECSuccess) {
SECU_PrintError(progName, "NSS_Shutdown");
if (loggerThread) {
diff --git a/cmd/tstclnt/tstclnt.c b/cmd/tstclnt/tstclnt.c
index 6fa154106..c37df118e 100644
--- a/cmd/tstclnt/tstclnt.c
+++ b/cmd/tstclnt/tstclnt.c
@@ -109,6 +109,8 @@ SSLNamedGroup *enabledGroups = NULL;
unsigned int enabledGroupsCount = 0;
const SSLSignatureScheme *enabledSigSchemes = NULL;
unsigned int enabledSigSchemeCount = 0;
+SECItem psk = { siBuffer, NULL, 0 };
+SECItem pskLabel = { siBuffer, NULL, 0 };
const char *
signatureSchemeName(SSLSignatureScheme scheme)
@@ -229,7 +231,7 @@ PrintUsageHeader()
" [-r N] [-w passwd] [-W pwfile] [-q [-t seconds]]\n"
" [-I groups] [-J signatureschemes]\n"
" [-A requestfile] [-L totalconnections] [-P {client,server}]\n"
- " [-N encryptedSniKeys] [-Q]\n"
+ " [-N encryptedSniKeys] [-Q] [-z externalPsk]\n"
"\n",
progName);
}
@@ -325,6 +327,12 @@ PrintParameterUsage()
"%-20s a hex string if it is preceded by \"0x\"; OUTPUT-LENGTH\n"
"%-20s is a decimal integer.\n",
"-x", "", "", "", "", "");
+ fprintf(stderr,
+ "%-20s Configure a TLS 1.3 External PSK with the given hex string for a key\n"
+ "%-20s To specify a label, use ':' as a delimiter. For example\n"
+ "%-20s 0xAAAABBBBCCCCDDDD:mylabel. Otherwise, the default label of\n"
+ "%-20s 'Client_identity' will be used.\n",
+ "-z externalPsk", "", "", "");
}
static void
@@ -1230,6 +1238,31 @@ connectToServer(PRFileDesc *s, PRPollDesc *pollset)
return SECSuccess;
}
+static SECStatus
+importPsk(PRFileDesc *s)
+{
+ SECU_PrintAsHex(stdout, &psk, "Using External PSK", 0);
+ PK11SlotInfo *slot = NULL;
+ PK11SymKey *symKey = NULL;
+ slot = PK11_GetInternalSlot();
+ if (!slot) {
+ SECU_PrintError(progName, "PK11_GetInternalSlot failed");
+ return SECFailure;
+ }
+ symKey = PK11_ImportSymKey(slot, CKM_HKDF_KEY_GEN, PK11_OriginUnwrap,
+ CKA_DERIVE, &psk, NULL);
+ PK11_FreeSlot(slot);
+ if (!symKey) {
+ SECU_PrintError(progName, "PK11_ImportSymKey failed");
+ return SECFailure;
+ }
+
+ SECStatus rv = SSL_AddExternalPsk(s, symKey, (const PRUint8 *)pskLabel.data,
+ pskLabel.len, ssl_hash_sha256);
+ PK11_FreeSymKey(symKey);
+ return rv;
+}
+
static int
run()
{
@@ -1498,6 +1531,15 @@ run()
}
}
+ if (psk.data) {
+ rv = importPsk(s);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "importPsk failed");
+ error = 1;
+ goto done;
+ }
+ }
+
serverCertAuth.dbHandle = CERT_GetDefaultCertDB();
SSL_AuthCertificateHook(s, ownAuthCertificate, &serverCertAuth);
@@ -1752,11 +1794,8 @@ main(int argc, char **argv)
}
}
- /* Note: 'z' was removed in 3.39
- * Please leave some time before reusing these.
- */
optstate = PL_CreateOptState(argc, argv,
- "46A:BCDEFGHI:J:KL:M:N:OP:QR:STUV:W:X:YZa:bc:d:fgh:m:n:op:qr:st:uvw:x:");
+ "46A:BCDEFGHI:J:KL:M:N:OP:QR:STUV:W:X:YZa:bc:d:fgh:m:n:op:qr:st:uvw:x:z:");
while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
case '?':
@@ -2015,6 +2054,15 @@ main(int argc, char **argv)
Usage();
}
break;
+
+ case 'z':
+ rv = readPSK(optstate->value, &psk, &pskLabel);
+ if (rv != SECSuccess) {
+ PL_DestroyOptState(optstate);
+ fprintf(stderr, "Bad PSK specified.\n");
+ Usage();
+ }
+ break;
}
}
PL_DestroyOptState(optstate);
@@ -2210,6 +2258,8 @@ done:
PORT_Free(host);
PORT_Free(zeroRttData);
PORT_Free(encryptedSNIKeys);
+ SECITEM_ZfreeItem(&psk, PR_FALSE);
+ SECITEM_ZfreeItem(&pskLabel, PR_FALSE);
if (enabledGroups) {
PORT_Free(enabledGroups);
diff --git a/lib/ssl/tls13psk.c b/lib/ssl/tls13psk.c
index cc1d14106..7343c5a6f 100644
--- a/lib/ssl/tls13psk.c
+++ b/lib/ssl/tls13psk.c
@@ -130,7 +130,7 @@ tls13_CopyPsk(sslPsk *opsk)
* are derived during the handshake. */
PORT_Assert(opsk->type == ssl_psk_external);
PORT_Assert(opsk->key);
- PORT_Assert(opsk->binderKey);
+ PORT_Assert(!opsk->binderKey);
psk->hash = opsk->hash;
psk->type = opsk->type;
psk->key = opsk->key ? PK11_ReferenceSymKey(opsk->key) : NULL;
@@ -216,4 +216,4 @@ tls13_ResetHandshakePsks(sslSocket *ss, PRCList *list)
PR_APPEND_LINK(&epsk->link, list);
}
return SECSuccess;
-} \ No newline at end of file
+}