Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 1494063, add -x option to tstclnt/selfserv to export keying mater…
…ial, r=mt

Reviewers: rrelyea, mt

Reviewed By: mt

Subscribers: HubertKario

Bug #: 1494063

Differential Revision: https://phabricator.services.mozilla.com/D29166

--HG--
extra : amend_source : 6dfd5e36e755ace210e517388c00f5eac5c71316
  • Loading branch information
ueno committed Sep 27, 2019
1 parent 2323fb4 commit 9192d33
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 9 deletions.
1 change: 1 addition & 0 deletions cmd/lib/Makefile
Expand Up @@ -27,6 +27,7 @@ include $(CORE_DEPTH)/coreconf/config.mk
#######################################################################

include config.mk
include ../platlibs.mk

#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
Expand Down
3 changes: 2 additions & 1 deletion cmd/lib/lib.gyp
Expand Up @@ -27,7 +27,8 @@
],
'target_defaults': {
'defines': [
'NSPR20'
'NSPR20',
'NSS_USE_STATIC_LIBS'
]
},
'variables': {
Expand Down
2 changes: 2 additions & 0 deletions cmd/lib/manifest.mn
Expand Up @@ -37,3 +37,5 @@ CSRCS = basicutil.c \
endif

NO_MD_RELEASE = 1

USE_STATIC_LIBS = 1
162 changes: 162 additions & 0 deletions cmd/lib/secutil.c
Expand Up @@ -22,6 +22,7 @@
#include <stdarg.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>

#ifdef XP_UNIX
#include <unistd.h>
Expand Down Expand Up @@ -3979,3 +3980,164 @@ parseSigSchemeList(const char *arg, const SSLSignatureScheme **enabledSigSchemes
*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;
}
14 changes: 14 additions & 0 deletions cmd/lib/secutil.h
Expand Up @@ -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);

/*
*
Expand Down
4 changes: 2 additions & 2 deletions cmd/platlibs.mk
Expand Up @@ -144,8 +144,8 @@ endif
ifeq ($(OS_ARCH), WINNT)

EXTRA_LIBS += \
$(NSS_LIBS_1) \
$(SECTOOL_LIB) \
$(NSS_LIBS_1) \
$(NSS_LIBS_2) \
$(SOFTOKENLIB) \
$(CRYPTOLIB) \
Expand All @@ -161,8 +161,8 @@ EXTRA_LIBS += \
else

EXTRA_LIBS += \
$(NSS_LIBS_1) \
$(SECTOOL_LIB) \
$(NSS_LIBS_1) \
$(NSS_LIBS_2) \
$(SOFTOKENLIB) \
$(NSS_LIBS_3) \
Expand Down
36 changes: 32 additions & 4 deletions cmd/selfserv/selfserv.c
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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");
Expand Down
34 changes: 33 additions & 1 deletion cmd/tstclnt/tstclnt.c
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 '?':
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 9192d33

Please sign in to comment.