selfserv.c (nss-3.61) | : | selfserv.c (nss-3.62) | ||
---|---|---|---|---|
skipping to change at line 45 | skipping to change at line 45 | |||
#include "plgetopt.h" | #include "plgetopt.h" | |||
#include "pk11func.h" | #include "pk11func.h" | |||
#include "secitem.h" | #include "secitem.h" | |||
#include "nss.h" | #include "nss.h" | |||
#include "ssl.h" | #include "ssl.h" | |||
#include "sslproto.h" | #include "sslproto.h" | |||
#include "sslexp.h" | #include "sslexp.h" | |||
#include "cert.h" | #include "cert.h" | |||
#include "certt.h" | #include "certt.h" | |||
#include "ocsp.h" | #include "ocsp.h" | |||
#include "nssb64.h" | ||||
#ifndef PORT_Sprintf | #ifndef PORT_Sprintf | |||
#define PORT_Sprintf sprintf | #define PORT_Sprintf sprintf | |||
#endif | #endif | |||
#ifndef PORT_Strstr | #ifndef PORT_Strstr | |||
#define PORT_Strstr strstr | #define PORT_Strstr strstr | |||
#endif | #endif | |||
#ifndef PORT_Malloc | #ifndef PORT_Malloc | |||
skipping to change at line 143 | skipping to change at line 144 | |||
static PRBool noDelay; | static PRBool noDelay; | |||
static int requestCert; | static int requestCert; | |||
static int verbose; | static int verbose; | |||
static SECItem bigBuf; | static SECItem bigBuf; | |||
static int configureDHE = -1; /* -1: don't configure, 0 disable, >=1 enab le*/ | static int configureDHE = -1; /* -1: don't configure, 0 disable, >=1 enab le*/ | |||
static int configureReuseECDHE = -1; /* -1: don't configure, 0 refresh, >=1 reus e*/ | static int configureReuseECDHE = -1; /* -1: don't configure, 0 refresh, >=1 reus e*/ | |||
static int configureWeakDHE = -1; /* -1: don't configure, 0 disable, >=1 enab le*/ | static int configureWeakDHE = -1; /* -1: don't configure, 0 disable, >=1 enab le*/ | |||
SECItem psk = { siBuffer, NULL, 0 }; | SECItem psk = { siBuffer, NULL, 0 }; | |||
SECItem pskLabel = { siBuffer, NULL, 0 }; | SECItem pskLabel = { siBuffer, NULL, 0 }; | |||
char *echParamsStr = NULL; | ||||
static PRThread *acceptorThread; | static PRThread *acceptorThread; | |||
static PRLogModuleInfo *lm; | static PRLogModuleInfo *lm; | |||
#define PRINTF \ | #define PRINTF \ | |||
if (verbose) \ | if (verbose) \ | |||
printf | printf | |||
#define FPRINTF \ | #define FPRINTF \ | |||
if (verbose) \ | if (verbose) \ | |||
skipping to change at line 250 | skipping to change at line 252 | |||
" (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" | "-x Export and print keying material after successful handshake\n" | |||
" The argument is a comma separated list of exporters in the form:\n" | " The argument is a comma separated list of exporters in the form:\n" | |||
" LABEL[:OUTPUT-LENGTH[:CONTEXT]]\n" | " LABEL[:OUTPUT-LENGTH[:CONTEXT]]\n" | |||
" where LABEL and CONTEXT can be either a free-form string or\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" | " 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" | "-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" | " To specify a label, use ':' as a delimiter. For example:\n" | |||
" 0xAAAABBBBCCCCDDDD:mylabel. Otherwise, the default label of\n" | " 0xAAAABBBBCCCCDDDD:mylabel. Otherwise, the default label of\n" | |||
" 'Client_identity' will be used.\n", | " 'Client_identity' will be used.\n" | |||
"-X Configure the server for ECH via the given <ECHParams>. ECHParams\n | ||||
" | ||||
" are expected in one of two formats:\n" | ||||
" 1. A string containing the ECH public name prefixed by the substr | ||||
ing\n" | ||||
" \"publicname:\". For example, \"publicname:example.com\". In t | ||||
his mode,\n" | ||||
" an ephemeral ECH keypair is generated and ECHConfigs are print | ||||
ed to stdout.\n" | ||||
" 2. As a Base64 tuple of <ECHRawPrivateKey> || <ECHConfigs>. In th | ||||
is mode, the\n" | ||||
" raw private key is used to bootstrap the HPKE context.\n", | ||||
stderr); | stderr); | |||
} | } | |||
static void | static void | |||
Usage(const char *progName) | Usage(const char *progName) | |||
{ | { | |||
PrintUsageHeader(progName); | PrintUsageHeader(progName); | |||
PrintParameterUsage(); | PrintParameterUsage(); | |||
} | } | |||
skipping to change at line 1876 | skipping to change at line 1885 | |||
return SECFailure; | return SECFailure; | |||
} | } | |||
SECStatus rv = SSL_AddExternalPsk(model_sock, symKey, | SECStatus rv = SSL_AddExternalPsk(model_sock, symKey, | |||
(const PRUint8 *)pskLabel.data, | (const PRUint8 *)pskLabel.data, | |||
pskLabel.len, ssl_hash_sha256); | pskLabel.len, ssl_hash_sha256); | |||
PK11_FreeSymKey(symKey); | PK11_FreeSymKey(symKey); | |||
return rv; | return rv; | |||
} | } | |||
static SECStatus | ||||
configureEchWithPublicName(PRFileDesc *model_sock, const char *public_name) | ||||
{ | ||||
SECStatus rv; | ||||
#define OID_LEN 65 | ||||
unsigned char paramBuf[OID_LEN]; | ||||
SECItem ecParams = { siBuffer, paramBuf, sizeof(paramBuf) }; | ||||
SECKEYPublicKey *pubKey = NULL; | ||||
SECKEYPrivateKey *privKey = NULL; | ||||
SECOidData *oidData; | ||||
char *echConfigBase64 = NULL; | ||||
PRUint8 configBuf[1000]; | ||||
unsigned int len = 0; | ||||
unsigned int echCipherSuite = ((unsigned int)HpkeKdfHkdfSha256 << 16) | | ||||
HpkeAeadChaCha20Poly1305; | ||||
PK11SlotInfo *slot = PK11_GetInternalKeySlot(); | ||||
if (!slot) { | ||||
errWarn("PK11_GetInternalKeySlot failed"); | ||||
return SECFailure; | ||||
} | ||||
oidData = SECOID_FindOIDByTag(SEC_OID_CURVE25519); | ||||
if (oidData && (2 + oidData->oid.len) < sizeof(paramBuf)) { | ||||
ecParams.data[0] = SEC_ASN1_OBJECT_ID; | ||||
ecParams.data[1] = oidData->oid.len; | ||||
memcpy(ecParams.data + 2, oidData->oid.data, oidData->oid.len); | ||||
ecParams.len = oidData->oid.len + 2; | ||||
} else { | ||||
errWarn("SECOID_FindOIDByTag failed"); | ||||
goto loser; | ||||
} | ||||
privKey = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, &ecParams, | ||||
&pubKey, PR_FALSE, PR_FALSE, NULL); | ||||
if (!privKey || !pubKey) { | ||||
errWarn("Failed to generate ECH keypair"); | ||||
goto loser; | ||||
} | ||||
rv = SSL_EncodeEchConfig(echParamsStr, &echCipherSuite, 1, | ||||
HpkeDhKemX25519Sha256, pubKey, 50, | ||||
configBuf, &len, sizeof(configBuf)); | ||||
if (rv != SECSuccess) { | ||||
errWarn("SSL_EncodeEchConfig failed"); | ||||
goto loser; | ||||
} | ||||
rv = SSL_SetServerEchConfigs(model_sock, pubKey, privKey, configBuf, len); | ||||
if (rv != SECSuccess) { | ||||
errWarn("SSL_SetServerEchConfigs failed"); | ||||
goto loser; | ||||
} | ||||
SECItem echConfigItem = { siBuffer, configBuf, len }; | ||||
echConfigBase64 = NSSBase64_EncodeItem(NULL, NULL, 0, &echConfigItem); | ||||
if (!echConfigBase64) { | ||||
errWarn("NSSBase64_EncodeItem failed"); | ||||
goto loser; | ||||
} | ||||
// Remove the newline characters that NSSBase64_EncodeItem unhelpfully inser | ||||
ts. | ||||
char *newline = strstr(echConfigBase64, "\r\n"); | ||||
if (newline) { | ||||
memmove(newline, newline + 2, strlen(newline + 2) + 1); | ||||
} | ||||
printf("%s\n", echConfigBase64); | ||||
PORT_Free(echConfigBase64); | ||||
SECKEY_DestroyPrivateKey(privKey); | ||||
SECKEY_DestroyPublicKey(pubKey); | ||||
PK11_FreeSlot(slot); | ||||
return SECSuccess; | ||||
loser: | ||||
PORT_Free(echConfigBase64); | ||||
SECKEY_DestroyPrivateKey(privKey); | ||||
SECKEY_DestroyPublicKey(pubKey); | ||||
PK11_FreeSlot(slot); | ||||
return SECFailure; | ||||
} | ||||
static SECStatus | ||||
configureEchWithData(PRFileDesc *model_sock) | ||||
{ | ||||
/* The input should be a Base64-encoded ECHKey struct: | ||||
* struct { | ||||
* opaque pkcs8_ech_keypair<0..2^16-1>; | ||||
* ECHConfigs configs<0..2^16>; // draft-ietf-tls-esni-09 | ||||
* } ECHKey; | ||||
* | ||||
* This is not a standardized format, rather it's designed for | ||||
* interoperability with https://github.com/xvzcf/tls-interop-runner. | ||||
* It is the user's responsibility to ensure that the PKCS8 keypair | ||||
* corresponds to the public key embedded in the ECHConfigs. | ||||
*/ | ||||
#define REMAINING_BYTES(rdr, buf) \ | ||||
buf->len - (rdr - buf->data) | ||||
SECStatus rv; | ||||
size_t len; | ||||
unsigned char *reader; | ||||
PK11SlotInfo *slot = NULL; | ||||
SECItem *decoded = NULL; | ||||
SECKEYPublicKey *pk = NULL; | ||||
SECKEYPrivateKey *sk = NULL; | ||||
SECItem pkcs8Key = { siBuffer, NULL, 0 }; | ||||
decoded = NSSBase64_DecodeBuffer(NULL, NULL, echParamsStr, PORT_Strlen(echPa | ||||
ramsStr)); | ||||
if (!decoded || decoded->len < 2) { | ||||
errWarn("Couldn't decode ECHParams"); | ||||
goto loser; | ||||
}; | ||||
reader = decoded->data; | ||||
len = (*(reader++) << 8); | ||||
len |= *(reader++); | ||||
if (len > (REMAINING_BYTES(reader, decoded) - 2)) { | ||||
errWarn("Bad ECHParams encoding"); | ||||
goto loser; | ||||
} | ||||
pkcs8Key.data = reader; | ||||
pkcs8Key.len = len; | ||||
reader += len; | ||||
/* Convert the key bytes to key handles */ | ||||
slot = PK11_GetInternalKeySlot(); | ||||
rv = PK11_ImportDERPrivateKeyInfoAndReturnKey( | ||||
slot, &pkcs8Key, NULL, NULL, PR_FALSE, PR_FALSE, KU_ALL, &sk, NULL); | ||||
if (rv != SECSuccess || !sk) { | ||||
errWarn("ECH key import failed"); | ||||
goto loser; | ||||
} | ||||
pk = SECKEY_ConvertToPublicKey(sk); | ||||
if (!pk) { | ||||
errWarn("ECH key conversion failed"); | ||||
goto loser; | ||||
} | ||||
/* Remainder is the ECHConfigs. */ | ||||
rv = SSL_SetServerEchConfigs(model_sock, pk, sk, reader, | ||||
REMAINING_BYTES(reader, decoded)); | ||||
if (rv != SECSuccess) { | ||||
errWarn("SSL_SetServerEchConfigs failed"); | ||||
goto loser; | ||||
} | ||||
PK11_FreeSlot(slot); | ||||
SECKEY_DestroyPrivateKey(sk); | ||||
SECKEY_DestroyPublicKey(pk); | ||||
SECITEM_FreeItem(decoded, PR_TRUE); | ||||
return SECSuccess; | ||||
loser: | ||||
if (slot) { | ||||
PK11_FreeSlot(slot); | ||||
} | ||||
SECKEY_DestroyPrivateKey(sk); | ||||
SECKEY_DestroyPublicKey(pk); | ||||
SECITEM_FreeItem(decoded, PR_TRUE); | ||||
return SECFailure; | ||||
} | ||||
static SECStatus | ||||
configureEch(PRFileDesc *model_sock) | ||||
{ | ||||
if (!PORT_Strncmp(echParamsStr, "publicname:", PORT_Strlen("publicname:"))) | ||||
{ | ||||
return configureEchWithPublicName(model_sock, | ||||
&echParamsStr[PORT_Strlen("publicname: | ||||
")]); | ||||
} | ||||
return configureEchWithData(model_sock); | ||||
} | ||||
void | void | |||
server_main( | server_main( | |||
PRFileDesc *listen_sock, | PRFileDesc *listen_sock, | |||
SECKEYPrivateKey **privKey, | SECKEYPrivateKey **privKey, | |||
CERTCertificate **cert, | CERTCertificate **cert, | |||
const char *expectedHostNameVal) | const char *expectedHostNameVal) | |||
{ | { | |||
int i; | int i; | |||
PRFileDesc *model_sock = NULL; | PRFileDesc *model_sock = NULL; | |||
int rv; | int rv; | |||
skipping to change at line 2092 | skipping to change at line 2273 | |||
} | } | |||
} | } | |||
if (psk.data) { | if (psk.data) { | |||
rv = importPsk(model_sock); | rv = importPsk(model_sock); | |||
if (rv != SECSuccess) { | if (rv != SECSuccess) { | |||
errExit("importPsk failed"); | errExit("importPsk failed"); | |||
} | } | |||
} | } | |||
if (echParamsStr) { | ||||
rv = configureEch(model_sock); | ||||
if (rv != SECSuccess) { | ||||
errExit("configureEch failed"); | ||||
} | ||||
} | ||||
if (MakeCertOK) | if (MakeCertOK) | |||
SSL_BadCertHook(model_sock, myBadCertHandler, NULL); | SSL_BadCertHook(model_sock, myBadCertHandler, NULL); | |||
/* end of ssl configuration. */ | /* end of ssl configuration. */ | |||
/* Now, do the accepting, here in the main thread. */ | /* Now, do the accepting, here in the main thread. */ | |||
rv = do_accepts(listen_sock, model_sock); | rv = do_accepts(listen_sock, model_sock); | |||
terminateWorkerThreads(); | terminateWorkerThreads(); | |||
skipping to change at line 2335 | skipping to change at line 2523 | |||
progName = progName ? progName + 1 : tmp; | progName = progName ? progName + 1 : tmp; | |||
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); | PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); | |||
SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions); | SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions); | |||
/* please keep this list of options in ASCII collating sequence. | /* please keep this list of options in ASCII collating sequence. | |||
** numbers, then capital letters, then lower case, alphabetical. | ** numbers, then capital letters, then lower case, alphabetical. | |||
** XXX: 'B', and 'q' 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. */ | ** in 3.28, please leave some time before resuing those. */ | |||
optstate = PL_CreateOptState(argc, argv, | 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:yz:"); | "2:A:C:DEGH:I:J:L:M:NP:QRS:T:U:V:W:X:YZa:bc:d:e :f:g:hi:jk:lmn:op:rst:uvw:x:yz:"); | |||
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { | while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { | |||
++optionsFound; | ++optionsFound; | |||
switch (optstate->option) { | switch (optstate->option) { | |||
case '2': | case '2': | |||
fileName = optstate->value; | fileName = optstate->value; | |||
break; | break; | |||
case 'A': | case 'A': | |||
ocspStaplingCA = PORT_Strdup(optstate->value); | ocspStaplingCA = PORT_Strdup(optstate->value); | |||
break; | break; | |||
skipping to change at line 2602 | skipping to change at line 2790 | |||
rv = parseExporters(optstate->value, | rv = parseExporters(optstate->value, | |||
&enabledExporters, &enabledExporterCount); | &enabledExporters, &enabledExporterCount); | |||
if (rv != SECSuccess) { | if (rv != SECSuccess) { | |||
PL_DestroyOptState(optstate); | PL_DestroyOptState(optstate); | |||
fprintf(stderr, "Bad exporter specified.\n"); | fprintf(stderr, "Bad exporter specified.\n"); | |||
fprintf(stderr, "Run '%s -h' for usage information.\n", prog Name); | fprintf(stderr, "Run '%s -h' for usage information.\n", prog Name); | |||
exit(5); | exit(5); | |||
} | } | |||
break; | break; | |||
case 'X': | ||||
echParamsStr = PORT_Strdup(optstate->value); | ||||
if (echParamsStr == NULL) { | ||||
PL_DestroyOptState(optstate); | ||||
fprintf(stderr, "echParamsStr copy failed.\n"); | ||||
exit(5); | ||||
} | ||||
break; | ||||
default: | default: | |||
case '?': | case '?': | |||
fprintf(stderr, "Unrecognized or bad option specified.\n"); | fprintf(stderr, "Unrecognized or bad option specified: %c\n", op tstate->option); | |||
fprintf(stderr, "Run '%s -h' for usage information.\n", progName ); | fprintf(stderr, "Run '%s -h' for usage information.\n", progName ); | |||
exit(4); | exit(4); | |||
break; | break; | |||
} | } | |||
} | } | |||
PL_DestroyOptState(optstate); | PL_DestroyOptState(optstate); | |||
if (status == PL_OPT_BAD) { | if (status == PL_OPT_BAD) { | |||
fprintf(stderr, "Unrecognized or bad option specified.\n"); | fprintf(stderr, "Unrecognized or bad option specified.\n"); | |||
fprintf(stderr, "Run '%s -h' for usage information.\n", progName); | fprintf(stderr, "Run '%s -h' for usage information.\n", progName); | |||
exit(5); | exit(5); | |||
skipping to change at line 2924 | skipping to change at line 3120 | |||
PORT_FreeArena(certStatusArena, PR_FALSE); | PORT_FreeArena(certStatusArena, PR_FALSE); | |||
} | } | |||
if (enabledGroups) { | if (enabledGroups) { | |||
PORT_Free(enabledGroups); | PORT_Free(enabledGroups); | |||
} | } | |||
if (antiReplay) { | if (antiReplay) { | |||
SSL_ReleaseAntiReplayContext(antiReplay); | SSL_ReleaseAntiReplayContext(antiReplay); | |||
} | } | |||
SECITEM_ZfreeItem(&psk, PR_FALSE); | SECITEM_ZfreeItem(&psk, PR_FALSE); | |||
SECITEM_ZfreeItem(&pskLabel, PR_FALSE); | SECITEM_ZfreeItem(&pskLabel, PR_FALSE); | |||
PORT_Free(echParamsStr); | ||||
if (NSS_Shutdown() != SECSuccess) { | if (NSS_Shutdown() != SECSuccess) { | |||
SECU_PrintError(progName, "NSS_Shutdown"); | SECU_PrintError(progName, "NSS_Shutdown"); | |||
if (loggerThread) { | if (loggerThread) { | |||
PR_JoinThread(loggerThread); | PR_JoinThread(loggerThread); | |||
} | } | |||
PR_Cleanup(); | PR_Cleanup(); | |||
exit(1); | exit(1); | |||
} | } | |||
PR_Cleanup(); | PR_Cleanup(); | |||
printf("selfserv: normal termination\n"); | printf("selfserv: normal termination\n"); | |||
End of changes. 9 change blocks. | ||||
3 lines changed or deleted | 209 lines changed or added |