summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <dueno@redhat.com>2019-09-27 17:36:35 +0200
committerDaiki Ueno <dueno@redhat.com>2019-09-27 17:36:35 +0200
commit058733416a418b99efd4b4091fea4d23bdcb6bae (patch)
tree4d519131bed7520c8888a0952ab17f0726e0ccd3
parent6a0599347d881a2b6dee6dd1f996045605da08e2 (diff)
downloadnss-hg-058733416a418b99efd4b4091fea4d23bdcb6bae.tar.gz
Bug 1494063, add -x option to tstclnt/selfserv to export keying material, r=mt
Reviewers: rrelyea, mt Reviewed By: mt Subscribers: HubertKario Bug #: 1494063 Differential Revision: https://phabricator.services.mozilla.com/D29166
-rw-r--r--cmd/lib/Makefile1
-rw-r--r--cmd/lib/lib.gyp3
-rw-r--r--cmd/lib/manifest.mn2
-rw-r--r--cmd/lib/secutil.c162
-rw-r--r--cmd/lib/secutil.h14
-rw-r--r--cmd/platlibs.mk4
-rw-r--r--cmd/selfserv/selfserv.c36
-rw-r--r--cmd/tstclnt/tstclnt.c34
-rwxr-xr-xtests/ssl/ssl.sh37
9 files changed, 284 insertions, 9 deletions
diff --git a/cmd/lib/Makefile b/cmd/lib/Makefile
index 0fb6c9058..6b53451ef 100644
--- a/cmd/lib/Makefile
+++ b/cmd/lib/Makefile
@@ -27,6 +27,7 @@ include $(CORE_DEPTH)/coreconf/config.mk
#######################################################################
include config.mk
+include ../platlibs.mk
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
diff --git a/cmd/lib/lib.gyp b/cmd/lib/lib.gyp
index 6b7da5810..c5835a869 100644
--- a/cmd/lib/lib.gyp
+++ b/cmd/lib/lib.gyp
@@ -27,7 +27,8 @@
],
'target_defaults': {
'defines': [
- 'NSPR20'
+ 'NSPR20',
+ 'NSS_USE_STATIC_LIBS'
]
},
'variables': {
diff --git a/cmd/lib/manifest.mn b/cmd/lib/manifest.mn
index 87440c052..b3c36b3a9 100644
--- a/cmd/lib/manifest.mn
+++ b/cmd/lib/manifest.mn
@@ -37,3 +37,5 @@ CSRCS = basicutil.c \
endif
NO_MD_RELEASE = 1
+
+USE_STATIC_LIBS = 1
diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c
index 97c7f750a..aafde9b5f 100644
--- a/cmd/lib/secutil.c
+++ b/cmd/lib/secutil.c
@@ -22,6 +22,7 @@
#include <stdarg.h>
#include <sys/stat.h>
#include <errno.h>
+#include <limits.h>
#ifdef XP_UNIX
#include <unistd.h>
@@ -3979,3 +3980,164 @@ done:
*enabledSigSchemes = schemes;
return SECSuccess;
}
+
+/* Parse the exporter spec in the form: LABEL[:OUTPUT-LENGTH[:CONTEXT]] */
+static SECStatus
+parseExporter(const char *arg,
+ secuExporter *exporter)
+{
+ SECStatus rv = SECSuccess;
+
+ char *str = PORT_Strdup(arg);
+ if (!str) {
+ rv = SECFailure;
+ goto done;
+ }
+
+ char *labelEnd = strchr(str, ':');
+ if (labelEnd) {
+ *labelEnd = '\0';
+ labelEnd++;
+
+ /* To extract CONTEXT, first skip OUTPUT-LENGTH */
+ char *outputEnd = strchr(labelEnd, ':');
+ if (outputEnd) {
+ *outputEnd = '\0';
+ outputEnd++;
+
+ exporter->hasContext = PR_TRUE;
+ exporter->context.data = (unsigned char *)PORT_Strdup(outputEnd);
+ exporter->context.len = strlen(outputEnd);
+ if (PORT_Strncasecmp((char *)exporter->context.data, "0x", 2) == 0) {
+ rv = SECU_SECItemHexStringToBinary(&exporter->context);
+ if (rv != SECSuccess) {
+ goto done;
+ }
+ }
+ }
+ }
+
+ if (labelEnd && *labelEnd != '\0') {
+ long int outputLength = strtol(labelEnd, NULL, 10);
+ if (!(outputLength > 0 && outputLength <= UINT_MAX)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ goto done;
+ }
+ exporter->outputLength = outputLength;
+ } else {
+ exporter->outputLength = 20;
+ }
+
+ char *label = PORT_Strdup(str);
+ exporter->label.data = (unsigned char *)label;
+ exporter->label.len = strlen(label);
+ if (PORT_Strncasecmp((char *)exporter->label.data, "0x", 2) == 0) {
+ rv = SECU_SECItemHexStringToBinary(&exporter->label);
+ if (rv != SECSuccess) {
+ goto done;
+ }
+ }
+
+done:
+ PORT_Free(str);
+
+ return rv;
+}
+
+SECStatus
+parseExporters(const char *arg,
+ const secuExporter **enabledExporters,
+ unsigned int *enabledExporterCount)
+{
+ secuExporter *exporters;
+ unsigned int numValues = 0;
+ unsigned int count = 0;
+
+ if (countItems(arg, &numValues) != SECSuccess) {
+ return SECFailure;
+ }
+ exporters = PORT_ZNewArray(secuExporter, numValues);
+ if (!exporters) {
+ return SECFailure;
+ }
+
+ /* Get exporter definitions. */
+ char *str = PORT_Strdup(arg);
+ if (!str) {
+ goto done;
+ }
+ char *p = strtok(str, ",");
+ while (p) {
+ SECStatus rv = parseExporter(p, &exporters[count++]);
+ if (rv != SECSuccess) {
+ count = 0;
+ goto done;
+ }
+ p = strtok(NULL, ",");
+ }
+
+done:
+ PORT_Free(str);
+ if (!count) {
+ PORT_Free(exporters);
+ return SECFailure;
+ }
+
+ *enabledExporterCount = count;
+ *enabledExporters = exporters;
+ return SECSuccess;
+}
+
+static SECStatus
+exportKeyingMaterial(PRFileDesc *fd, const secuExporter *exporter)
+{
+ SECStatus rv = SECSuccess;
+ unsigned char *out = PORT_Alloc(exporter->outputLength);
+
+ if (!out) {
+ fprintf(stderr, "Unable to allocate buffer for keying material\n");
+ return SECFailure;
+ }
+ rv = SSL_ExportKeyingMaterial(fd,
+ (char *)exporter->label.data,
+ exporter->label.len,
+ exporter->hasContext,
+ exporter->context.data,
+ exporter->context.len,
+ out,
+ exporter->outputLength);
+ if (rv != SECSuccess) {
+ goto done;
+ }
+ fprintf(stdout, "Exported Keying Material:\n");
+ secu_PrintRawString(stdout, (SECItem *)&exporter->label, "Label", 1);
+ if (exporter->hasContext) {
+ SECU_PrintAsHex(stdout, &exporter->context, "Context", 1);
+ }
+ SECU_Indent(stdout, 1);
+ fprintf(stdout, "Length: %u\n", exporter->outputLength);
+ SECItem temp = { siBuffer, out, exporter->outputLength };
+ SECU_PrintAsHex(stdout, &temp, "Keying Material", 1);
+
+done:
+ PORT_Free(out);
+ return rv;
+}
+
+SECStatus
+exportKeyingMaterials(PRFileDesc *fd,
+ const secuExporter *exporters,
+ unsigned int exporterCount)
+{
+ unsigned int i;
+
+ for (i = 0; i < exporterCount; i++) {
+ SECStatus rv = exportKeyingMaterial(fd, &exporters[i]);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+
+ return SECSuccess;
+}
diff --git a/cmd/lib/secutil.h b/cmd/lib/secutil.h
index 90d763909..c6da961e7 100644
--- a/cmd/lib/secutil.h
+++ b/cmd/lib/secutil.h
@@ -409,6 +409,20 @@ SECStatus parseGroupList(const char *arg, SSLNamedGroup **enabledGroups,
SECStatus parseSigSchemeList(const char *arg,
const SSLSignatureScheme **enabledSigSchemes,
unsigned int *enabledSigSchemeCount);
+typedef struct {
+ SECItem label;
+ PRBool hasContext;
+ SECItem context;
+ unsigned int outputLength;
+} secuExporter;
+
+SECStatus parseExporters(const char *arg,
+ const secuExporter **enabledExporters,
+ unsigned int *enabledExporterCount);
+
+SECStatus exportKeyingMaterials(PRFileDesc *fd,
+ const secuExporter *exporters,
+ unsigned int exporterCount);
/*
*
diff --git a/cmd/platlibs.mk b/cmd/platlibs.mk
index a59d03d06..640177882 100644
--- a/cmd/platlibs.mk
+++ b/cmd/platlibs.mk
@@ -144,8 +144,8 @@ endif
ifeq ($(OS_ARCH), WINNT)
EXTRA_LIBS += \
- $(NSS_LIBS_1) \
$(SECTOOL_LIB) \
+ $(NSS_LIBS_1) \
$(NSS_LIBS_2) \
$(SOFTOKENLIB) \
$(CRYPTOLIB) \
@@ -161,8 +161,8 @@ EXTRA_LIBS += \
else
EXTRA_LIBS += \
- $(NSS_LIBS_1) \
$(SECTOOL_LIB) \
+ $(NSS_LIBS_1) \
$(NSS_LIBS_2) \
$(SOFTOKENLIB) \
$(NSS_LIBS_3) \
diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c
index fb2d8d53c..03e39d67b 100644
--- a/cmd/selfserv/selfserv.c
+++ b/cmd/selfserv/selfserv.c
@@ -235,7 +235,13 @@ PrintParameterUsage()
" rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n"
"-Z enable 0-RTT (for TLS 1.3; also use -u)\n"
"-E enable post-handshake authentication\n"
- " (for TLS 1.3; only has an effect with 3 or more -r options)\n",
+ " (for TLS 1.3; only has an effect with 3 or more -r options)\n"
+ "-x Export and print keying material after successful handshake\n"
+ " The argument is a comma separated list of exporters in the form:\n"
+ " 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",
stderr);
}
@@ -812,6 +818,8 @@ SSLNamedGroup *enabledGroups = NULL;
unsigned int enabledGroupsCount = 0;
const SSLSignatureScheme *enabledSigSchemes = NULL;
unsigned int enabledSigSchemeCount = 0;
+const secuExporter *enabledExporters = NULL;
+unsigned int enabledExporterCount = 0;
static char *virtServerNameArray[MAX_VIRT_SERVER_NAME_ARRAY_INDEX];
static int virtServerNameIndex = 1;
@@ -1822,6 +1830,15 @@ handshakeCallback(PRFileDesc *fd, void *client_data)
SECITEM_FreeItem(hostInfo, PR_TRUE);
}
}
+ if (enabledExporters) {
+ SECStatus rv = exportKeyingMaterials(fd, enabledExporters, enabledExporterCount);
+ if (rv != SECSuccess) {
+ PRErrorCode err = PR_GetError();
+ fprintf(stderr,
+ "couldn't export keying material: %s\n",
+ SECU_Strerror(err));
+ }
+ }
}
void
@@ -2012,7 +2029,7 @@ server_main(
errExit("SSL_CipherPrefSetDefault:TLS_RSA_WITH_NULL_MD5");
}
- if (expectedHostNameVal) {
+ if (expectedHostNameVal || enabledExporters) {
SSL_HandshakeCallback(model_sock, handshakeCallback,
(void *)expectedHostNameVal);
}
@@ -2246,11 +2263,11 @@ 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', 'E', 'q', and 'x' were used in the past but removed
+ ** 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. */
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: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:y");
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
++optionsFound;
switch (optstate->option) {
@@ -2496,6 +2513,17 @@ main(int argc, char **argv)
}
break;
+ case 'x':
+ rv = parseExporters(optstate->value,
+ &enabledExporters, &enabledExporterCount);
+ if (rv != SECSuccess) {
+ PL_DestroyOptState(optstate);
+ fprintf(stderr, "Bad exporter specified.\n");
+ fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
+ exit(5);
+ }
+ break;
+
default:
case '?':
fprintf(stderr, "Unrecognized or bad option specified.\n");
diff --git a/cmd/tstclnt/tstclnt.c b/cmd/tstclnt/tstclnt.c
index 7f560111e..6fa154106 100644
--- a/cmd/tstclnt/tstclnt.c
+++ b/cmd/tstclnt/tstclnt.c
@@ -318,6 +318,13 @@ PrintParameterUsage()
fprintf(stderr, "%-20s Enable post-handshake authentication\n"
"%-20s for TLS 1.3; need to specify -n\n",
"-E", "");
+ fprintf(stderr, "%-20s Export and print keying material after successful handshake.\n"
+ "%-20s The argument is a comma separated list of exporters in the form:\n"
+ "%-20s LABEL[:OUTPUT-LENGTH[:CONTEXT]]\n"
+ "%-20s where LABEL and CONTEXT can be either a free-form string or\n"
+ "%-20s a hex string if it is preceded by \"0x\"; OUTPUT-LENGTH\n"
+ "%-20s is a decimal integer.\n",
+ "-x", "", "", "", "", "");
}
static void
@@ -998,6 +1005,8 @@ PRBool handshakeComplete = PR_FALSE;
char *encryptedSNIKeys = NULL;
PRBool enablePostHandshakeAuth = PR_FALSE;
PRBool enableDelegatedCredentials = PR_FALSE;
+const secuExporter *enabledExporters = NULL;
+unsigned int enabledExporterCount = 0;
static int
writeBytesToServer(PRFileDesc *s, const PRUint8 *buf, int nb)
@@ -1093,6 +1102,18 @@ handshakeCallback(PRFileDesc *fd, void *client_data)
requestToExit = PR_TRUE;
}
handshakeComplete = PR_TRUE;
+
+ if (enabledExporters) {
+ SECStatus rv;
+
+ rv = exportKeyingMaterials(fd, enabledExporters, enabledExporterCount);
+ if (rv != SECSuccess) {
+ PRErrorCode err = PR_GetError();
+ FPRINTF(stderr,
+ "couldn't export keying material: %s\n",
+ SECU_Strerror(err));
+ }
+ }
}
static SECStatus
@@ -1735,7 +1756,7 @@ main(int argc, char **argv)
* 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:");
+ "46A:BCDEFGHI:J:KL:M:N:OP:QR:STUV:W:X:YZa:bc:d:fgh:m:n:op:qr:st:uvw:x:");
while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
case '?':
@@ -1983,6 +2004,17 @@ main(int argc, char **argv)
Usage();
}
break;
+
+ case 'x':
+ rv = parseExporters(optstate->value,
+ &enabledExporters,
+ &enabledExporterCount);
+ if (rv != SECSuccess) {
+ PL_DestroyOptState(optstate);
+ fprintf(stderr, "Bad exporter specified.\n");
+ Usage();
+ }
+ break;
}
}
PL_DestroyOptState(optstate);
diff --git a/tests/ssl/ssl.sh b/tests/ssl/ssl.sh
index a05090694..d8892ed87 100755
--- a/tests/ssl/ssl.sh
+++ b/tests/ssl/ssl.sh
@@ -84,7 +84,7 @@ ssl_init()
PORT=$(($PORT + $padd))
fi
NSS_SSL_TESTS=${NSS_SSL_TESTS:-normal_normal}
- nss_ssl_run="stapling signed_cert_timestamps cov auth dtls scheme"
+ nss_ssl_run="stapling signed_cert_timestamps cov auth dtls scheme exporter"
NSS_SSL_RUN=${NSS_SSL_RUN:-$nss_ssl_run}
# Test case files
@@ -1319,6 +1319,38 @@ ssl_scheme_stress()
html "</TABLE><BR>"
}
+############################ ssl_exporter ###################################
+# local shell function to test tstclnt and selfserv handling of TLS exporter
+#########################################################################
+ssl_exporter()
+{
+ html_head "SSL EXPORTER $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE"
+
+ save_fileout=${fileout}
+ fileout=1
+ SAVE_SERVEROUTFILE=${SERVEROUTFILE}
+ SERVEROUTFILE=server.out
+ exporters=("label" "label:10" "label:10:0xdeadbeef" "0x666f6f2c:10:0xdeadbeef" "label1:10:0xdeadbeef,label2:10")
+ for exporter in "${exporters[@]}"; do
+ start_selfserv -V tls1.2:tls1.2 -x "$exporter"
+
+ echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${P_R_CLIENTDIR} $verbose ${CLIENT_OPTIONS} \\"
+ echo " -V tls1.2:tls1.2 -x $exporter < ${REQUEST_FILE}"
+ ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f ${CLIENT_OPTIONS} \
+ -d ${P_R_CLIENTDIR} $verbose -V tls1.2:tls1.2 -x "$exporter" < ${REQUEST_FILE} 2>&1 > client.out
+ kill_selfserv
+ diff <(LC_ALL=C grep -A1 "^ *Keying Material:" server.out) \
+ <(LC_ALL=C grep -A1 "^ *Keying Material:" client.out)
+ ret=$?
+ html_msg $ret 0 "${testname}" \
+ "produced a returncode of $ret, expected is 0"
+ done
+ SERVEROUTFILE=${SAVE_SERVEROUTFILE}
+ fileout=${save_fileout}
+
+ html "</TABLE><BR>"
+}
+
############################## ssl_cleanup #############################
# local shell function to finish this script (no exit since it might be
# sourced)
@@ -1363,6 +1395,9 @@ ssl_run()
ssl_scheme
ssl_scheme_stress
;;
+ "exporter")
+ ssl_exporter
+ ;;
esac
done
}