зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1523175 - land NSS 1f04eea8834a UPGRADE_NSS_RELEASE, r=me
--HG-- extra : rebase_source : 898c7f9e93ce450d26c88e1715ef92ea6f203d91
This commit is contained in:
Родитель
d5502071ed
Коммит
5dd18017b0
|
@ -1 +1 @@
|
|||
b7713856ebf2
|
||||
1f04eea8834a
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
2 functions with some indirect sub-type change:
|
||||
|
||||
[C]'function SECStatus SSL_GetCipherSuiteInfo(PRUint16, SSLCipherSuiteInfo*, PRUintn)' at sslinfo.c:326:1 has some indirect sub-type changes:
|
||||
parameter 2 of type 'SSLCipherSuiteInfo*' has sub-type changes:
|
||||
in pointed to type 'typedef SSLCipherSuiteInfo' at sslt.h:433:1:
|
||||
underlying type 'struct SSLCipherSuiteInfoStr' at sslt.h:366:1 changed:
|
||||
type size changed from 768 to 832 (in bits)
|
||||
1 data member insertion:
|
||||
'SSLHashType SSLCipherSuiteInfoStr::kdfHash', at offset 768 (in bits) at sslt.h:429:1
|
||||
|
||||
[C]'function SECStatus SSL_GetPreliminaryChannelInfo(PRFileDesc*, SSLPreliminaryChannelInfo*, PRUintn)' at sslinfo.c:111:1 has some indirect sub-type changes:
|
||||
parameter 2 of type 'SSLPreliminaryChannelInfo*' has sub-type changes:
|
||||
in pointed to type 'typedef SSLPreliminaryChannelInfo' at sslt.h:379:1:
|
||||
underlying type 'struct SSLPreliminaryChannelInfoStr' at sslt.h:333:1 changed:
|
||||
type size changed from 160 to 192 (in bits)
|
||||
1 data member insertion:
|
||||
'PRUint16 SSLPreliminaryChannelInfoStr::zeroRttCipherSuite', at offset 160 (in bits) at sslt.h:375:1
|
||||
|
||||
|
|
@ -56,6 +56,7 @@ NSS_SRCDIRS = \
|
|||
p7sign \
|
||||
p7verify \
|
||||
pk12util \
|
||||
pk11importtest \
|
||||
pk11ectest \
|
||||
pk11gcmtest \
|
||||
pk11mode \
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
#! gmake
|
||||
#
|
||||
# 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/.
|
||||
|
||||
#######################################################################
|
||||
# (1) Include initial platform-independent assignments (MANDATORY). #
|
||||
#######################################################################
|
||||
|
||||
include manifest.mn
|
||||
|
||||
#######################################################################
|
||||
# (2) Include "global" configuration information. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/config.mk
|
||||
|
||||
#######################################################################
|
||||
# (3) Include "component" configuration information. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
#######################################################################
|
||||
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
|
||||
#######################################################################
|
||||
|
||||
include ../platlibs.mk
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/rules.mk
|
||||
|
||||
#######################################################################
|
||||
# (6) Execute "component" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
#######################################################################
|
||||
# (7) Execute "local" rules. (OPTIONAL). #
|
||||
#######################################################################
|
||||
|
||||
include ../platrules.mk
|
|
@ -0,0 +1,15 @@
|
|||
# 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/.
|
||||
|
||||
CORE_DEPTH = ../..
|
||||
|
||||
MODULE = nss
|
||||
|
||||
CSRCS = pk11importtest.c \
|
||||
$(NULL)
|
||||
|
||||
REQUIRES = seccmd
|
||||
|
||||
PROGRAM = pk11importtest
|
||||
|
|
@ -0,0 +1,406 @@
|
|||
/* 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 "secutil.h"
|
||||
#include "secmod.h"
|
||||
#include "cert.h"
|
||||
#include "secoid.h"
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pk11pqg.h"
|
||||
|
||||
/* NSPR 2.0 header files */
|
||||
#include "prinit.h"
|
||||
#include "prprf.h"
|
||||
#include "prsystem.h"
|
||||
#include "prmem.h"
|
||||
/* Portable layer header files */
|
||||
#include "plstr.h"
|
||||
|
||||
SECOidData *
|
||||
getCurveFromString(char *curve_name)
|
||||
{
|
||||
SECOidTag tag = SEC_OID_SECG_EC_SECP256R1;
|
||||
|
||||
if (PORT_Strcasecmp(curve_name, "NISTP256") == 0) {
|
||||
} else if (PORT_Strcasecmp(curve_name, "NISTP384") == 0) {
|
||||
tag = SEC_OID_SECG_EC_SECP384R1;
|
||||
} else if (PORT_Strcasecmp(curve_name, "NISTP521") == 0) {
|
||||
tag = SEC_OID_SECG_EC_SECP521R1;
|
||||
} else if (PORT_Strcasecmp(curve_name, "Curve25519") == 0) {
|
||||
tag = SEC_OID_CURVE25519;
|
||||
}
|
||||
return SECOID_FindOIDByTag(tag);
|
||||
}
|
||||
|
||||
void
|
||||
dumpItem(const char *label, const SECItem *item)
|
||||
{
|
||||
int i;
|
||||
printf("%s = [%d bytes] {", label, item->len);
|
||||
for (i = 0; i < item->len; i++) {
|
||||
if ((i & 0xf) == 0)
|
||||
printf("\n ");
|
||||
else
|
||||
printf(", ");
|
||||
printf("%02x", item->data[i]);
|
||||
}
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
SECStatus
|
||||
handleEncryptedPrivateImportTest(char *progName, PK11SlotInfo *slot,
|
||||
char *testname, CK_MECHANISM_TYPE genMech, void *params, void *pwArgs)
|
||||
{
|
||||
SECStatus rv = SECSuccess;
|
||||
SECItem privID = { 0 };
|
||||
SECItem pubID = { 0 };
|
||||
SECItem pubValue = { 0 };
|
||||
SECItem pbePwItem = { 0 };
|
||||
SECItem nickname = { 0 };
|
||||
SECItem token = { 0 };
|
||||
SECKEYPublicKey *pubKey = NULL;
|
||||
SECKEYPrivateKey *privKey = NULL;
|
||||
PK11GenericObject *objs = NULL;
|
||||
PK11GenericObject *obj = NULL;
|
||||
SECKEYEncryptedPrivateKeyInfo *epki = NULL;
|
||||
PRBool keyFound = 0;
|
||||
KeyType keyType;
|
||||
|
||||
fprintf(stderr, "Testing %s PrivateKeyImport ***********************\n",
|
||||
testname);
|
||||
|
||||
/* generate a temp key */
|
||||
privKey = PK11_GenerateKeyPair(slot, genMech, params, &pubKey,
|
||||
PR_FALSE, PR_TRUE, pwArgs);
|
||||
if (privKey == NULL) {
|
||||
SECU_PrintError(progName, "PK11_GenerateKeyPair Failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* wrap the temp key */
|
||||
pbePwItem.data = (unsigned char *)"pw";
|
||||
pbePwItem.len = 2;
|
||||
epki = PK11_ExportEncryptedPrivKeyInfo(slot, SEC_OID_AES_256_CBC,
|
||||
&pbePwItem, privKey, 1, NULL);
|
||||
if (epki == NULL) {
|
||||
SECU_PrintError(progName, "PK11_ExportEncryptedPrivKeyInfo Failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Save the public value, which we will need on import */
|
||||
keyType = pubKey->keyType;
|
||||
switch (keyType) {
|
||||
case rsaKey:
|
||||
SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.rsa.modulus);
|
||||
break;
|
||||
case dhKey:
|
||||
SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.dh.publicValue);
|
||||
break;
|
||||
case dsaKey:
|
||||
SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.dsa.publicValue);
|
||||
break;
|
||||
case ecKey:
|
||||
SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.ec.publicValue);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown keytype = %d\n", keyType);
|
||||
goto cleanup;
|
||||
}
|
||||
if (pubValue.data == NULL) {
|
||||
SECU_PrintError(progName, "Unable to allocate memory");
|
||||
goto cleanup;
|
||||
}
|
||||
dumpItem("pubValue", &pubValue);
|
||||
|
||||
/* when Asymetric keys represent session keys, those session keys are
|
||||
* destroyed when we destroy the Asymetric key representations */
|
||||
SECKEY_DestroyPublicKey(pubKey);
|
||||
pubKey = NULL;
|
||||
SECKEY_DestroyPrivateKey(privKey);
|
||||
privKey = NULL;
|
||||
|
||||
/* unwrap the temp key as a perm */
|
||||
nickname.data = (unsigned char *)"testKey";
|
||||
nickname.len = sizeof("testKey");
|
||||
rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
|
||||
slot, epki, &pbePwItem, &nickname, &pubValue,
|
||||
PR_TRUE, PR_TRUE, keyType, 0, &privKey, NULL);
|
||||
if (rv != SECSuccess) {
|
||||
SECU_PrintError(progName, "PK11_ImportEncryptedPrivateKeyInfo Failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* verify the public key exists */
|
||||
rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey, CKA_ID, &privID);
|
||||
if (rv != SECSuccess) {
|
||||
SECU_PrintError(progName,
|
||||
"Couldn't read CKA_ID from pub key, checking next key");
|
||||
goto cleanup;
|
||||
}
|
||||
dumpItem("privKey CKA_ID", &privID);
|
||||
objs = PK11_FindGenericObjects(slot, CKO_PUBLIC_KEY);
|
||||
for (obj = objs; obj; obj = PK11_GetNextGenericObject(obj)) {
|
||||
rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_ID, &pubID);
|
||||
if (rv != SECSuccess) {
|
||||
SECU_PrintError(progName,
|
||||
"Couldn't read CKA_ID from object, checking next key");
|
||||
continue;
|
||||
}
|
||||
dumpItem("pubKey CKA_ID", &pubID);
|
||||
if (!SECITEM_ItemsAreEqual(&privID, &pubID)) {
|
||||
fprintf(stderr,
|
||||
"CKA_ID does not match priv key, checking next key\n");
|
||||
SECITEM_FreeItem(&pubID, PR_FALSE);
|
||||
continue;
|
||||
}
|
||||
SECITEM_FreeItem(&pubID, PR_FALSE);
|
||||
rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_TOKEN, &token);
|
||||
if (rv == SECSuccess) {
|
||||
if (token.len == 1) {
|
||||
keyFound = token.data[0];
|
||||
}
|
||||
SECITEM_FreeItem(&token, PR_FALSE);
|
||||
}
|
||||
if (keyFound) {
|
||||
printf("matching public key found\n");
|
||||
break;
|
||||
}
|
||||
printf("Matching key was not a token key, checking next key\n");
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (objs) {
|
||||
PK11_DestroyGenericObjects(objs);
|
||||
}
|
||||
SECITEM_FreeItem(&pubValue, PR_FALSE);
|
||||
SECITEM_FreeItem(&privID, PR_FALSE);
|
||||
PORT_FreeArena(epki->arena, PR_TRUE);
|
||||
SECKEY_DestroyPublicKey(pubKey);
|
||||
SECKEY_DestroyPrivateKey(privKey);
|
||||
fprintf(stderr, "%s PrivateKeyImport %s ***********************\n",
|
||||
testname, keyFound ? "PASSED" : "FAILED");
|
||||
return keyFound ? SECSuccess : SECFailure;
|
||||
}
|
||||
|
||||
static const char *const usageInfo[] = {
|
||||
"pk11import - test PK11_PrivateKeyImport()"
|
||||
"Options:",
|
||||
" -d certdir directory containing cert database",
|
||||
" -k keysize size of the rsa, dh, and dsa key to test (default 1024)",
|
||||
" -C ecc_curve ecc curve (default )",
|
||||
" -f pwFile file to fetch the password from",
|
||||
" -p pwString password",
|
||||
" -r skip rsa test",
|
||||
" -D skip dsa test",
|
||||
" -h skip dh test",
|
||||
" -e skip ec test",
|
||||
};
|
||||
static int nUsageInfo = sizeof(usageInfo) / sizeof(char *);
|
||||
|
||||
static void
|
||||
Usage(char *progName, FILE *outFile)
|
||||
{
|
||||
int i;
|
||||
fprintf(outFile, "Usage: %s [ commands ] options\n", progName);
|
||||
for (i = 0; i < nUsageInfo; i++)
|
||||
fprintf(outFile, "%s\n", usageInfo[i]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
enum {
|
||||
opt_CertDir,
|
||||
opt_KeySize,
|
||||
opt_ECCurve,
|
||||
opt_PWFile,
|
||||
opt_PWString,
|
||||
opt_NoRSA,
|
||||
opt_NoDSA,
|
||||
opt_NoEC,
|
||||
opt_NoDH
|
||||
};
|
||||
|
||||
static secuCommandFlag options[] =
|
||||
{
|
||||
{ /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE },
|
||||
{ /* opt_KeySize */ 'k', PR_TRUE, 0, PR_FALSE },
|
||||
{ /* opt_ECCurve */ 'C', PR_TRUE, 0, PR_FALSE },
|
||||
{ /* opt_PWFile */ 'f', PR_TRUE, 0, PR_FALSE },
|
||||
{ /* opt_PWString */ 'p', PR_TRUE, 0, PR_FALSE },
|
||||
{ /* opt_NORSA */ 'r', PR_TRUE, 0, PR_FALSE },
|
||||
{ /* opt_NoDSA */ 'D', PR_TRUE, 0, PR_FALSE },
|
||||
{ /* opt_NoDH */ 'h', PR_TRUE, 0, PR_FALSE },
|
||||
{ /* opt_NoEC */ 'e', PR_TRUE, 0, PR_FALSE },
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *progName;
|
||||
SECStatus rv;
|
||||
secuCommand args;
|
||||
PK11SlotInfo *slot = NULL;
|
||||
PRBool failed = PR_FALSE;
|
||||
secuPWData pwArgs = { PW_NONE, 0 };
|
||||
PRBool doRSA = PR_TRUE;
|
||||
PRBool doDSA = PR_TRUE;
|
||||
PRBool doDH = PR_FALSE; /* NSS currently can't export wrapped DH keys */
|
||||
PRBool doEC = PR_TRUE;
|
||||
PQGParams *pqgParams = NULL;
|
||||
int keySize;
|
||||
|
||||
args.numCommands = 0;
|
||||
args.numOptions = sizeof(options) / sizeof(secuCommandFlag);
|
||||
args.commands = NULL;
|
||||
args.options = options;
|
||||
|
||||
#ifdef XP_PC
|
||||
progName = strrchr(argv[0], '\\');
|
||||
#else
|
||||
progName = strrchr(argv[0], '/');
|
||||
#endif
|
||||
progName = progName ? progName + 1 : argv[0];
|
||||
|
||||
rv = SECU_ParseCommandLine(argc, argv, progName, &args);
|
||||
if (SECSuccess != rv) {
|
||||
Usage(progName, stderr);
|
||||
}
|
||||
|
||||
/* Set the certdb directory (default is ~/.netscape) */
|
||||
rv = NSS_InitReadWrite(SECU_ConfigDirectory(args.options[opt_CertDir].arg));
|
||||
if (rv != SECSuccess) {
|
||||
SECU_PrintPRandOSError(progName);
|
||||
return 255;
|
||||
}
|
||||
PK11_SetPasswordFunc(SECU_GetModulePassword);
|
||||
|
||||
/* below here, goto cleanup */
|
||||
SECU_RegisterDynamicOids();
|
||||
|
||||
/* handle the arguments */
|
||||
if (args.options[opt_PWFile].arg) {
|
||||
pwArgs.source = PW_FROMFILE;
|
||||
pwArgs.data = args.options[opt_PWFile].arg;
|
||||
}
|
||||
if (args.options[opt_PWString].arg) {
|
||||
pwArgs.source = PW_PLAINTEXT;
|
||||
pwArgs.data = args.options[opt_PWString].arg;
|
||||
}
|
||||
if (args.options[opt_NoRSA].activated) {
|
||||
doRSA = PR_FALSE;
|
||||
}
|
||||
if (args.options[opt_NoDSA].activated) {
|
||||
doDSA = PR_FALSE;
|
||||
}
|
||||
if (args.options[opt_NoDH].activated) {
|
||||
doDH = PR_FALSE;
|
||||
}
|
||||
if (args.options[opt_NoEC].activated) {
|
||||
doEC = PR_FALSE;
|
||||
}
|
||||
|
||||
slot = PK11_GetInternalKeySlot();
|
||||
if (slot == NULL) {
|
||||
SECU_PrintError(progName, "Couldn't find the internal key slot\n");
|
||||
return 255;
|
||||
}
|
||||
rv = PK11_Authenticate(slot, PR_TRUE, &pwArgs);
|
||||
if (rv != SECSuccess) {
|
||||
SECU_PrintError(progName, "Failed to log into slot");
|
||||
PK11_FreeSlot(slot);
|
||||
return 255;
|
||||
}
|
||||
|
||||
keySize = 1024;
|
||||
if (args.options[opt_KeySize].activated &&
|
||||
args.options[opt_KeySize].arg) {
|
||||
keySize = atoi(args.options[opt_KeySize].arg);
|
||||
}
|
||||
|
||||
if (doDSA || doDH) {
|
||||
PQGVerify *pqgVfy;
|
||||
rv = PK11_PQG_ParamGenV2(keySize, 0, keySize / 16, &pqgParams, &pqgVfy);
|
||||
if (rv == SECSuccess) {
|
||||
PK11_PQG_DestroyVerify(pqgVfy);
|
||||
} else {
|
||||
SECU_PrintError(progName,
|
||||
"PK11_PQG_ParamGenV2 failed, can't test DH or DSA");
|
||||
doDSA = doDH = PR_FALSE;
|
||||
failed = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (doRSA) {
|
||||
PK11RSAGenParams rsaParams;
|
||||
rsaParams.keySizeInBits = keySize;
|
||||
rsaParams.pe = 0x010001;
|
||||
rv = handleEncryptedPrivateImportTest(progName, slot, "RSA",
|
||||
CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, &pwArgs);
|
||||
if (rv != SECSuccess) {
|
||||
fprintf(stderr, "RSA Import Failed!\n");
|
||||
failed = PR_TRUE;
|
||||
}
|
||||
}
|
||||
if (doDSA) {
|
||||
rv = handleEncryptedPrivateImportTest(progName, slot, "DSA",
|
||||
CKM_DSA_KEY_PAIR_GEN, pqgParams, &pwArgs);
|
||||
if (rv != SECSuccess) {
|
||||
fprintf(stderr, "DSA Import Failed!\n");
|
||||
failed = PR_TRUE;
|
||||
}
|
||||
}
|
||||
if (doDH) {
|
||||
SECKEYDHParams dhParams;
|
||||
dhParams.prime = pqgParams->prime;
|
||||
dhParams.base = pqgParams->base;
|
||||
rv = handleEncryptedPrivateImportTest(progName, slot, "DH",
|
||||
CKM_DH_PKCS_KEY_PAIR_GEN, &dhParams, &pwArgs);
|
||||
if (rv != SECSuccess) {
|
||||
fprintf(stderr, "DH Import Failed!\n");
|
||||
failed = PR_TRUE;
|
||||
}
|
||||
}
|
||||
if (doEC) {
|
||||
SECKEYECParams ecParams;
|
||||
SECOidData *curve = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
|
||||
if (args.options[opt_ECCurve].activated &&
|
||||
args.options[opt_ECCurve].arg) {
|
||||
curve = getCurveFromString(args.options[opt_ECCurve].arg);
|
||||
}
|
||||
ecParams.data = PORT_Alloc(curve->oid.len + 2);
|
||||
if (ecParams.data == NULL) {
|
||||
rv = SECFailure;
|
||||
goto ec_failed;
|
||||
}
|
||||
ecParams.data[0] = SEC_ASN1_OBJECT_ID;
|
||||
ecParams.data[1] = (unsigned char)curve->oid.len;
|
||||
PORT_Memcpy(&ecParams.data[2], curve->oid.data, curve->oid.len);
|
||||
ecParams.len = curve->oid.len + 2;
|
||||
rv = handleEncryptedPrivateImportTest(progName, slot, "ECC",
|
||||
CKM_EC_KEY_PAIR_GEN, &ecParams, &pwArgs);
|
||||
PORT_Free(ecParams.data);
|
||||
ec_failed:
|
||||
if (rv != SECSuccess) {
|
||||
fprintf(stderr, "ECC Import Failed!\n");
|
||||
failed = PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pqgParams) {
|
||||
PK11_PQG_DestroyParams(pqgParams);
|
||||
}
|
||||
|
||||
if (slot) {
|
||||
PK11_FreeSlot(slot);
|
||||
}
|
||||
|
||||
rv = NSS_Shutdown();
|
||||
if (rv != SECSuccess) {
|
||||
fprintf(stderr, "Shutdown failed\n");
|
||||
SECU_PrintPRandOSError(progName);
|
||||
return 255;
|
||||
}
|
||||
|
||||
return failed ? 1 : 0;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
# 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/.
|
||||
{
|
||||
'includes': [
|
||||
'../../coreconf/config.gypi',
|
||||
'../../cmd/platlibs.gypi'
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'pk11importtest',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'pk11importtest.c'
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:dbm_exports',
|
||||
'<(DEPTH)/exports.gyp:nss_exports'
|
||||
]
|
||||
}
|
||||
],
|
||||
'variables': {
|
||||
'module': 'nss'
|
||||
}
|
||||
}
|
|
@ -10,4 +10,3 @@
|
|||
*/
|
||||
|
||||
#error "Do not include this header file."
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "cert.h"
|
||||
#include "keyhi.h"
|
||||
#include "p12.h"
|
||||
#include "pk11pqg.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pkcs11uri.h"
|
||||
|
||||
|
@ -41,6 +42,7 @@ struct ScopedDelete {
|
|||
void operator()(PLArenaPool* arena) { PORT_FreeArena(arena, PR_FALSE); }
|
||||
void operator()(PK11Context* context) { PK11_DestroyContext(context, true); }
|
||||
void operator()(PK11GenericObject* obj) { PK11_DestroyGenericObject(obj); }
|
||||
void operator()(PQGParams* pqg) { PK11_PQG_DestroyParams(pqg); }
|
||||
void operator()(SEC_PKCS12DecoderContext* dcx) {
|
||||
SEC_PKCS12DecoderFinish(dcx);
|
||||
}
|
||||
|
@ -66,6 +68,7 @@ SCOPED(CERTName);
|
|||
SCOPED(CERTSubjectPublicKeyInfo);
|
||||
SCOPED(PK11SlotInfo);
|
||||
SCOPED(PK11SymKey);
|
||||
SCOPED(PQGParams);
|
||||
SCOPED(PRFileDesc);
|
||||
SCOPED(SECAlgorithmID);
|
||||
SCOPED(SECKEYEncryptedPrivateKeyInfo);
|
||||
|
@ -82,4 +85,9 @@ SCOPED(CERTDistNames);
|
|||
|
||||
#undef SCOPED
|
||||
|
||||
struct StackSECItem : public SECItem {
|
||||
StackSECItem() : SECItem({siBuffer, nullptr, 0}) {}
|
||||
~StackSECItem() { SECITEM_FreeItem(this, PR_FALSE); }
|
||||
};
|
||||
|
||||
#endif // nss_scoped_ptrs_h__
|
||||
|
|
|
@ -33,6 +33,7 @@ struct ScopedMaybeDelete {
|
|||
SCOPED(SECAlgorithmID);
|
||||
SCOPED(SECItem);
|
||||
SCOPED(PK11URI);
|
||||
SCOPED(PLArenaPool);
|
||||
|
||||
#undef SCOPED
|
||||
|
||||
|
|
|
@ -80,6 +80,32 @@ inline std::ostream& operator<<(std::ostream& os, SSLProtocolVariant v) {
|
|||
return os << ((v == ssl_variant_stream) ? "TLS" : "DTLS");
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, SSLContentType v) {
|
||||
switch (v) {
|
||||
case ssl_ct_change_cipher_spec:
|
||||
return os << "CCS";
|
||||
case ssl_ct_alert:
|
||||
return os << "alert";
|
||||
case ssl_ct_handshake:
|
||||
return os << "handshake";
|
||||
case ssl_ct_application_data:
|
||||
return os << "application data";
|
||||
case ssl_ct_ack:
|
||||
return os << "ack";
|
||||
}
|
||||
return os << "UNKNOWN content type " << static_cast<int>(v);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, SSLSecretDirection v) {
|
||||
switch (v) {
|
||||
case ssl_secret_read:
|
||||
return os << "read";
|
||||
case ssl_secret_write:
|
||||
return os << "write";
|
||||
}
|
||||
return os << "UNKNOWN secret direction " << static_cast<int>(v);
|
||||
}
|
||||
|
||||
inline bool IsDtls(uint16_t version) { return (version & 0x8000) == 0x8000; }
|
||||
|
||||
inline uint16_t NormalizeTlsVersion(uint16_t version) {
|
||||
|
|
|
@ -10,7 +10,23 @@
|
|||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
if (NSS_NoDB_Init(nullptr) != SECSuccess) {
|
||||
const char *workdir = "";
|
||||
uint32_t flags = NSS_INIT_READONLY;
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-d")) {
|
||||
if (i + 1 >= argc) {
|
||||
PR_fprintf(PR_STDERR, "Usage: %s [-d <dir> [-w]]\n", argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
workdir = argv[i + 1];
|
||||
i++;
|
||||
} else if (!strcmp(argv[i], "-w")) {
|
||||
flags &= ~NSS_INIT_READONLY;
|
||||
}
|
||||
}
|
||||
|
||||
if (NSS_Initialize(workdir, "", "", SECMOD_DB, flags) != SECSuccess) {
|
||||
return 1;
|
||||
}
|
||||
if (NSS_SetDomesticPolicy() != SECSuccess) {
|
||||
|
|
|
@ -13,6 +13,7 @@ CPPSRCS = \
|
|||
pk11_ecdsa_unittest.cc \
|
||||
pk11_encrypt_derive_unittest.cc \
|
||||
pk11_export_unittest.cc \
|
||||
pk11_import_unittest.cc \
|
||||
pk11_pbkdf2_unittest.cc \
|
||||
pk11_prf_unittest.cc \
|
||||
pk11_prng_unittest.cc \
|
||||
|
@ -33,4 +34,3 @@ EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \
|
|||
$(DIST)/lib/$(LIB_PREFIX)cpputil.$(LIB_SUFFIX) \
|
||||
$(DIST)/lib/$(LIB_PREFIX)gtestutil.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
'pk11_curve25519_unittest.cc',
|
||||
'pk11_ecdsa_unittest.cc',
|
||||
'pk11_encrypt_derive_unittest.cc',
|
||||
'pk11_import_unittest.cc',
|
||||
'pk11_pbkdf2_unittest.cc',
|
||||
'pk11_prf_unittest.cc',
|
||||
'pk11_prng_unittest.cc',
|
||||
|
|
|
@ -297,38 +297,6 @@ SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group) {
|
|||
return groupDef->keaType;
|
||||
}
|
||||
|
||||
SECStatus SSLInt_SetCipherSpecChangeFunc(PRFileDesc *fd,
|
||||
sslCipherSpecChangedFunc func,
|
||||
void *arg) {
|
||||
sslSocket *ss;
|
||||
|
||||
ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ss->ssl3.changedCipherSpecFunc = func;
|
||||
ss->ssl3.changedCipherSpecArg = arg;
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
PK11SymKey *SSLInt_CipherSpecToKey(const ssl3CipherSpec *spec) {
|
||||
return spec->keyMaterial.key;
|
||||
}
|
||||
|
||||
SSLCipherAlgorithm SSLInt_CipherSpecToAlgorithm(const ssl3CipherSpec *spec) {
|
||||
return spec->cipherDef->calg;
|
||||
}
|
||||
|
||||
const PRUint8 *SSLInt_CipherSpecToIv(const ssl3CipherSpec *spec) {
|
||||
return spec->keyMaterial.iv;
|
||||
}
|
||||
|
||||
PRUint16 SSLInt_CipherSpecToEpoch(const ssl3CipherSpec *spec) {
|
||||
return spec->epoch;
|
||||
}
|
||||
|
||||
void SSLInt_SetTicketLifetime(uint32_t lifetime) {
|
||||
ssl_ticket_lifetime = lifetime;
|
||||
}
|
||||
|
@ -360,16 +328,14 @@ void SSLInt_RolloverAntiReplay(void) {
|
|||
tls13_AntiReplayRollover(ssl_TimeUsec());
|
||||
}
|
||||
|
||||
SECStatus SSLInt_GetEpochs(PRFileDesc *fd, PRUint16 *readEpoch,
|
||||
PRUint16 *writeEpoch) {
|
||||
SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending) {
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss || !readEpoch || !writeEpoch) {
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ssl_GetSpecReadLock(ss);
|
||||
*readEpoch = ss->ssl3.crSpec->epoch;
|
||||
*writeEpoch = ss->ssl3.cwSpec->epoch;
|
||||
ssl_ReleaseSpecReadLock(ss);
|
||||
ssl_GetSSL3HandshakeLock(ss);
|
||||
*pending = ss->ssl3.hs.msg_body.len > 0;
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
|
|
@ -39,16 +39,7 @@ SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to);
|
|||
SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to);
|
||||
SECStatus SSLInt_AdvanceWriteSeqByAWindow(PRFileDesc *fd, PRInt32 extra);
|
||||
SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group);
|
||||
SECStatus SSLInt_GetEpochs(PRFileDesc *fd, PRUint16 *readEpoch,
|
||||
PRUint16 *writeEpoch);
|
||||
|
||||
SECStatus SSLInt_SetCipherSpecChangeFunc(PRFileDesc *fd,
|
||||
sslCipherSpecChangedFunc func,
|
||||
void *arg);
|
||||
PRUint16 SSLInt_CipherSpecToEpoch(const ssl3CipherSpec *spec);
|
||||
PK11SymKey *SSLInt_CipherSpecToKey(const ssl3CipherSpec *spec);
|
||||
SSLCipherAlgorithm SSLInt_CipherSpecToAlgorithm(const ssl3CipherSpec *spec);
|
||||
const PRUint8 *SSLInt_CipherSpecToIv(const ssl3CipherSpec *spec);
|
||||
SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending);
|
||||
void SSLInt_SetTicketLifetime(uint32_t lifetime);
|
||||
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size);
|
||||
void SSLInt_RolloverAntiReplay(void);
|
||||
|
|
|
@ -36,6 +36,7 @@ CPPSRCS = \
|
|||
ssl_loopback_unittest.cc \
|
||||
ssl_misc_unittest.cc \
|
||||
ssl_record_unittest.cc \
|
||||
ssl_recordsep_unittest.cc \
|
||||
ssl_recordsize_unittest.cc \
|
||||
ssl_resumption_unittest.cc \
|
||||
ssl_renegotiation_unittest.cc \
|
||||
|
|
|
@ -176,6 +176,321 @@ TEST_P(TlsConnectGeneric, ClientAuth) {
|
|||
CheckKeys();
|
||||
}
|
||||
|
||||
class TlsCertificateRequestContextRecorder : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsCertificateRequestContextRecorder(const std::shared_ptr<TlsAgent>& a,
|
||||
uint8_t handshake_type)
|
||||
: TlsHandshakeFilter(a, {handshake_type}), buffer_(), filtered_(false) {
|
||||
EnableDecryption();
|
||||
}
|
||||
|
||||
bool filtered() const { return filtered_; }
|
||||
const DataBuffer& buffer() const { return buffer_; }
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
assert(1 < input.len());
|
||||
size_t len = input.data()[0];
|
||||
assert(len + 1 < input.len());
|
||||
buffer_.Assign(input.data() + 1, len);
|
||||
filtered_ = true;
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
private:
|
||||
DataBuffer buffer_;
|
||||
bool filtered_;
|
||||
};
|
||||
|
||||
// All stream only tests; DTLS isn't supported yet.
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, PostHandshakeAuth) {
|
||||
EnsureTlsSetup();
|
||||
auto capture_cert_req = MakeTlsFilter<TlsCertificateRequestContextRecorder>(
|
||||
server_, kTlsHandshakeCertificateRequest);
|
||||
auto capture_certificate =
|
||||
MakeTlsFilter<TlsCertificateRequestContextRecorder>(
|
||||
client_, kTlsHandshakeCertificate);
|
||||
client_->SetupClientAuth();
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
|
||||
size_t called = 0;
|
||||
server_->SetAuthCertificateCallback(
|
||||
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
|
||||
called++;
|
||||
return SECSuccess;
|
||||
});
|
||||
Connect();
|
||||
EXPECT_EQ(0U, called);
|
||||
EXPECT_FALSE(capture_cert_req->filtered());
|
||||
EXPECT_FALSE(capture_certificate->filtered());
|
||||
// Send CertificateRequest.
|
||||
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
|
||||
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
|
||||
// Need to do a round-trip so that the post-handshake message is
|
||||
// handled on both client and server.
|
||||
server_->SendData(50);
|
||||
client_->ReadBytes(50);
|
||||
client_->SendData(50);
|
||||
server_->ReadBytes(50);
|
||||
EXPECT_EQ(1U, called);
|
||||
EXPECT_TRUE(capture_cert_req->filtered());
|
||||
EXPECT_TRUE(capture_certificate->filtered());
|
||||
// Check if a non-empty request context is generated and it is
|
||||
// properly sent back.
|
||||
EXPECT_LT(0U, capture_cert_req->buffer().len());
|
||||
EXPECT_EQ(capture_cert_req->buffer().len(),
|
||||
capture_certificate->buffer().len());
|
||||
EXPECT_EQ(0, memcmp(capture_cert_req->buffer().data(),
|
||||
capture_certificate->buffer().data(),
|
||||
capture_cert_req->buffer().len()));
|
||||
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
|
||||
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
|
||||
}
|
||||
|
||||
static SECStatus GetClientAuthDataHook(void* self, PRFileDesc* fd,
|
||||
CERTDistNames* caNames,
|
||||
CERTCertificate** clientCert,
|
||||
SECKEYPrivateKey** clientKey) {
|
||||
ScopedCERTCertificate cert;
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
// use a different certificate than TlsAgent::kClient
|
||||
if (!TlsAgent::LoadCertificate(TlsAgent::kRsa2048, &cert, &priv)) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
*clientCert = cert.release();
|
||||
*clientKey = priv.release();
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthMultiple) {
|
||||
client_->SetupClientAuth();
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
|
||||
size_t called = 0;
|
||||
server_->SetAuthCertificateCallback(
|
||||
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
|
||||
called++;
|
||||
return SECSuccess;
|
||||
});
|
||||
Connect();
|
||||
EXPECT_EQ(0U, called);
|
||||
EXPECT_EQ(nullptr, SSL_PeerCertificate(server_->ssl_fd()));
|
||||
// Send 1st CertificateRequest.
|
||||
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
|
||||
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
|
||||
server_->SendData(50);
|
||||
client_->ReadBytes(50);
|
||||
client_->SendData(50);
|
||||
server_->ReadBytes(50);
|
||||
EXPECT_EQ(1U, called);
|
||||
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
|
||||
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
|
||||
// Send 2nd CertificateRequest.
|
||||
EXPECT_EQ(SECSuccess, SSL_GetClientAuthDataHook(
|
||||
client_->ssl_fd(), GetClientAuthDataHook, nullptr));
|
||||
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
|
||||
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
|
||||
server_->SendData(50);
|
||||
client_->ReadBytes(50);
|
||||
client_->SendData(50);
|
||||
server_->ReadBytes(50);
|
||||
EXPECT_EQ(2U, called);
|
||||
ScopedCERTCertificate cert3(SSL_PeerCertificate(server_->ssl_fd()));
|
||||
ScopedCERTCertificate cert4(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert4->derCert));
|
||||
EXPECT_FALSE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert1->derCert));
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthConcurrent) {
|
||||
client_->SetupClientAuth();
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
|
||||
Connect();
|
||||
// Send 1st CertificateRequest.
|
||||
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
|
||||
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
|
||||
// Send 2nd CertificateRequest.
|
||||
EXPECT_EQ(SECFailure, SSL_SendCertificateRequest(server_->ssl_fd()));
|
||||
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthMissingExtension) {
|
||||
client_->SetupClientAuth();
|
||||
Connect();
|
||||
// Send CertificateRequest, should fail due to missing
|
||||
// post_handshake_auth extension.
|
||||
EXPECT_EQ(SECFailure, SSL_SendCertificateRequest(server_->ssl_fd()));
|
||||
EXPECT_EQ(SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthAfterClientAuth) {
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
|
||||
size_t called = 0;
|
||||
server_->SetAuthCertificateCallback(
|
||||
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
|
||||
called++;
|
||||
return SECSuccess;
|
||||
});
|
||||
Connect();
|
||||
EXPECT_EQ(1U, called);
|
||||
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
|
||||
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
|
||||
// Send CertificateRequest.
|
||||
EXPECT_EQ(SECSuccess, SSL_GetClientAuthDataHook(
|
||||
client_->ssl_fd(), GetClientAuthDataHook, nullptr));
|
||||
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
|
||||
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
|
||||
server_->SendData(50);
|
||||
client_->ReadBytes(50);
|
||||
client_->SendData(50);
|
||||
server_->ReadBytes(50);
|
||||
EXPECT_EQ(2U, called);
|
||||
ScopedCERTCertificate cert3(SSL_PeerCertificate(server_->ssl_fd()));
|
||||
ScopedCERTCertificate cert4(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert4->derCert));
|
||||
EXPECT_FALSE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert1->derCert));
|
||||
}
|
||||
|
||||
// Damages the request context in a CertificateRequest message.
|
||||
// We don't modify a Certificate message instead, so that the client
|
||||
// can compute CertificateVerify correctly.
|
||||
class TlsDamageCertificateRequestContextFilter : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsDamageCertificateRequestContextFilter(const std::shared_ptr<TlsAgent>& a)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateRequest}) {
|
||||
EnableDecryption();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
*output = input;
|
||||
assert(1 < output->len());
|
||||
// The request context has a 1 octet length.
|
||||
output->data()[1] ^= 73;
|
||||
return CHANGE;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthContextMismatch) {
|
||||
EnsureTlsSetup();
|
||||
MakeTlsFilter<TlsDamageCertificateRequestContextFilter>(server_);
|
||||
client_->SetupClientAuth();
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
|
||||
Connect();
|
||||
// Send CertificateRequest.
|
||||
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
|
||||
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
|
||||
server_->SendData(50);
|
||||
client_->ReadBytes(50);
|
||||
client_->SendData(50);
|
||||
server_->ExpectSendAlert(kTlsAlertIllegalParameter);
|
||||
server_->ReadBytes(50);
|
||||
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CERTIFICATE, PORT_GetError());
|
||||
server_->ExpectReadWriteError();
|
||||
server_->SendData(50);
|
||||
client_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
|
||||
client_->ReadBytes(50);
|
||||
EXPECT_EQ(SSL_ERROR_ILLEGAL_PARAMETER_ALERT, PORT_GetError());
|
||||
}
|
||||
|
||||
// Replaces signature in a CertificateVerify message.
|
||||
class TlsDamageSignatureFilter : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsDamageSignatureFilter(const std::shared_ptr<TlsAgent>& a)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateVerify}) {
|
||||
EnableDecryption();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
*output = input;
|
||||
assert(2 < output->len());
|
||||
// The signature follows a 2-octet signature scheme.
|
||||
output->data()[2] ^= 73;
|
||||
return CHANGE;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthBadSignature) {
|
||||
EnsureTlsSetup();
|
||||
MakeTlsFilter<TlsDamageSignatureFilter>(client_);
|
||||
client_->SetupClientAuth();
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
|
||||
Connect();
|
||||
// Send CertificateRequest.
|
||||
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
|
||||
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
|
||||
server_->SendData(50);
|
||||
client_->ReadBytes(50);
|
||||
client_->SendData(50);
|
||||
server_->ExpectSendAlert(kTlsAlertDecodeError);
|
||||
server_->ReadBytes(50);
|
||||
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CERT_VERIFY, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthDecline) {
|
||||
EnsureTlsSetup();
|
||||
auto capture_cert_req = MakeTlsFilter<TlsCertificateRequestContextRecorder>(
|
||||
server_, kTlsHandshakeCertificateRequest);
|
||||
auto capture_certificate =
|
||||
MakeTlsFilter<TlsCertificateRequestContextRecorder>(
|
||||
client_, kTlsHandshakeCertificate);
|
||||
client_->SetupClientAuth();
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
|
||||
// Client to decline the certificate request.
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetClientAuthDataHook(
|
||||
client_->ssl_fd(),
|
||||
[](void*, PRFileDesc*, CERTDistNames*, CERTCertificate**,
|
||||
SECKEYPrivateKey**) -> SECStatus { return SECFailure; },
|
||||
nullptr));
|
||||
size_t called = 0;
|
||||
server_->SetAuthCertificateCallback(
|
||||
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
|
||||
called++;
|
||||
return SECSuccess;
|
||||
});
|
||||
Connect();
|
||||
EXPECT_EQ(0U, called);
|
||||
// Send CertificateRequest.
|
||||
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
|
||||
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
|
||||
server_->SendData(50);
|
||||
client_->ReadBytes(50);
|
||||
client_->SendData(50);
|
||||
server_->ReadBytes(50);
|
||||
// AuthCertificateCallback is not called, because the client sends
|
||||
// an empty certificate_list.
|
||||
EXPECT_EQ(0U, called);
|
||||
EXPECT_TRUE(capture_cert_req->filtered());
|
||||
EXPECT_TRUE(capture_certificate->filtered());
|
||||
// Check if a non-empty request context is generated and it is
|
||||
// properly sent back.
|
||||
EXPECT_LT(0U, capture_cert_req->buffer().len());
|
||||
EXPECT_EQ(capture_cert_req->buffer().len(),
|
||||
capture_certificate->buffer().len());
|
||||
EXPECT_EQ(0, memcmp(capture_cert_req->buffer().data(),
|
||||
capture_certificate->buffer().data(),
|
||||
capture_cert_req->buffer().len()));
|
||||
}
|
||||
|
||||
// In TLS 1.3, the client sends its cert rejection on the
|
||||
// second flight, and since it has already received the
|
||||
// server's Finished, it transitions to complete and
|
||||
|
@ -273,9 +588,7 @@ class TlsReplaceSignatureSchemeFilter : public TlsHandshakeFilter {
|
|||
TlsReplaceSignatureSchemeFilter(const std::shared_ptr<TlsAgent>& a,
|
||||
SSLSignatureScheme scheme)
|
||||
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateVerify}),
|
||||
scheme_(scheme) {
|
||||
EnableDecryption();
|
||||
}
|
||||
scheme_(scheme) {}
|
||||
|
||||
protected:
|
||||
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
|
||||
|
@ -552,7 +865,9 @@ TEST_P(TlsConnectTls12, SignatureAlgorithmDrop) {
|
|||
|
||||
TEST_P(TlsConnectTls13, UnsupportedSignatureSchemeAlert) {
|
||||
EnsureTlsSetup();
|
||||
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(server_, ssl_sig_none);
|
||||
auto filter =
|
||||
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(server_, ssl_sig_none);
|
||||
filter->EnableDecryption();
|
||||
|
||||
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
||||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
|
@ -563,8 +878,9 @@ TEST_P(TlsConnectTls13, InconsistentSignatureSchemeAlert) {
|
|||
EnsureTlsSetup();
|
||||
|
||||
// This won't work because we use an RSA cert by default.
|
||||
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(
|
||||
auto filter = MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(
|
||||
server_, ssl_sig_ecdsa_secp256r1_sha256);
|
||||
filter->EnableDecryption();
|
||||
|
||||
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
||||
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
|
||||
|
|
|
@ -62,7 +62,6 @@ TEST_P(TlsConnectGenericPre13, DamageServerSignature) {
|
|||
EnsureTlsSetup();
|
||||
auto filter = MakeTlsFilter<TlsLastByteDamager>(
|
||||
server_, kTlsHandshakeServerKeyExchange);
|
||||
filter->EnableDecryption();
|
||||
ExpectAlert(client_, kTlsAlertDecryptError);
|
||||
ConnectExpectFail();
|
||||
client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
|
||||
|
@ -84,7 +83,9 @@ TEST_P(TlsConnectGeneric, DamageClientSignature) {
|
|||
server_->RequestClientAuth(true);
|
||||
auto filter = MakeTlsFilter<TlsLastByteDamager>(
|
||||
client_, kTlsHandshakeCertificateVerify);
|
||||
filter->EnableDecryption();
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
filter->EnableDecryption();
|
||||
}
|
||||
server_->ExpectSendAlert(kTlsAlertDecryptError);
|
||||
// Do these handshakes by hand to avoid race condition on
|
||||
// the client processing the server's alert.
|
||||
|
|
|
@ -66,6 +66,38 @@ TEST_P(TlsConnectDatagramPre13, DropServerSecondFlightThrice) {
|
|||
Connect();
|
||||
}
|
||||
|
||||
static void CheckAcks(const std::shared_ptr<TlsRecordRecorder>& acks,
|
||||
size_t index, std::vector<uint64_t> expected) {
|
||||
ASSERT_LT(index, acks->count());
|
||||
const DataBuffer& buf = acks->record(index).buffer;
|
||||
size_t offset = 2;
|
||||
uint64_t len;
|
||||
|
||||
EXPECT_EQ(2 + expected.size() * 8, buf.len());
|
||||
ASSERT_TRUE(buf.Read(0, 2, &len));
|
||||
ASSERT_EQ(static_cast<size_t>(len + 2), buf.len());
|
||||
if ((2 + expected.size() * 8) != buf.len()) {
|
||||
while (offset < buf.len()) {
|
||||
uint64_t ack;
|
||||
ASSERT_TRUE(buf.Read(offset, 8, &ack));
|
||||
offset += 8;
|
||||
std::cerr << "Ack=0x" << std::hex << ack << std::dec << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < expected.size(); ++i) {
|
||||
uint64_t a = expected[i];
|
||||
uint64_t ack;
|
||||
ASSERT_TRUE(buf.Read(offset, 8, &ack));
|
||||
offset += 8;
|
||||
if (a != ack) {
|
||||
ADD_FAILURE() << "Wrong ack " << i << " expected=0x" << std::hex << a
|
||||
<< " got=0x" << ack << std::dec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TlsDropDatagram13 : public TlsConnectDatagram13,
|
||||
public ::testing::WithParamInterface<bool> {
|
||||
public:
|
||||
|
@ -139,37 +171,6 @@ class TlsDropDatagram13 : public TlsConnectDatagram13,
|
|||
std::shared_ptr<PacketFilter> chain_;
|
||||
};
|
||||
|
||||
void CheckAcks(const DropAckChain& chain, size_t index,
|
||||
std::vector<uint64_t> acks) {
|
||||
const DataBuffer& buf = chain.ack_->record(index).buffer;
|
||||
size_t offset = 2;
|
||||
uint64_t len;
|
||||
|
||||
EXPECT_EQ(2 + acks.size() * 8, buf.len());
|
||||
ASSERT_TRUE(buf.Read(0, 2, &len));
|
||||
ASSERT_EQ(static_cast<size_t>(len + 2), buf.len());
|
||||
if ((2 + acks.size() * 8) != buf.len()) {
|
||||
while (offset < buf.len()) {
|
||||
uint64_t ack;
|
||||
ASSERT_TRUE(buf.Read(offset, 8, &ack));
|
||||
offset += 8;
|
||||
std::cerr << "Ack=0x" << std::hex << ack << std::dec << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < acks.size(); ++i) {
|
||||
uint64_t a = acks[i];
|
||||
uint64_t ack;
|
||||
ASSERT_TRUE(buf.Read(offset, 8, &ack));
|
||||
offset += 8;
|
||||
if (a != ack) {
|
||||
ADD_FAILURE() << "Wrong ack " << i << " expected=0x" << std::hex << a
|
||||
<< " got=0x" << ack << std::dec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckedHandshakeSendReceive() {
|
||||
Handshake();
|
||||
CheckPostHandshake();
|
||||
|
@ -199,7 +200,7 @@ TEST_P(TlsDropDatagram13, DropClientFirstFlightOnce) {
|
|||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
CheckedHandshakeSendReceive();
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
TEST_P(TlsDropDatagram13, DropServerFirstFlightOnce) {
|
||||
|
@ -210,7 +211,7 @@ TEST_P(TlsDropDatagram13, DropServerFirstFlightOnce) {
|
|||
server_->Handshake();
|
||||
server_filters_.drop_->Disable();
|
||||
CheckedHandshakeSendReceive();
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
// Dropping the server's first record also does not produce
|
||||
|
@ -223,7 +224,7 @@ TEST_P(TlsDropDatagram13, DropServerFirstRecordOnce) {
|
|||
server_->Handshake();
|
||||
Handshake();
|
||||
CheckedHandshakeSendReceive();
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
// Dropping the second packet of the server's flight should
|
||||
|
@ -236,8 +237,8 @@ TEST_P(TlsDropDatagram13, DropServerSecondRecordOnce) {
|
|||
HandshakeAndAck(client_);
|
||||
expected_client_acks_ = 1;
|
||||
CheckedHandshakeSendReceive();
|
||||
CheckAcks(client_filters_, 0, {0}); // ServerHello
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(client_filters_.ack_, 0, {0}); // ServerHello
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
// Drop the server ACK and verify that the client retransmits
|
||||
|
@ -265,8 +266,8 @@ TEST_P(TlsDropDatagram13, DropServerAckOnce) {
|
|||
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
|
||||
CheckPostHandshake();
|
||||
// There should be two copies of the finished ACK
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_, 1, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 1, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
// Drop the client certificate verify.
|
||||
|
@ -281,10 +282,10 @@ TEST_P(TlsDropDatagram13, DropClientCertVerify) {
|
|||
expected_server_acks_ = 2;
|
||||
CheckedHandshakeSendReceive();
|
||||
// Ack of the Cert.
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
// Ack of the whole client handshake.
|
||||
CheckAcks(
|
||||
server_filters_, 1,
|
||||
server_filters_.ack_, 1,
|
||||
{0x0002000000000000ULL, // CH (we drop everything after this on client)
|
||||
0x0002000000000003ULL, // CT (2)
|
||||
0x0002000000000004ULL}); // FIN (2)
|
||||
|
@ -310,11 +311,11 @@ TEST_P(TlsDropDatagram13, DropFirstHalfOfServerCertificate) {
|
|||
// as the previous CT1).
|
||||
EXPECT_EQ(ct1_size, server_filters_.record(0).buffer.len());
|
||||
CheckedHandshakeSendReceive();
|
||||
CheckAcks(client_filters_, 0,
|
||||
CheckAcks(client_filters_.ack_, 0,
|
||||
{0, // SH
|
||||
0x0002000000000000ULL, // EE
|
||||
0x0002000000000002ULL}); // CT2
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
// Shrink the MTU down so that certs get split and drop the second piece.
|
||||
|
@ -336,13 +337,13 @@ TEST_P(TlsDropDatagram13, DropSecondHalfOfServerCertificate) {
|
|||
// Check that the first record is CT1
|
||||
EXPECT_EQ(ct1_size, server_filters_.record(0).buffer.len());
|
||||
CheckedHandshakeSendReceive();
|
||||
CheckAcks(client_filters_, 0,
|
||||
CheckAcks(client_filters_.ack_, 0,
|
||||
{
|
||||
0, // SH
|
||||
0x0002000000000000ULL, // EE
|
||||
0x0002000000000001ULL, // CT1
|
||||
});
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
// In this test, the Certificate message is sent four times, we drop all or part
|
||||
|
@ -392,18 +393,18 @@ class TlsFragmentationAndRecoveryTest : public TlsDropDatagram13 {
|
|||
0, // SH
|
||||
0x0002000000000000ULL // EE
|
||||
};
|
||||
CheckAcks(client_filters_, 0, client_acks);
|
||||
CheckAcks(client_filters_.ack_, 0, client_acks);
|
||||
// And from the second attempt for the half was kept (we delayed this ACK).
|
||||
client_acks.push_back(0x0002000000000000ULL + second_flight_count +
|
||||
~dropped_half % 2);
|
||||
CheckAcks(client_filters_, 1, client_acks);
|
||||
CheckAcks(client_filters_.ack_, 1, client_acks);
|
||||
// And the third attempt where the first and last thirds got through.
|
||||
client_acks.push_back(0x0002000000000000ULL + second_flight_count +
|
||||
third_flight_count - 1);
|
||||
client_acks.push_back(0x0002000000000000ULL + second_flight_count +
|
||||
third_flight_count + 1);
|
||||
CheckAcks(client_filters_, 2, client_acks);
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(client_filters_.ack_, 2, client_acks);
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -548,7 +549,7 @@ TEST_P(TlsDropDatagram13, NoDropsDuringZeroRtt) {
|
|||
CheckConnected();
|
||||
SendReceive();
|
||||
EXPECT_EQ(0U, client_filters_.ack_->count());
|
||||
CheckAcks(server_filters_, 0,
|
||||
CheckAcks(server_filters_.ack_, 0,
|
||||
{0x0001000000000001ULL, // EOED
|
||||
0x0002000000000000ULL}); // Finished
|
||||
}
|
||||
|
@ -567,8 +568,8 @@ TEST_P(TlsDropDatagram13, DropEEDuringZeroRtt) {
|
|||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
CheckAcks(client_filters_, 0, {0});
|
||||
CheckAcks(server_filters_, 0,
|
||||
CheckAcks(client_filters_.ack_, 0, {0});
|
||||
CheckAcks(server_filters_.ack_, 0,
|
||||
{0x0001000000000002ULL, // EOED
|
||||
0x0002000000000000ULL}); // Finished
|
||||
}
|
||||
|
@ -608,22 +609,22 @@ TEST_P(TlsDropDatagram13, ReorderServerEE) {
|
|||
expected_client_acks_ = 1;
|
||||
HandshakeAndAck(client_);
|
||||
CheckedHandshakeSendReceive();
|
||||
CheckAcks(client_filters_, 0,
|
||||
CheckAcks(client_filters_.ack_, 0,
|
||||
{
|
||||
0, // SH
|
||||
0x0002000000000000, // EE
|
||||
});
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
// The client sends an out of order non-handshake message
|
||||
// but with the handshake key.
|
||||
class TlsSendCipherSpecCapturer {
|
||||
public:
|
||||
TlsSendCipherSpecCapturer(std::shared_ptr<TlsAgent>& agent)
|
||||
: send_cipher_specs_() {
|
||||
SSLInt_SetCipherSpecChangeFunc(agent->ssl_fd(), CipherSpecChanged,
|
||||
(void*)this);
|
||||
TlsSendCipherSpecCapturer(const std::shared_ptr<TlsAgent>& agent)
|
||||
: agent_(agent), send_cipher_specs_() {
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_SecretCallback(agent_->ssl_fd(), SecretCallback, this));
|
||||
}
|
||||
|
||||
std::shared_ptr<TlsCipherSpec> spec(size_t i) {
|
||||
|
@ -634,28 +635,42 @@ class TlsSendCipherSpecCapturer {
|
|||
}
|
||||
|
||||
private:
|
||||
static void CipherSpecChanged(void* arg, PRBool sending,
|
||||
ssl3CipherSpec* newSpec) {
|
||||
if (!sending) {
|
||||
static void SecretCallback(PRFileDesc* fd, PRUint16 epoch,
|
||||
SSLSecretDirection dir, PK11SymKey* secret,
|
||||
void* arg) {
|
||||
auto self = static_cast<TlsSendCipherSpecCapturer*>(arg);
|
||||
std::cerr << self->agent_->role_str() << ": capture " << dir
|
||||
<< " secret for epoch " << epoch << std::endl;
|
||||
|
||||
if (dir == ssl_secret_read) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto self = static_cast<TlsSendCipherSpecCapturer*>(arg);
|
||||
SSLPreliminaryChannelInfo preinfo;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetPreliminaryChannelInfo(self->agent_->ssl_fd(), &preinfo,
|
||||
sizeof(preinfo)));
|
||||
EXPECT_EQ(sizeof(preinfo), preinfo.length);
|
||||
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_cipher_suite);
|
||||
|
||||
auto spec = std::make_shared<TlsCipherSpec>();
|
||||
bool ret = spec->Init(SSLInt_CipherSpecToEpoch(newSpec),
|
||||
SSLInt_CipherSpecToAlgorithm(newSpec),
|
||||
SSLInt_CipherSpecToKey(newSpec),
|
||||
SSLInt_CipherSpecToIv(newSpec));
|
||||
EXPECT_EQ(true, ret);
|
||||
SSLCipherSuiteInfo cipherinfo;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetCipherSuiteInfo(preinfo.cipherSuite, &cipherinfo,
|
||||
sizeof(cipherinfo)));
|
||||
EXPECT_EQ(sizeof(cipherinfo), cipherinfo.length);
|
||||
|
||||
auto spec = std::make_shared<TlsCipherSpec>(true, epoch);
|
||||
EXPECT_TRUE(spec->SetKeys(&cipherinfo, secret));
|
||||
self->send_cipher_specs_.push_back(spec);
|
||||
}
|
||||
|
||||
std::shared_ptr<TlsAgent> agent_;
|
||||
std::vector<std::shared_ptr<TlsCipherSpec>> send_cipher_specs_;
|
||||
};
|
||||
|
||||
TEST_P(TlsDropDatagram13, SendOutOfOrderAppWithHandshakeKey) {
|
||||
TEST_F(TlsConnectDatagram13, SendOutOfOrderAppWithHandshakeKey) {
|
||||
StartConnect();
|
||||
// Capturing secrets means that we can't use decrypting filters on the client.
|
||||
TlsSendCipherSpecCapturer capturer(client_);
|
||||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
|
@ -680,9 +695,12 @@ TEST_P(TlsDropDatagram13, SendOutOfOrderAppWithHandshakeKey) {
|
|||
EXPECT_EQ(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_P(TlsDropDatagram13, SendOutOfOrderHsNonsenseWithHandshakeKey) {
|
||||
TEST_F(TlsConnectDatagram13, SendOutOfOrderHsNonsenseWithHandshakeKey) {
|
||||
StartConnect();
|
||||
TlsSendCipherSpecCapturer capturer(client_);
|
||||
auto acks = MakeTlsFilter<TlsRecordRecorder>(server_, ssl_ct_ack);
|
||||
acks->EnableDecryption();
|
||||
|
||||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
client_->Handshake();
|
||||
|
@ -699,10 +717,10 @@ TEST_P(TlsDropDatagram13, SendOutOfOrderHsNonsenseWithHandshakeKey) {
|
|||
ssl_ct_handshake,
|
||||
DataBuffer(buf, sizeof(buf))));
|
||||
server_->Handshake();
|
||||
EXPECT_EQ(2UL, server_filters_.ack_->count());
|
||||
EXPECT_EQ(2UL, acks->count());
|
||||
// The server acknowledges client Finished twice.
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_, 1, {0x0002000000000000ULL});
|
||||
CheckAcks(acks, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(acks, 1, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
// Shrink the MTU down so that certs get split and then swap the first and
|
||||
|
@ -726,7 +744,7 @@ TEST_P(TlsReorderDatagram13, ReorderServerCertificate) {
|
|||
ShiftDtlsTimers();
|
||||
CheckedHandshakeSendReceive();
|
||||
EXPECT_EQ(2UL, server_filters_.records_->count()); // ACK + Data
|
||||
CheckAcks(server_filters_, 0, {0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0, {0x0002000000000000ULL});
|
||||
}
|
||||
|
||||
TEST_P(TlsReorderDatagram13, DataAfterEOEDDuringZeroRtt) {
|
||||
|
@ -761,7 +779,8 @@ TEST_P(TlsReorderDatagram13, DataAfterEOEDDuringZeroRtt) {
|
|||
CheckConnected();
|
||||
EXPECT_EQ(0U, client_filters_.ack_->count());
|
||||
// Acknowledgements for EOED and Finished.
|
||||
CheckAcks(server_filters_, 0, {0x0001000000000002ULL, 0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0,
|
||||
{0x0001000000000002ULL, 0x0002000000000000ULL});
|
||||
uint8_t buf[8];
|
||||
rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
|
||||
EXPECT_EQ(-1, rv);
|
||||
|
@ -800,7 +819,8 @@ TEST_P(TlsReorderDatagram13, DataAfterFinDuringZeroRtt) {
|
|||
CheckConnected();
|
||||
EXPECT_EQ(0U, client_filters_.ack_->count());
|
||||
// Acknowledgements for EOED and Finished.
|
||||
CheckAcks(server_filters_, 0, {0x0001000000000002ULL, 0x0002000000000000ULL});
|
||||
CheckAcks(server_filters_.ack_, 0,
|
||||
{0x0001000000000002ULL, 0x0002000000000000ULL});
|
||||
uint8_t buf[8];
|
||||
rv = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
|
||||
EXPECT_EQ(-1, rv);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
'ssl_loopback_unittest.cc',
|
||||
'ssl_misc_unittest.cc',
|
||||
'ssl_record_unittest.cc',
|
||||
'ssl_recordsep_unittest.cc',
|
||||
'ssl_recordsize_unittest.cc',
|
||||
'ssl_resumption_unittest.cc',
|
||||
'ssl_renegotiation_unittest.cc',
|
||||
|
|
|
@ -0,0 +1,518 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 "secerr.h"
|
||||
#include "ssl.h"
|
||||
#include "sslerr.h"
|
||||
#include "sslproto.h"
|
||||
|
||||
extern "C" {
|
||||
// This is not something that should make you happy.
|
||||
#include "libssl_internals.h"
|
||||
}
|
||||
|
||||
#include <queue>
|
||||
#include "gtest_utils.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "tls_connect.h"
|
||||
#include "tls_filter.h"
|
||||
#include "tls_parser.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class HandshakeSecretTracker {
|
||||
public:
|
||||
HandshakeSecretTracker(const std::shared_ptr<TlsAgent>& agent,
|
||||
uint16_t first_read_epoch, uint16_t first_write_epoch)
|
||||
: agent_(agent),
|
||||
next_read_epoch_(first_read_epoch),
|
||||
next_write_epoch_(first_write_epoch) {
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_SecretCallback(agent_->ssl_fd(),
|
||||
HandshakeSecretTracker::SecretCb, this));
|
||||
}
|
||||
|
||||
void CheckComplete() const {
|
||||
EXPECT_EQ(0, next_read_epoch_);
|
||||
EXPECT_EQ(0, next_write_epoch_);
|
||||
}
|
||||
|
||||
private:
|
||||
static void SecretCb(PRFileDesc* fd, PRUint16 epoch, SSLSecretDirection dir,
|
||||
PK11SymKey* secret, void* arg) {
|
||||
HandshakeSecretTracker* t = reinterpret_cast<HandshakeSecretTracker*>(arg);
|
||||
t->SecretUpdated(epoch, dir, secret);
|
||||
}
|
||||
|
||||
void SecretUpdated(PRUint16 epoch, SSLSecretDirection dir,
|
||||
PK11SymKey* secret) {
|
||||
if (g_ssl_gtest_verbose) {
|
||||
std::cerr << agent_->role_str() << ": secret callback for " << dir
|
||||
<< " epoch " << epoch << std::endl;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(secret);
|
||||
uint16_t* p;
|
||||
if (dir == ssl_secret_read) {
|
||||
p = &next_read_epoch_;
|
||||
} else {
|
||||
ASSERT_EQ(ssl_secret_write, dir);
|
||||
p = &next_write_epoch_;
|
||||
}
|
||||
EXPECT_EQ(*p, epoch);
|
||||
switch (*p) {
|
||||
case 1: // 1 == 0-RTT, next should be handshake.
|
||||
case 2: // 2 == handshake, next should be application data.
|
||||
(*p)++;
|
||||
break;
|
||||
|
||||
case 3: // 3 == application data, there should be no more.
|
||||
// Use 0 as a sentinel value.
|
||||
*p = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ADD_FAILURE() << "Unexpected next epoch: " << *p;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<TlsAgent> agent_;
|
||||
uint16_t next_read_epoch_;
|
||||
uint16_t next_write_epoch_;
|
||||
};
|
||||
|
||||
TEST_F(TlsConnectTest, HandshakeSecrets) {
|
||||
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
EnsureTlsSetup();
|
||||
|
||||
HandshakeSecretTracker c(client_, 2, 2);
|
||||
HandshakeSecretTracker s(server_, 2, 2);
|
||||
|
||||
Connect();
|
||||
SendReceive();
|
||||
|
||||
c.CheckComplete();
|
||||
s.CheckComplete();
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectTest, ZeroRttSecrets) {
|
||||
SetupForZeroRtt();
|
||||
|
||||
HandshakeSecretTracker c(client_, 2, 1);
|
||||
HandshakeSecretTracker s(server_, 1, 2);
|
||||
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, true);
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
|
||||
c.CheckComplete();
|
||||
s.CheckComplete();
|
||||
}
|
||||
|
||||
class KeyUpdateTracker {
|
||||
public:
|
||||
KeyUpdateTracker(const std::shared_ptr<TlsAgent>& agent,
|
||||
bool expect_read_secret)
|
||||
: agent_(agent), expect_read_secret_(expect_read_secret), called_(false) {
|
||||
EXPECT_EQ(SECSuccess, SSL_SecretCallback(agent_->ssl_fd(),
|
||||
KeyUpdateTracker::SecretCb, this));
|
||||
}
|
||||
|
||||
void CheckCalled() const { EXPECT_TRUE(called_); }
|
||||
|
||||
private:
|
||||
static void SecretCb(PRFileDesc* fd, PRUint16 epoch, SSLSecretDirection dir,
|
||||
PK11SymKey* secret, void* arg) {
|
||||
KeyUpdateTracker* t = reinterpret_cast<KeyUpdateTracker*>(arg);
|
||||
t->SecretUpdated(epoch, dir, secret);
|
||||
}
|
||||
|
||||
void SecretUpdated(PRUint16 epoch, SSLSecretDirection dir,
|
||||
PK11SymKey* secret) {
|
||||
EXPECT_EQ(4U, epoch);
|
||||
EXPECT_EQ(expect_read_secret_, dir == ssl_secret_read);
|
||||
EXPECT_TRUE(secret);
|
||||
called_ = true;
|
||||
}
|
||||
|
||||
std::shared_ptr<TlsAgent> agent_;
|
||||
bool expect_read_secret_;
|
||||
bool called_;
|
||||
};
|
||||
|
||||
TEST_F(TlsConnectTest, KeyUpdateSecrets) {
|
||||
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
Connect();
|
||||
// The update is to the client write secret; the server read secret.
|
||||
KeyUpdateTracker c(client_, false);
|
||||
KeyUpdateTracker s(server_, true);
|
||||
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_FALSE));
|
||||
SendReceive(50);
|
||||
SendReceive(60);
|
||||
CheckEpochs(4, 3);
|
||||
c.CheckCalled();
|
||||
s.CheckCalled();
|
||||
}
|
||||
|
||||
// BadPrSocket is an instance of a PR IO layer that crashes the test if it is
|
||||
// ever used for reading or writing. It does that by failing to overwrite any
|
||||
// of the DummyIOLayerMethods, which all crash when invoked.
|
||||
class BadPrSocket : public DummyIOLayerMethods {
|
||||
public:
|
||||
BadPrSocket(std::shared_ptr<TlsAgent>& agent) : DummyIOLayerMethods() {
|
||||
static PRDescIdentity bad_identity = PR_GetUniqueIdentity("bad NSPR id");
|
||||
fd_ = DummyIOLayerMethods::CreateFD(bad_identity, this);
|
||||
|
||||
// This is terrible, but NSPR doesn't provide an easy way to replace the
|
||||
// bottom layer of an IO stack. Take the DummyPrSocket and replace its
|
||||
// NSPR method vtable with the ones from this object.
|
||||
dummy_layer_ =
|
||||
PR_GetIdentitiesLayer(agent->ssl_fd(), DummyPrSocket::LayerId());
|
||||
original_methods_ = dummy_layer_->methods;
|
||||
original_secret_ = dummy_layer_->secret;
|
||||
dummy_layer_->methods = fd_->methods;
|
||||
dummy_layer_->secret = reinterpret_cast<PRFilePrivate*>(this);
|
||||
}
|
||||
|
||||
// This will be destroyed before the agent, so we need to restore the state
|
||||
// before we tampered with it.
|
||||
virtual ~BadPrSocket() {
|
||||
dummy_layer_->methods = original_methods_;
|
||||
dummy_layer_->secret = original_secret_;
|
||||
}
|
||||
|
||||
private:
|
||||
ScopedPRFileDesc fd_;
|
||||
PRFileDesc* dummy_layer_;
|
||||
const PRIOMethods* original_methods_;
|
||||
PRFilePrivate* original_secret_;
|
||||
};
|
||||
|
||||
class StagedRecords {
|
||||
public:
|
||||
StagedRecords(std::shared_ptr<TlsAgent>& agent) : agent_(agent), records_() {
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_RecordLayerWriteCallback(
|
||||
agent_->ssl_fd(), StagedRecords::StageRecordData, this));
|
||||
}
|
||||
|
||||
virtual ~StagedRecords() {
|
||||
// Uninstall so that the callback doesn't fire during cleanup.
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_RecordLayerWriteCallback(agent_->ssl_fd(), nullptr, nullptr));
|
||||
}
|
||||
|
||||
bool empty() const { return records_.empty(); }
|
||||
|
||||
void ForwardAll(std::shared_ptr<TlsAgent>& peer) {
|
||||
EXPECT_NE(agent_, peer) << "can't forward to self";
|
||||
for (auto r : records_) {
|
||||
r.Forward(peer);
|
||||
}
|
||||
records_.clear();
|
||||
}
|
||||
|
||||
// This forwards all saved data and checks the resulting state.
|
||||
void ForwardAll(std::shared_ptr<TlsAgent>& peer,
|
||||
TlsAgent::State expected_state) {
|
||||
ForwardAll(peer);
|
||||
peer->Handshake();
|
||||
EXPECT_EQ(expected_state, peer->state());
|
||||
}
|
||||
|
||||
void ForwardPartial(std::shared_ptr<TlsAgent>& peer) {
|
||||
if (records_.empty()) {
|
||||
ADD_FAILURE() << "No records to slice";
|
||||
return;
|
||||
}
|
||||
auto& last = records_.back();
|
||||
auto tail = last.SliceTail();
|
||||
ForwardAll(peer, TlsAgent::STATE_CONNECTING);
|
||||
records_.push_back(tail);
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTING, peer->state());
|
||||
}
|
||||
|
||||
private:
|
||||
// A single record.
|
||||
class StagedRecord {
|
||||
public:
|
||||
StagedRecord(const std::string role, uint16_t epoch, SSLContentType ct,
|
||||
const uint8_t* data, size_t len)
|
||||
: role_(role), epoch_(epoch), content_type_(ct), data_(data, len) {
|
||||
if (g_ssl_gtest_verbose) {
|
||||
std::cerr << role_ << ": staged epoch " << epoch_ << " "
|
||||
<< content_type_ << ": " << data_ << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// This forwards staged data to the identified agent.
|
||||
void Forward(std::shared_ptr<TlsAgent>& peer) {
|
||||
// Now there should be staged data.
|
||||
EXPECT_FALSE(data_.empty());
|
||||
if (g_ssl_gtest_verbose) {
|
||||
std::cerr << role_ << ": forward " << data_ << std::endl;
|
||||
}
|
||||
SECStatus rv = SSL_RecordLayerData(
|
||||
peer->ssl_fd(), epoch_, content_type_, data_.data(),
|
||||
static_cast<unsigned int>(data_.len()));
|
||||
if (rv != SECSuccess) {
|
||||
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
// Slices the tail off this record and returns it.
|
||||
StagedRecord SliceTail() {
|
||||
size_t slice = 1;
|
||||
if (data_.len() <= slice) {
|
||||
ADD_FAILURE() << "record too small to slice in two";
|
||||
slice = 0;
|
||||
}
|
||||
size_t keep = data_.len() - slice;
|
||||
StagedRecord tail(role_, epoch_, content_type_, data_.data() + keep,
|
||||
slice);
|
||||
data_.Truncate(keep);
|
||||
return tail;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string role_;
|
||||
uint16_t epoch_;
|
||||
SSLContentType content_type_;
|
||||
DataBuffer data_;
|
||||
};
|
||||
|
||||
// This is an SSLRecordWriteCallback that stages data.
|
||||
static SECStatus StageRecordData(PRFileDesc* fd, PRUint16 epoch,
|
||||
SSLContentType content_type,
|
||||
const PRUint8* data, unsigned int len,
|
||||
void* arg) {
|
||||
auto stage = reinterpret_cast<StagedRecords*>(arg);
|
||||
stage->records_.push_back(StagedRecord(stage->agent_->role_str(), epoch,
|
||||
content_type, data,
|
||||
static_cast<size_t>(len)));
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
std::shared_ptr<TlsAgent>& agent_;
|
||||
std::deque<StagedRecord> records_;
|
||||
};
|
||||
|
||||
// Attempting to feed application data in before the handshake is complete
|
||||
// should be caught.
|
||||
static void RefuseApplicationData(std::shared_ptr<TlsAgent>& peer,
|
||||
uint16_t epoch) {
|
||||
static const uint8_t d[] = {1, 2, 3};
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_RecordLayerData(peer->ssl_fd(), epoch, ssl_ct_application_data,
|
||||
d, static_cast<unsigned int>(sizeof(d))));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
}
|
||||
|
||||
static void SendForwardReceive(std::shared_ptr<TlsAgent>& sender,
|
||||
StagedRecords& sender_stage,
|
||||
std::shared_ptr<TlsAgent>& receiver) {
|
||||
const size_t count = 10;
|
||||
sender->SendData(count, count);
|
||||
sender_stage.ForwardAll(receiver);
|
||||
receiver->ReadBytes(count);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectStream, ReplaceRecordLayer) {
|
||||
StartConnect();
|
||||
client_->SetServerKeyBits(server_->server_key_bits());
|
||||
|
||||
// BadPrSocket installs an IO layer that crashes when the SSL layer attempts
|
||||
// to read or write.
|
||||
BadPrSocket bad_layer_client(client_);
|
||||
BadPrSocket bad_layer_server(server_);
|
||||
|
||||
// StagedRecords installs a handler for unprotected data from the socket, and
|
||||
// captures that data.
|
||||
StagedRecords client_stage(client_);
|
||||
StagedRecords server_stage(server_);
|
||||
|
||||
// Both peers should refuse application data from epoch 0.
|
||||
RefuseApplicationData(client_, 0);
|
||||
RefuseApplicationData(server_, 0);
|
||||
|
||||
// This first call forwards nothing, but it causes the client to handshake,
|
||||
// which starts things off. This stages the ClientHello as a result.
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTING);
|
||||
// This processes the ClientHello and stages the first server flight.
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTING);
|
||||
RefuseApplicationData(server_, 1);
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
// Process the server flight and the client is done.
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTED);
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
|
||||
} else {
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTING);
|
||||
RefuseApplicationData(client_, 1);
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTED);
|
||||
}
|
||||
CheckKeys();
|
||||
|
||||
// Reading and writing application data should work.
|
||||
SendForwardReceive(client_, client_stage, server_);
|
||||
SendForwardReceive(server_, server_stage, client_);
|
||||
}
|
||||
|
||||
static SECStatus AuthCompleteBlock(TlsAgent*, PRBool, PRBool) {
|
||||
return SECWouldBlock;
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectStream, ReplaceRecordLayerAsyncLateAuth) {
|
||||
StartConnect();
|
||||
client_->SetServerKeyBits(server_->server_key_bits());
|
||||
|
||||
BadPrSocket bad_layer_client(client_);
|
||||
BadPrSocket bad_layer_server(server_);
|
||||
StagedRecords client_stage(client_);
|
||||
StagedRecords server_stage(server_);
|
||||
|
||||
client_->SetAuthCertificateCallback(AuthCompleteBlock);
|
||||
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTING);
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTING);
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTING);
|
||||
|
||||
// Prior to TLS 1.3, the client sends its second flight immediately. But in
|
||||
// TLS 1.3, a client won't send a Finished until it is happy with the server
|
||||
// certificate. So blocking certificate validation causes the client to send
|
||||
// nothing.
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
ASSERT_TRUE(client_stage.empty());
|
||||
|
||||
// Client should have stopped reading when it saw the Certificate message,
|
||||
// so it will be reading handshake epoch, and writing cleartext.
|
||||
client_->CheckEpochs(2, 0);
|
||||
// Server should be reading handshake, and writing application data.
|
||||
server_->CheckEpochs(2, 3);
|
||||
|
||||
// Handshake again and the client will read the remainder of the server's
|
||||
// flight, but it will remain blocked.
|
||||
client_->Handshake();
|
||||
ASSERT_TRUE(client_stage.empty());
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
|
||||
} else {
|
||||
// In prior versions, the client's second flight is always sent.
|
||||
ASSERT_FALSE(client_stage.empty());
|
||||
}
|
||||
|
||||
// Now declare the certificate good.
|
||||
EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
|
||||
client_->Handshake();
|
||||
ASSERT_FALSE(client_stage.empty());
|
||||
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
|
||||
} else {
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTED);
|
||||
}
|
||||
CheckKeys();
|
||||
|
||||
// Reading and writing application data should work.
|
||||
SendForwardReceive(client_, client_stage, server_);
|
||||
}
|
||||
|
||||
// This test ensures that data is correctly forwarded when the handshake is
|
||||
// resumed after asynchronous server certificate authentication, when
|
||||
// SSL_AuthCertificateComplete() is called. The logic for resuming the
|
||||
// handshake involves a different code path than the usual one, so this test
|
||||
// exercises that code fully.
|
||||
TEST_F(TlsConnectStreamTls13, ReplaceRecordLayerAsyncEarlyAuth) {
|
||||
StartConnect();
|
||||
client_->SetServerKeyBits(server_->server_key_bits());
|
||||
|
||||
BadPrSocket bad_layer_client(client_);
|
||||
BadPrSocket bad_layer_server(server_);
|
||||
StagedRecords client_stage(client_);
|
||||
StagedRecords server_stage(server_);
|
||||
|
||||
client_->SetAuthCertificateCallback(AuthCompleteBlock);
|
||||
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTING);
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTING);
|
||||
|
||||
// Send a partial flight on to the client.
|
||||
// This includes enough to trigger the certificate callback.
|
||||
server_stage.ForwardPartial(client_);
|
||||
EXPECT_TRUE(client_stage.empty());
|
||||
|
||||
// Declare the certificate good.
|
||||
EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
|
||||
client_->Handshake();
|
||||
EXPECT_TRUE(client_stage.empty());
|
||||
|
||||
// Send the remainder of the server flight.
|
||||
PRBool pending = PR_FALSE;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSLInt_HasPendingHandshakeData(client_->ssl_fd(), &pending));
|
||||
EXPECT_EQ(PR_TRUE, pending);
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
|
||||
server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTED);
|
||||
client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
|
||||
CheckKeys();
|
||||
|
||||
SendForwardReceive(server_, server_stage, client_);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectStream, ForwardDataFromWrongEpoch) {
|
||||
const uint8_t data[] = {1};
|
||||
Connect();
|
||||
uint16_t next_epoch;
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_RecordLayerData(client_->ssl_fd(), 2, ssl_ct_application_data,
|
||||
data, sizeof(data)));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError())
|
||||
<< "Passing data from an old epoch is rejected";
|
||||
next_epoch = 4;
|
||||
} else {
|
||||
// Prior to TLS 1.3, the epoch is only updated once during the handshake.
|
||||
next_epoch = 2;
|
||||
}
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_RecordLayerData(client_->ssl_fd(), next_epoch,
|
||||
ssl_ct_application_data, data, sizeof(data)));
|
||||
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError())
|
||||
<< "Passing data from a future epoch blocks";
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, ForwardInvalidData) {
|
||||
const uint8_t data[1] = {0};
|
||||
|
||||
EnsureTlsSetup();
|
||||
// Zero-length data.
|
||||
EXPECT_EQ(SECFailure, SSL_RecordLayerData(client_->ssl_fd(), 0,
|
||||
ssl_ct_application_data, data, 0));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
|
||||
// NULL data.
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_RecordLayerData(client_->ssl_fd(), 0, ssl_ct_application_data,
|
||||
nullptr, 1));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectDatagram13, ForwardDataDtls) {
|
||||
EnsureTlsSetup();
|
||||
const uint8_t data[1] = {0};
|
||||
EXPECT_EQ(SECFailure,
|
||||
SSL_RecordLayerData(client_->ssl_fd(), 0, ssl_ct_application_data,
|
||||
data, sizeof(data)));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
|
@ -123,9 +123,11 @@ TEST_P(TlsConnectGeneric, RecordSizeMaximum) {
|
|||
|
||||
EnsureTlsSetup();
|
||||
auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
|
||||
client_max->EnableDecryption();
|
||||
auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
|
||||
server_max->EnableDecryption();
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
client_max->EnableDecryption();
|
||||
server_max->EnableDecryption();
|
||||
}
|
||||
|
||||
Connect();
|
||||
client_->SendData(send_size, send_size);
|
||||
|
@ -140,7 +142,9 @@ TEST_P(TlsConnectGeneric, RecordSizeMaximum) {
|
|||
TEST_P(TlsConnectGeneric, RecordSizeMinimumClient) {
|
||||
EnsureTlsSetup();
|
||||
auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
|
||||
server_max->EnableDecryption();
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
server_max->EnableDecryption();
|
||||
}
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
Connect();
|
||||
|
@ -152,7 +156,9 @@ TEST_P(TlsConnectGeneric, RecordSizeMinimumClient) {
|
|||
TEST_P(TlsConnectGeneric, RecordSizeMinimumServer) {
|
||||
EnsureTlsSetup();
|
||||
auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
|
||||
client_max->EnableDecryption();
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
client_max->EnableDecryption();
|
||||
}
|
||||
|
||||
server_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
Connect();
|
||||
|
@ -164,9 +170,11 @@ TEST_P(TlsConnectGeneric, RecordSizeMinimumServer) {
|
|||
TEST_P(TlsConnectGeneric, RecordSizeAsymmetric) {
|
||||
EnsureTlsSetup();
|
||||
auto client_max = MakeTlsFilter<TlsRecordMaximum>(client_);
|
||||
client_max->EnableDecryption();
|
||||
auto server_max = MakeTlsFilter<TlsRecordMaximum>(server_);
|
||||
server_max->EnableDecryption();
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
client_max->EnableDecryption();
|
||||
server_max->EnableDecryption();
|
||||
}
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
server_->SetOption(SSL_RECORD_SIZE_LIMIT, 100);
|
||||
|
@ -256,9 +264,11 @@ class TlsRecordPadder : public TlsRecordFilter {
|
|||
return KEEP;
|
||||
}
|
||||
|
||||
uint16_t protection_epoch;
|
||||
uint8_t inner_content_type;
|
||||
DataBuffer plaintext;
|
||||
if (!Unprotect(header, record, &inner_content_type, &plaintext)) {
|
||||
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
|
||||
&plaintext)) {
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
|
@ -267,8 +277,8 @@ class TlsRecordPadder : public TlsRecordFilter {
|
|||
}
|
||||
|
||||
DataBuffer ciphertext;
|
||||
bool ok =
|
||||
Protect(header, inner_content_type, plaintext, &ciphertext, padding_);
|
||||
bool ok = Protect(spec(protection_epoch), header, inner_content_type,
|
||||
plaintext, &ciphertext, padding_);
|
||||
EXPECT_TRUE(ok);
|
||||
if (!ok) {
|
||||
return KEEP;
|
||||
|
@ -334,7 +344,9 @@ TEST_P(TlsConnectGeneric, RecordSizeCapExtensionClient) {
|
|||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 16385);
|
||||
auto capture =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_record_size_limit_xtn);
|
||||
capture->EnableDecryption();
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
capture->EnableDecryption();
|
||||
}
|
||||
Connect();
|
||||
|
||||
uint64_t val = 0;
|
||||
|
@ -352,7 +364,9 @@ TEST_P(TlsConnectGeneric, RecordSizeCapExtensionServer) {
|
|||
server_->SetOption(SSL_RECORD_SIZE_LIMIT, 16385);
|
||||
auto capture =
|
||||
MakeTlsFilter<TlsExtensionCapture>(server_, ssl_record_size_limit_xtn);
|
||||
capture->EnableDecryption();
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
capture->EnableDecryption();
|
||||
}
|
||||
Connect();
|
||||
|
||||
uint64_t val = 0;
|
||||
|
@ -393,7 +407,9 @@ TEST_P(TlsConnectGeneric, RecordSizeServerExtensionInvalid) {
|
|||
static const uint8_t v[] = {0xf4, 0x1f};
|
||||
auto replace = MakeTlsFilter<TlsExtensionReplacer>(
|
||||
server_, ssl_record_size_limit_xtn, DataBuffer(v, sizeof(v)));
|
||||
replace->EnableDecryption();
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
replace->EnableDecryption();
|
||||
}
|
||||
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
||||
}
|
||||
|
||||
|
@ -403,7 +419,9 @@ TEST_P(TlsConnectGeneric, RecordSizeServerExtensionExtra) {
|
|||
static const uint8_t v[] = {0x01, 0x00, 0x00};
|
||||
auto replace = MakeTlsFilter<TlsExtensionReplacer>(
|
||||
server_, ssl_record_size_limit_xtn, DataBuffer(v, sizeof(v)));
|
||||
replace->EnableDecryption();
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
replace->EnableDecryption();
|
||||
}
|
||||
ConnectExpectAlert(client_, kTlsAlertDecodeError);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,13 @@ namespace nss_test {
|
|||
if (g_ssl_gtest_verbose) LOG(a); \
|
||||
} while (false)
|
||||
|
||||
PRDescIdentity DummyPrSocket::LayerId() {
|
||||
static PRDescIdentity id = PR_GetUniqueIdentity("dummysocket");
|
||||
return id;
|
||||
}
|
||||
|
||||
ScopedPRFileDesc DummyPrSocket::CreateFD() {
|
||||
static PRDescIdentity test_fd_identity =
|
||||
PR_GetUniqueIdentity("testtransportadapter");
|
||||
return DummyIOLayerMethods::CreateFD(test_fd_identity, this);
|
||||
return DummyIOLayerMethods::CreateFD(DummyPrSocket::LayerId(), this);
|
||||
}
|
||||
|
||||
void DummyPrSocket::Reset() {
|
||||
|
@ -136,19 +139,18 @@ int32_t DummyPrSocket::Write(PRFileDesc *f, const void *buf, int32_t length) {
|
|||
DataBuffer filtered;
|
||||
PacketFilter::Action action = PacketFilter::KEEP;
|
||||
if (filter_) {
|
||||
LOGV("Original packet: " << packet);
|
||||
action = filter_->Process(packet, &filtered);
|
||||
}
|
||||
switch (action) {
|
||||
case PacketFilter::CHANGE:
|
||||
LOG("Original packet: " << packet);
|
||||
LOG("Filtered packet: " << filtered);
|
||||
dst->PacketReceived(filtered);
|
||||
break;
|
||||
case PacketFilter::DROP:
|
||||
LOG("Droppped packet: " << packet);
|
||||
LOG("Drop packet");
|
||||
break;
|
||||
case PacketFilter::KEEP:
|
||||
LOGV("Packet: " << packet);
|
||||
dst->PacketReceived(packet);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -68,6 +68,8 @@ class DummyPrSocket : public DummyIOLayerMethods {
|
|||
write_error_(0) {}
|
||||
virtual ~DummyPrSocket() {}
|
||||
|
||||
static PRDescIdentity LayerId();
|
||||
|
||||
// Create a file descriptor that will reference this object. The fd must not
|
||||
// live longer than this adapter; call PR_Close() before.
|
||||
ScopedPRFileDesc CreateFD();
|
||||
|
|
|
@ -640,6 +640,16 @@ void TlsAgent::CheckAlpn(SSLNextProtoState expected_state,
|
|||
}
|
||||
}
|
||||
|
||||
void TlsAgent::CheckEpochs(uint16_t expected_read,
|
||||
uint16_t expected_write) const {
|
||||
uint16_t read_epoch = 0;
|
||||
uint16_t write_epoch = 0;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetCurrentEpoch(ssl_fd(), &read_epoch, &write_epoch));
|
||||
EXPECT_EQ(expected_read, read_epoch) << role_str() << " read epoch";
|
||||
EXPECT_EQ(expected_write, write_epoch) << role_str() << " write epoch";
|
||||
}
|
||||
|
||||
void TlsAgent::EnableSrtp() {
|
||||
EXPECT_TRUE(EnsureTlsSetup());
|
||||
const uint16_t ciphers[] = {SRTP_AES128_CM_HMAC_SHA1_80,
|
||||
|
|
|
@ -139,6 +139,7 @@ class TlsAgent : public PollTarget {
|
|||
const std::string& expected = "") const;
|
||||
void EnableSrtp();
|
||||
void CheckSrtp() const;
|
||||
void CheckEpochs(uint16_t expected_read, uint16_t expected_write) const;
|
||||
void CheckErrorCode(int32_t expected) const;
|
||||
void WaitForErrorCode(int32_t expected, uint32_t delay) const;
|
||||
// Send data on the socket, encrypting it.
|
||||
|
|
|
@ -167,18 +167,8 @@ void TlsConnectTestBase::CheckShares(
|
|||
|
||||
void TlsConnectTestBase::CheckEpochs(uint16_t client_epoch,
|
||||
uint16_t server_epoch) const {
|
||||
uint16_t read_epoch = 0;
|
||||
uint16_t write_epoch = 0;
|
||||
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSLInt_GetEpochs(client_->ssl_fd(), &read_epoch, &write_epoch));
|
||||
EXPECT_EQ(server_epoch, read_epoch) << "client read epoch";
|
||||
EXPECT_EQ(client_epoch, write_epoch) << "client write epoch";
|
||||
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSLInt_GetEpochs(server_->ssl_fd(), &read_epoch, &write_epoch));
|
||||
EXPECT_EQ(client_epoch, read_epoch) << "server read epoch";
|
||||
EXPECT_EQ(server_epoch, write_epoch) << "server write epoch";
|
||||
client_->CheckEpochs(server_epoch, client_epoch);
|
||||
server_->CheckEpochs(client_epoch, server_epoch);
|
||||
}
|
||||
|
||||
void TlsConnectTestBase::ClearStats() {
|
||||
|
|
|
@ -45,40 +45,65 @@ void TlsVersioned::WriteStream(std::ostream& stream) const {
|
|||
}
|
||||
}
|
||||
|
||||
void TlsRecordFilter::EnableDecryption() {
|
||||
SSLInt_SetCipherSpecChangeFunc(agent()->ssl_fd(), CipherSpecChanged,
|
||||
(void*)this);
|
||||
TlsRecordFilter::TlsRecordFilter(const std::shared_ptr<TlsAgent>& a)
|
||||
: agent_(a) {
|
||||
cipher_specs_.emplace_back(a->variant() == ssl_variant_datagram, 0);
|
||||
}
|
||||
|
||||
void TlsRecordFilter::CipherSpecChanged(void* arg, PRBool sending,
|
||||
ssl3CipherSpec* newSpec) {
|
||||
TlsRecordFilter* self = static_cast<TlsRecordFilter*>(arg);
|
||||
PRBool isServer = self->agent()->role() == TlsAgent::SERVER;
|
||||
void TlsRecordFilter::EnableDecryption() {
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_SecretCallback(agent()->ssl_fd(), SecretCallback, this));
|
||||
decrypting_ = true;
|
||||
}
|
||||
|
||||
void TlsRecordFilter::SecretCallback(PRFileDesc* fd, PRUint16 epoch,
|
||||
SSLSecretDirection dir, PK11SymKey* secret,
|
||||
void* arg) {
|
||||
TlsRecordFilter* self = static_cast<TlsRecordFilter*>(arg);
|
||||
if (g_ssl_gtest_verbose) {
|
||||
std::cerr << (isServer ? "server" : "client") << ": "
|
||||
<< (sending ? "send" : "receive")
|
||||
<< " cipher spec changed: " << newSpec->epoch << " ("
|
||||
<< newSpec->phase << ")" << std::endl;
|
||||
std::cerr << self->agent()->role_str() << ": " << dir
|
||||
<< " secret changed for epoch " << epoch << std::endl;
|
||||
}
|
||||
if (!sending) {
|
||||
|
||||
if (dir == ssl_secret_read) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t seq_no;
|
||||
if (self->agent()->variant() == ssl_variant_datagram) {
|
||||
seq_no = static_cast<uint64_t>(SSLInt_CipherSpecToEpoch(newSpec)) << 48;
|
||||
} else {
|
||||
seq_no = 0;
|
||||
for (auto& spec : self->cipher_specs_) {
|
||||
ASSERT_NE(spec.epoch(), epoch) << "duplicate spec for epoch " << epoch;
|
||||
}
|
||||
self->in_sequence_number_ = seq_no;
|
||||
self->out_sequence_number_ = seq_no;
|
||||
self->dropped_record_ = false;
|
||||
self->cipher_spec_.reset(new TlsCipherSpec());
|
||||
bool ret = self->cipher_spec_->Init(
|
||||
SSLInt_CipherSpecToEpoch(newSpec), SSLInt_CipherSpecToAlgorithm(newSpec),
|
||||
SSLInt_CipherSpecToKey(newSpec), SSLInt_CipherSpecToIv(newSpec));
|
||||
EXPECT_EQ(true, ret);
|
||||
|
||||
SSLPreliminaryChannelInfo preinfo;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetPreliminaryChannelInfo(self->agent()->ssl_fd(), &preinfo,
|
||||
sizeof(preinfo)));
|
||||
EXPECT_EQ(sizeof(preinfo), preinfo.length);
|
||||
|
||||
// Check the version.
|
||||
if (preinfo.valuesSet & ssl_preinfo_version) {
|
||||
EXPECT_EQ(SSL_LIBRARY_VERSION_TLS_1_3, preinfo.protocolVersion);
|
||||
} else {
|
||||
EXPECT_EQ(1U, epoch);
|
||||
}
|
||||
|
||||
uint16_t suite;
|
||||
if (epoch == 1) {
|
||||
// 0-RTT
|
||||
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_0rtt_cipher_suite);
|
||||
suite = preinfo.zeroRttCipherSuite;
|
||||
} else {
|
||||
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_cipher_suite);
|
||||
suite = preinfo.cipherSuite;
|
||||
}
|
||||
|
||||
SSLCipherSuiteInfo cipherinfo;
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_GetCipherSuiteInfo(suite, &cipherinfo, sizeof(cipherinfo)));
|
||||
EXPECT_EQ(sizeof(cipherinfo), cipherinfo.length);
|
||||
|
||||
bool is_dtls = self->agent()->variant() == ssl_variant_datagram;
|
||||
self->cipher_specs_.emplace_back(is_dtls, epoch);
|
||||
EXPECT_TRUE(self->cipher_specs_.back().SetKeys(&cipherinfo, secret));
|
||||
}
|
||||
|
||||
bool TlsRecordFilter::is_dtls13() const {
|
||||
|
@ -95,6 +120,23 @@ bool TlsRecordFilter::is_dtls13() const {
|
|||
info.canSendEarlyData;
|
||||
}
|
||||
|
||||
// Gets the cipher spec that matches the specified epoch.
|
||||
TlsCipherSpec& TlsRecordFilter::spec(uint16_t write_epoch) {
|
||||
for (auto& sp : cipher_specs_) {
|
||||
if (sp.epoch() == write_epoch) {
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
|
||||
// If we aren't decrypting, provide a cipher spec that does nothing other than
|
||||
// count sequence numbers.
|
||||
EXPECT_FALSE(decrypting_) << "No spec available for epoch " << write_epoch;
|
||||
;
|
||||
bool is_dtls = agent()->variant() == ssl_variant_datagram;
|
||||
cipher_specs_.emplace_back(is_dtls, write_epoch);
|
||||
return cipher_specs_.back();
|
||||
}
|
||||
|
||||
PacketFilter::Action TlsRecordFilter::Filter(const DataBuffer& input,
|
||||
DataBuffer* output) {
|
||||
// Disable during shutdown.
|
||||
|
@ -108,34 +150,28 @@ PacketFilter::Action TlsRecordFilter::Filter(const DataBuffer& input,
|
|||
output->Allocate(input.len());
|
||||
TlsParser parser(input);
|
||||
|
||||
// This uses the current write spec for the purposes of parsing the epoch and
|
||||
// sequence number from the header. This might be wrong because we can
|
||||
// receive records from older specs, but guessing is good enough:
|
||||
// - In DTLS, parsing the sequence number corrects any errors.
|
||||
// - In TLS, we don't use the sequence number unless decrypting, where we use
|
||||
// trial decryption to get the right epoch.
|
||||
uint16_t write_epoch = 0;
|
||||
SECStatus rv = SSL_GetCurrentEpoch(agent()->ssl_fd(), nullptr, &write_epoch);
|
||||
if (rv != SECSuccess) {
|
||||
ADD_FAILURE() << "unable to read epoch";
|
||||
return KEEP;
|
||||
}
|
||||
uint64_t guess_seqno = static_cast<uint64_t>(write_epoch) << 48;
|
||||
|
||||
while (parser.remaining()) {
|
||||
TlsRecordHeader header;
|
||||
DataBuffer record;
|
||||
|
||||
if (!header.Parse(is_dtls13(), in_sequence_number_, &parser, &record)) {
|
||||
if (!header.Parse(is_dtls13(), guess_seqno, &parser, &record)) {
|
||||
ADD_FAILURE() << "not a valid record";
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
// Track the sequence number, which is necessary for stream mode when
|
||||
// decrypting and for TLS 1.3 datagram to recover the sequence number.
|
||||
//
|
||||
// We reset the counter when the cipher spec changes, but that notification
|
||||
// appears before a record is sent. If multiple records are sent with
|
||||
// different cipher specs, this would fail. This filters out cleartext
|
||||
// records, so we don't get confused by handshake messages that are sent at
|
||||
// the same time as encrypted records. Sequence numbers are therefore
|
||||
// likely to be incorrect for cleartext records.
|
||||
//
|
||||
// This isn't perfectly robust: if there is a change from an active cipher
|
||||
// spec to another active cipher spec (KeyUpdate for instance) AND writes
|
||||
// are consolidated across that change, this code could use the wrong
|
||||
// sequence numbers when re-encrypting records with the old keys.
|
||||
if (header.content_type() == ssl_ct_application_data) {
|
||||
in_sequence_number_ =
|
||||
(std::max)(in_sequence_number_, header.sequence_number() + 1);
|
||||
}
|
||||
|
||||
if (FilterRecord(header, record, &offset, output) != KEEP) {
|
||||
changed = true;
|
||||
} else {
|
||||
|
@ -159,14 +195,16 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(
|
|||
DataBuffer filtered;
|
||||
uint8_t inner_content_type;
|
||||
DataBuffer plaintext;
|
||||
uint16_t protection_epoch = 0;
|
||||
|
||||
if (!Unprotect(header, record, &inner_content_type, &plaintext)) {
|
||||
if (g_ssl_gtest_verbose) {
|
||||
std::cerr << "unprotect failed: " << header << ":" << record << std::endl;
|
||||
}
|
||||
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
|
||||
&plaintext)) {
|
||||
std::cerr << agent()->role_str() << ": unprotect failed: " << header << ":"
|
||||
<< record << std::endl;
|
||||
return KEEP;
|
||||
}
|
||||
|
||||
auto& protection_spec = spec(protection_epoch);
|
||||
TlsRecordHeader real_header(header.variant(), header.version(),
|
||||
inner_content_type, header.sequence_number());
|
||||
|
||||
|
@ -174,7 +212,9 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(
|
|||
// In stream mode, even if something doesn't change we need to re-encrypt if
|
||||
// previous packets were dropped.
|
||||
if (action == KEEP) {
|
||||
if (header.is_dtls() || !dropped_record_) {
|
||||
if (header.is_dtls() || !protection_spec.record_dropped()) {
|
||||
// Count every outgoing packet.
|
||||
protection_spec.RecordProtected();
|
||||
return KEEP;
|
||||
}
|
||||
filtered = plaintext;
|
||||
|
@ -182,7 +222,7 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(
|
|||
|
||||
if (action == DROP) {
|
||||
std::cerr << "record drop: " << header << ":" << record << std::endl;
|
||||
dropped_record_ = true;
|
||||
protection_spec.RecordDropped();
|
||||
return DROP;
|
||||
}
|
||||
|
||||
|
@ -192,19 +232,18 @@ PacketFilter::Action TlsRecordFilter::FilterRecord(
|
|||
std::cerr << "record new: " << filtered << std::endl;
|
||||
}
|
||||
|
||||
uint64_t seq_num;
|
||||
if (header.is_dtls() || !cipher_spec_ ||
|
||||
header.content_type() != ssl_ct_application_data) {
|
||||
seq_num = header.sequence_number();
|
||||
} else {
|
||||
seq_num = out_sequence_number_++;
|
||||
uint64_t seq_num = protection_spec.next_out_seqno();
|
||||
if (!decrypting_ && header.is_dtls()) {
|
||||
// Copy over the epoch, which isn't tracked when not decrypting.
|
||||
seq_num |= header.sequence_number() & (0xffffULL << 48);
|
||||
}
|
||||
|
||||
TlsRecordHeader out_header(header.variant(), header.version(),
|
||||
header.content_type(), seq_num);
|
||||
|
||||
DataBuffer ciphertext;
|
||||
bool rv = Protect(out_header, inner_content_type, filtered, &ciphertext);
|
||||
EXPECT_TRUE(rv);
|
||||
bool rv = Protect(protection_spec, out_header, inner_content_type, filtered,
|
||||
&ciphertext);
|
||||
if (!rv) {
|
||||
return KEEP;
|
||||
}
|
||||
|
@ -227,15 +266,20 @@ uint64_t TlsRecordHeader::RecoverSequenceNumber(uint64_t expected,
|
|||
uint32_t partial,
|
||||
size_t partial_bits) {
|
||||
EXPECT_GE(32U, partial_bits);
|
||||
uint64_t mask = (1 << partial_bits) - 1;
|
||||
uint64_t mask = (1ULL << partial_bits) - 1;
|
||||
// First we determine the highest possible value. This is half the
|
||||
// expressible range above the expected value.
|
||||
uint64_t cap = expected + (1ULL << (partial_bits - 1));
|
||||
// expressible range above the expected value, less 1.
|
||||
//
|
||||
// We subtract the extra 1 from the cap so that when given a choice between
|
||||
// the equidistant expected+N and expected-N we want to chose the lower. With
|
||||
// 0-RTT, we sometimes have to recover an epoch of 1 when we expect an epoch
|
||||
// of 3 and with 2 partial bits, the alternative result of 5 is wrong.
|
||||
uint64_t cap = expected + (1ULL << (partial_bits - 1)) - 1;
|
||||
// Add the partial piece in. e.g., xxxx789a and 1234 becomes xxxx1234.
|
||||
uint64_t seq_no = (cap & ~mask) | partial;
|
||||
// If the partial value is higher than the same partial piece from the cap,
|
||||
// then the real value has to be lower. e.g., xxxx1234 can't become xxxx5678.
|
||||
if (partial > (cap & mask)) {
|
||||
if (partial > (cap & mask) && (seq_no >= (1ULL << partial_bits))) {
|
||||
seq_no -= 1ULL << partial_bits;
|
||||
}
|
||||
return seq_no;
|
||||
|
@ -375,16 +419,41 @@ size_t TlsRecordHeader::Write(DataBuffer* buffer, size_t offset,
|
|||
|
||||
bool TlsRecordFilter::Unprotect(const TlsRecordHeader& header,
|
||||
const DataBuffer& ciphertext,
|
||||
uint16_t* protection_epoch,
|
||||
uint8_t* inner_content_type,
|
||||
DataBuffer* plaintext) {
|
||||
if (!cipher_spec_ || header.content_type() != ssl_ct_application_data) {
|
||||
if (!decrypting_ || header.content_type() != ssl_ct_application_data) {
|
||||
// Maintain the epoch and sequence number for plaintext records.
|
||||
uint16_t ep = 0;
|
||||
if (agent()->variant() == ssl_variant_datagram) {
|
||||
ep = static_cast<uint16_t>(header.sequence_number() >> 48);
|
||||
}
|
||||
spec(ep).RecordUnprotected(header.sequence_number());
|
||||
*protection_epoch = ep;
|
||||
*inner_content_type = header.content_type();
|
||||
*plaintext = ciphertext;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!cipher_spec_->Unprotect(header, ciphertext, plaintext)) {
|
||||
return false;
|
||||
uint16_t ep = 0;
|
||||
if (agent()->variant() == ssl_variant_datagram) {
|
||||
ep = static_cast<uint16_t>(header.sequence_number() >> 48);
|
||||
if (!spec(ep).Unprotect(header, ciphertext, plaintext)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// In TLS, records aren't clearly labelled with their epoch, and we
|
||||
// can't just use the newest keys because the same flight of messages can
|
||||
// contain multiple epochs. So... trial decrypt!
|
||||
for (size_t i = cipher_specs_.size() - 1; i > 0; --i) {
|
||||
if (cipher_specs_[i].Unprotect(header, ciphertext, plaintext)) {
|
||||
ep = cipher_specs_[i].epoch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ep) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t len = plaintext->len();
|
||||
|
@ -396,33 +465,45 @@ bool TlsRecordFilter::Unprotect(const TlsRecordHeader& header,
|
|||
return false;
|
||||
}
|
||||
|
||||
*protection_epoch = ep;
|
||||
*inner_content_type = plaintext->data()[len - 1];
|
||||
plaintext->Truncate(len - 1);
|
||||
if (g_ssl_gtest_verbose) {
|
||||
std::cerr << "unprotect: " << std::hex << header.sequence_number()
|
||||
<< std::dec << " type=" << static_cast<int>(*inner_content_type)
|
||||
std::cerr << agent()->role_str() << ": unprotect: epoch=" << ep
|
||||
<< " seq=" << std::hex << header.sequence_number() << std::dec
|
||||
<< " " << *plaintext << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TlsRecordFilter::Protect(const TlsRecordHeader& header,
|
||||
bool TlsRecordFilter::Protect(TlsCipherSpec& protection_spec,
|
||||
const TlsRecordHeader& header,
|
||||
uint8_t inner_content_type,
|
||||
const DataBuffer& plaintext,
|
||||
DataBuffer* ciphertext, size_t padding) {
|
||||
if (!cipher_spec_ || header.content_type() != ssl_ct_application_data) {
|
||||
if (!protection_spec.is_protected()) {
|
||||
// Not protected, just keep the sequence numbers updated.
|
||||
protection_spec.RecordProtected();
|
||||
*ciphertext = plaintext;
|
||||
return true;
|
||||
}
|
||||
if (g_ssl_gtest_verbose) {
|
||||
std::cerr << "protect: " << header.sequence_number() << std::endl;
|
||||
}
|
||||
|
||||
DataBuffer padded;
|
||||
padded.Allocate(plaintext.len() + 1 + padding);
|
||||
size_t offset = padded.Write(0, plaintext.data(), plaintext.len());
|
||||
padded.Write(offset, inner_content_type, 1);
|
||||
return cipher_spec_->Protect(header, padded, ciphertext);
|
||||
|
||||
bool ok = protection_spec.Protect(header, padded, ciphertext);
|
||||
if (!ok) {
|
||||
ADD_FAILURE() << "protect fail";
|
||||
} else if (g_ssl_gtest_verbose) {
|
||||
std::cerr << agent()->role_str()
|
||||
<< ": protect: epoch=" << protection_spec.epoch()
|
||||
<< " seq=" << std::hex << header.sequence_number() << std::dec
|
||||
<< " " << *ciphertext << std::endl;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool IsHelloRetry(const DataBuffer& body) {
|
||||
|
|
|
@ -97,13 +97,7 @@ inline std::shared_ptr<T> MakeTlsFilter(const std::shared_ptr<TlsAgent>& agent,
|
|||
// Abstract filter that operates on entire (D)TLS records.
|
||||
class TlsRecordFilter : public PacketFilter {
|
||||
public:
|
||||
TlsRecordFilter(const std::shared_ptr<TlsAgent>& a)
|
||||
: agent_(a),
|
||||
count_(0),
|
||||
cipher_spec_(),
|
||||
dropped_record_(false),
|
||||
in_sequence_number_(0),
|
||||
out_sequence_number_(0) {}
|
||||
TlsRecordFilter(const std::shared_ptr<TlsAgent>& a);
|
||||
|
||||
std::shared_ptr<TlsAgent> agent() const { return agent_.lock(); }
|
||||
|
||||
|
@ -118,10 +112,11 @@ class TlsRecordFilter : public PacketFilter {
|
|||
// behavior.
|
||||
void EnableDecryption();
|
||||
bool Unprotect(const TlsRecordHeader& header, const DataBuffer& cipherText,
|
||||
uint8_t* inner_content_type, DataBuffer* plaintext);
|
||||
bool Protect(const TlsRecordHeader& header, uint8_t inner_content_type,
|
||||
const DataBuffer& plaintext, DataBuffer* ciphertext,
|
||||
size_t padding = 0);
|
||||
uint16_t* protection_epoch, uint8_t* inner_content_type,
|
||||
DataBuffer* plaintext);
|
||||
bool Protect(TlsCipherSpec& protection_spec, const TlsRecordHeader& header,
|
||||
uint8_t inner_content_type, const DataBuffer& plaintext,
|
||||
DataBuffer* ciphertext, size_t padding = 0);
|
||||
|
||||
protected:
|
||||
// There are two filter functions which can be overriden. Both are
|
||||
|
@ -146,20 +141,17 @@ class TlsRecordFilter : public PacketFilter {
|
|||
}
|
||||
|
||||
bool is_dtls13() const;
|
||||
TlsCipherSpec& spec(uint16_t epoch);
|
||||
|
||||
private:
|
||||
static void CipherSpecChanged(void* arg, PRBool sending,
|
||||
ssl3CipherSpec* newSpec);
|
||||
static void SecretCallback(PRFileDesc* fd, PRUint16 epoch,
|
||||
SSLSecretDirection dir, PK11SymKey* secret,
|
||||
void* arg);
|
||||
|
||||
std::weak_ptr<TlsAgent> agent_;
|
||||
size_t count_;
|
||||
std::unique_ptr<TlsCipherSpec> cipher_spec_;
|
||||
// Whether we dropped a record since the cipher spec changed.
|
||||
bool dropped_record_;
|
||||
// The sequence number we use for reading records as they are written.
|
||||
uint64_t in_sequence_number_;
|
||||
// The sequence number we use for writing modified records.
|
||||
uint64_t out_sequence_number_;
|
||||
size_t count_ = 0;
|
||||
std::vector<TlsCipherSpec> cipher_specs_;
|
||||
bool decrypting_ = false;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& stream, const TlsVersioned& v) {
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#include "tls_protect.h"
|
||||
#include "tls_filter.h"
|
||||
|
||||
// Do this to avoid having to re-implement HKDF.
|
||||
#include "tls13hkdf.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
AeadCipher::~AeadCipher() {
|
||||
|
@ -15,32 +18,37 @@ AeadCipher::~AeadCipher() {
|
|||
}
|
||||
}
|
||||
|
||||
bool AeadCipher::Init(PK11SymKey *key, const uint8_t *iv) {
|
||||
key_ = PK11_ReferenceSymKey(key);
|
||||
bool AeadCipher::Init(PK11SymKey* key, const uint8_t* iv) {
|
||||
key_ = key;
|
||||
if (!key_) return false;
|
||||
|
||||
memcpy(iv_, iv, sizeof(iv_));
|
||||
if (g_ssl_gtest_verbose) {
|
||||
EXPECT_EQ(SECSuccess, PK11_ExtractKeyValue(key_));
|
||||
SECItem* raw_key = PK11_GetKeyData(key_);
|
||||
std::cerr << "key: " << DataBuffer(raw_key->data, raw_key->len)
|
||||
<< std::endl;
|
||||
std::cerr << "iv: " << DataBuffer(iv_, 12) << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AeadCipher::FormatNonce(uint64_t seq, uint8_t *nonce) {
|
||||
void AeadCipher::FormatNonce(uint64_t seq, uint8_t* nonce) {
|
||||
memcpy(nonce, iv_, 12);
|
||||
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
nonce[12 - (i + 1)] ^= seq & 0xff;
|
||||
seq >>= 8;
|
||||
}
|
||||
|
||||
DataBuffer d(nonce, 12);
|
||||
}
|
||||
|
||||
bool AeadCipher::AeadInner(bool decrypt, void *params, size_t param_length,
|
||||
const uint8_t *in, size_t inlen, uint8_t *out,
|
||||
size_t *outlen, size_t maxlen) {
|
||||
bool AeadCipher::AeadInner(bool decrypt, void* params, size_t param_length,
|
||||
const uint8_t* in, size_t inlen, uint8_t* out,
|
||||
size_t* outlen, size_t maxlen) {
|
||||
SECStatus rv;
|
||||
unsigned int uoutlen = 0;
|
||||
SECItem param = {
|
||||
siBuffer, static_cast<unsigned char *>(params),
|
||||
siBuffer, static_cast<unsigned char*>(params),
|
||||
static_cast<unsigned int>(param_length),
|
||||
};
|
||||
|
||||
|
@ -54,28 +62,28 @@ bool AeadCipher::AeadInner(bool decrypt, void *params, size_t param_length,
|
|||
return rv == SECSuccess;
|
||||
}
|
||||
|
||||
bool AeadCipherAesGcm::Aead(bool decrypt, const uint8_t *hdr, size_t hdr_len,
|
||||
uint64_t seq, const uint8_t *in, size_t inlen,
|
||||
uint8_t *out, size_t *outlen, size_t maxlen) {
|
||||
bool AeadCipherAesGcm::Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len,
|
||||
uint64_t seq, const uint8_t* in, size_t inlen,
|
||||
uint8_t* out, size_t* outlen, size_t maxlen) {
|
||||
CK_GCM_PARAMS aeadParams;
|
||||
unsigned char nonce[12];
|
||||
|
||||
memset(&aeadParams, 0, sizeof(aeadParams));
|
||||
aeadParams.pIv = nonce;
|
||||
aeadParams.ulIvLen = sizeof(nonce);
|
||||
aeadParams.pAAD = const_cast<uint8_t *>(hdr);
|
||||
aeadParams.pAAD = const_cast<uint8_t*>(hdr);
|
||||
aeadParams.ulAADLen = hdr_len;
|
||||
aeadParams.ulTagBits = 128;
|
||||
|
||||
FormatNonce(seq, nonce);
|
||||
return AeadInner(decrypt, (unsigned char *)&aeadParams, sizeof(aeadParams),
|
||||
in, inlen, out, outlen, maxlen);
|
||||
return AeadInner(decrypt, (unsigned char*)&aeadParams, sizeof(aeadParams), in,
|
||||
inlen, out, outlen, maxlen);
|
||||
}
|
||||
|
||||
bool AeadCipherChacha20Poly1305::Aead(bool decrypt, const uint8_t *hdr,
|
||||
bool AeadCipherChacha20Poly1305::Aead(bool decrypt, const uint8_t* hdr,
|
||||
size_t hdr_len, uint64_t seq,
|
||||
const uint8_t *in, size_t inlen,
|
||||
uint8_t *out, size_t *outlen,
|
||||
const uint8_t* in, size_t inlen,
|
||||
uint8_t* out, size_t* outlen,
|
||||
size_t maxlen) {
|
||||
CK_NSS_AEAD_PARAMS aeadParams;
|
||||
unsigned char nonce[12];
|
||||
|
@ -83,67 +91,126 @@ bool AeadCipherChacha20Poly1305::Aead(bool decrypt, const uint8_t *hdr,
|
|||
memset(&aeadParams, 0, sizeof(aeadParams));
|
||||
aeadParams.pNonce = nonce;
|
||||
aeadParams.ulNonceLen = sizeof(nonce);
|
||||
aeadParams.pAAD = const_cast<uint8_t *>(hdr);
|
||||
aeadParams.pAAD = const_cast<uint8_t*>(hdr);
|
||||
aeadParams.ulAADLen = hdr_len;
|
||||
aeadParams.ulTagLen = 16;
|
||||
|
||||
FormatNonce(seq, nonce);
|
||||
return AeadInner(decrypt, (unsigned char *)&aeadParams, sizeof(aeadParams),
|
||||
in, inlen, out, outlen, maxlen);
|
||||
return AeadInner(decrypt, (unsigned char*)&aeadParams, sizeof(aeadParams), in,
|
||||
inlen, out, outlen, maxlen);
|
||||
}
|
||||
|
||||
bool TlsCipherSpec::Init(uint16_t epoc, SSLCipherAlgorithm cipher,
|
||||
PK11SymKey *key, const uint8_t *iv) {
|
||||
epoch_ = epoc;
|
||||
switch (cipher) {
|
||||
static uint64_t FirstSeqno(bool dtls, uint16_t epoc) {
|
||||
if (dtls) {
|
||||
return static_cast<uint64_t>(epoc) << 48;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TlsCipherSpec::TlsCipherSpec(bool dtls, uint16_t epoc)
|
||||
: dtls_(dtls),
|
||||
epoch_(epoc),
|
||||
in_seqno_(FirstSeqno(dtls, epoc)),
|
||||
out_seqno_(FirstSeqno(dtls, epoc)) {}
|
||||
|
||||
bool TlsCipherSpec::SetKeys(SSLCipherSuiteInfo* cipherinfo,
|
||||
PK11SymKey* secret) {
|
||||
CK_MECHANISM_TYPE mech;
|
||||
switch (cipherinfo->symCipher) {
|
||||
case ssl_calg_aes_gcm:
|
||||
aead_.reset(new AeadCipherAesGcm());
|
||||
mech = CKM_AES_GCM;
|
||||
break;
|
||||
case ssl_calg_chacha20:
|
||||
aead_.reset(new AeadCipherChacha20Poly1305());
|
||||
mech = CKM_NSS_CHACHA20_POLY1305;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
PK11SymKey* key;
|
||||
const std::string kPurposeKey = "key";
|
||||
SECStatus rv = tls13_HkdfExpandLabel(
|
||||
secret, cipherinfo->kdfHash, NULL, 0, kPurposeKey.c_str(),
|
||||
kPurposeKey.length(), mech, cipherinfo->symKeyBits / 8, &key);
|
||||
if (rv != SECSuccess) {
|
||||
ADD_FAILURE() << "unable to derive key for epoch " << epoch_;
|
||||
return false;
|
||||
}
|
||||
|
||||
// No constant for IV length, but everything we know of uses 12.
|
||||
uint8_t iv[12];
|
||||
const std::string kPurposeIv = "iv";
|
||||
rv = tls13_HkdfExpandLabelRaw(secret, cipherinfo->kdfHash, NULL, 0,
|
||||
kPurposeIv.c_str(), kPurposeIv.length(), iv,
|
||||
sizeof(iv));
|
||||
if (rv != SECSuccess) {
|
||||
ADD_FAILURE() << "unable to derive IV for epoch " << epoch_;
|
||||
return false;
|
||||
}
|
||||
|
||||
return aead_->Init(key, iv);
|
||||
}
|
||||
|
||||
bool TlsCipherSpec::Unprotect(const TlsRecordHeader &header,
|
||||
const DataBuffer &ciphertext,
|
||||
DataBuffer *plaintext) {
|
||||
bool TlsCipherSpec::Unprotect(const TlsRecordHeader& header,
|
||||
const DataBuffer& ciphertext,
|
||||
DataBuffer* plaintext) {
|
||||
if (aead_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
// Make space.
|
||||
plaintext->Allocate(ciphertext.len());
|
||||
|
||||
auto header_bytes = header.header();
|
||||
size_t len;
|
||||
bool ret =
|
||||
aead_->Aead(true, header_bytes.data(), header_bytes.len(),
|
||||
header.sequence_number(), ciphertext.data(), ciphertext.len(),
|
||||
plaintext->data(), &len, plaintext->len());
|
||||
if (!ret) return false;
|
||||
uint64_t seqno;
|
||||
if (dtls_) {
|
||||
seqno = header.sequence_number();
|
||||
} else {
|
||||
seqno = in_seqno_;
|
||||
}
|
||||
bool ret = aead_->Aead(true, header_bytes.data(), header_bytes.len(), seqno,
|
||||
ciphertext.data(), ciphertext.len(), plaintext->data(),
|
||||
&len, plaintext->len());
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RecordUnprotected(seqno);
|
||||
plaintext->Truncate(len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TlsCipherSpec::Protect(const TlsRecordHeader &header,
|
||||
const DataBuffer &plaintext,
|
||||
DataBuffer *ciphertext) {
|
||||
bool TlsCipherSpec::Protect(const TlsRecordHeader& header,
|
||||
const DataBuffer& plaintext,
|
||||
DataBuffer* ciphertext) {
|
||||
if (aead_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
// Make a padded buffer.
|
||||
|
||||
ciphertext->Allocate(plaintext.len() +
|
||||
32); // Room for any plausible auth tag
|
||||
size_t len;
|
||||
|
||||
DataBuffer header_bytes;
|
||||
(void)header.WriteHeader(&header_bytes, 0, plaintext.len() + 16);
|
||||
bool ret =
|
||||
aead_->Aead(false, header_bytes.data(), header_bytes.len(),
|
||||
header.sequence_number(), plaintext.data(), plaintext.len(),
|
||||
ciphertext->data(), &len, ciphertext->len());
|
||||
if (!ret) return false;
|
||||
uint64_t seqno;
|
||||
if (dtls_) {
|
||||
seqno = header.sequence_number();
|
||||
} else {
|
||||
seqno = out_seqno_;
|
||||
}
|
||||
|
||||
bool ret = aead_->Aead(false, header_bytes.data(), header_bytes.len(), seqno,
|
||||
plaintext.data(), plaintext.len(), ciphertext->data(),
|
||||
&len, ciphertext->len());
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RecordProtected();
|
||||
ciphertext->Truncate(len);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -22,19 +22,19 @@ class AeadCipher {
|
|||
AeadCipher(CK_MECHANISM_TYPE mech) : mech_(mech), key_(nullptr) {}
|
||||
virtual ~AeadCipher();
|
||||
|
||||
bool Init(PK11SymKey *key, const uint8_t *iv);
|
||||
virtual bool Aead(bool decrypt, const uint8_t *hdr, size_t hdr_len,
|
||||
uint64_t seq, const uint8_t *in, size_t inlen, uint8_t *out,
|
||||
size_t *outlen, size_t maxlen) = 0;
|
||||
bool Init(PK11SymKey* key, const uint8_t* iv);
|
||||
virtual bool Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len,
|
||||
uint64_t seq, const uint8_t* in, size_t inlen, uint8_t* out,
|
||||
size_t* outlen, size_t maxlen) = 0;
|
||||
|
||||
protected:
|
||||
void FormatNonce(uint64_t seq, uint8_t *nonce);
|
||||
bool AeadInner(bool decrypt, void *params, size_t param_length,
|
||||
const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen,
|
||||
void FormatNonce(uint64_t seq, uint8_t* nonce);
|
||||
bool AeadInner(bool decrypt, void* params, size_t param_length,
|
||||
const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen,
|
||||
size_t maxlen);
|
||||
|
||||
CK_MECHANISM_TYPE mech_;
|
||||
PK11SymKey *key_;
|
||||
PK11SymKey* key_;
|
||||
uint8_t iv_[12];
|
||||
};
|
||||
|
||||
|
@ -43,8 +43,8 @@ class AeadCipherChacha20Poly1305 : public AeadCipher {
|
|||
AeadCipherChacha20Poly1305() : AeadCipher(CKM_NSS_CHACHA20_POLY1305) {}
|
||||
|
||||
protected:
|
||||
bool Aead(bool decrypt, const uint8_t *hdr, size_t hdr_len, uint64_t seq,
|
||||
const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen,
|
||||
bool Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len, uint64_t seq,
|
||||
const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen,
|
||||
size_t maxlen);
|
||||
};
|
||||
|
||||
|
@ -53,27 +53,42 @@ class AeadCipherAesGcm : public AeadCipher {
|
|||
AeadCipherAesGcm() : AeadCipher(CKM_AES_GCM) {}
|
||||
|
||||
protected:
|
||||
bool Aead(bool decrypt, const uint8_t *hdr, size_t hdr_len, uint64_t seq,
|
||||
const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen,
|
||||
bool Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len, uint64_t seq,
|
||||
const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen,
|
||||
size_t maxlen);
|
||||
};
|
||||
|
||||
// Our analog of ssl3CipherSpec
|
||||
class TlsCipherSpec {
|
||||
public:
|
||||
TlsCipherSpec() : epoch_(0), aead_() {}
|
||||
TlsCipherSpec(bool dtls, uint16_t epoc);
|
||||
bool SetKeys(SSLCipherSuiteInfo* cipherinfo, PK11SymKey* secret);
|
||||
|
||||
bool Init(uint16_t epoch, SSLCipherAlgorithm cipher, PK11SymKey *key,
|
||||
const uint8_t *iv);
|
||||
bool Protect(const TlsRecordHeader& header, const DataBuffer& plaintext,
|
||||
DataBuffer* ciphertext);
|
||||
bool Unprotect(const TlsRecordHeader& header, const DataBuffer& ciphertext,
|
||||
DataBuffer* plaintext);
|
||||
|
||||
bool Protect(const TlsRecordHeader &header, const DataBuffer &plaintext,
|
||||
DataBuffer *ciphertext);
|
||||
bool Unprotect(const TlsRecordHeader &header, const DataBuffer &ciphertext,
|
||||
DataBuffer *plaintext);
|
||||
uint16_t epoch() const { return epoch_; }
|
||||
uint64_t next_in_seqno() const { return in_seqno_; }
|
||||
void RecordUnprotected(uint64_t seqno) {
|
||||
// Reordering happens, so don't let this go backwards.
|
||||
in_seqno_ = (std::max)(in_seqno_, seqno + 1);
|
||||
}
|
||||
uint64_t next_out_seqno() { return out_seqno_; }
|
||||
void RecordProtected() { out_seqno_++; }
|
||||
|
||||
void RecordDropped() { record_dropped_ = true; }
|
||||
bool record_dropped() const { return record_dropped_; }
|
||||
|
||||
bool is_protected() const { return aead_ != nullptr; }
|
||||
|
||||
private:
|
||||
bool dtls_;
|
||||
uint16_t epoch_;
|
||||
uint64_t in_seqno_;
|
||||
uint64_t out_seqno_;
|
||||
bool record_dropped_ = false;
|
||||
std::unique_ptr<AeadCipher> aead_;
|
||||
};
|
||||
|
||||
|
|
|
@ -1677,6 +1677,92 @@ PK11_MakeKEAPubKey(unsigned char *keyData, int length)
|
|||
return pubk;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SECKEY_SetPublicValue(SECKEYPrivateKey *privKey, SECItem *publicValue)
|
||||
{
|
||||
SECStatus rv;
|
||||
SECKEYPublicKey pubKey;
|
||||
PLArenaPool *arena;
|
||||
PK11SlotInfo *slot = privKey->pkcs11Slot;
|
||||
CK_OBJECT_HANDLE privKeyID = privKey->pkcs11ID;
|
||||
|
||||
if (privKey == NULL || publicValue == NULL ||
|
||||
publicValue->data == NULL || publicValue->len == 0) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
pubKey.arena = NULL;
|
||||
pubKey.keyType = privKey->keyType;
|
||||
pubKey.pkcs11Slot = NULL;
|
||||
pubKey.pkcs11ID = CK_INVALID_HANDLE;
|
||||
/* can't use PORT_InitCheapArena here becase SECKEY_DestroyPublic is used
|
||||
* to free it, and it uses PORT_FreeArena which not only frees the
|
||||
* underlying arena, it also frees the allocated arena struct. */
|
||||
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
||||
pubKey.arena = arena;
|
||||
if (arena == NULL) {
|
||||
return SECFailure;
|
||||
}
|
||||
rv = SECFailure;
|
||||
switch (privKey->keyType) {
|
||||
default:
|
||||
/* error code already set to SECFailure */
|
||||
break;
|
||||
case rsaKey:
|
||||
pubKey.u.rsa.modulus = *publicValue;
|
||||
rv = PK11_ReadAttribute(slot, privKeyID, CKA_PUBLIC_EXPONENT,
|
||||
arena, &pubKey.u.rsa.publicExponent);
|
||||
break;
|
||||
case dsaKey:
|
||||
pubKey.u.dsa.publicValue = *publicValue;
|
||||
rv = PK11_ReadAttribute(slot, privKeyID, CKA_PRIME,
|
||||
arena, &pubKey.u.dsa.params.prime);
|
||||
if (rv != SECSuccess) {
|
||||
break;
|
||||
}
|
||||
rv = PK11_ReadAttribute(slot, privKeyID, CKA_SUBPRIME,
|
||||
arena, &pubKey.u.dsa.params.subPrime);
|
||||
if (rv != SECSuccess) {
|
||||
break;
|
||||
}
|
||||
rv = PK11_ReadAttribute(slot, privKeyID, CKA_BASE,
|
||||
arena, &pubKey.u.dsa.params.base);
|
||||
break;
|
||||
case dhKey:
|
||||
pubKey.u.dh.publicValue = *publicValue;
|
||||
rv = PK11_ReadAttribute(slot, privKeyID, CKA_PRIME,
|
||||
arena, &pubKey.u.dh.prime);
|
||||
if (rv != SECSuccess) {
|
||||
break;
|
||||
}
|
||||
rv = PK11_ReadAttribute(slot, privKeyID, CKA_BASE,
|
||||
arena, &pubKey.u.dh.base);
|
||||
break;
|
||||
case ecKey:
|
||||
pubKey.u.ec.publicValue = *publicValue;
|
||||
pubKey.u.ec.encoding = ECPoint_Undefined;
|
||||
pubKey.u.ec.size = 0;
|
||||
rv = PK11_ReadAttribute(slot, privKeyID, CKA_EC_PARAMS,
|
||||
arena, &pubKey.u.ec.DEREncodedParams);
|
||||
break;
|
||||
}
|
||||
if (rv == SECSuccess) {
|
||||
rv = PK11_ImportPublicKey(slot, &pubKey, PR_TRUE);
|
||||
}
|
||||
/* Even though pubKey is stored on the stack, we've allocated
|
||||
* some of it's data from the arena. SECKEY_DestroyPublicKey
|
||||
* destroys keys by freeing the arena, so this will clean up all
|
||||
* the data we allocated specifically for the key above. It will
|
||||
* also free any slot references which we may have picked up in
|
||||
* PK11_ImportPublicKey. It won't delete the underlying key if
|
||||
* its a Token/Permanent key (which it will be if
|
||||
* PK11_ImportPublicKey succeeds). */
|
||||
SECKEY_DestroyPublicKey(&pubKey);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: This function doesn't return a SECKEYPrivateKey struct to represent
|
||||
* the new private key object. If it were to create a session object that
|
||||
|
@ -1802,12 +1888,6 @@ try_faulty_3des:
|
|||
nickname, publicValue, isPerm, isPrivate,
|
||||
key_type, usage, usageCount, wincx);
|
||||
if (privKey) {
|
||||
if (privk) {
|
||||
*privk = privKey;
|
||||
} else {
|
||||
SECKEY_DestroyPrivateKey(privKey);
|
||||
}
|
||||
privKey = NULL;
|
||||
rv = SECSuccess;
|
||||
goto done;
|
||||
}
|
||||
|
@ -1837,6 +1917,25 @@ try_faulty_3des:
|
|||
rv = SECFailure;
|
||||
|
||||
done:
|
||||
if ((rv == SECSuccess) && isPerm) {
|
||||
/* If we are importing a token object,
|
||||
* create the corresponding public key.
|
||||
* If this fails, just continue as the target
|
||||
* token simply might not support persistant
|
||||
* public keys. Such tokens are usable, but
|
||||
* need to be authenticated before searching
|
||||
* for user certs. */
|
||||
(void)SECKEY_SetPublicValue(privKey, publicValue);
|
||||
}
|
||||
|
||||
if (privKey) {
|
||||
if (privk) {
|
||||
*privk = privKey;
|
||||
} else {
|
||||
SECKEY_DestroyPrivateKey(privKey);
|
||||
}
|
||||
privKey = NULL;
|
||||
}
|
||||
if (crypto_param != NULL) {
|
||||
SECITEM_ZfreeItem(crypto_param, PR_TRUE);
|
||||
}
|
||||
|
|
|
@ -1815,8 +1815,6 @@ sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type,
|
|||
break; /* key was not DER encoded, no need to unwrap */
|
||||
}
|
||||
|
||||
PORT_Assert(pubKey->u.ec.ecParams.name != ECCurve25519);
|
||||
|
||||
/* handle the encoded case */
|
||||
if ((pubKey->u.ec.publicValue.data[0] == SEC_ASN1_OCTET_STRING) &&
|
||||
pubKey->u.ec.publicValue.len > keyLen) {
|
||||
|
@ -1827,7 +1825,13 @@ sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type,
|
|||
SEC_ASN1_GET(SEC_OctetStringTemplate),
|
||||
&pubKey->u.ec.publicValue);
|
||||
/* nope, didn't decode correctly */
|
||||
if ((rv != SECSuccess) || (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) || (publicValue.len != keyLen)) {
|
||||
if ((rv != SECSuccess) || (publicValue.len != keyLen)) {
|
||||
crv = CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
break;
|
||||
}
|
||||
/* we don't handle compressed points except in the case of ECCurve25519 */
|
||||
if ((pubKey->u.ec.ecParams.fieldID.type != ec_field_plain) &&
|
||||
(publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED)) {
|
||||
crv = CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -482,7 +482,7 @@ dtls13_HandleAck(sslSocket *ss, sslBuffer *databuf)
|
|||
* for the holddown period to process retransmitted Finisheds.
|
||||
*/
|
||||
if (!ss->sec.isServer && (ss->ssl3.hs.ws == idle_handshake)) {
|
||||
ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead,
|
||||
ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read,
|
||||
TrafficKeyHandshake);
|
||||
}
|
||||
}
|
||||
|
@ -509,6 +509,6 @@ dtls13_HolddownTimerCb(sslSocket *ss)
|
|||
{
|
||||
SSL_TRC(10, ("%d: SSL3[%d]: holddown timer fired",
|
||||
SSL_GETPID(), ss->fd));
|
||||
ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyHandshake);
|
||||
ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyHandshake);
|
||||
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
|
||||
}
|
||||
|
|
|
@ -542,7 +542,6 @@ dtls_QueueMessage(sslSocket *ss, SSLContentType ct,
|
|||
|
||||
/* Add DTLS handshake message to the pending queue
|
||||
* Empty the sendBuf buffer.
|
||||
* This function returns SECSuccess or SECFailure, never SECWouldBlock.
|
||||
* Always set sendBuf.len to 0, even when returning SECFailure.
|
||||
*
|
||||
* Called from:
|
||||
|
|
|
@ -299,6 +299,17 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
|
|||
* This is disabled by default and will be removed in a future version. */
|
||||
#define SSL_ENABLE_V2_COMPATIBLE_HELLO 38
|
||||
|
||||
/* Enables the post-handshake authentication in TLS 1.3. If it is set
|
||||
* to PR_TRUE, the client will send the "post_handshake_auth"
|
||||
* extension to indicate that it will process CertificateRequest
|
||||
* messages after handshake.
|
||||
*
|
||||
* This option applies only to clients. For a server, the
|
||||
* SSL_SendCertificateRequest can be used to request post-handshake
|
||||
* authentication.
|
||||
*/
|
||||
#define SSL_ENABLE_POST_HANDSHAKE_AUTH 39
|
||||
|
||||
#ifdef SSL_DEPRECATED_FUNCTION
|
||||
/* Old deprecated function names */
|
||||
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
|
||||
|
|
|
@ -1394,14 +1394,14 @@ loser:
|
|||
}
|
||||
|
||||
static SECStatus
|
||||
ssl3_SetupPendingCipherSpec(sslSocket *ss, CipherSpecDirection direction,
|
||||
ssl3_SetupPendingCipherSpec(sslSocket *ss, SSLSecretDirection direction,
|
||||
const ssl3CipherSuiteDef *suiteDef,
|
||||
ssl3CipherSpec **specp)
|
||||
{
|
||||
ssl3CipherSpec *spec;
|
||||
const ssl3CipherSpec *prev;
|
||||
|
||||
prev = (direction == CipherSpecWrite) ? ss->ssl3.cwSpec : ss->ssl3.crSpec;
|
||||
prev = (direction == ssl_secret_write) ? ss->ssl3.cwSpec : ss->ssl3.crSpec;
|
||||
if (prev->epoch == PR_UINT16_MAX) {
|
||||
PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
|
||||
return SECFailure;
|
||||
|
@ -1417,7 +1417,7 @@ ssl3_SetupPendingCipherSpec(sslSocket *ss, CipherSpecDirection direction,
|
|||
|
||||
spec->epoch = prev->epoch + 1;
|
||||
spec->nextSeqNum = 0;
|
||||
if (IS_DTLS(ss) && direction == CipherSpecRead) {
|
||||
if (IS_DTLS(ss) && direction == ssl_secret_read) {
|
||||
dtls_InitRecvdRecords(&spec->recvdRecords);
|
||||
}
|
||||
ssl_SetSpecVersions(ss, spec);
|
||||
|
@ -1471,12 +1471,12 @@ ssl3_SetupBothPendingCipherSpecs(sslSocket *ss)
|
|||
ss->ssl3.hs.kea_def = &kea_defs[kea];
|
||||
PORT_Assert(ss->ssl3.hs.kea_def->kea == kea);
|
||||
|
||||
rv = ssl3_SetupPendingCipherSpec(ss, CipherSpecRead, suiteDef,
|
||||
rv = ssl3_SetupPendingCipherSpec(ss, ssl_secret_read, suiteDef,
|
||||
&ss->ssl3.prSpec);
|
||||
if (rv != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
rv = ssl3_SetupPendingCipherSpec(ss, CipherSpecWrite, suiteDef,
|
||||
rv = ssl3_SetupPendingCipherSpec(ss, ssl_secret_write, suiteDef,
|
||||
&ss->ssl3.pwSpec);
|
||||
if (rv != SECSuccess) {
|
||||
goto loser;
|
||||
|
@ -1727,7 +1727,7 @@ ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec)
|
|||
|
||||
spec->cipher = (SSLCipher)PK11_CipherOp;
|
||||
encMechanism = ssl3_Alg2Mech(calg);
|
||||
encMode = (spec->direction == CipherSpecWrite) ? CKA_ENCRYPT : CKA_DECRYPT;
|
||||
encMode = (spec->direction == ssl_secret_write) ? CKA_ENCRYPT : CKA_DECRYPT;
|
||||
|
||||
/*
|
||||
* build the context
|
||||
|
@ -2215,7 +2215,7 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct,
|
|||
unsigned int lenOffset;
|
||||
SECStatus rv;
|
||||
|
||||
PORT_Assert(cwSpec->direction == CipherSpecWrite);
|
||||
PORT_Assert(cwSpec->direction == ssl_secret_write);
|
||||
PORT_Assert(SSL_BUFFER_LEN(wrBuf) == 0);
|
||||
PORT_Assert(cwSpec->cipherDef->max_records <= RECORD_SEQ_MAX);
|
||||
|
||||
|
@ -2314,8 +2314,8 @@ ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSLContentType ct,
|
|||
* Returns the number of bytes of plaintext that were successfully sent
|
||||
* plus the number of bytes of plaintext that were copied into the
|
||||
* output (write) buffer.
|
||||
* Returns SECFailure on a hard IO error, memory error, or crypto error.
|
||||
* Does NOT return SECWouldBlock.
|
||||
* Returns -1 on an error. PR_WOULD_BLOCK_ERROR is set if the error is blocking
|
||||
* and not terminal.
|
||||
*
|
||||
* Notes on the use of the private ssl flags:
|
||||
* (no private SSL flags)
|
||||
|
@ -2360,13 +2360,26 @@ ssl3_SendRecord(sslSocket *ss,
|
|||
* error, so don't overwrite. */
|
||||
PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
|
||||
}
|
||||
return SECFailure;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check for Token Presence */
|
||||
if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) {
|
||||
PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
|
||||
return SECFailure;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ss->recordWriteCallback) {
|
||||
PRUint16 epoch;
|
||||
ssl_GetSpecReadLock(ss);
|
||||
epoch = ss->ssl3.cwSpec->epoch;
|
||||
ssl_ReleaseSpecReadLock(ss);
|
||||
rv = ss->recordWriteCallback(ss->fd, epoch, ct, pIn, nIn,
|
||||
ss->recordWriteCallbackArg);
|
||||
if (rv != SECSuccess) {
|
||||
return -1;
|
||||
}
|
||||
return nIn;
|
||||
}
|
||||
|
||||
if (cwSpec) {
|
||||
|
@ -2470,7 +2483,7 @@ loser:
|
|||
#define SSL3_PENDING_HIGH_WATER 1024
|
||||
|
||||
/* Attempt to send the content of "in" in an SSL application_data record.
|
||||
* Returns "len" or SECFailure, never SECWouldBlock, nor SECSuccess.
|
||||
* Returns "len" or -1 on failure.
|
||||
*/
|
||||
int
|
||||
ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
|
||||
|
@ -2485,21 +2498,21 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
|
|||
PORT_Assert(!(flags & ssl_SEND_FLAG_NO_RETRANSMIT));
|
||||
if (len < 0 || !in) {
|
||||
PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
|
||||
return SECFailure;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ss->pendingBuf.len > SSL3_PENDING_HIGH_WATER &&
|
||||
!ssl_SocketIsBlocking(ss)) {
|
||||
PORT_Assert(!ssl_SocketIsBlocking(ss));
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return SECFailure;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ss->appDataBuffered && len) {
|
||||
PORT_Assert(in[0] == (unsigned char)(ss->appDataBuffered));
|
||||
if (in[0] != (unsigned char)(ss->appDataBuffered)) {
|
||||
PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
|
||||
return SECFailure;
|
||||
return -1;
|
||||
}
|
||||
in++;
|
||||
len--;
|
||||
|
@ -2548,7 +2561,7 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
|
|||
PORT_Assert(ss->lastWriteBlocked);
|
||||
break;
|
||||
}
|
||||
return SECFailure; /* error code set by ssl3_SendRecord */
|
||||
return -1; /* error code set by ssl3_SendRecord */
|
||||
}
|
||||
totalSent += sent;
|
||||
if (ss->pendingBuf.len) {
|
||||
|
@ -2577,7 +2590,6 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
|
|||
}
|
||||
|
||||
/* Attempt to send buffered handshake messages.
|
||||
* This function returns SECSuccess or SECFailure, never SECWouldBlock.
|
||||
* Always set sendBuf.len to 0, even when returning SECFailure.
|
||||
*
|
||||
* Depending on whether we are doing DTLS or not, this either calls
|
||||
|
@ -2600,7 +2612,6 @@ ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags)
|
|||
}
|
||||
|
||||
/* Attempt to send the content of sendBuf buffer in an SSL handshake record.
|
||||
* This function returns SECSuccess or SECFailure, never SECWouldBlock.
|
||||
* Always set sendBuf.len to 0, even when returning SECFailure.
|
||||
*
|
||||
* Called from ssl3_FlushHandshake
|
||||
|
@ -7382,6 +7393,9 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss,
|
|||
if (ss->getClientAuthData != NULL) {
|
||||
PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
|
||||
ssl_preinfo_all);
|
||||
PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
|
||||
PORT_Assert(ss->ssl3.clientCertificate == NULL);
|
||||
PORT_Assert(ss->ssl3.clientCertChain == NULL);
|
||||
/* XXX Should pass cert_types and algorithms in this call!! */
|
||||
rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg,
|
||||
ss->fd, ca_list,
|
||||
|
@ -7603,7 +7617,8 @@ ssl3_SendClientSecondRound(sslSocket *ss)
|
|||
" certificate authentication is still pending.",
|
||||
SSL_GETPID(), ss->fd));
|
||||
ss->ssl3.hs.restartTarget = ssl3_SendClientSecondRound;
|
||||
return SECWouldBlock;
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ssl_GetXmitBufLock(ss); /*******************************/
|
||||
|
@ -10737,6 +10752,9 @@ ssl3_AuthCertificate(sslSocket *ss)
|
|||
}
|
||||
}
|
||||
|
||||
if (ss->sec.ci.sid->peerCert) {
|
||||
CERT_DestroyCertificate(ss->sec.ci.sid->peerCert);
|
||||
}
|
||||
ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
|
||||
|
||||
if (!ss->sec.isServer) {
|
||||
|
@ -10898,13 +10916,6 @@ ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error)
|
|||
}
|
||||
|
||||
rv = target(ss);
|
||||
/* Even if we blocked here, we have accomplished enough to claim
|
||||
* success. Any remaining work will be taken care of by subsequent
|
||||
* calls to SSL_ForceHandshake/PR_Send/PR_Read/etc.
|
||||
*/
|
||||
if (rv == SECWouldBlock) {
|
||||
rv = SECSuccess;
|
||||
}
|
||||
} else {
|
||||
SSL_TRC(3, ("%d: SSL3[%p]: certificate authentication won the race with"
|
||||
" peer's finished message",
|
||||
|
@ -11445,7 +11456,8 @@ xmit_loser:
|
|||
}
|
||||
|
||||
ss->ssl3.hs.restartTarget = ssl3_FinishHandshake;
|
||||
return SECWouldBlock;
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = ssl3_FinishHandshake(ss);
|
||||
|
@ -11649,9 +11661,10 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length,
|
|||
* authenticate the certificate in ssl3_HandleCertificateStatus.
|
||||
*/
|
||||
rv = ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
|
||||
PORT_Assert(rv != SECWouldBlock);
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
/* This can't block. */
|
||||
PORT_Assert(PORT_GetError() != PR_WOULD_BLOCK_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11809,28 +11822,17 @@ ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b,
|
|||
static SECStatus
|
||||
ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
||||
{
|
||||
/*
|
||||
* There may be a partial handshake message already in the handshake
|
||||
* state. The incoming buffer may contain another portion, or a
|
||||
* complete message or several messages followed by another portion.
|
||||
*
|
||||
* Each message is made contiguous before being passed to the actual
|
||||
* message parser.
|
||||
*/
|
||||
sslBuffer *buf = &ss->ssl3.hs.msgState; /* do not lose the original buffer pointer */
|
||||
sslBuffer buf = *origBuf; /* Work from a copy. */
|
||||
SECStatus rv;
|
||||
|
||||
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
|
||||
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
||||
|
||||
if (buf->buf == NULL) {
|
||||
*buf = *origBuf;
|
||||
}
|
||||
while (buf->len > 0) {
|
||||
while (buf.len > 0) {
|
||||
if (ss->ssl3.hs.header_bytes < 4) {
|
||||
PRUint8 t;
|
||||
t = *(buf->buf++);
|
||||
buf->len--;
|
||||
t = *(buf.buf++);
|
||||
buf.len--;
|
||||
if (ss->ssl3.hs.header_bytes++ == 0)
|
||||
ss->ssl3.hs.msg_type = (SSLHandshakeType)t;
|
||||
else
|
||||
|
@ -11847,7 +11849,7 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
|||
#undef MAX_HANDSHAKE_MSG_LEN
|
||||
|
||||
/* If msg_len is zero, be sure we fall through,
|
||||
** even if buf->len is zero.
|
||||
** even if buf.len is zero.
|
||||
*/
|
||||
if (ss->ssl3.hs.msg_len > 0)
|
||||
continue;
|
||||
|
@ -11858,22 +11860,15 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
|||
* data available for this message. If it can be done right out
|
||||
* of the original buffer, then use it from there.
|
||||
*/
|
||||
if (ss->ssl3.hs.msg_body.len == 0 && buf->len >= ss->ssl3.hs.msg_len) {
|
||||
if (ss->ssl3.hs.msg_body.len == 0 && buf.len >= ss->ssl3.hs.msg_len) {
|
||||
/* handle it from input buffer */
|
||||
rv = ssl3_HandleHandshakeMessage(ss, buf->buf, ss->ssl3.hs.msg_len,
|
||||
buf->len == ss->ssl3.hs.msg_len);
|
||||
if (rv == SECFailure) {
|
||||
/* This test wants to fall through on either
|
||||
* SECSuccess or SECWouldBlock.
|
||||
* ssl3_HandleHandshakeMessage MUST set the error code.
|
||||
*/
|
||||
return rv;
|
||||
}
|
||||
buf->buf += ss->ssl3.hs.msg_len;
|
||||
buf->len -= ss->ssl3.hs.msg_len;
|
||||
rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len,
|
||||
buf.len == ss->ssl3.hs.msg_len);
|
||||
buf.buf += ss->ssl3.hs.msg_len;
|
||||
buf.len -= ss->ssl3.hs.msg_len;
|
||||
ss->ssl3.hs.msg_len = 0;
|
||||
ss->ssl3.hs.header_bytes = 0;
|
||||
if (rv != SECSuccess) { /* return if SECWouldBlock. */
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
|
@ -11881,7 +11876,7 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
|||
unsigned int bytes;
|
||||
|
||||
PORT_Assert(ss->ssl3.hs.msg_body.len < ss->ssl3.hs.msg_len);
|
||||
bytes = PR_MIN(buf->len, ss->ssl3.hs.msg_len - ss->ssl3.hs.msg_body.len);
|
||||
bytes = PR_MIN(buf.len, ss->ssl3.hs.msg_len - ss->ssl3.hs.msg_body.len);
|
||||
|
||||
/* Grow the buffer if needed */
|
||||
rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, ss->ssl3.hs.msg_len);
|
||||
|
@ -11891,10 +11886,10 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
|||
}
|
||||
|
||||
PORT_Memcpy(ss->ssl3.hs.msg_body.buf + ss->ssl3.hs.msg_body.len,
|
||||
buf->buf, bytes);
|
||||
buf.buf, bytes);
|
||||
ss->ssl3.hs.msg_body.len += bytes;
|
||||
buf->buf += bytes;
|
||||
buf->len -= bytes;
|
||||
buf.buf += bytes;
|
||||
buf.len -= bytes;
|
||||
|
||||
PORT_Assert(ss->ssl3.hs.msg_body.len <= ss->ssl3.hs.msg_len);
|
||||
|
||||
|
@ -11902,29 +11897,21 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
|||
if (ss->ssl3.hs.msg_body.len == ss->ssl3.hs.msg_len) {
|
||||
rv = ssl3_HandleHandshakeMessage(
|
||||
ss, ss->ssl3.hs.msg_body.buf, ss->ssl3.hs.msg_len,
|
||||
buf->len == 0);
|
||||
if (rv == SECFailure) {
|
||||
/* This test wants to fall through on either
|
||||
* SECSuccess or SECWouldBlock.
|
||||
* ssl3_HandleHandshakeMessage MUST set error code.
|
||||
*/
|
||||
return rv;
|
||||
}
|
||||
buf.len == 0);
|
||||
ss->ssl3.hs.msg_body.len = 0;
|
||||
ss->ssl3.hs.msg_len = 0;
|
||||
ss->ssl3.hs.header_bytes = 0;
|
||||
if (rv != SECSuccess) { /* return if SECWouldBlock. */
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
PORT_Assert(buf->len == 0);
|
||||
PORT_Assert(buf.len == 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* end loop */
|
||||
|
||||
origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */
|
||||
buf->buf = NULL; /* not a leak. */
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
|
@ -12183,7 +12170,7 @@ ssl3_UnprotectRecord(sslSocket *ss,
|
|||
unsigned int hashBytes = MAX_MAC_LENGTH + 1;
|
||||
SECStatus rv;
|
||||
|
||||
PORT_Assert(spec->direction == CipherSpecRead);
|
||||
PORT_Assert(spec->direction == ssl_secret_read);
|
||||
|
||||
good = ~0U;
|
||||
minLength = spec->macDef->mac_size;
|
||||
|
@ -12372,7 +12359,7 @@ ssl3_HandleNonApplicationData(sslSocket *ss, SSLContentType rType,
|
|||
ssl_GetSSL3HandshakeLock(ss);
|
||||
|
||||
/* All the functions called in this switch MUST set error code if
|
||||
** they return SECFailure or SECWouldBlock.
|
||||
** they return SECFailure.
|
||||
*/
|
||||
switch (rType) {
|
||||
case ssl_ct_change_cipher_spec:
|
||||
|
@ -12429,7 +12416,7 @@ ssl3_GetCipherSpec(sslSocket *ss, SSL3Ciphertext *cText)
|
|||
}
|
||||
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
/* Try to find the cipher spec. */
|
||||
newSpec = ssl_FindCipherSpecByEpoch(ss, CipherSpecRead,
|
||||
newSpec = ssl_FindCipherSpecByEpoch(ss, ssl_secret_read,
|
||||
epoch);
|
||||
if (newSpec != NULL) {
|
||||
return newSpec;
|
||||
|
@ -12694,8 +12681,8 @@ ssl3_InitState(sslSocket *ss)
|
|||
|
||||
ssl_GetSpecWriteLock(ss);
|
||||
PR_INIT_CLIST(&ss->ssl3.hs.cipherSpecs);
|
||||
rv = ssl_SetupNullCipherSpec(ss, CipherSpecRead);
|
||||
rv |= ssl_SetupNullCipherSpec(ss, CipherSpecWrite);
|
||||
rv = ssl_SetupNullCipherSpec(ss, ssl_secret_read);
|
||||
rv |= ssl_SetupNullCipherSpec(ss, ssl_secret_write);
|
||||
ss->ssl3.pwSpec = ss->ssl3.prSpec = NULL;
|
||||
ssl_ReleaseSpecWriteLock(ss);
|
||||
if (rv != SECSuccess) {
|
||||
|
|
|
@ -51,6 +51,7 @@ static const ssl3ExtensionHandler clientHelloHandlers[] = {
|
|||
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ServerHandlePskModesXtn },
|
||||
{ ssl_tls13_cookie_xtn, &tls13_ServerHandleCookieXtn },
|
||||
{ ssl_tls13_encrypted_sni_xtn, &tls13_ServerHandleEsniXtn },
|
||||
{ ssl_tls13_post_handshake_auth_xtn, &tls13_ServerHandlePostHandshakeAuthXtn },
|
||||
{ ssl_record_size_limit_xtn, &ssl_HandleRecordSizeLimitXtn },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
@ -138,6 +139,7 @@ static const sslExtensionBuilder clientHelloSendersTLS[] =
|
|||
{ ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn },
|
||||
{ ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskModesXtn },
|
||||
{ ssl_tls13_encrypted_sni_xtn, &tls13_ClientSendEsniXtn },
|
||||
{ ssl_tls13_post_handshake_auth_xtn, &tls13_ClientSendPostHandshakeAuthXtn },
|
||||
{ ssl_record_size_limit_xtn, &ssl_SendRecordSizeLimitXtn },
|
||||
/* The pre_shared_key extension MUST be last. */
|
||||
{ ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn },
|
||||
|
|
|
@ -389,7 +389,6 @@ dtls_GatherData(sslSocket *ss, sslGather *gs, int flags)
|
|||
* application data is available.
|
||||
* Returns 0 if ssl3_GatherData hits EOF.
|
||||
* Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
|
||||
* Returns -2 on SECWouldBlock return from ssl3_HandleRecord.
|
||||
*
|
||||
* Called from ssl_GatherRecord1stHandshake in sslcon.c,
|
||||
* and from SSL_ForceHandshake in sslsecur.c
|
||||
|
@ -422,13 +421,19 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
|
|||
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
|
||||
|
||||
do {
|
||||
PRBool handleRecordNow = PR_FALSE;
|
||||
PRBool processingEarlyData;
|
||||
|
||||
ssl_GetSSL3HandshakeLock(ss);
|
||||
|
||||
processingEarlyData = ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted;
|
||||
|
||||
/* If we have a detached record layer, don't ever gather. */
|
||||
if (ss->recordWriteCallback) {
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return (int)SECFailure;
|
||||
}
|
||||
|
||||
/* Without this, we may end up wrongly reporting
|
||||
* SSL_ERROR_RX_UNEXPECTED_* errors if we receive any records from the
|
||||
* peer while we are waiting to be restarted.
|
||||
|
@ -439,93 +444,68 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
|
|||
return (int)SECFailure;
|
||||
}
|
||||
|
||||
/* Treat an empty msgState like a NULL msgState. (Most of the time
|
||||
* when ssl3_HandleHandshake returns SECWouldBlock, it leaves
|
||||
* behind a non-NULL but zero-length msgState).
|
||||
* Test: async_cert_restart_server_sends_hello_request_first_in_separate_record
|
||||
*/
|
||||
if (ss->ssl3.hs.msgState.buf) {
|
||||
if (ss->ssl3.hs.msgState.len == 0) {
|
||||
ss->ssl3.hs.msgState.buf = NULL;
|
||||
} else {
|
||||
handleRecordNow = PR_TRUE;
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
|
||||
/* State for SSLv2 client hello support. */
|
||||
ssl2Gather ssl2gs = { PR_FALSE, 0 };
|
||||
ssl2Gather *ssl2gs_ptr = NULL;
|
||||
|
||||
/* If we're a server and waiting for a client hello, accept v2. */
|
||||
if (ss->sec.isServer && ss->opt.enableV2CompatibleHello &&
|
||||
ss->ssl3.hs.ws == wait_client_hello) {
|
||||
ssl2gs_ptr = &ssl2gs;
|
||||
}
|
||||
|
||||
/* bring in the next sslv3 record. */
|
||||
if (ss->recvdCloseNotify) {
|
||||
/* RFC 5246 Section 7.2.1:
|
||||
* Any data received after a closure alert is ignored.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!IS_DTLS(ss)) {
|
||||
/* If we're a server waiting for a ClientHello then pass
|
||||
* ssl2gs to support SSLv2 ClientHello messages. */
|
||||
rv = ssl3_GatherData(ss, &ss->gs, flags, ssl2gs_ptr);
|
||||
} else {
|
||||
rv = dtls_GatherData(ss, &ss->gs, flags);
|
||||
|
||||
/* If we got a would block error, that means that no data was
|
||||
* available, so we check the timer to see if it's time to
|
||||
* retransmit */
|
||||
if (rv == SECFailure &&
|
||||
(PORT_GetError() == PR_WOULD_BLOCK_ERROR)) {
|
||||
dtls_CheckTimer(ss);
|
||||
/* Restore the error in case something succeeded */
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
if (rv <= 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (handleRecordNow) {
|
||||
/* ssl3_HandleHandshake previously returned SECWouldBlock and the
|
||||
* as-yet-unprocessed plaintext of that previous handshake record.
|
||||
* We need to process it now before we overwrite it with the next
|
||||
* handshake record.
|
||||
*/
|
||||
SSL_DBG(("%d: SSL3[%d]: resuming handshake",
|
||||
SSL_GETPID(), ss->fd));
|
||||
PORT_Assert(!IS_DTLS(ss));
|
||||
rv = ssl3_HandleNonApplicationData(ss, ssl_ct_handshake,
|
||||
0, 0, &ss->gs.buf);
|
||||
} else {
|
||||
/* State for SSLv2 client hello support. */
|
||||
ssl2Gather ssl2gs = { PR_FALSE, 0 };
|
||||
ssl2Gather *ssl2gs_ptr = NULL;
|
||||
|
||||
if (ss->sec.isServer && ss->opt.enableV2CompatibleHello &&
|
||||
ss->ssl3.hs.ws == wait_client_hello) {
|
||||
ssl2gs_ptr = &ssl2gs;
|
||||
}
|
||||
|
||||
/* bring in the next sslv3 record. */
|
||||
if (ss->recvdCloseNotify) {
|
||||
/* RFC 5246 Section 7.2.1:
|
||||
* Any data received after a closure alert is ignored.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!IS_DTLS(ss)) {
|
||||
/* Passing a non-NULL ssl2gs here enables detection of
|
||||
* SSLv2-compatible ClientHello messages. */
|
||||
rv = ssl3_GatherData(ss, &ss->gs, flags, ssl2gs_ptr);
|
||||
} else {
|
||||
rv = dtls_GatherData(ss, &ss->gs, flags);
|
||||
|
||||
/* If we got a would block error, that means that no data was
|
||||
* available, so we check the timer to see if it's time to
|
||||
* retransmit */
|
||||
if (rv == SECFailure &&
|
||||
(PORT_GetError() == PR_WOULD_BLOCK_ERROR)) {
|
||||
dtls_CheckTimer(ss);
|
||||
/* Restore the error in case something succeeded */
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if (rv <= 0) {
|
||||
if (ssl2gs.isV2) {
|
||||
rv = ssl3_HandleV2ClientHello(ss, ss->gs.inbuf.buf,
|
||||
ss->gs.inbuf.len,
|
||||
ssl2gs.padding);
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (ssl2gs.isV2) {
|
||||
rv = ssl3_HandleV2ClientHello(ss, ss->gs.inbuf.buf,
|
||||
ss->gs.inbuf.len,
|
||||
ssl2gs.padding);
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
/* decipher it, and handle it if it's a handshake.
|
||||
* If it's application data, ss->gs.buf will not be empty upon return.
|
||||
* If it's a change cipher spec, alert, or handshake message,
|
||||
* ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
|
||||
*
|
||||
* cText only needs to be valid for this next function call, so
|
||||
* it can borrow gs.hdr.
|
||||
*/
|
||||
cText.hdr = ss->gs.hdr;
|
||||
cText.hdrLen = ss->gs.hdrLen;
|
||||
cText.buf = &ss->gs.inbuf;
|
||||
rv = ssl3_HandleRecord(ss, &cText);
|
||||
}
|
||||
} else {
|
||||
/* decipher it, and handle it if it's a handshake.
|
||||
* If it's application data, ss->gs.buf will not be empty upon return.
|
||||
* If it's a change cipher spec, alert, or handshake message,
|
||||
* ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
|
||||
*
|
||||
* cText only needs to be valid for this next function call, so
|
||||
* it can borrow gs.hdr.
|
||||
*/
|
||||
cText.hdr = ss->gs.hdr;
|
||||
cText.hdrLen = ss->gs.hdrLen;
|
||||
cText.buf = &ss->gs.inbuf;
|
||||
rv = ssl3_HandleRecord(ss, &cText);
|
||||
}
|
||||
if (rv < 0) {
|
||||
return ss->recvdCloseNotify ? 0 : rv;
|
||||
|
@ -575,7 +555,7 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
|
|||
* delivered to the application before the handshake completes. */
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return SECWouldBlock;
|
||||
return -1;
|
||||
}
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
} while (keepGoing);
|
||||
|
@ -596,7 +576,6 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
|
|||
* Returns 1 when application data is available.
|
||||
* Returns 0 if ssl3_GatherData hits EOF.
|
||||
* Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
|
||||
* Returns -2 on SECWouldBlock return from ssl3_HandleRecord.
|
||||
*
|
||||
* Called from DoRecv in sslsecur.c
|
||||
* Caller must hold the recv buf lock.
|
||||
|
@ -616,3 +595,108 @@ ssl3_GatherAppDataRecord(sslSocket *ss, int flags)
|
|||
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
|
||||
SSLContentType contentType,
|
||||
const PRUint8 *data, unsigned int len)
|
||||
{
|
||||
SECStatus rv;
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (IS_DTLS(ss) || data == NULL || len == 0) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* Run any handshake function. If SSL_RecordLayerData is the only way that
|
||||
* the handshake is driven, then this is necessary to ensure that
|
||||
* ssl_BeginClientHandshake or ssl_BeginServerHandshake is called. Note that
|
||||
* the other function that might be set to ss->handshake,
|
||||
* ssl3_GatherCompleteHandshake, does nothing when this function is used. */
|
||||
ssl_Get1stHandshakeLock(ss);
|
||||
rv = ssl_Do1stHandshake(ss);
|
||||
if (rv != SECSuccess && PORT_GetError() != PR_WOULD_BLOCK_ERROR) {
|
||||
goto early_loser; /* Rely on the existing code. */
|
||||
}
|
||||
|
||||
/* Don't allow application data before handshake completion. */
|
||||
if (contentType == ssl_ct_application_data && !ss->firstHsDone) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
goto early_loser;
|
||||
}
|
||||
|
||||
/* Then we can validate the epoch. */
|
||||
PRErrorCode epochError;
|
||||
ssl_GetSpecReadLock(ss);
|
||||
if (epoch < ss->ssl3.crSpec->epoch) {
|
||||
epochError = SEC_ERROR_INVALID_ARGS; /* Too c/old. */
|
||||
} else if (epoch > ss->ssl3.crSpec->epoch) {
|
||||
epochError = PR_WOULD_BLOCK_ERROR; /* Too warm/new. */
|
||||
} else {
|
||||
epochError = 0; /* Just right. */
|
||||
}
|
||||
ssl_ReleaseSpecReadLock(ss);
|
||||
if (epochError) {
|
||||
PORT_SetError(epochError);
|
||||
goto early_loser;
|
||||
}
|
||||
|
||||
/* If the handshake is still running, we need to run that. */
|
||||
ssl_Get1stHandshakeLock(ss);
|
||||
rv = ssl_Do1stHandshake(ss);
|
||||
if (rv != SECSuccess && PORT_GetError() != PR_WOULD_BLOCK_ERROR) {
|
||||
ssl_Release1stHandshakeLock(ss);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* Finally, save the data... */
|
||||
ssl_GetRecvBufLock(ss);
|
||||
rv = sslBuffer_Append(&ss->gs.buf, data, len);
|
||||
if (rv != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
|
||||
/* ...and process it. Just saving application data is enough for it to be
|
||||
* available to PR_Read(). */
|
||||
if (contentType != ssl_ct_application_data) {
|
||||
rv = ssl3_HandleNonApplicationData(ss, contentType, 0, 0, &ss->gs.buf);
|
||||
if (rv != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
}
|
||||
|
||||
ssl_ReleaseRecvBufLock(ss);
|
||||
ssl_Release1stHandshakeLock(ss);
|
||||
return SECSuccess;
|
||||
|
||||
loser:
|
||||
/* Make sure that any data is not used again. */
|
||||
ss->gs.buf.len = 0;
|
||||
ssl_ReleaseRecvBufLock(ss);
|
||||
early_loser:
|
||||
ssl_Release1stHandshakeLock(ss);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLExp_GetCurrentEpoch(PRFileDesc *fd, PRUint16 *readEpoch,
|
||||
PRUint16 *writeEpoch)
|
||||
{
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ssl_GetSpecReadLock(ss);
|
||||
if (readEpoch) {
|
||||
*readEpoch = ss->ssl3.crSpec->epoch;
|
||||
}
|
||||
if (writeEpoch) {
|
||||
*writeEpoch = ss->ssl3.cwSpec->epoch;
|
||||
}
|
||||
ssl_ReleaseSpecReadLock(ss);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
|
|
@ -44,17 +44,13 @@ const char *ssl_version = "SECURITY_VERSION:"
|
|||
* This function acquires and releases the RecvBufLock.
|
||||
*
|
||||
* returns SECSuccess for success.
|
||||
* returns SECWouldBlock when that value is returned by
|
||||
* ssl3_GatherCompleteHandshake().
|
||||
* returns SECFailure on all other errors.
|
||||
* returns SECFailure on error, setting PR_WOULD_BLOCK_ERROR if only blocked.
|
||||
*
|
||||
* The gather functions called by ssl_GatherRecord1stHandshake are expected
|
||||
* to return values interpreted as follows:
|
||||
* 1 : the function completed without error.
|
||||
* 0 : the function read EOF.
|
||||
* -1 : read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
|
||||
* -2 : the function wants ssl_GatherRecord1stHandshake to be called again
|
||||
* immediately, by ssl_Do1stHandshake.
|
||||
*
|
||||
* This code is similar to, and easily confused with, DoRecv() in sslsecur.c
|
||||
*
|
||||
|
@ -82,16 +78,14 @@ ssl_GatherRecord1stHandshake(sslSocket *ss)
|
|||
ssl_ReleaseRecvBufLock(ss);
|
||||
|
||||
if (rv <= 0) {
|
||||
if (rv == SECWouldBlock) {
|
||||
/* Progress is blocked waiting for callback completion. */
|
||||
SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)",
|
||||
SSL_GETPID(), ss->fd, ss->gs.remainder));
|
||||
return SECWouldBlock;
|
||||
}
|
||||
if (rv == 0) {
|
||||
/* EOF. Loser */
|
||||
PORT_SetError(PR_END_OF_FILE_ERROR);
|
||||
}
|
||||
if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {
|
||||
SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)",
|
||||
SSL_GETPID(), ss->fd, ss->gs.remainder));
|
||||
}
|
||||
return SECFailure; /* rv is < 0 here. */
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
|
|||
* For blocking sockets, always returns len or SECFailure, no short writes.
|
||||
* For non-blocking sockets:
|
||||
* Returns positive count if any data was written, else returns SECFailure.
|
||||
* Short writes may occur. Does not return SECWouldBlock.
|
||||
* Short writes may occur.
|
||||
*/
|
||||
int
|
||||
ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
|
||||
|
|
|
@ -268,6 +268,7 @@ typedef enum {
|
|||
SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION = (SSL_ERROR_BASE + 177),
|
||||
SSL_ERROR_MISSING_ESNI_EXTENSION = (SSL_ERROR_BASE + 178),
|
||||
SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE = (SSL_ERROR_BASE + 179),
|
||||
SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION = (SSL_ERROR_BASE + 180),
|
||||
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
|
||||
} SSLErrorCodes;
|
||||
#endif /* NO_SECURITY_ERROR_ENUM */
|
||||
|
|
|
@ -350,6 +350,27 @@ typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
|
|||
(PRFileDesc * _fd, PRBool _requestUpdate), \
|
||||
(fd, requestUpdate))
|
||||
|
||||
/* This function allows a server application to trigger
|
||||
* re-authentication (TLS 1.3 only) after handshake.
|
||||
*
|
||||
* This function will cause a CertificateRequest message to be sent by
|
||||
* a server. This can be called once at a time, and is not allowed
|
||||
* until an answer is received.
|
||||
*
|
||||
* The AuthCertificateCallback is called when the answer is received.
|
||||
* If the answer is accepted by the server, the value returned by
|
||||
* SSL_PeerCertificate() is replaced. If you need to remember all the
|
||||
* certificates, you will need to call SSL_PeerCertificate() and save
|
||||
* what you get before calling this.
|
||||
*
|
||||
* If the AuthCertificateCallback returns SECFailure, the connection
|
||||
* is aborted.
|
||||
*/
|
||||
#define SSL_SendCertificateRequest(fd) \
|
||||
SSL_EXPERIMENTAL_API("SSL_SendCertificateRequest", \
|
||||
(PRFileDesc * _fd), \
|
||||
(fd))
|
||||
|
||||
/*
|
||||
* Session cache API.
|
||||
*/
|
||||
|
@ -511,6 +532,100 @@ typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)(
|
|||
group, pubKey, pad, notBefore, notAfter, \
|
||||
out, outlen, maxlen))
|
||||
|
||||
/* SSL_SetSecretCallback installs a callback that TLS calls when it installs new
|
||||
* traffic secrets.
|
||||
*
|
||||
* SSLSecretCallback is called with the current epoch and the corresponding
|
||||
* secret; this matches the epoch used in DTLS 1.3, even if the socket is
|
||||
* operating in stream mode:
|
||||
*
|
||||
* - client_early_traffic_secret corresponds to epoch 1
|
||||
* - {client|server}_handshake_traffic_secret is epoch 2
|
||||
* - {client|server}_application_traffic_secret_{N} is epoch 3+N
|
||||
*
|
||||
* The callback is invoked separately for read secrets (client secrets on the
|
||||
* server; server secrets on the client), and write secrets.
|
||||
*
|
||||
* This callback is only called if (D)TLS 1.3 is negotiated.
|
||||
*/
|
||||
typedef void(PR_CALLBACK *SSLSecretCallback)(
|
||||
PRFileDesc *fd, PRUint16 epoch, SSLSecretDirection dir, PK11SymKey *secret,
|
||||
void *arg);
|
||||
|
||||
#define SSL_SecretCallback(fd, cb, arg) \
|
||||
SSL_EXPERIMENTAL_API("SSL_SecretCallback", \
|
||||
(PRFileDesc * _fd, SSLSecretCallback _cb, void *_arg), \
|
||||
(fd, cb, arg))
|
||||
|
||||
/* SSL_RecordLayerWriteCallback() is used to replace the TLS record layer. This
|
||||
* function installs a callback that TLS calls when it would otherwise encrypt
|
||||
* and write a record to the underlying NSPR IO layer. The application is
|
||||
* responsible for ensuring that these records are encrypted and written.
|
||||
*
|
||||
* Calling this API also disables reads from the underlying NSPR layer. The
|
||||
* application is expected to push data when it is available using
|
||||
* SSL_RecordLayerData().
|
||||
*
|
||||
* When data would be written, the provided SSLRecordWriteCallback with the
|
||||
* epoch, TLS content type, and the data. The data provided to the callback is
|
||||
* not split into record-sized writes. If the callback returns SECFailure, the
|
||||
* write will be considered to have failed; in particular, PR_WOULD_BLOCK_ERROR
|
||||
* is not handled specially.
|
||||
*
|
||||
* If TLS 1.3 is in use, the epoch indicates the expected level of protection
|
||||
* that the record would receive, this matches that used in DTLS 1.3:
|
||||
*
|
||||
* - epoch 0 corresponds to no record protection
|
||||
* - epoch 1 corresponds to 0-RTT
|
||||
* - epoch 2 corresponds to TLS handshake
|
||||
* - epoch 3 and higher are application data
|
||||
*
|
||||
* Prior versions of TLS use epoch 1 and higher for application data.
|
||||
*
|
||||
* This API is not supported for DTLS.
|
||||
*/
|
||||
typedef SECStatus(PR_CALLBACK *SSLRecordWriteCallback)(
|
||||
PRFileDesc *fd, PRUint16 epoch, SSLContentType contentType,
|
||||
const PRUint8 *data, unsigned int len, void *arg);
|
||||
|
||||
#define SSL_RecordLayerWriteCallback(fd, writeCb, arg) \
|
||||
SSL_EXPERIMENTAL_API("SSL_RecordLayerWriteCallback", \
|
||||
(PRFileDesc * _fd, SSLRecordWriteCallback _wCb, \
|
||||
void *_arg), \
|
||||
(fd, writeCb, arg))
|
||||
|
||||
/* SSL_RecordLayerData() is used to provide new data to TLS. The application
|
||||
* indicates the epoch (see the description of SSL_RecordLayerWriteCallback()),
|
||||
* content type, and the data that was received. The application is responsible
|
||||
* for removing any encryption or other protection before passing data to this
|
||||
* function.
|
||||
*
|
||||
* This returns SECSuccess if the data was successfully processed. If this
|
||||
* function is used to drive the handshake and the caller needs to know when the
|
||||
* handshake is complete, a call to SSL_ForceHandshake will return SECSuccess
|
||||
* when the handshake is complete.
|
||||
*
|
||||
* This API is not supported for DTLS sockets.
|
||||
*/
|
||||
#define SSL_RecordLayerData(fd, epoch, ct, data, len) \
|
||||
SSL_EXPERIMENTAL_API("SSL_RecordLayerData", \
|
||||
(PRFileDesc * _fd, PRUint16 _epoch, \
|
||||
SSLContentType _contentType, \
|
||||
const PRUint8 *_data, unsigned int _len), \
|
||||
(fd, epoch, ct, data, len))
|
||||
|
||||
/*
|
||||
* SSL_GetCurrentEpoch() returns the read and write epochs that the socket is
|
||||
* currently using. NULL values for readEpoch or writeEpoch are ignored.
|
||||
*
|
||||
* See SSL_RecordLayerWriteCallback() for details on epochs.
|
||||
*/
|
||||
#define SSL_GetCurrentEpoch(fd, readEpoch, writeEpoch) \
|
||||
SSL_EXPERIMENTAL_API("SSL_GetCurrentEpoch", \
|
||||
(PRFileDesc * _fd, PRUint16 * _readEpoch, \
|
||||
PRUint16 * _writeEpoch), \
|
||||
(fd, readEpoch, writeEpoch))
|
||||
|
||||
/* Deprecated experimental APIs */
|
||||
#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
|
||||
|
||||
|
|
|
@ -272,6 +272,7 @@ typedef struct sslOptionsStr {
|
|||
unsigned int enableDtlsShortHeader : 1;
|
||||
unsigned int enableHelloDowngradeCheck : 1;
|
||||
unsigned int enableV2CompatibleHello : 1;
|
||||
unsigned int enablePostHandshakeAuth : 1;
|
||||
} sslOptions;
|
||||
|
||||
typedef enum { sslHandshakingUndetermined = 0,
|
||||
|
@ -622,8 +623,6 @@ typedef struct SSL3HandshakeStateStr {
|
|||
unsigned long msg_len;
|
||||
PRBool isResuming; /* we are resuming (not used in TLS 1.3) */
|
||||
PRBool sendingSCSV; /* instead of empty RI */
|
||||
sslBuffer msgState; /* current state for handshake messages*/
|
||||
/* protected by recvBufLock */
|
||||
|
||||
/* The session ticket received in a NewSessionTicket message is temporarily
|
||||
* stored in newSessionTicket until the handshake is finished; then it is
|
||||
|
@ -744,10 +743,10 @@ struct ssl3StateStr {
|
|||
* update is initiated locally. */
|
||||
PRBool peerRequestedKeyUpdate;
|
||||
|
||||
/* Internal callback for when we do a cipher suite change. Used for
|
||||
* debugging in TLS 1.3. This can only be set by non-public functions. */
|
||||
sslCipherSpecChangedFunc changedCipherSpecFunc;
|
||||
void *changedCipherSpecArg;
|
||||
/* This is true after the server requests client certificate;
|
||||
* false after the client certificate is received. Used by the
|
||||
* server. */
|
||||
PRBool clientCertRequested;
|
||||
|
||||
CERTCertificate *clientCertificate; /* used by client */
|
||||
SECKEYPrivateKey *clientPrivateKey; /* used by client */
|
||||
|
@ -994,6 +993,10 @@ struct sslSocketStr {
|
|||
PRCList extensionHooks;
|
||||
SSLResumptionTokenCallback resumptionTokenCallback;
|
||||
void *resumptionTokenContext;
|
||||
SSLSecretCallback secretCallback;
|
||||
void *secretCallbackArg;
|
||||
SSLRecordWriteCallback recordWriteCallback;
|
||||
void *recordWriteCallbackArg;
|
||||
|
||||
PRIntervalTime rTimeout; /* timeout for NSPR I/O */
|
||||
PRIntervalTime wTimeout; /* timeout for NSPR I/O */
|
||||
|
@ -1174,7 +1177,7 @@ extern SECStatus ssl_SaveWriteData(sslSocket *ss,
|
|||
const void *p, unsigned int l);
|
||||
extern SECStatus ssl_BeginClientHandshake(sslSocket *ss);
|
||||
extern SECStatus ssl_BeginServerHandshake(sslSocket *ss);
|
||||
extern int ssl_Do1stHandshake(sslSocket *ss);
|
||||
extern SECStatus ssl_Do1stHandshake(sslSocket *ss);
|
||||
|
||||
extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret,
|
||||
PRBool derive);
|
||||
|
@ -1742,6 +1745,17 @@ SECStatus SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int t
|
|||
|
||||
SECStatus SSLExp_DestroyResumptionTokenInfo(SSLResumptionTokenInfo *token);
|
||||
|
||||
SECStatus SSLExp_SecretCallback(PRFileDesc *fd, SSLSecretCallback cb,
|
||||
void *arg);
|
||||
SECStatus SSLExp_RecordLayerWriteCallback(PRFileDesc *fd,
|
||||
SSLRecordWriteCallback write,
|
||||
void *arg);
|
||||
SECStatus SSLExp_RecordLayerData(PRFileDesc *fd, PRUint16 epoch,
|
||||
SSLContentType contentType,
|
||||
const PRUint8 *data, unsigned int len);
|
||||
SECStatus SSLExp_GetCurrentEpoch(PRFileDesc *fd, PRUint16 *readEpoch,
|
||||
PRUint16 *writeEpoch);
|
||||
|
||||
#define SSLResumptionTokenVersion 2
|
||||
|
||||
SEC_END_PROTOS
|
||||
|
|
|
@ -150,6 +150,7 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
|
|||
} else {
|
||||
inf.maxEarlyDataSize = 0;
|
||||
}
|
||||
inf.zeroRttCipherSuite = ss->ssl3.hs.zeroRttSuite;
|
||||
|
||||
memcpy(info, &inf, inf.length);
|
||||
return SECSuccess;
|
||||
|
@ -234,89 +235,89 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
|
|||
|
||||
static const SSLCipherSuiteInfo suiteInfo[] = {
|
||||
/* <------ Cipher suite --------------------> <auth> <KEA> <bulk cipher> <MAC> <FIPS> */
|
||||
{ 0, CS_(TLS_AES_128_GCM_SHA256), S_ANY, K_ANY, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ANY },
|
||||
{ 0, CS_(TLS_CHACHA20_POLY1305_SHA256), S_ANY, K_ANY, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_ANY },
|
||||
{ 0, CS_(TLS_AES_256_GCM_SHA384), S_ANY, K_ANY, C_AESGCM, B_256, M_AEAD_128, F_NFIPS_STD, A_ANY },
|
||||
{ 0, CS_(TLS_AES_128_GCM_SHA256), S_ANY, K_ANY, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ANY, ssl_hash_sha256 },
|
||||
{ 0, CS_(TLS_CHACHA20_POLY1305_SHA256), S_ANY, K_ANY, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_ANY, ssl_hash_sha256 },
|
||||
{ 0, CS_(TLS_AES_256_GCM_SHA384), S_ANY, K_ANY, C_AESGCM, B_256, M_AEAD_128, F_NFIPS_STD, A_ANY, ssl_hash_sha384 },
|
||||
|
||||
{ 0, CS(RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAD },
|
||||
{ 0, CS(DHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_DHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_RSAS },
|
||||
{ 0, CS(RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAD, ssl_hash_sha256 },
|
||||
{ 0, CS(DHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_DHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_RSAS, ssl_hash_sha256 },
|
||||
|
||||
{ 0, CS(DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_RSAS },
|
||||
{ 0, CS(DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_DSA },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_DHE, C_AES, B_256, M_SHA256, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_DHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_256_CBC_SHA), S_DSA, K_DHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_DSA },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_256_CBC_SHA256), S_DSA, K_DHE, C_AES, B_256, M_SHA256, F_FIPS_STD, A_DSA },
|
||||
{ 0, CS(RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_RSAD },
|
||||
{ 0, CS(RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_RSA, C_AES, B_256, M_SHA256, F_FIPS_STD, A_RSAD },
|
||||
{ 0, CS(RSA_WITH_AES_256_CBC_SHA), S_RSA, K_RSA, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAD },
|
||||
{ 0, CS(DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_DSA, ssl_hash_none },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_DHE, C_AES, B_256, M_SHA256, F_FIPS_STD, A_RSAS, ssl_hash_sha256 },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_DHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_256_CBC_SHA), S_DSA, K_DHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_DSA, ssl_hash_none },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_256_CBC_SHA256), S_DSA, K_DHE, C_AES, B_256, M_SHA256, F_FIPS_STD, A_DSA, ssl_hash_sha256 },
|
||||
{ 0, CS(RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_256, M_SHA, F_NFIPS_STD, A_RSAD, ssl_hash_none },
|
||||
{ 0, CS(RSA_WITH_AES_256_CBC_SHA256), S_RSA, K_RSA, C_AES, B_256, M_SHA256, F_FIPS_STD, A_RSAD, ssl_hash_sha256 },
|
||||
{ 0, CS(RSA_WITH_AES_256_CBC_SHA), S_RSA, K_RSA, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAD, ssl_hash_none },
|
||||
|
||||
{ 0, CS(DHE_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_RSAS },
|
||||
{ 0, CS(DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_DSA },
|
||||
{ 0, CS(DHE_DSS_WITH_RC4_128_SHA), S_DSA, K_DHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_DSA },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_DHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_DHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_128_GCM_SHA256), S_DSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_DSA },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_128_CBC_SHA), S_DSA, K_DHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_DSA },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_128_CBC_SHA256), S_DSA, K_DHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_DSA },
|
||||
{ 0, CS(RSA_WITH_SEED_CBC_SHA), S_RSA, K_RSA, C_SEED, B_128, M_SHA, F_FIPS_STD, A_RSAD },
|
||||
{ 0, CS(RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_RSAD },
|
||||
{ 0, CS(RSA_WITH_RC4_128_SHA), S_RSA, K_RSA, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_RSAD },
|
||||
{ 0, CS(RSA_WITH_RC4_128_MD5), S_RSA, K_RSA, C_RC4, B_128, M_MD5, F_NFIPS_STD, A_RSAD },
|
||||
{ 0, CS(RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_RSA, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAD },
|
||||
{ 0, CS(RSA_WITH_AES_128_CBC_SHA), S_RSA, K_RSA, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAD },
|
||||
{ 0, CS(DHE_RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(DHE_DSS_WITH_CAMELLIA_128_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_DSA, ssl_hash_none },
|
||||
{ 0, CS(DHE_DSS_WITH_RC4_128_SHA), S_DSA, K_DHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_DSA, ssl_hash_none },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_DHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAS, ssl_hash_sha256 },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAS, ssl_hash_sha256 },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_DHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_128_GCM_SHA256), S_DSA, K_DHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_DSA, ssl_hash_sha256 },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_128_CBC_SHA), S_DSA, K_DHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_DSA, ssl_hash_none },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_128_CBC_SHA256), S_DSA, K_DHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_DSA, ssl_hash_sha256 },
|
||||
{ 0, CS(RSA_WITH_SEED_CBC_SHA), S_RSA, K_RSA, C_SEED, B_128, M_SHA, F_FIPS_STD, A_RSAD, ssl_hash_none },
|
||||
{ 0, CS(RSA_WITH_CAMELLIA_128_CBC_SHA), S_RSA, K_RSA, C_CAMELLIA, B_128, M_SHA, F_NFIPS_STD, A_RSAD, ssl_hash_none },
|
||||
{ 0, CS(RSA_WITH_RC4_128_SHA), S_RSA, K_RSA, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_RSAD, ssl_hash_none },
|
||||
{ 0, CS(RSA_WITH_RC4_128_MD5), S_RSA, K_RSA, C_RC4, B_128, M_MD5, F_NFIPS_STD, A_RSAD, ssl_hash_none },
|
||||
{ 0, CS(RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_RSA, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAD, ssl_hash_sha256 },
|
||||
{ 0, CS(RSA_WITH_AES_128_CBC_SHA), S_RSA, K_RSA, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAD, ssl_hash_none },
|
||||
|
||||
{ 0, CS(DHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_DHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(DHE_DSS_WITH_3DES_EDE_CBC_SHA), S_DSA, K_DHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_DSA },
|
||||
{ 0, CS(RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAD },
|
||||
{ 0, CS(DHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_DHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(DHE_DSS_WITH_3DES_EDE_CBC_SHA), S_DSA, K_DHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_DSA, ssl_hash_none },
|
||||
{ 0, CS(RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_RSA, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAD, ssl_hash_none },
|
||||
|
||||
{ 0, CS(DHE_RSA_WITH_DES_CBC_SHA), S_RSA, K_DHE, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_RSAS },
|
||||
{ 0, CS(DHE_DSS_WITH_DES_CBC_SHA), S_DSA, K_DHE, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_DSA },
|
||||
{ 0, CS(RSA_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_RSAD },
|
||||
{ 0, CS(DHE_RSA_WITH_DES_CBC_SHA), S_RSA, K_DHE, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(DHE_DSS_WITH_DES_CBC_SHA), S_DSA, K_DHE, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_DSA, ssl_hash_none },
|
||||
{ 0, CS(RSA_WITH_DES_CBC_SHA), S_RSA, K_RSA, C_DES, B_DES, M_SHA, F_NFIPS_STD, A_RSAD, ssl_hash_none },
|
||||
|
||||
{ 0, CS(RSA_WITH_NULL_SHA256), S_RSA, K_RSA, C_NULL, B_0, M_SHA256, F_EXPORT, A_RSAD },
|
||||
{ 0, CS(RSA_WITH_NULL_SHA), S_RSA, K_RSA, C_NULL, B_0, M_SHA, F_EXPORT, A_RSAD },
|
||||
{ 0, CS(RSA_WITH_NULL_MD5), S_RSA, K_RSA, C_NULL, B_0, M_MD5, F_EXPORT, A_RSAD },
|
||||
{ 0, CS(RSA_WITH_NULL_SHA256), S_RSA, K_RSA, C_NULL, B_0, M_SHA256, F_EXPORT, A_RSAD, ssl_hash_sha256 },
|
||||
{ 0, CS(RSA_WITH_NULL_SHA), S_RSA, K_RSA, C_NULL, B_0, M_SHA, F_EXPORT, A_RSAD, ssl_hash_none },
|
||||
{ 0, CS(RSA_WITH_NULL_MD5), S_RSA, K_RSA, C_NULL, B_0, M_MD5, F_EXPORT, A_RSAD, ssl_hash_none },
|
||||
|
||||
/* ECC cipher suites */
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ECDSA },
|
||||
{ 0, CS(ECDH_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH_E },
|
||||
{ 0, CS(ECDH_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH_E },
|
||||
{ 0, CS(ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH_E },
|
||||
{ 0, CS(ECDH_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH_E },
|
||||
{ 0, CS(ECDH_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH_E },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_128_GCM_SHA256), S_RSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_RSAS, ssl_hash_sha256 },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_128_GCM_SHA256), S_ECDSA, K_ECDHE, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ECDSA, ssl_hash_sha256 },
|
||||
{ 0, CS(ECDH_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH_E, ssl_hash_none },
|
||||
{ 0, CS(ECDH_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH_E, ssl_hash_none },
|
||||
{ 0, CS(ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH_E, ssl_hash_none },
|
||||
{ 0, CS(ECDH_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH_E, ssl_hash_none },
|
||||
{ 0, CS(ECDH_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH_E, ssl_hash_none },
|
||||
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDSA },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDSA },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDSA },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDSA },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_ECDSA },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDSA },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), S_ECDSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_ECDSA },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDSA, ssl_hash_none },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDSA, ssl_hash_none },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDSA, ssl_hash_none },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDSA, ssl_hash_none },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_ECDSA, ssl_hash_sha256 },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDSA, ssl_hash_none },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), S_ECDSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_ECDSA, ssl_hash_sha256 },
|
||||
|
||||
{ 0, CS(ECDH_RSA_WITH_NULL_SHA), S_RSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH_R },
|
||||
{ 0, CS(ECDH_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH_R },
|
||||
{ 0, CS(ECDH_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH_R },
|
||||
{ 0, CS(ECDH_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH_R },
|
||||
{ 0, CS(ECDH_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH_R },
|
||||
{ 0, CS(ECDH_RSA_WITH_NULL_SHA), S_RSA, K_ECDH, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_ECDH_R, ssl_hash_none },
|
||||
{ 0, CS(ECDH_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDH, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_ECDH_R, ssl_hash_none },
|
||||
{ 0, CS(ECDH_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_ECDH_R, ssl_hash_none },
|
||||
{ 0, CS(ECDH_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDH, C_AES, B_128, M_SHA, F_FIPS_STD, A_ECDH_R, ssl_hash_none },
|
||||
{ 0, CS(ECDH_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDH, C_AES, B_256, M_SHA, F_FIPS_STD, A_ECDH_R, ssl_hash_none },
|
||||
|
||||
{ 0, CS(ECDHE_RSA_WITH_NULL_SHA), S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_RSAS },
|
||||
{ 0, CS(ECDHE_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_RSAS },
|
||||
{ 0, CS(ECDHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_ECDHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_RSAS },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_256_CBC_SHA384), S_RSA, K_ECDHE, C_AES, B_256, M_SHA384, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_256_CBC_SHA384), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA384, F_FIPS_STD, A_ECDSA },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_256_GCM_SHA384), S_ECDSA, K_ECDHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_ECDSA },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_ECDHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(ECDHE_RSA_WITH_NULL_SHA), S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, F_NFIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(ECDHE_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, F_NFIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(ECDHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_128, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_ECDHE, C_AES, B_128, M_SHA256, F_FIPS_STD, A_RSAS, ssl_hash_sha256 },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_256, M_SHA, F_FIPS_STD, A_RSAS, ssl_hash_none },
|
||||
{ 0, CS(ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, F_NFIPS_STD, A_RSAS, ssl_hash_sha256 },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_256_CBC_SHA384), S_RSA, K_ECDHE, C_AES, B_256, M_SHA384, F_FIPS_STD, A_RSAS, ssl_hash_sha384 },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_256_CBC_SHA384), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA384, F_FIPS_STD, A_ECDSA, ssl_hash_sha384 },
|
||||
{ 0, CS(ECDHE_ECDSA_WITH_AES_256_GCM_SHA384), S_ECDSA, K_ECDHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_ECDSA, ssl_hash_sha384 },
|
||||
{ 0, CS(ECDHE_RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_ECDHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_RSAS, ssl_hash_sha384 },
|
||||
|
||||
{ 0, CS(DHE_DSS_WITH_AES_256_GCM_SHA384), S_DSA, K_DHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_DSA },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_DHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_RSAS },
|
||||
{ 0, CS(RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_RSA, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_RSAD },
|
||||
{ 0, CS(DHE_DSS_WITH_AES_256_GCM_SHA384), S_DSA, K_DHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_DSA, ssl_hash_sha384 },
|
||||
{ 0, CS(DHE_RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_DHE, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_RSAS, ssl_hash_sha384 },
|
||||
{ 0, CS(RSA_WITH_AES_256_GCM_SHA384), S_RSA, K_RSA, C_AESGCM, B_256, M_AEAD_128, F_FIPS_STD, A_RSAD, ssl_hash_sha384 },
|
||||
};
|
||||
|
||||
#define NUM_SUITEINFOS ((sizeof suiteInfo) / (sizeof suiteInfo[0]))
|
||||
|
|
|
@ -16,32 +16,7 @@
|
|||
#include "nss.h" /* for NSS_RegisterShutdown */
|
||||
#include "prinit.h" /* for PR_CallOnceWithArg */
|
||||
|
||||
/* Returns a SECStatus: SECSuccess or SECFailure, NOT SECWouldBlock.
|
||||
*
|
||||
* Currently, the list of functions called through ss->handshake is:
|
||||
*
|
||||
* In sslsocks.c:
|
||||
* SocksGatherRecord
|
||||
* SocksHandleReply
|
||||
* SocksStartGather
|
||||
*
|
||||
* In sslcon.c:
|
||||
* ssl_GatherRecord1stHandshake
|
||||
* ssl_BeginClientHandshake
|
||||
* ssl_BeginServerHandshake
|
||||
*
|
||||
* The ss->handshake function returns SECWouldBlock if it was returned by
|
||||
* one of the callback functions, via one of these paths:
|
||||
*
|
||||
* - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() ->
|
||||
* ssl3_HandleRecord() -> ssl3_HandleHandshake() ->
|
||||
* ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificate() ->
|
||||
* ss->handleBadCert()
|
||||
*
|
||||
* - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() ->
|
||||
* ssl3_HandleRecord() -> ssl3_HandleHandshake() ->
|
||||
* ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificateRequest() ->
|
||||
* ss->getClientAuthData()
|
||||
/* Step through the handshake functions.
|
||||
*
|
||||
* Called from: SSL_ForceHandshake (below),
|
||||
* ssl_SecureRecv (below) and
|
||||
|
@ -52,10 +27,10 @@
|
|||
*
|
||||
* Caller must hold the (write) handshakeLock.
|
||||
*/
|
||||
int
|
||||
SECStatus
|
||||
ssl_Do1stHandshake(sslSocket *ss)
|
||||
{
|
||||
int rv = SECSuccess;
|
||||
SECStatus rv = SECSuccess;
|
||||
|
||||
while (ss->handshake && rv == SECSuccess) {
|
||||
PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
|
||||
|
@ -70,10 +45,6 @@ ssl_Do1stHandshake(sslSocket *ss)
|
|||
PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss));
|
||||
PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss));
|
||||
|
||||
if (rv == SECWouldBlock) {
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
rv = SECFailure;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -106,8 +77,8 @@ ssl_FinishHandshake(sslSocket *ss)
|
|||
static SECStatus
|
||||
ssl3_AlwaysBlock(sslSocket *ss)
|
||||
{
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR); /* perhaps redundant. */
|
||||
return SECWouldBlock;
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -400,10 +371,13 @@ SSL_ForceHandshake(PRFileDesc *fd)
|
|||
ssl_ReleaseRecvBufLock(ss);
|
||||
if (gatherResult > 0) {
|
||||
rv = SECSuccess;
|
||||
} else if (gatherResult == 0) {
|
||||
PORT_SetError(PR_END_OF_FILE_ERROR);
|
||||
} else if (gatherResult == SECWouldBlock) {
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
} else {
|
||||
if (gatherResult == 0) {
|
||||
PORT_SetError(PR_END_OF_FILE_ERROR);
|
||||
}
|
||||
/* We can rely on ssl3_GatherCompleteHandshake to set
|
||||
* PR_WOULD_BLOCK_ERROR as needed here. */
|
||||
rv = SECFailure;
|
||||
}
|
||||
} else {
|
||||
PORT_Assert(!ss->firstHsDone);
|
||||
|
@ -515,8 +489,7 @@ DoRecv(sslSocket *ss, unsigned char *out, int len, int flags)
|
|||
SSL_GETPID(), ss->fd));
|
||||
goto done;
|
||||
}
|
||||
if ((rv != SECWouldBlock) &&
|
||||
(PR_GetError() != PR_WOULD_BLOCK_ERROR)) {
|
||||
if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
|
||||
/* Some random error */
|
||||
goto done;
|
||||
}
|
||||
|
@ -741,7 +714,7 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow)
|
|||
/************************************************************************/
|
||||
|
||||
static SECStatus
|
||||
tls13_CheckKeyUpdate(sslSocket *ss, CipherSpecDirection dir)
|
||||
tls13_CheckKeyUpdate(sslSocket *ss, SSLSecretDirection dir)
|
||||
{
|
||||
PRBool keyUpdate;
|
||||
ssl3CipherSpec *spec;
|
||||
|
@ -765,7 +738,7 @@ tls13_CheckKeyUpdate(sslSocket *ss, CipherSpecDirection dir)
|
|||
* having the write margin larger reduces the number of times that a
|
||||
* KeyUpdate is sent by a reader. */
|
||||
ssl_GetSpecReadLock(ss);
|
||||
if (dir == CipherSpecRead) {
|
||||
if (dir == ssl_secret_read) {
|
||||
spec = ss->ssl3.crSpec;
|
||||
margin = spec->cipherDef->max_records / 8;
|
||||
} else {
|
||||
|
@ -781,10 +754,10 @@ tls13_CheckKeyUpdate(sslSocket *ss, CipherSpecDirection dir)
|
|||
|
||||
SSL_TRC(5, ("%d: SSL[%d]: automatic key update at %llx for %s cipher spec",
|
||||
SSL_GETPID(), ss->fd, seqNum,
|
||||
(dir == CipherSpecRead) ? "read" : "write"));
|
||||
(dir == ssl_secret_read) ? "read" : "write"));
|
||||
ssl_GetSSL3HandshakeLock(ss);
|
||||
rv = tls13_SendKeyUpdate(ss, (dir == CipherSpecRead) ? update_requested : update_not_requested,
|
||||
dir == CipherSpecWrite /* buffer */);
|
||||
rv = tls13_SendKeyUpdate(ss, (dir == ssl_secret_read) ? update_requested : update_not_requested,
|
||||
dir == ssl_secret_write /* buffer */);
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
return rv;
|
||||
}
|
||||
|
@ -829,7 +802,7 @@ ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
|
|||
}
|
||||
ssl_Release1stHandshakeLock(ss);
|
||||
} else {
|
||||
if (tls13_CheckKeyUpdate(ss, CipherSpecRead) != SECSuccess) {
|
||||
if (tls13_CheckKeyUpdate(ss, ssl_secret_read) != SECSuccess) {
|
||||
rv = PR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
@ -955,7 +928,7 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
|
|||
}
|
||||
|
||||
if (ss->firstHsDone) {
|
||||
if (tls13_CheckKeyUpdate(ss, CipherSpecWrite) != SECSuccess) {
|
||||
if (tls13_CheckKeyUpdate(ss, ssl_secret_write) != SECSuccess) {
|
||||
rv = PR_FAILURE;
|
||||
goto done;
|
||||
}
|
||||
|
@ -1010,6 +983,35 @@ ssl_SecureWrite(sslSocket *ss, const unsigned char *buf, int len)
|
|||
return ssl_SecureSend(ss, buf, len, 0);
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLExp_RecordLayerWriteCallback(PRFileDesc *fd, SSLRecordWriteCallback cb,
|
||||
void *arg)
|
||||
{
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
SSL_DBG(("%d: SSL[%d]: invalid socket for SSL_RecordLayerWriteCallback",
|
||||
SSL_GETPID(), fd));
|
||||
return SECFailure;
|
||||
}
|
||||
if (IS_DTLS(ss)) {
|
||||
SSL_DBG(("%d: SSL[%d]: DTLS socket for SSL_RecordLayerWriteCallback",
|
||||
SSL_GETPID(), fd));
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* This needs both HS and Xmit locks because this value is checked under
|
||||
* both locks. HS to disable reading from the underlying IO layer; Xmit to
|
||||
* prevent writing. */
|
||||
ssl_GetSSL3HandshakeLock(ss);
|
||||
ssl_GetXmitBufLock(ss);
|
||||
ss->recordWriteCallback = cb;
|
||||
ss->recordWriteCallbackArg = arg;
|
||||
ssl_ReleaseXmitBufLock(ss);
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSL_AlertReceivedCallback(PRFileDesc *fd, SSLAlertCallback cb, void *arg)
|
||||
{
|
||||
|
|
|
@ -86,7 +86,8 @@ static sslOptions ssl_defaults = {
|
|||
.enableTls13CompatMode = PR_FALSE,
|
||||
.enableDtlsShortHeader = PR_FALSE,
|
||||
.enableHelloDowngradeCheck = PR_FALSE,
|
||||
.enableV2CompatibleHello = PR_FALSE
|
||||
.enableV2CompatibleHello = PR_FALSE,
|
||||
.enablePostHandshakeAuth = PR_FALSE
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -842,6 +843,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val)
|
|||
ss->opt.enableV2CompatibleHello = val;
|
||||
break;
|
||||
|
||||
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
|
||||
ss->opt.enablePostHandshakeAuth = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
rv = SECFailure;
|
||||
|
@ -990,6 +995,9 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRIntn *pVal)
|
|||
case SSL_ENABLE_V2_COMPATIBLE_HELLO:
|
||||
val = ss->opt.enableV2CompatibleHello;
|
||||
break;
|
||||
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
|
||||
val = ss->opt.enablePostHandshakeAuth;
|
||||
break;
|
||||
default:
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
rv = SECFailure;
|
||||
|
@ -1122,6 +1130,9 @@ SSL_OptionGetDefault(PRInt32 which, PRIntn *pVal)
|
|||
case SSL_ENABLE_V2_COMPATIBLE_HELLO:
|
||||
val = ssl_defaults.enableV2CompatibleHello;
|
||||
break;
|
||||
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
|
||||
val = ssl_defaults.enablePostHandshakeAuth;
|
||||
break;
|
||||
default:
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
rv = SECFailure;
|
||||
|
@ -1325,6 +1336,10 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val)
|
|||
ssl_defaults.enableV2CompatibleHello = val;
|
||||
break;
|
||||
|
||||
case SSL_ENABLE_POST_HANDSHAKE_AUTH:
|
||||
ssl_defaults.enablePostHandshakeAuth = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
|
@ -4026,20 +4041,25 @@ struct {
|
|||
void *function;
|
||||
} ssl_experimental_functions[] = {
|
||||
#ifndef SSL_DISABLE_EXPERIMENTAL_API
|
||||
EXP(DestroyResumptionTokenInfo),
|
||||
EXP(EnableESNI),
|
||||
EXP(EncodeESNIKeys),
|
||||
EXP(GetCurrentEpoch),
|
||||
EXP(GetExtensionSupport),
|
||||
EXP(GetResumptionTokenInfo),
|
||||
EXP(HelloRetryRequestCallback),
|
||||
EXP(InstallExtensionHooks),
|
||||
EXP(KeyUpdate),
|
||||
EXP(RecordLayerData),
|
||||
EXP(RecordLayerWriteCallback),
|
||||
EXP(SecretCallback),
|
||||
EXP(SendCertificateRequest),
|
||||
EXP(SendSessionTicket),
|
||||
EXP(SetESNIKeyPair),
|
||||
EXP(SetMaxEarlyDataSize),
|
||||
EXP(SetupAntiReplay),
|
||||
EXP(SetResumptionTokenCallback),
|
||||
EXP(SetResumptionToken),
|
||||
EXP(GetResumptionTokenInfo),
|
||||
EXP(DestroyResumptionTokenInfo),
|
||||
EXP(SetESNIKeyPair),
|
||||
EXP(EncodeESNIKeys),
|
||||
EXP(EnableESNI),
|
||||
EXP(SetupAntiReplay),
|
||||
#endif
|
||||
{ "", NULL }
|
||||
};
|
||||
|
|
|
@ -113,7 +113,7 @@ ssl_GetMacDef(const sslSocket *ss, const ssl3CipherSuiteDef *suiteDef)
|
|||
}
|
||||
|
||||
ssl3CipherSpec *
|
||||
ssl_FindCipherSpecByEpoch(sslSocket *ss, CipherSpecDirection direction,
|
||||
ssl_FindCipherSpecByEpoch(sslSocket *ss, SSLSecretDirection direction,
|
||||
DTLSEpoch epoch)
|
||||
{
|
||||
PRCList *cur_p;
|
||||
|
@ -134,7 +134,7 @@ ssl_FindCipherSpecByEpoch(sslSocket *ss, CipherSpecDirection direction,
|
|||
}
|
||||
|
||||
ssl3CipherSpec *
|
||||
ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction)
|
||||
ssl_CreateCipherSpec(sslSocket *ss, SSLSecretDirection direction)
|
||||
{
|
||||
ssl3CipherSpec *spec = PORT_ZNew(ssl3CipherSpec);
|
||||
if (!spec) {
|
||||
|
@ -159,7 +159,7 @@ ssl_SaveCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
|
|||
/* Called from ssl3_InitState. */
|
||||
/* Caller must hold the SpecWriteLock. */
|
||||
SECStatus
|
||||
ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir)
|
||||
ssl_SetupNullCipherSpec(sslSocket *ss, SSLSecretDirection dir)
|
||||
{
|
||||
ssl3CipherSpec *spec;
|
||||
|
||||
|
@ -187,7 +187,7 @@ ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir)
|
|||
dtls_InitRecvdRecords(&spec->recvdRecords);
|
||||
|
||||
ssl_SaveCipherSpec(ss, spec);
|
||||
if (dir == CipherSpecRead) {
|
||||
if (dir == ssl_secret_read) {
|
||||
ss->ssl3.crSpec = spec;
|
||||
} else {
|
||||
ss->ssl3.cwSpec = spec;
|
||||
|
@ -259,13 +259,13 @@ ssl_DestroyCipherSpecs(PRCList *list)
|
|||
}
|
||||
|
||||
void
|
||||
ssl_CipherSpecReleaseByEpoch(sslSocket *ss, CipherSpecDirection dir,
|
||||
ssl_CipherSpecReleaseByEpoch(sslSocket *ss, SSLSecretDirection dir,
|
||||
DTLSEpoch epoch)
|
||||
{
|
||||
ssl3CipherSpec *spec;
|
||||
SSL_TRC(10, ("%d: SSL[%d]: releasing %s cipher spec for epoch %d",
|
||||
SSL_GETPID(), ss->fd,
|
||||
(dir == CipherSpecRead) ? "read" : "write", epoch));
|
||||
(dir == ssl_secret_read) ? "read" : "write", epoch));
|
||||
|
||||
spec = ssl_FindCipherSpecByEpoch(ss, dir, epoch);
|
||||
if (spec) {
|
||||
|
|
|
@ -19,13 +19,8 @@ typedef enum {
|
|||
TrafficKeyApplicationData = 3
|
||||
} TrafficKeyType;
|
||||
|
||||
typedef enum {
|
||||
CipherSpecRead,
|
||||
CipherSpecWrite,
|
||||
} CipherSpecDirection;
|
||||
|
||||
#define SPEC_DIR(spec) \
|
||||
((spec->direction == CipherSpecRead) ? "read" : "write")
|
||||
((spec->direction == ssl_secret_read) ? "read" : "write")
|
||||
|
||||
typedef struct ssl3CipherSpecStr ssl3CipherSpec;
|
||||
typedef struct ssl3BulkCipherDefStr ssl3BulkCipherDef;
|
||||
|
@ -146,7 +141,7 @@ struct ssl3CipherSpecStr {
|
|||
PRCList link;
|
||||
PRUint8 refCt;
|
||||
|
||||
CipherSpecDirection direction;
|
||||
SSLSecretDirection direction;
|
||||
SSL3ProtocolVersion version;
|
||||
SSL3ProtocolVersion recordVersion;
|
||||
|
||||
|
@ -184,17 +179,17 @@ const ssl3BulkCipherDef *ssl_GetBulkCipherDef(const ssl3CipherSuiteDef *cipher_d
|
|||
const ssl3MACDef *ssl_GetMacDefByAlg(SSL3MACAlgorithm mac);
|
||||
const ssl3MACDef *ssl_GetMacDef(const sslSocket *ss, const ssl3CipherSuiteDef *suiteDef);
|
||||
|
||||
ssl3CipherSpec *ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction);
|
||||
ssl3CipherSpec *ssl_CreateCipherSpec(sslSocket *ss, SSLSecretDirection direction);
|
||||
void ssl_SaveCipherSpec(sslSocket *ss, ssl3CipherSpec *spec);
|
||||
void ssl_CipherSpecAddRef(ssl3CipherSpec *spec);
|
||||
void ssl_CipherSpecRelease(ssl3CipherSpec *spec);
|
||||
void ssl_DestroyCipherSpecs(PRCList *list);
|
||||
SECStatus ssl_SetupNullCipherSpec(sslSocket *ss, CipherSpecDirection dir);
|
||||
SECStatus ssl_SetupNullCipherSpec(sslSocket *ss, SSLSecretDirection dir);
|
||||
|
||||
ssl3CipherSpec *ssl_FindCipherSpecByEpoch(sslSocket *ss,
|
||||
CipherSpecDirection direction,
|
||||
SSLSecretDirection direction,
|
||||
DTLSEpoch epoch);
|
||||
void ssl_CipherSpecReleaseByEpoch(sslSocket *ss, CipherSpecDirection direction,
|
||||
void ssl_CipherSpecReleaseByEpoch(sslSocket *ss, SSLSecretDirection direction,
|
||||
DTLSEpoch epoch);
|
||||
|
||||
#endif /* __sslspec_h_ */
|
||||
|
|
|
@ -43,6 +43,11 @@ typedef enum {
|
|||
ssl_ct_ack = 25
|
||||
} SSLContentType;
|
||||
|
||||
typedef enum {
|
||||
ssl_secret_read = 1,
|
||||
ssl_secret_write = 2,
|
||||
} SSLSecretDirection;
|
||||
|
||||
typedef struct SSL3StatisticsStr {
|
||||
/* statistics from ssl3_SendClientHello (sch) */
|
||||
long sch_sid_cache_hits;
|
||||
|
@ -328,6 +333,9 @@ typedef struct SSLChannelInfoStr {
|
|||
/* Preliminary channel info */
|
||||
#define ssl_preinfo_version (1U << 0)
|
||||
#define ssl_preinfo_cipher_suite (1U << 1)
|
||||
#define ssl_preinfo_0rtt_cipher_suite (1U << 2)
|
||||
/* ssl_preinfo_all doesn't contain ssl_preinfo_0rtt_cipher_suite because that
|
||||
* field is only set if 0-RTT is sent (client) or accepted (server). */
|
||||
#define ssl_preinfo_all (ssl_preinfo_version | ssl_preinfo_cipher_suite)
|
||||
|
||||
typedef struct SSLPreliminaryChannelInfoStr {
|
||||
|
@ -359,6 +367,13 @@ typedef struct SSLPreliminaryChannelInfoStr {
|
|||
* resume this session. */
|
||||
PRUint32 maxEarlyDataSize;
|
||||
|
||||
/* The following fields were added in NSS 3.39. */
|
||||
/* This reports the cipher suite used for 0-RTT if it sent or accepted. For
|
||||
* a client, this is set earlier than |cipherSuite|, and will match that
|
||||
* value if 0-RTT is accepted by the server. The server only sets this
|
||||
* after accepting 0-RTT, so this will contain the same value. */
|
||||
PRUint16 zeroRttCipherSuite;
|
||||
|
||||
/* When adding new fields to this structure, please document the
|
||||
* NSS version in which they were added. */
|
||||
} SSLPreliminaryChannelInfo;
|
||||
|
@ -407,6 +422,12 @@ typedef struct SSLCipherSuiteInfoStr {
|
|||
* this instead of |authAlgorithm|. */
|
||||
SSLAuthType authType;
|
||||
|
||||
/* The following fields were added in NSS 3.39. */
|
||||
/* This reports the hash function used in the TLS KDF, or HKDF for TLS 1.3.
|
||||
* For suites defined for versions of TLS earlier than TLS 1.2, this reports
|
||||
* ssl_hash_none. */
|
||||
SSLHashType kdfHash;
|
||||
|
||||
/* When adding new fields to this structure, please document the
|
||||
* NSS version in which they were added. */
|
||||
} SSLCipherSuiteInfo;
|
||||
|
@ -450,6 +471,7 @@ typedef enum {
|
|||
ssl_tls13_psk_key_exchange_modes_xtn = 45,
|
||||
ssl_tls13_ticket_early_data_info_xtn = 46, /* Deprecated. */
|
||||
ssl_tls13_certificate_authorities_xtn = 47,
|
||||
ssl_tls13_post_handshake_auth_xtn = 49,
|
||||
ssl_signature_algorithms_cert_xtn = 50,
|
||||
ssl_tls13_key_share_xtn = 51,
|
||||
ssl_next_proto_nego_xtn = 13172, /* Deprecated. */
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "tls13hashstate.h"
|
||||
|
||||
static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
|
||||
CipherSpecDirection install,
|
||||
SSLSecretDirection install,
|
||||
PRBool deleteSecret);
|
||||
static SECStatus tls13_AESGCM(
|
||||
ssl3KeyMaterial *keys,
|
||||
|
@ -56,6 +56,7 @@ static SECStatus tls13_SendCertificate(sslSocket *ss);
|
|||
static SECStatus tls13_HandleCertificate(
|
||||
sslSocket *ss, PRUint8 *b, PRUint32 length);
|
||||
static SECStatus tls13_ReinjectHandshakeTranscript(sslSocket *ss);
|
||||
static SECStatus tls13_SendCertificateRequest(sslSocket *ss);
|
||||
static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b,
|
||||
PRUint32 length);
|
||||
static SECStatus
|
||||
|
@ -104,6 +105,9 @@ static SECStatus tls13_ComputeFinished(
|
|||
PRBool sending, PRUint8 *output, unsigned int *outputLen,
|
||||
unsigned int maxOutputLen);
|
||||
static SECStatus tls13_SendClientSecondRound(sslSocket *ss);
|
||||
static SECStatus tls13_SendClientSecondFlight(sslSocket *ss,
|
||||
PRBool sendClientCert,
|
||||
SSL3AlertDescription *sendAlert);
|
||||
static SECStatus tls13_FinishHandshake(sslSocket *ss);
|
||||
|
||||
const char kHkdfLabelClient[] = "c";
|
||||
|
@ -588,13 +592,13 @@ loser:
|
|||
}
|
||||
|
||||
static PRBool
|
||||
tls13_UseServerSecret(sslSocket *ss, CipherSpecDirection direction)
|
||||
tls13_UseServerSecret(sslSocket *ss, SSLSecretDirection direction)
|
||||
{
|
||||
return ss->sec.isServer == (direction == CipherSpecWrite);
|
||||
return ss->sec.isServer == (direction == ssl_secret_write);
|
||||
}
|
||||
|
||||
static PK11SymKey **
|
||||
tls13_TrafficSecretRef(sslSocket *ss, CipherSpecDirection direction)
|
||||
tls13_TrafficSecretRef(sslSocket *ss, SSLSecretDirection direction)
|
||||
{
|
||||
if (tls13_UseServerSecret(ss, direction)) {
|
||||
return &ss->ssl3.hs.serverTrafficSecret;
|
||||
|
@ -603,7 +607,7 @@ tls13_TrafficSecretRef(sslSocket *ss, CipherSpecDirection direction)
|
|||
}
|
||||
|
||||
SECStatus
|
||||
tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
|
||||
tls13_UpdateTrafficKeys(sslSocket *ss, SSLSecretDirection direction)
|
||||
{
|
||||
PK11SymKey **secret;
|
||||
PK11SymKey *updatedSecret;
|
||||
|
@ -626,7 +630,7 @@ tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
|
|||
*secret = updatedSecret;
|
||||
|
||||
ssl_GetSpecReadLock(ss);
|
||||
if (direction == CipherSpecRead) {
|
||||
if (direction == ssl_secret_read) {
|
||||
epoch = ss->ssl3.crSpec->epoch;
|
||||
} else {
|
||||
epoch = ss->ssl3.cwSpec->epoch;
|
||||
|
@ -640,6 +644,11 @@ tls13_UpdateTrafficKeys(sslSocket *ss, CipherSpecDirection direction)
|
|||
}
|
||||
++epoch;
|
||||
|
||||
if (ss->secretCallback) {
|
||||
ss->secretCallback(ss->fd, epoch, direction, updatedSecret,
|
||||
ss->secretCallbackArg);
|
||||
}
|
||||
|
||||
rv = tls13_SetCipherSpec(ss, epoch, direction, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
|
||||
|
@ -698,7 +707,7 @@ tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request, PRBool buffer)
|
|||
}
|
||||
ssl_ReleaseXmitBufLock(ss);
|
||||
|
||||
rv = tls13_UpdateTrafficKeys(ss, CipherSpecWrite);
|
||||
rv = tls13_UpdateTrafficKeys(ss, ssl_secret_write);
|
||||
if (rv != SECSuccess) {
|
||||
goto loser; /* error code set by tls13_UpdateTrafficKeys */
|
||||
}
|
||||
|
@ -791,7 +800,7 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length)
|
|||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = tls13_UpdateTrafficKeys(ss, CipherSpecRead);
|
||||
rv = tls13_UpdateTrafficKeys(ss, ssl_secret_read);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure; /* Error code set by tls13_UpdateTrafficKeys. */
|
||||
}
|
||||
|
@ -820,6 +829,56 @@ tls13_HandleKeyUpdate(sslSocket *ss, PRUint8 *b, unsigned int length)
|
|||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLExp_SendCertificateRequest(PRFileDesc *fd)
|
||||
{
|
||||
SECStatus rv;
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* Not supported. */
|
||||
if (IS_DTLS(ss)) {
|
||||
PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (!ss->firstHsDone || ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (ss->ssl3.clientCertRequested) {
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = TLS13_CHECK_HS_STATE(ss, SEC_ERROR_INVALID_ARGS,
|
||||
idle_handshake);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (!ssl3_ExtensionNegotiated(ss, ssl_tls13_post_handshake_auth_xtn)) {
|
||||
PORT_SetError(SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ssl_GetSSL3HandshakeLock(ss);
|
||||
|
||||
rv = tls13_SendCertificateRequest(ss);
|
||||
if (rv == SECSuccess) {
|
||||
ssl_GetXmitBufLock(ss);
|
||||
rv = ssl3_FlushHandshake(ss, 0);
|
||||
ssl_ReleaseXmitBufLock(ss);
|
||||
ss->ssl3.clientCertRequested = PR_TRUE;
|
||||
}
|
||||
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length)
|
||||
{
|
||||
|
@ -1030,6 +1089,13 @@ tls13_DeriveEarlySecrets(sslSocket *ss)
|
|||
return SECFailure;
|
||||
}
|
||||
|
||||
if (ss->secretCallback) {
|
||||
ss->secretCallback(ss->fd, (PRUint16)TrafficKeyEarlyApplicationData,
|
||||
ss->sec.isServer ? ssl_secret_read : ssl_secret_write,
|
||||
ss->ssl3.hs.clientEarlyTrafficSecret,
|
||||
ss->secretCallbackArg);
|
||||
}
|
||||
|
||||
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
|
||||
NULL, kHkdfLabelEarlyExporterSecret,
|
||||
keylogLabelEarlyExporterSecret,
|
||||
|
@ -1098,6 +1164,18 @@ tls13_ComputeHandshakeSecrets(sslSocket *ss)
|
|||
return rv;
|
||||
}
|
||||
|
||||
if (ss->secretCallback) {
|
||||
SSLSecretDirection dir =
|
||||
ss->sec.isServer ? ssl_secret_read : ssl_secret_write;
|
||||
ss->secretCallback(ss->fd, (PRUint16)TrafficKeyHandshake, dir,
|
||||
ss->ssl3.hs.clientHsTrafficSecret,
|
||||
ss->secretCallbackArg);
|
||||
dir = ss->sec.isServer ? ssl_secret_write : ssl_secret_read;
|
||||
ss->secretCallback(ss->fd, (PRUint16)TrafficKeyHandshake, dir,
|
||||
ss->ssl3.hs.serverHsTrafficSecret,
|
||||
ss->secretCallbackArg);
|
||||
}
|
||||
|
||||
SSL_TRC(5, ("%d: TLS13[%d]: compute master secret (%s)",
|
||||
SSL_GETPID(), ss->fd, SSL_ROLE(ss)));
|
||||
|
||||
|
@ -1148,6 +1226,18 @@ tls13_ComputeApplicationSecrets(sslSocket *ss)
|
|||
return SECFailure;
|
||||
}
|
||||
|
||||
if (ss->secretCallback) {
|
||||
SSLSecretDirection dir =
|
||||
ss->sec.isServer ? ssl_secret_read : ssl_secret_write;
|
||||
ss->secretCallback(ss->fd, (PRUint16)TrafficKeyApplicationData,
|
||||
dir, ss->ssl3.hs.clientTrafficSecret,
|
||||
ss->secretCallbackArg);
|
||||
dir = ss->sec.isServer ? ssl_secret_write : ssl_secret_read;
|
||||
ss->secretCallback(ss->fd, (PRUint16)TrafficKeyApplicationData,
|
||||
dir, ss->ssl3.hs.serverTrafficSecret,
|
||||
ss->secretCallbackArg);
|
||||
}
|
||||
|
||||
rv = tls13_DeriveSecretWrap(ss, ss->ssl3.hs.currentSecret,
|
||||
NULL, kHkdfLabelExporterMasterSecret,
|
||||
keylogLabelExporterSecret,
|
||||
|
@ -1294,6 +1384,8 @@ tls13_NegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid)
|
|||
PORT_Assert(ss->statelessResume);
|
||||
ss->ssl3.hs.zeroRttState = ssl_0rtt_accepted;
|
||||
ss->ssl3.hs.zeroRttIgnore = ssl_0rtt_ignore_none;
|
||||
ss->ssl3.hs.zeroRttSuite = ss->ssl3.hs.cipher_suite;
|
||||
ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_0rtt_cipher_suite;
|
||||
}
|
||||
|
||||
/* Check if the offered group is acceptable. */
|
||||
|
@ -2101,8 +2193,27 @@ tls13_SendCertificateRequest(sslSocket *ss)
|
|||
/* We should always have at least one of these. */
|
||||
PORT_Assert(SSL_BUFFER_LEN(&extensionBuf) > 0);
|
||||
|
||||
/* Create a new request context for post-handshake authentication */
|
||||
if (ss->firstHsDone) {
|
||||
PRUint8 context[16];
|
||||
SECItem contextItem = { siBuffer, context, sizeof(context) };
|
||||
|
||||
rv = PK11_GenerateRandom(context, sizeof(context));
|
||||
if (rv != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
|
||||
SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
|
||||
rv = SECITEM_CopyItem(NULL, &ss->xtnData.certReqContext, &contextItem);
|
||||
if (rv != SECSuccess) {
|
||||
FATAL_ERROR(ss, SEC_ERROR_NO_MEMORY, internal_error);
|
||||
goto loser;
|
||||
}
|
||||
}
|
||||
|
||||
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request,
|
||||
1 + 0 + /* empty request context */
|
||||
1 + /* request context length */
|
||||
ss->xtnData.certReqContext.len +
|
||||
2 + /* extension length */
|
||||
SSL_BUFFER_LEN(&extensionBuf));
|
||||
if (rv != SECSuccess) {
|
||||
|
@ -2110,7 +2221,8 @@ tls13_SendCertificateRequest(sslSocket *ss)
|
|||
}
|
||||
|
||||
/* Context. */
|
||||
rv = ssl3_AppendHandshakeNumber(ss, 0, 1);
|
||||
rv = ssl3_AppendHandshakeVariable(ss, ss->xtnData.certReqContext.data,
|
||||
ss->xtnData.certReqContext.len, 1);
|
||||
if (rv != SECSuccess) {
|
||||
goto loser; /* err set by AppendHandshake. */
|
||||
}
|
||||
|
@ -2198,7 +2310,7 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg,
|
|||
/* Restore the null cipher spec for writing. */
|
||||
ssl_GetSpecWriteLock(ss);
|
||||
ssl_CipherSpecRelease(ss->ssl3.cwSpec);
|
||||
ss->ssl3.cwSpec = ssl_FindCipherSpecByEpoch(ss, CipherSpecWrite,
|
||||
ss->ssl3.cwSpec = ssl_FindCipherSpecByEpoch(ss, ssl_secret_write,
|
||||
TrafficKeyClearText);
|
||||
PORT_Assert(ss->ssl3.cwSpec);
|
||||
ssl_ReleaseSpecWriteLock(ss);
|
||||
|
@ -2274,25 +2386,49 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
|
|||
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
||||
|
||||
/* Client */
|
||||
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
|
||||
wait_cert_request);
|
||||
if (ss->opt.enablePostHandshakeAuth) {
|
||||
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
|
||||
wait_cert_request, idle_handshake);
|
||||
} else {
|
||||
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST,
|
||||
wait_cert_request);
|
||||
}
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
PORT_Assert(ss->ssl3.clientCertChain == NULL);
|
||||
PORT_Assert(ss->ssl3.clientCertificate == NULL);
|
||||
PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
|
||||
PORT_Assert(!ss->ssl3.hs.clientCertRequested);
|
||||
if (ss->firstHsDone) {
|
||||
/* clean up anything left from previous handshake. */
|
||||
if (ss->ssl3.clientCertChain != NULL) {
|
||||
CERT_DestroyCertificateList(ss->ssl3.clientCertChain);
|
||||
ss->ssl3.clientCertChain = NULL;
|
||||
}
|
||||
if (ss->ssl3.clientCertificate != NULL) {
|
||||
CERT_DestroyCertificate(ss->ssl3.clientCertificate);
|
||||
ss->ssl3.clientCertificate = NULL;
|
||||
}
|
||||
if (ss->ssl3.clientPrivateKey != NULL) {
|
||||
SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
|
||||
ss->ssl3.clientPrivateKey = NULL;
|
||||
}
|
||||
SECITEM_FreeItem(&ss->xtnData.certReqContext, PR_FALSE);
|
||||
ss->xtnData.certReqContext.data = NULL;
|
||||
} else {
|
||||
PORT_Assert(ss->ssl3.clientCertChain == NULL);
|
||||
PORT_Assert(ss->ssl3.clientCertificate == NULL);
|
||||
PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
|
||||
PORT_Assert(!ss->ssl3.hs.clientCertRequested);
|
||||
PORT_Assert(ss->xtnData.certReqContext.data == NULL);
|
||||
}
|
||||
|
||||
rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* We don't support post-handshake client auth, the certificate request
|
||||
* context must always be empty. */
|
||||
if (context.len > 0) {
|
||||
/* Unless it is a post-handshake client auth, the certificate
|
||||
* request context must be empty. */
|
||||
if (!ss->firstHsDone && context.len > 0) {
|
||||
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, illegal_parameter);
|
||||
return SECFailure;
|
||||
}
|
||||
|
@ -2326,7 +2462,35 @@ tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
|
|||
}
|
||||
|
||||
ss->ssl3.hs.clientCertRequested = PR_TRUE;
|
||||
TLS13_SET_HS_STATE(ss, wait_server_cert);
|
||||
|
||||
if (ss->firstHsDone) {
|
||||
SSL3AlertDescription sendAlert = no_alert;
|
||||
|
||||
/* Request a client certificate. */
|
||||
rv = ssl3_CompleteHandleCertificateRequest(
|
||||
ss, ss->xtnData.sigSchemes, ss->xtnData.numSigSchemes,
|
||||
&ss->xtnData.certReqAuthorities);
|
||||
if (rv != SECSuccess) {
|
||||
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
|
||||
return rv;
|
||||
}
|
||||
|
||||
ssl_GetXmitBufLock(ss);
|
||||
rv = tls13_SendClientSecondFlight(ss, !ss->ssl3.sendEmptyCert,
|
||||
&sendAlert);
|
||||
ssl_ReleaseXmitBufLock(ss);
|
||||
if (rv != SECSuccess) {
|
||||
if (sendAlert != no_alert) {
|
||||
FATAL_ERROR(ss, PORT_GetError(), sendAlert);
|
||||
} else {
|
||||
LOG_ERROR(ss, PORT_GetError());
|
||||
}
|
||||
return SECFailure;
|
||||
}
|
||||
PORT_Assert(ss->ssl3.hs.ws == idle_handshake);
|
||||
} else {
|
||||
TLS13_SET_HS_STATE(ss, wait_server_cert);
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
|
@ -2348,7 +2512,7 @@ tls13_SendEncryptedServerSequence(sslSocket *ss)
|
|||
}
|
||||
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
|
||||
CipherSpecWrite, PR_FALSE);
|
||||
ssl_secret_write, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
|
||||
return SECFailure;
|
||||
|
@ -2458,7 +2622,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
|
|||
}
|
||||
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
|
||||
CipherSpecWrite, PR_FALSE);
|
||||
ssl_secret_write, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
|
||||
return SECFailure;
|
||||
|
@ -2470,7 +2634,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
|
|||
}
|
||||
if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) {
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
|
||||
CipherSpecRead, PR_TRUE);
|
||||
ssl_secret_read, PR_TRUE);
|
||||
if (rv != SECSuccess) {
|
||||
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
|
||||
return SECFailure;
|
||||
|
@ -2482,7 +2646,7 @@ tls13_SendServerHelloSequence(sslSocket *ss)
|
|||
|
||||
rv = tls13_SetCipherSpec(ss,
|
||||
TrafficKeyHandshake,
|
||||
CipherSpecRead, PR_FALSE);
|
||||
ssl_secret_read, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
LOG_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE);
|
||||
return SECFailure;
|
||||
|
@ -2591,11 +2755,11 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
|
|||
/* When we send 0-RTT, we saved the null spec in case we needed it to
|
||||
* send another ClientHello in response to a HelloRetryRequest. Now
|
||||
* that we won't be receiving a HelloRetryRequest, release the spec. */
|
||||
ssl_CipherSpecReleaseByEpoch(ss, CipherSpecWrite, TrafficKeyClearText);
|
||||
ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_write, TrafficKeyClearText);
|
||||
}
|
||||
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
|
||||
CipherSpecRead, PR_FALSE);
|
||||
ssl_secret_read, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
|
||||
return SECFailure;
|
||||
|
@ -2862,8 +3026,13 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
|
|||
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
||||
|
||||
if (ss->sec.isServer) {
|
||||
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
|
||||
wait_client_cert);
|
||||
if (ss->ssl3.clientCertRequested) {
|
||||
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
|
||||
idle_handshake);
|
||||
} else {
|
||||
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
|
||||
wait_client_cert);
|
||||
}
|
||||
} else {
|
||||
rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
|
||||
wait_cert_request, wait_server_cert);
|
||||
|
@ -2873,7 +3042,7 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
|
|||
|
||||
/* We can ignore any other cleartext from the client. */
|
||||
if (ss->sec.isServer && IS_DTLS(ss)) {
|
||||
ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyClearText);
|
||||
ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyClearText);
|
||||
dtls_ReceivedFirstMessageInFlight(ss);
|
||||
}
|
||||
/* Process the context string */
|
||||
|
@ -2881,10 +3050,12 @@ tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length)
|
|||
if (rv != SECSuccess)
|
||||
return SECFailure;
|
||||
|
||||
if (context.len) {
|
||||
/* The context string MUST be empty */
|
||||
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, illegal_parameter);
|
||||
return SECFailure;
|
||||
if (ss->ssl3.clientCertRequested) {
|
||||
PORT_Assert(ss->sec.isServer);
|
||||
if (SECITEM_CompareItem(&context, &ss->xtnData.certReqContext) != 0) {
|
||||
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, illegal_parameter);
|
||||
return SECFailure;
|
||||
}
|
||||
}
|
||||
|
||||
rv = ssl3_ConsumeHandshakeVariable(ss, &certList, 3, &b, &length);
|
||||
|
@ -3125,6 +3296,25 @@ tls13_DeriveSecretWrap(sslSocket *ss, PK11SymKey *key,
|
|||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SSLExp_SecretCallback(PRFileDesc *fd, SSLSecretCallback cb, void *arg)
|
||||
{
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SecretCallback",
|
||||
SSL_GETPID(), fd));
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ssl_Get1stHandshakeLock(ss);
|
||||
ssl_GetSSL3HandshakeLock(ss);
|
||||
ss->secretCallback = cb;
|
||||
ss->secretCallbackArg = arg;
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
ssl_Release1stHandshakeLock(ss);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
/* Derive traffic keys for the next cipher spec in the queue. */
|
||||
static SECStatus
|
||||
tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *spec,
|
||||
|
@ -3251,7 +3441,7 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
|
|||
/* We want to keep read cipher specs around longer because
|
||||
* there are cases where we might get either epoch N or
|
||||
* epoch N+1. */
|
||||
if (IS_DTLS(ss) && spec->direction == CipherSpecRead) {
|
||||
if (IS_DTLS(ss) && spec->direction == ssl_secret_read) {
|
||||
ssl_CipherSpecAddRef(spec);
|
||||
}
|
||||
|
||||
|
@ -3274,7 +3464,7 @@ tls13_SetupPendingCipherSpec(sslSocket *ss, ssl3CipherSpec *spec)
|
|||
/* The record size limit is reduced by one so that the remainder of the
|
||||
* record handling code can use the same checks for all versions. */
|
||||
if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
|
||||
spec->recordSizeLimit = ((spec->direction == CipherSpecRead)
|
||||
spec->recordSizeLimit = ((spec->direction == ssl_secret_read)
|
||||
? ss->opt.recordSizeLimit
|
||||
: ss->xtnData.recordSizeLimit) -
|
||||
1;
|
||||
|
@ -3310,7 +3500,7 @@ tls13_SetAlertCipherSpec(sslSocket *ss)
|
|||
}
|
||||
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
|
||||
CipherSpecWrite, PR_FALSE);
|
||||
ssl_secret_write, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
||||
return SECFailure;
|
||||
|
@ -3325,7 +3515,7 @@ tls13_SetAlertCipherSpec(sslSocket *ss)
|
|||
*/
|
||||
static SECStatus
|
||||
tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
|
||||
CipherSpecDirection direction, PRBool deleteSecret)
|
||||
SSLSecretDirection direction, PRBool deleteSecret)
|
||||
{
|
||||
TrafficKeyType type;
|
||||
SECStatus rv;
|
||||
|
@ -3364,7 +3554,7 @@ tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
|
|||
}
|
||||
|
||||
/* Now that we've set almost everything up, finally cut over. */
|
||||
specp = (direction == CipherSpecRead) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec;
|
||||
specp = (direction == ssl_secret_read) ? &ss->ssl3.crSpec : &ss->ssl3.cwSpec;
|
||||
ssl_GetSpecWriteLock(ss);
|
||||
ssl_CipherSpecRelease(*specp); /* May delete old cipher. */
|
||||
*specp = spec; /* Overwrite. */
|
||||
|
@ -3373,11 +3563,6 @@ tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
|
|||
SSL_TRC(3, ("%d: TLS13[%d]: %s installed key for epoch=%d (%s) dir=%s",
|
||||
SSL_GETPID(), ss->fd, SSL_ROLE(ss), spec->epoch,
|
||||
spec->phase, SPEC_DIR(spec)));
|
||||
|
||||
if (ss->ssl3.changedCipherSpecFunc) {
|
||||
ss->ssl3.changedCipherSpecFunc(ss->ssl3.changedCipherSpecArg,
|
||||
direction == CipherSpecWrite, spec);
|
||||
}
|
||||
return SECSuccess;
|
||||
|
||||
loser:
|
||||
|
@ -3937,6 +4122,10 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
|
|||
}
|
||||
}
|
||||
|
||||
if (ss->ssl3.clientCertRequested) {
|
||||
PORT_Assert(ss->sec.isServer);
|
||||
ss->ssl3.clientCertRequested = PR_FALSE;
|
||||
}
|
||||
TLS13_SET_HS_STATE(ss, wait_finished);
|
||||
|
||||
return SECSuccess;
|
||||
|
@ -4238,26 +4427,32 @@ tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length)
|
|||
SSL_TRC(3, ("%d: TLS13[%d]: server handle finished handshake",
|
||||
SSL_GETPID(), ss->fd));
|
||||
|
||||
rv = tls13_CommonHandleFinished(ss, ss->ssl3.hs.clientHsTrafficSecret,
|
||||
rv = tls13_CommonHandleFinished(ss,
|
||||
ss->firstHsDone ? ss->ssl3.hs.clientTrafficSecret : ss->ssl3.hs.clientHsTrafficSecret,
|
||||
b, length);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (ss->firstHsDone) {
|
||||
TLS13_SET_HS_STATE(ss, idle_handshake);
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
if (!tls13_ShouldRequestClientAuth(ss) &&
|
||||
(ss->ssl3.hs.zeroRttState != ssl_0rtt_done)) {
|
||||
dtls_ReceivedFirstMessageInFlight(ss);
|
||||
}
|
||||
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
|
||||
CipherSpecRead, PR_FALSE);
|
||||
ssl_secret_read, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (IS_DTLS(ss)) {
|
||||
ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead, TrafficKeyClearText);
|
||||
ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyClearText);
|
||||
/* We need to keep the handshake cipher spec so we can
|
||||
* read re-transmitted client Finished. */
|
||||
rv = dtls_StartTimer(ss, ss->ssl3.hs.hdTimer,
|
||||
|
@ -4361,7 +4556,7 @@ tls13_SendClientSecondFlight(sslSocket *ss, PRBool sendClientCert,
|
|||
}
|
||||
}
|
||||
|
||||
rv = tls13_SendFinished(ss, ss->ssl3.hs.clientHsTrafficSecret);
|
||||
rv = tls13_SendFinished(ss, ss->firstHsDone ? ss->ssl3.hs.clientTrafficSecret : ss->ssl3.hs.clientHsTrafficSecret);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure; /* err code was set. */
|
||||
}
|
||||
|
@ -4404,7 +4599,8 @@ tls13_SendClientSecondRound(sslSocket *ss)
|
|||
" certificate authentication is still pending.",
|
||||
SSL_GETPID(), ss->fd));
|
||||
ss->ssl3.hs.restartTarget = tls13_SendClientSecondRound;
|
||||
return SECWouldBlock;
|
||||
PORT_SetError(PR_WOULD_BLOCK_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = tls13_ComputeApplicationSecrets(ss);
|
||||
|
@ -4432,14 +4628,14 @@ tls13_SendClientSecondRound(sslSocket *ss)
|
|||
}
|
||||
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
|
||||
CipherSpecWrite, PR_FALSE);
|
||||
ssl_secret_write, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
|
||||
CipherSpecRead, PR_FALSE);
|
||||
ssl_secret_read, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
|
||||
return SECFailure;
|
||||
|
@ -4457,7 +4653,7 @@ tls13_SendClientSecondRound(sslSocket *ss)
|
|||
return SECFailure;
|
||||
}
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyApplicationData,
|
||||
CipherSpecWrite, PR_FALSE);
|
||||
ssl_secret_write, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
||||
return SECFailure;
|
||||
|
@ -4815,7 +5011,8 @@ static const struct {
|
|||
{ ssl_tls13_supported_versions_xtn, _M3(client_hello, server_hello,
|
||||
hello_retry_request) },
|
||||
{ ssl_record_size_limit_xtn, _M2(client_hello, encrypted_extensions) },
|
||||
{ ssl_tls13_encrypted_sni_xtn, _M2(client_hello, encrypted_extensions) }
|
||||
{ ssl_tls13_encrypted_sni_xtn, _M2(client_hello, encrypted_extensions) },
|
||||
{ ssl_tls13_post_handshake_auth_xtn, _M1(client_hello) }
|
||||
};
|
||||
|
||||
tls13ExtensionStatus
|
||||
|
@ -4924,7 +5121,7 @@ tls13_ProtectRecord(sslSocket *ss,
|
|||
const int tagLen = cipher_def->tag_size;
|
||||
SECStatus rv;
|
||||
|
||||
PORT_Assert(cwSpec->direction == CipherSpecWrite);
|
||||
PORT_Assert(cwSpec->direction == ssl_secret_write);
|
||||
SSL_TRC(3, ("%d: TLS13[%d]: spec=%d epoch=%d (%s) protect 0x%0llx len=%u",
|
||||
SSL_GETPID(), ss->fd, cwSpec, cwSpec->epoch, cwSpec->phase,
|
||||
cwSpec->nextSeqNum, contentLen));
|
||||
|
@ -5018,7 +5215,7 @@ tls13_UnprotectRecord(sslSocket *ss,
|
|||
|
||||
*alert = bad_record_mac; /* Default alert for most issues. */
|
||||
|
||||
PORT_Assert(spec->direction == CipherSpecRead);
|
||||
PORT_Assert(spec->direction == ssl_secret_read);
|
||||
SSL_TRC(3, ("%d: TLS13[%d]: spec=%d epoch=%d (%s) unprotect 0x%0llx len=%u",
|
||||
SSL_GETPID(), ss->fd, spec, spec->epoch, spec->phase,
|
||||
cText->seqNum, cText->buf->len));
|
||||
|
@ -5175,6 +5372,9 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
|
|||
|
||||
ss->ssl3.hs.zeroRttState = ssl_0rtt_sent;
|
||||
ss->ssl3.hs.zeroRttSuite = ss->ssl3.hs.cipher_suite;
|
||||
/* Note: Reset the preliminary info here rather than just add 0-RTT. We are
|
||||
* only guessing what might happen at this point.*/
|
||||
ss->ssl3.hs.preliminaryInfo = ssl_preinfo_0rtt_cipher_suite;
|
||||
|
||||
SSL_TRC(3, ("%d: TLS13[%d]: in 0-RTT mode", SSL_GETPID(), ss->fd));
|
||||
|
||||
|
@ -5203,9 +5403,6 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
|
|||
}
|
||||
}
|
||||
|
||||
/* Cipher suite already set in tls13_SetupClientHello. */
|
||||
ss->ssl3.hs.preliminaryInfo = 0;
|
||||
|
||||
rv = tls13_DeriveEarlySecrets(ss);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
|
@ -5216,7 +5413,7 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss)
|
|||
ssl_CipherSpecAddRef(ss->ssl3.cwSpec);
|
||||
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyEarlyApplicationData,
|
||||
CipherSpecWrite, PR_TRUE);
|
||||
ssl_secret_write, PR_TRUE);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
@ -5279,7 +5476,7 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
|
|||
/* We shouldn't be getting any more early data, and if we do,
|
||||
* it is because of reordering and we drop it. */
|
||||
if (IS_DTLS(ss)) {
|
||||
ssl_CipherSpecReleaseByEpoch(ss, CipherSpecRead,
|
||||
ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read,
|
||||
TrafficKeyEarlyApplicationData);
|
||||
dtls_ReceivedFirstMessageInFlight(ss);
|
||||
}
|
||||
|
@ -5292,7 +5489,7 @@ tls13_HandleEndOfEarlyData(sslSocket *ss, PRUint8 *b, PRUint32 length)
|
|||
}
|
||||
|
||||
rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake,
|
||||
CipherSpecRead, PR_FALSE);
|
||||
ssl_secret_read, PR_FALSE);
|
||||
if (rv != SECSuccess) {
|
||||
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
||||
return SECFailure;
|
||||
|
|
|
@ -131,6 +131,7 @@ SECStatus SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate);
|
|||
PRBool tls13_MaybeTls13(sslSocket *ss);
|
||||
SSLAEADCipher tls13_GetAead(const ssl3BulkCipherDef *cipherDef);
|
||||
void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec);
|
||||
SECStatus SSLExp_SendCertificateRequest(PRFileDesc *fd);
|
||||
|
||||
/* Use this instead of FATAL_ERROR when no alert shall be sent. */
|
||||
#define LOG_ERROR(ss, prError) \
|
||||
|
|
|
@ -915,6 +915,37 @@ tls13_ServerHandleCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
|
|||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
tls13_ClientSendPostHandshakeAuthXtn(const sslSocket *ss,
|
||||
TLSExtensionData *xtnData,
|
||||
sslBuffer *buf, PRBool *added)
|
||||
{
|
||||
SSL_TRC(3, ("%d: TLS13[%d]: send post_handshake_auth extension",
|
||||
SSL_GETPID(), ss->fd));
|
||||
|
||||
*added = ss->opt.enablePostHandshakeAuth;
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
tls13_ServerHandlePostHandshakeAuthXtn(const sslSocket *ss,
|
||||
TLSExtensionData *xtnData,
|
||||
SECItem *data)
|
||||
{
|
||||
SSL_TRC(3, ("%d: TLS13[%d]: handle post_handshake_auth extension",
|
||||
SSL_GETPID(), ss->fd));
|
||||
|
||||
if (data->len) {
|
||||
PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* Keep track of negotiated extensions. */
|
||||
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_post_handshake_auth_xtn;
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;
|
||||
*
|
||||
|
|
|
@ -93,5 +93,11 @@ SECStatus tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData
|
|||
SECStatus tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
|
||||
SECItem *data);
|
||||
SECStatus tls13_ClientCheckEsniXtn(sslSocket *ss);
|
||||
SECStatus tls13_ClientSendPostHandshakeAuthXtn(const sslSocket *ss,
|
||||
TLSExtensionData *xtnData,
|
||||
sslBuffer *buf, PRBool *added);
|
||||
SECStatus tls13_ServerHandlePostHandshakeAuthXtn(const sslSocket *ss,
|
||||
TLSExtensionData *xtnData,
|
||||
SECItem *data);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -168,6 +168,7 @@
|
|||
'cmd/pk11ectest/pk11ectest.gyp:pk11ectest',
|
||||
'cmd/pk11gcmtest/pk11gcmtest.gyp:pk11gcmtest',
|
||||
'cmd/pk11mode/pk11mode.gyp:pk11mode',
|
||||
'cmd/pk11importtest/pk11importtest.gyp:pk11importtest',
|
||||
'cmd/pk1sign/pk1sign.gyp:pk1sign',
|
||||
'cmd/pp/pp.gyp:pp',
|
||||
'cmd/rsaperf/rsaperf.gyp:rsaperf',
|
||||
|
|
|
@ -252,7 +252,15 @@ dbtest_main()
|
|||
else
|
||||
html_passed "Nicknane conflict test-setting nickname conflict was correctly rejected"
|
||||
fi
|
||||
|
||||
# import a token private key and make sure the corresponding public key is
|
||||
# created
|
||||
${BINDIR}/pk11importtest -d ${CONFLICT_DIR} -f ${R_PWFILE}
|
||||
ret=$?
|
||||
if [ $ret -ne 0 ]; then
|
||||
html_failed "Importing Token Private Key does not create the corrresponding Public Key"
|
||||
else
|
||||
html_passed "Importing Token Private Key correctly creates the corrresponding Public Key"
|
||||
fi
|
||||
}
|
||||
|
||||
################## main #################################################
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
gtest_init()
|
||||
{
|
||||
cd "$(dirname "$1")"
|
||||
SOURCE_DIR="$PWD"/../..
|
||||
if [ -z "${INIT_SOURCED}" -o "${INIT_SOURCED}" != "TRUE" ]; then
|
||||
cd ../common
|
||||
. ./init.sh
|
||||
|
@ -33,6 +34,7 @@ gtest_init()
|
|||
if [ -z "${CLEANUP}" ] ; then # if nobody else is responsible for
|
||||
CLEANUP="${SCRIPTNAME}" # cleaning this script will do it
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
########################## gtest_start #############################
|
||||
|
@ -42,7 +44,7 @@ gtest_start()
|
|||
{
|
||||
echo "gtests: ${GTESTS}"
|
||||
for i in ${GTESTS}; do
|
||||
if [ ! -f ${BINDIR}/$i ]; then
|
||||
if [ ! -f "${BINDIR}/$i" ]; then
|
||||
html_unknown "Skipping $i (not built)"
|
||||
continue
|
||||
fi
|
||||
|
@ -50,20 +52,22 @@ gtest_start()
|
|||
html_head "$i"
|
||||
if [ ! -d "$GTESTDIR" ]; then
|
||||
mkdir -p "$GTESTDIR"
|
||||
echo "${BINDIR}/certutil" -N -d "$GTESTDIR" --empty-password 2>&1
|
||||
"${BINDIR}/certutil" -N -d "$GTESTDIR" --empty-password 2>&1
|
||||
fi
|
||||
cd "$GTESTDIR"
|
||||
GTESTREPORT="$GTESTDIR/report.xml"
|
||||
PARSED_REPORT="$GTESTDIR/report.parsed"
|
||||
echo "executing $i"
|
||||
${BINDIR}/$i "${SOURCE_DIR}/gtests/freebl_gtest/kat/Hash_DRBG.rsp" \
|
||||
-d "$GTESTDIR" --gtest_output=xml:"${GTESTREPORT}" \
|
||||
--gtest_filter="${GTESTFILTER-*}"
|
||||
"${BINDIR}/$i" "${SOURCE_DIR}/gtests/freebl_gtest/kat/Hash_DRBG.rsp" \
|
||||
-d "$GTESTDIR" -w --gtest_output=xml:"${GTESTREPORT}" \
|
||||
--gtest_filter="${GTESTFILTER:-*}"
|
||||
html_msg $? 0 "$i run successfully"
|
||||
echo "test output dir: ${GTESTREPORT}"
|
||||
echo "executing sed to parse the xml report"
|
||||
sed -f ${COMMON}/parsegtestreport.sed "${GTESTREPORT}" > "${PARSED_REPORT}"
|
||||
sed -f "${COMMON}/parsegtestreport.sed" "$GTESTREPORT" > "$PARSED_REPORT"
|
||||
echo "processing the parsed report"
|
||||
cat "${PARSED_REPORT}" | while read result name; do
|
||||
cat "$PARSED_REPORT" | while read result name; do
|
||||
if [ "$result" = "notrun" ]; then
|
||||
echo "$name" SKIPPED
|
||||
elif [ "$result" = "run" ]; then
|
||||
|
@ -78,13 +82,12 @@ gtest_start()
|
|||
gtest_cleanup()
|
||||
{
|
||||
html "</TABLE><BR>"
|
||||
cd ${QADIR}
|
||||
cd "${QADIR}"
|
||||
. common/cleanup.sh
|
||||
}
|
||||
|
||||
################## main #################################################
|
||||
GTESTS="prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest softoken_gtest sysinit_gtest blake2b_gtest"
|
||||
SOURCE_DIR="$PWD"/../..
|
||||
gtest_init $0
|
||||
GTESTS="${GTESTS:-prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest softoken_gtest sysinit_gtest blake2b_gtest}"
|
||||
gtest_init "$0"
|
||||
gtest_start
|
||||
gtest_cleanup
|
||||
|
|
Загрузка…
Ссылка в новой задаче