mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-20 23:37:33 +09:00
Issue #1338 - Part 2: Update NSS to 3.48-RTM
This commit is contained in:
parent
1a92143e68
commit
c57cac24e8
885 changed files with 1650639 additions and 59530 deletions
|
|
@ -26,6 +26,16 @@ include $(CORE_DEPTH)/coreconf/config.mk
|
|||
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
|
||||
#######################################################################
|
||||
|
||||
# Don't build sysinit gtests unless we are also building libnsssysinit.
|
||||
# See lib/Makefile for the corresponding rules.
|
||||
ifndef MOZILLA_CLIENT
|
||||
ifeq ($(OS_ARCH),Linux)
|
||||
ifneq ($(NSS_BUILD_UTIL_ONLY),1)
|
||||
SYSINIT_GTEST=sysinit_gtest
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
|
|
|
|||
0
security/nss/gtests/__init__.py
Normal file
0
security/nss/gtests/__init__.py
Normal file
47
security/nss/gtests/certdb_gtest/cert_unittest.cc
Normal file
47
security/nss/gtests/certdb_gtest/cert_unittest.cc
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- 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 "gtest/gtest.h"
|
||||
|
||||
#include "nss.h"
|
||||
#include "secerr.h"
|
||||
#include "pk11pub.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class CertTest : public ::testing::Test {};
|
||||
|
||||
// Tests CERT_GetCertificateDer for the certs we have.
|
||||
TEST_F(CertTest, GetCertDer) {
|
||||
// Listing all the certs should get us the default trust anchors.
|
||||
ScopedCERTCertList certs(PK11_ListCerts(PK11CertListAll, nullptr));
|
||||
ASSERT_FALSE(PR_CLIST_IS_EMPTY(&certs->list));
|
||||
|
||||
for (PRCList* cursor = PR_NEXT_LINK(&certs->list); cursor != &certs->list;
|
||||
cursor = PR_NEXT_LINK(cursor)) {
|
||||
CERTCertListNode* node = (CERTCertListNode*)cursor;
|
||||
SECItem der;
|
||||
ASSERT_EQ(SECSuccess, CERT_GetCertificateDer(node->cert, &der));
|
||||
ASSERT_EQ(0, SECITEM_CompareItem(&der, &node->cert->derCert));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CertTest, GetCertDerBad) {
|
||||
EXPECT_EQ(SECFailure, CERT_GetCertificateDer(nullptr, nullptr));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
|
||||
ScopedCERTCertList certs(PK11_ListCerts(PK11CertListAll, nullptr));
|
||||
ASSERT_FALSE(PR_CLIST_IS_EMPTY(&certs->list));
|
||||
CERTCertListNode* node = (CERTCertListNode*)PR_NEXT_LINK(&certs->list);
|
||||
EXPECT_EQ(SECFailure, CERT_GetCertificateDer(node->cert, nullptr));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
|
||||
SECItem der;
|
||||
EXPECT_EQ(SECFailure, CERT_GetCertificateDer(nullptr, &der));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
'type': 'executable',
|
||||
'sources': [
|
||||
'alg1485_unittest.cc',
|
||||
'cert_unittest.cc',
|
||||
'decode_certs_unittest.cc',
|
||||
'<(DEPTH)/gtests/common/gtests.cc'
|
||||
],
|
||||
'dependencies': [
|
||||
|
|
@ -20,6 +22,7 @@
|
|||
'<(DEPTH)/lib/util/util.gyp:nssutil3',
|
||||
'<(DEPTH)/lib/ssl/ssl.gyp:ssl3',
|
||||
'<(DEPTH)/lib/nss/nss.gyp:nss3',
|
||||
'<(DEPTH)/lib/smime/smime.gyp:smime3',
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
|
|||
28
security/nss/gtests/certdb_gtest/decode_certs_unittest.cc
Normal file
28
security/nss/gtests/certdb_gtest/decode_certs_unittest.cc
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* -*- 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 "gtest/gtest.h"
|
||||
|
||||
#include "cert.h"
|
||||
#include "prerror.h"
|
||||
#include "secerr.h"
|
||||
|
||||
class DecodeCertsTest : public ::testing::Test {};
|
||||
|
||||
TEST_F(DecodeCertsTest, EmptyCertPackage) {
|
||||
// This represents a PKCS#7 ContentInfo with a contentType of
|
||||
// '2.16.840.1.113730.2.5' (Netscape data-type cert-sequence) and a content
|
||||
// consisting of an empty SEQUENCE. This is valid ASN.1, but it contains no
|
||||
// certificates, so CERT_DecodeCertFromPackage should just return a null
|
||||
// pointer.
|
||||
unsigned char emptyCertPackage[] = {0x30, 0x0f, 0x06, 0x09, 0x60, 0x86,
|
||||
0x48, 0x01, 0x86, 0xf8, 0x42, 0x02,
|
||||
0x05, 0xa0, 0x02, 0x30, 0x00};
|
||||
EXPECT_EQ(nullptr, CERT_DecodeCertFromPackage(
|
||||
reinterpret_cast<char*>(emptyCertPackage),
|
||||
sizeof(emptyCertPackage)));
|
||||
EXPECT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||
}
|
||||
|
|
@ -8,6 +8,8 @@ MODULE = nss
|
|||
|
||||
CPPSRCS = \
|
||||
alg1485_unittest.cc \
|
||||
cert_unittest.cc \
|
||||
decode_certs_unittest.cc \
|
||||
$(NULL)
|
||||
|
||||
INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
|
||||
|
|
|
|||
0
security/nss/gtests/common/__init__.py
Normal file
0
security/nss/gtests/common/__init__.py
Normal file
|
|
@ -21,6 +21,13 @@
|
|||
'libraries': [
|
||||
'-lws2_32',
|
||||
],
|
||||
'conditions': [
|
||||
['static_libs==1', {
|
||||
'libraries': [
|
||||
'-ladvapi32',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}],
|
||||
['OS=="android"', {
|
||||
'libraries': [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#include "nspr.h"
|
||||
#include "nss.h"
|
||||
#include "ssl.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
|
|
@ -10,10 +9,23 @@
|
|||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
if (NSS_NoDB_Init(nullptr) != SECSuccess) {
|
||||
return 1;
|
||||
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_SetDomesticPolicy() != SECSuccess) {
|
||||
|
||||
if (NSS_Initialize(workdir, "", "", SECMOD_DB, flags) != SECSuccess) {
|
||||
return 1;
|
||||
}
|
||||
int rv = RUN_ALL_TESTS();
|
||||
|
|
|
|||
3299
security/nss/gtests/common/testvectors/chachapoly-vectors.h
Normal file
3299
security/nss/gtests/common/testvectors/chachapoly-vectors.h
Normal file
File diff suppressed because it is too large
Load diff
1879
security/nss/gtests/common/testvectors/curve25519-vectors.h
Normal file
1879
security/nss/gtests/common/testvectors/curve25519-vectors.h
Normal file
File diff suppressed because it is too large
Load diff
1535
security/nss/gtests/common/testvectors/gcm-vectors.h
Normal file
1535
security/nss/gtests/common/testvectors/gcm-vectors.h
Normal file
File diff suppressed because it is too large
Load diff
1940
security/nss/gtests/common/testvectors/kw-vectors.h
Normal file
1940
security/nss/gtests/common/testvectors/kw-vectors.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,117 @@
|
|||
/* 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/. */
|
||||
|
||||
/* This file is generated from sources in nss/gtests/common/wycheproof
|
||||
* automatically and should not be touched manually.
|
||||
* Generation is trigged by calling ./mach wycheproof */
|
||||
|
||||
#ifndef chachapoly_vectors_h__
|
||||
#define chachapoly_vectors_h__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef struct chaChaTestVectorStr {
|
||||
uint32_t id;
|
||||
std::vector<uint8_t> Data;
|
||||
std::vector<uint8_t> AAD;
|
||||
std::vector<uint8_t> Key;
|
||||
std::vector<uint8_t> IV;
|
||||
std::vector<uint8_t> CT;
|
||||
bool invalidTag;
|
||||
bool invalidIV;
|
||||
} chaChaTestVector;
|
||||
|
||||
// ChaCha20/Poly1305 Test Vector 1, RFC 7539
|
||||
// <http://tools.ietf.org/html/rfc7539#section-2.8.2>
|
||||
// ChaCha20/Poly1305 Test Vector 2, RFC 7539
|
||||
// <http://tools.ietf.org/html/rfc7539#appendix-A.5>
|
||||
const chaChaTestVector kChaCha20Vectors[] = {
|
||||
{0,
|
||||
{0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47,
|
||||
0x65, 0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
|
||||
0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66,
|
||||
0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
|
||||
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79,
|
||||
0x6f, 0x75, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
|
||||
0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20,
|
||||
0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
|
||||
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
|
||||
0x62, 0x65, 0x20, 0x69, 0x74, 0x2e},
|
||||
{0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7},
|
||||
{0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
|
||||
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
|
||||
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f},
|
||||
{0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47},
|
||||
{0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc,
|
||||
0x53, 0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
|
||||
0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e,
|
||||
0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
|
||||
0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6,
|
||||
0x7e, 0xcd, 0x3b, 0x36, 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
|
||||
0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4,
|
||||
0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
|
||||
0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65,
|
||||
0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16, 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09,
|
||||
0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91},
|
||||
false,
|
||||
false},
|
||||
{1,
|
||||
{0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61,
|
||||
0x66, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66,
|
||||
0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20,
|
||||
0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20,
|
||||
0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x6f, 0x66, 0x20, 0x73,
|
||||
0x69, 0x78, 0x20, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e,
|
||||
0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x75, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63,
|
||||
0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f, 0x62, 0x73, 0x6f, 0x6c,
|
||||
0x65, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65,
|
||||
0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20,
|
||||
0x61, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e,
|
||||
0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x61, 0x70, 0x70,
|
||||
0x72, 0x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20,
|
||||
0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
||||
0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72,
|
||||
0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6d, 0x61, 0x74,
|
||||
0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20,
|
||||
0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6d, 0x20, 0x6f, 0x74,
|
||||
0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20,
|
||||
0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x20,
|
||||
0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80,
|
||||
0x9d},
|
||||
{0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x91},
|
||||
{0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, 0xf3, 0x33, 0x88,
|
||||
0x86, 0x04, 0xf6, 0xb5, 0xf0, 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b,
|
||||
0x80, 0x09, 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
|
||||
{0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4, 0x60, 0xf0, 0x62, 0xc7,
|
||||
0x9b, 0xe6, 0x43, 0xbd, 0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89,
|
||||
0xf1, 0x08, 0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2, 0x4c, 0x6c, 0xfc, 0x18,
|
||||
0x75, 0x5d, 0x43, 0xee, 0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0,
|
||||
0xbd, 0xb7, 0xb7, 0x3c, 0x32, 0x1b, 0x01, 0x00, 0xd4, 0xf0, 0x3b, 0x7f,
|
||||
0x35, 0x58, 0x94, 0xcf, 0x33, 0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce,
|
||||
0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b, 0x94, 0x81, 0x14, 0xad, 0x17, 0x6e,
|
||||
0x00, 0x8d, 0x33, 0xbd, 0x60, 0xf9, 0x82, 0xb1, 0xff, 0x37, 0xc8, 0x55,
|
||||
0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61, 0xc1, 0x86, 0x32, 0x4e,
|
||||
0x2b, 0x35, 0x06, 0x38, 0x36, 0x06, 0x90, 0x7b, 0x6a, 0x7c, 0x02, 0xb0,
|
||||
0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4, 0xb9, 0x16, 0x6c, 0x76,
|
||||
0x7b, 0x80, 0x4d, 0x46, 0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4, 0xe9,
|
||||
0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e, 0xe2, 0x82, 0xa1, 0xb0,
|
||||
0xa0, 0x6c, 0x52, 0x3e, 0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15,
|
||||
0x5b, 0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a, 0x0d, 0x07, 0x2b, 0x04,
|
||||
0xb3, 0x56, 0x4e, 0xea, 0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a,
|
||||
0x0b, 0xb2, 0x31, 0x60, 0x53, 0xfa, 0x76, 0x99, 0x19, 0x55, 0xeb, 0xd6,
|
||||
0x31, 0x59, 0x43, 0x4e, 0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10,
|
||||
0x73, 0xa6, 0x72, 0x76, 0x27, 0x09, 0x7a, 0x10, 0x49, 0xe6, 0x17, 0xd9,
|
||||
0x1d, 0x36, 0x10, 0x94, 0xfa, 0x68, 0xf0, 0xff, 0x77, 0x98, 0x71, 0x30,
|
||||
0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04, 0xdf, 0x99, 0x7b, 0x71, 0x4d,
|
||||
0x6c, 0x6f, 0x2c, 0x29, 0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70,
|
||||
0x9b, 0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb, 0x22, 0x39, 0x23, 0x36,
|
||||
0xfe, 0xa1, 0x85, 0x1f, 0x38},
|
||||
false,
|
||||
false}};
|
||||
|
||||
#endif // chachapoly_vectors_h__
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef curve25519_vectors_h__
|
||||
#define curve25519_vectors_h__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef struct curve25519_testvector_str {
|
||||
std::vector<uint8_t> private_key;
|
||||
std::vector<uint8_t> public_key;
|
||||
std::vector<uint8_t> secret;
|
||||
bool valid;
|
||||
} curve25519_testvector;
|
||||
|
||||
const curve25519_testvector kCurve25519Vectors[] = {
|
||||
{{0x30, 0x67, 0x02, 0x01, 0x00, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48,
|
||||
0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda,
|
||||
0x47, 0x0f, 0x01, 0x04, 0x4c, 0x30, 0x4a, 0x02, 0x01, 0x01, 0x04, 0x20,
|
||||
0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72,
|
||||
0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
|
||||
0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a, 0xa1, 0x23, 0x03, 0x21,
|
||||
0x00, 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d,
|
||||
0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a,
|
||||
0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a},
|
||||
{0x30, 0x39, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||
0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01,
|
||||
0x03, 0x21, 0x00, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3,
|
||||
0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b,
|
||||
0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f},
|
||||
{0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1, 0x72, 0x8e, 0x3b,
|
||||
0xf4, 0x80, 0x35, 0x0f, 0x25, 0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1,
|
||||
0x9e, 0x33, 0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42},
|
||||
true},
|
||||
|
||||
// A public key that's too short (31 bytes).
|
||||
{{0x30, 0x67, 0x02, 0x01, 0x00, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48,
|
||||
0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda,
|
||||
0x47, 0x0f, 0x01, 0x04, 0x4c, 0x30, 0x4a, 0x02, 0x01, 0x01, 0x04, 0x20,
|
||||
0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72,
|
||||
0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
|
||||
0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a, 0xa1, 0x23, 0x03, 0x21,
|
||||
0x00, 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d,
|
||||
0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a,
|
||||
0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a},
|
||||
{0x30, 0x38, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||
0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01,
|
||||
0x03, 0x20, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b,
|
||||
0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78,
|
||||
0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f},
|
||||
{},
|
||||
false},
|
||||
|
||||
// A public key that's too long (33 bytes).
|
||||
{{0x30, 0x67, 0x02, 0x01, 0x00, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48,
|
||||
0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda,
|
||||
0x47, 0x0f, 0x01, 0x04, 0x4c, 0x30, 0x4a, 0x02, 0x01, 0x01, 0x04, 0x20,
|
||||
0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72,
|
||||
0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
|
||||
0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a, 0xa1, 0x23, 0x03, 0x21,
|
||||
0x00, 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d,
|
||||
0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a,
|
||||
0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a},
|
||||
{0x30, 0x3a, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||
0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01,
|
||||
0x03, 0x22, 0x00, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3,
|
||||
0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b,
|
||||
0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f, 0x34},
|
||||
{},
|
||||
false}};
|
||||
|
||||
#endif // curve25519_vectors_h__
|
||||
|
|
@ -3,12 +3,17 @@
|
|||
* 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/. */
|
||||
|
||||
/* This file is generated from sources in nss/gtests/common/wycheproof
|
||||
* automatically and should not be touched manually.
|
||||
* Generation is trigged by calling ./mach wycheproof */
|
||||
|
||||
#ifndef gcm_vectors_h__
|
||||
#define gcm_vectors_h__
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef struct gcm_kat_str {
|
||||
uint32_t test_id;
|
||||
std::string key;
|
||||
std::string plaintext;
|
||||
std::string additional_data;
|
||||
|
|
@ -16,49 +21,55 @@ typedef struct gcm_kat_str {
|
|||
std::string hash_key;
|
||||
std::string ghash;
|
||||
std::string result;
|
||||
bool invalid_ct;
|
||||
bool invalid_iv;
|
||||
} gcm_kat_value;
|
||||
|
||||
/*
|
||||
* http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
|
||||
*/
|
||||
const gcm_kat_value kGcmKatValues[] = {
|
||||
{"00000000000000000000000000000000", "", "", "000000000000000000000000",
|
||||
{1, "00000000000000000000000000000000", "", "", "000000000000000000000000",
|
||||
"66e94bd4ef8a2c3b884cfa59ca342b2e", "00000000000000000000000000000000",
|
||||
"58e2fccefa7e3061367f1d57a4e7455a"},
|
||||
"58e2fccefa7e3061367f1d57a4e7455a", false, false},
|
||||
|
||||
{"00000000000000000000000000000000", "00000000000000000000000000000000", "",
|
||||
"000000000000000000000000", "66e94bd4ef8a2c3b884cfa59ca342b2e",
|
||||
{2, "00000000000000000000000000000000", "00000000000000000000000000000000",
|
||||
"", "000000000000000000000000", "66e94bd4ef8a2c3b884cfa59ca342b2e",
|
||||
"f38cbb1ad69223dcc3457ae5b6b0f885",
|
||||
"0388dace60b6a392f328c2b971b2fe78ab6e47d42cec13bdf53a67b21257bddf"},
|
||||
"0388dace60b6a392f328c2b971b2fe78ab6e47d42cec13bdf53a67b21257bddf", false,
|
||||
false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308",
|
||||
{3, "feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
|
||||
"", "cafebabefacedbaddecaf888", "b83b533708bf535d0aa6e52980d53b78",
|
||||
"7f1b32b81b820d02614f8895ac1d4eac",
|
||||
"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25"
|
||||
"466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f59854d5c2af327cd64a62c"
|
||||
"f35abd2ba6fab4"},
|
||||
"f35abd2ba6fab4",
|
||||
false, false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308",
|
||||
{4, "feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2", "cafebabefacedbaddecaf888",
|
||||
"b83b533708bf535d0aa6e52980d53b78", "698e57f70e6ecc7fd9463b7260a9ae5f",
|
||||
"42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25"
|
||||
"466931c7d8f6a5aac84aa051ba30b396a0aac973d58e0915bc94fbc3221a5db94fae95ae7"
|
||||
"121a47"},
|
||||
"121a47",
|
||||
false, false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308",
|
||||
{5, "feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2", "cafebabefacedbad",
|
||||
"b83b533708bf535d0aa6e52980d53b78", "df586bb4c249b92cb6922877e444d37b",
|
||||
"61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e"
|
||||
"49f24b22b097544d4896b424989b5e1ebac0f07c23f45983612d2e79e3b0785561be14aac"
|
||||
"a2fccb"},
|
||||
"a2fccb",
|
||||
false, false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308",
|
||||
{6, "feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
|
|
@ -67,45 +78,51 @@ const gcm_kat_value kGcmKatValues[] = {
|
|||
"b83b533708bf535d0aa6e52980d53b78", "1c5afe9760d3932f3c9a878aac3dc3de",
|
||||
"8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4f"
|
||||
"ba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5619cc5aefffe0bfa462af43c16"
|
||||
"99d050"},
|
||||
"99d050",
|
||||
false, false},
|
||||
|
||||
{"000000000000000000000000000000000000000000000000", "", "",
|
||||
{7, "000000000000000000000000000000000000000000000000", "", "",
|
||||
"000000000000000000000000", "aae06992acbf52a3e8f4a96ec9300bd7",
|
||||
"00000000000000000000000000000000", "cd33b28ac773f74ba00ed1f312572435"},
|
||||
"00000000000000000000000000000000", "cd33b28ac773f74ba00ed1f312572435",
|
||||
false, false},
|
||||
|
||||
{"000000000000000000000000000000000000000000000000",
|
||||
{8, "000000000000000000000000000000000000000000000000",
|
||||
"00000000000000000000000000000000", "", "000000000000000000000000",
|
||||
"aae06992acbf52a3e8f4a96ec9300bd7", "e2c63f0ac44ad0e02efa05ab6743d4ce",
|
||||
"98e7247c07f0fe411c267e4384b0f6002ff58d80033927ab8ef4d4587514f0fb"},
|
||||
"98e7247c07f0fe411c267e4384b0f6002ff58d80033927ab8ef4d4587514f0fb", false,
|
||||
false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
{9, "feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
|
||||
"", "cafebabefacedbaddecaf888", "466923ec9ae682214f2c082badb39249",
|
||||
"51110d40f6c8fff0eb1ae33445a889f0",
|
||||
"3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c"
|
||||
"144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade2569924a7c8587336bfb1"
|
||||
"18024db8674a14"},
|
||||
"18024db8674a14",
|
||||
false, false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
{10, "feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2", "cafebabefacedbaddecaf888",
|
||||
"466923ec9ae682214f2c082badb39249", "ed2ce3062e4a8ec06db8b4c490e8a268",
|
||||
"3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c"
|
||||
"144c525ac619d18c84a3f4718e2448b2fe324d9ccda27102519498e80f1478f37ba55bd6d"
|
||||
"27618c"},
|
||||
"27618c",
|
||||
false, false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
{11, "feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2", "cafebabefacedbad",
|
||||
"466923ec9ae682214f2c082badb39249", "1e6a133806607858ee80eaf237064089",
|
||||
"0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9"
|
||||
"a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f765dcc57fcf623a24094fcca40d"
|
||||
"3533f8"},
|
||||
"3533f8",
|
||||
false, false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
{12, "feffe9928665731c6d6a8f9467308308feffe9928665731c",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
|
|
@ -114,45 +131,51 @@ const gcm_kat_value kGcmKatValues[] = {
|
|||
"466923ec9ae682214f2c082badb39249", "82567fb0b4cc371801eadec005968e94",
|
||||
"d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012a"
|
||||
"f34ddd9e2f037589b292db3e67c036745fa22e7e9b7373bdcf566ff291c25bbb8568fc3d3"
|
||||
"76a6d9"},
|
||||
"76a6d9",
|
||||
false, false},
|
||||
|
||||
{"0000000000000000000000000000000000000000000000000000000000000000", "", "",
|
||||
"000000000000000000000000", "dc95c078a2408989ad48a21492842087",
|
||||
"00000000000000000000000000000000", "530f8afbc74536b9a963b4f1c4cb738b"},
|
||||
{13, "0000000000000000000000000000000000000000000000000000000000000000", "",
|
||||
"", "000000000000000000000000", "dc95c078a2408989ad48a21492842087",
|
||||
"00000000000000000000000000000000", "530f8afbc74536b9a963b4f1c4cb738b",
|
||||
false, false},
|
||||
|
||||
{"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
{14, "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"00000000000000000000000000000000", "", "000000000000000000000000",
|
||||
"dc95c078a2408989ad48a21492842087", "83de425c5edc5d498f382c441041ca92",
|
||||
"cea7403d4d606b6e074ec5d3baf39d18d0d1c8a799996bf0265b98b5d48ab919"},
|
||||
"cea7403d4d606b6e074ec5d3baf39d18d0d1c8a799996bf0265b98b5d48ab919", false,
|
||||
false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
{15, "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
|
||||
"", "cafebabefacedbaddecaf888", "acbef20579b4b8ebce889bac8732dad7",
|
||||
"4db870d37cb75fcb46097c36230d1612",
|
||||
"522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e485"
|
||||
"90dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015adb094dac5d93471bdec"
|
||||
"1a502270e3cc6c"},
|
||||
"1a502270e3cc6c",
|
||||
false, false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
{16, "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2", "cafebabefacedbaddecaf888",
|
||||
"acbef20579b4b8ebce889bac8732dad7", "8bd0c4d8aacd391e67cca447e8c38f65",
|
||||
"522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e485"
|
||||
"90dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f66276fc6ece0f4e1768cddf8853bb"
|
||||
"2d551b"},
|
||||
"2d551b",
|
||||
false, false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
{17, "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2", "cafebabefacedbad",
|
||||
"acbef20579b4b8ebce889bac8732dad7", "75a34288b8c68f811c52b2e9a2f97f63",
|
||||
"c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33"
|
||||
"934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f3a337dbf46a792c45e454913fe"
|
||||
"2ea8f2"},
|
||||
"2ea8f2",
|
||||
false, false},
|
||||
|
||||
{"feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
{18, "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
|
||||
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c959"
|
||||
"56809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
|
||||
"feedfacedeadbeeffeedfacedeadbeefabaddad2",
|
||||
|
|
@ -161,12 +184,14 @@ const gcm_kat_value kGcmKatValues[] = {
|
|||
"acbef20579b4b8ebce889bac8732dad7", "d5ffcf6fc5ac4d69722187421a7f170b",
|
||||
"5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b78"
|
||||
"0f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3fa44a8266ee1c8eb0c8b5d4cf5a"
|
||||
"e9f19a"},
|
||||
"e9f19a",
|
||||
false, false},
|
||||
|
||||
/* Extra, non-NIST, test case to test 64-bit binary multiplication carry
|
||||
* correctness. This is a GHASH-only test. */
|
||||
{"", "", "", "", "0000000000000000fcefef64ffc4766c",
|
||||
{19, "", "", "", "", "0000000000000000fcefef64ffc4766c",
|
||||
"3561e34e52d8b598f9937982512fff27",
|
||||
"0000000000000000ffcef9ebbffdbd8b00000000000000000000000000000000"}};
|
||||
"0000000000000000ffcef9ebbffdbd8b00000000000000000000000000000000", false,
|
||||
false}};
|
||||
|
||||
#endif // gcm_vectors_h__
|
||||
|
|
@ -8,7 +8,21 @@
|
|||
#define util_h__
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
#include <vector>
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <codecvt>
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "nspr.h"
|
||||
|
||||
static inline std::vector<uint8_t> hex_string_to_bytes(std::string s) {
|
||||
std::vector<uint8_t> bytes;
|
||||
|
|
@ -18,4 +32,81 @@ static inline std::vector<uint8_t> hex_string_to_bytes(std::string s) {
|
|||
return bytes;
|
||||
}
|
||||
|
||||
// Given a prefix, attempts to create a unique directory that the user can do
|
||||
// work in without impacting other tests. For example, if given the prefix
|
||||
// "scratch", a directory like "scratch05c17b25" will be created in the current
|
||||
// working directory (or the location specified by NSS_GTEST_WORKDIR, if
|
||||
// defined).
|
||||
// Upon destruction, the implementation will attempt to delete the directory.
|
||||
// However, no attempt is made to first remove files in the directory - the
|
||||
// user is responsible for this. If the directory is not empty, deleting it will
|
||||
// fail.
|
||||
// Statistically, it is technically possible to fail to create a unique
|
||||
// directory name, but this is extremely unlikely given the expected workload of
|
||||
// this implementation.
|
||||
class ScopedUniqueDirectory {
|
||||
public:
|
||||
explicit ScopedUniqueDirectory(const std::string &prefix) {
|
||||
std::string path;
|
||||
const char *workingDirectory = PR_GetEnvSecure("NSS_GTEST_WORKDIR");
|
||||
if (workingDirectory) {
|
||||
path.assign(workingDirectory);
|
||||
}
|
||||
path.append(prefix);
|
||||
for (int i = 0; i < RETRY_LIMIT; i++) {
|
||||
std::string pathCopy(path);
|
||||
// TryMakingDirectory will modify its input. If it fails, we want to throw
|
||||
// away the modified result.
|
||||
if (TryMakingDirectory(pathCopy)) {
|
||||
mPath.assign(pathCopy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(mPath.length() > 0);
|
||||
#if defined(_WIN32)
|
||||
// sqldb always uses UTF-8 regardless of the current system locale.
|
||||
DWORD len =
|
||||
MultiByteToWideChar(CP_ACP, 0, mPath.data(), mPath.size(), nullptr, 0);
|
||||
std::vector<wchar_t> buf(len, L'\0');
|
||||
MultiByteToWideChar(CP_ACP, 0, mPath.data(), mPath.size(), buf.data(),
|
||||
buf.size());
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
mUTF8Path = converter.to_bytes(std::wstring(buf.begin(), buf.end()));
|
||||
#else
|
||||
mUTF8Path = mPath;
|
||||
#endif
|
||||
}
|
||||
|
||||
// NB: the directory must be empty upon destruction
|
||||
~ScopedUniqueDirectory() { assert(rmdir(mPath.c_str()) == 0); }
|
||||
|
||||
const std::string &GetPath() { return mPath; }
|
||||
const std::string &GetUTF8Path() { return mUTF8Path; }
|
||||
|
||||
private:
|
||||
static const int RETRY_LIMIT = 5;
|
||||
|
||||
static void GenerateRandomName(/*in/out*/ std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << prefix;
|
||||
// RAND_MAX is at least 32767.
|
||||
ss << std::setfill('0') << std::setw(4) << std::hex << rand() << rand();
|
||||
// This will overwrite the value of prefix. This is a little inefficient,
|
||||
// but at least it makes the code simple.
|
||||
ss >> prefix;
|
||||
}
|
||||
|
||||
static bool TryMakingDirectory(/*in/out*/ std::string &prefix) {
|
||||
GenerateRandomName(prefix);
|
||||
#if defined(_WIN32)
|
||||
return _mkdir(prefix.c_str()) == 0;
|
||||
#else
|
||||
return mkdir(prefix.c_str(), 0777) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string mPath;
|
||||
std::string mUTF8Path;
|
||||
};
|
||||
|
||||
#endif // util_h__
|
||||
|
|
|
|||
0
security/nss/gtests/common/wycheproof/__init__.py
Normal file
0
security/nss/gtests/common/wycheproof/__init__.py
Normal file
191
security/nss/gtests/common/wycheproof/genTestVectors.py
Normal file
191
security/nss/gtests/common/wycheproof/genTestVectors.py
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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/.
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Imports a JSON testvector file.
|
||||
def import_testvector(file):
|
||||
"""Import a JSON testvector file and return an array of the contained objects."""
|
||||
with open(file) as f:
|
||||
vectors = json.loads(f.read())
|
||||
return vectors
|
||||
|
||||
# Convert a test data string to a hex array.
|
||||
def string_to_hex_array(string):
|
||||
"""Convert a string of hex chars to a string representing a C-format array of hex bytes."""
|
||||
b = bytearray.fromhex(string)
|
||||
result = '{' + ', '.join("{:#04x}".format(x) for x in b) + '}'
|
||||
return result
|
||||
|
||||
# Writes one AES-GCM testvector into C-header format. (Not clang-format conform)
|
||||
class AESGCM():
|
||||
"""Class that provides the generator function for a single AES-GCM test case."""
|
||||
|
||||
def format_testcase(self, vector):
|
||||
"""Format an AES-GCM testcase object. Return a string in C-header format."""
|
||||
result = '{{ {},\n'.format(vector['tcId'])
|
||||
for key in ['key', 'msg', 'aad', 'iv']:
|
||||
result += ' \"{}\",\n'.format(vector[key])
|
||||
result += ' \"\",\n'
|
||||
result += ' \"{}\",\n'.format(vector['tag'])
|
||||
result += ' \"{}\",\n'.format(vector['ct'] + vector['tag'])
|
||||
result += ' {},\n'.format(str(vector['result'] == 'invalid').lower())
|
||||
result += ' {}}},\n\n'.format(str('ZeroLengthIv' in vector['flags']).lower())
|
||||
|
||||
return result
|
||||
|
||||
# Writes one ChaChaPoly testvector into C-header format. (Not clang-format conform)
|
||||
class ChaChaPoly():
|
||||
"""Class that provides the generator function for a single ChaCha test case."""
|
||||
|
||||
def format_testcase(self, testcase):
|
||||
"""Format an ChaCha testcase object. Return a string in C-header format."""
|
||||
result = '\n// Comment: {}'.format(testcase['comment'])
|
||||
result += '\n{{{},\n'.format(testcase['tcId']-1)
|
||||
for key in ['msg', 'aad', 'key', 'iv']:
|
||||
result += '{},\n'.format(string_to_hex_array(testcase[key]))
|
||||
ct = testcase['ct'] + testcase['tag']
|
||||
result += '{},\n'.format(string_to_hex_array(ct))
|
||||
result += '{},\n'.format(str(testcase['result'] == 'invalid').lower())
|
||||
result += '{}}},\n'.format(str(testcase['comment'] == 'invalid nonce size').lower())
|
||||
|
||||
return result
|
||||
|
||||
# Writes one Curve25519 testvector into C-header format. (Not clang-format conform)
|
||||
class Curve25519():
|
||||
"""Class that provides the generator function for a single curve25519 test case."""
|
||||
|
||||
# Static pkcs8 and skpi wrappers for the raw keys from Wycheproof.
|
||||
# The public key section of the pkcs8 wrapper is filled up with 0's, which is
|
||||
# not correct, but acceptable for the tests at this moment because
|
||||
# validity of the public key is not checked.
|
||||
# It's still necessary because of
|
||||
# https://searchfox.org/nss/rev/7bc70a3317b800aac07bad83e74b6c79a9ec5bff/lib/pk11wrap/pk11pk12.c#171
|
||||
pkcs8WrapperStart = "3067020100301406072a8648ce3d020106092b06010401da470f01044c304a0201010420"
|
||||
pkcs8WrapperEnd = "a1230321000000000000000000000000000000000000000000000000000000000000000000"
|
||||
spkiWrapper = "3039301406072a8648ce3d020106092b06010401da470f01032100"
|
||||
|
||||
def format_testcase(self, testcase):
|
||||
result = '\n// Comment: {}'.format(testcase['comment'])
|
||||
result += '\n{{{},\n'.format(string_to_hex_array(self.pkcs8WrapperStart + testcase['private'] + self.pkcs8WrapperEnd))
|
||||
result += '{},\n'.format(string_to_hex_array(self.spkiWrapper + testcase['public']))
|
||||
result += '{},\n'.format(string_to_hex_array(testcase['shared']))
|
||||
|
||||
# Flag 'acceptable' cases with secret == 0 as invalid for NSS.
|
||||
# Flag 'acceptable' cases with forbidden public key values as invalid for NSS.
|
||||
# Flag 'acceptable' cases with small public key (0 or 1) as invalid for NSS.
|
||||
valid = testcase['result'] in ['valid', 'acceptable'] \
|
||||
and not testcase['shared'] == "0000000000000000000000000000000000000000000000000000000000000000" \
|
||||
and not testcase["public"] == "daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" \
|
||||
and not testcase["public"] == "dbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" \
|
||||
and not 'Small public key' in testcase['flags']
|
||||
result += '{}}},\n'.format(str(valid).lower())
|
||||
|
||||
return result
|
||||
|
||||
def generate_vectors_file(params):
|
||||
"""
|
||||
Generate and store a .h-file with test vectors for one test.
|
||||
|
||||
params -- Dictionary with parameters for test vector generation for the desired test.
|
||||
"""
|
||||
|
||||
cases = import_testvector(os.path.join(script_dir, params['source_dir'] + params['source_file']))
|
||||
|
||||
with open(os.path.join(script_dir, params['base'])) as base:
|
||||
header = base.read()
|
||||
|
||||
header = header[:params['crop_size_start']]
|
||||
header += '\n\n// Testvectors from project wycheproof\n'
|
||||
header += '// <https://github.com/google/wycheproof>\n'
|
||||
vectors_file = header + params['array_init']
|
||||
|
||||
for group in cases['testGroups']:
|
||||
for test in group['tests']:
|
||||
vectors_file += params['formatter'].format_testcase(test)
|
||||
|
||||
vectors_file = vectors_file[:params['crop_size_end']] + '};\n\n'
|
||||
vectors_file += params['finish']
|
||||
|
||||
with open(os.path.join(script_dir, params['target']), 'w') as target:
|
||||
target.write(vectors_file)
|
||||
|
||||
# Parameters that describe the generation of a testvector file for each supoorted testself.
|
||||
# source -- relaive path the wycheproof JSON source file with testvectorsself.
|
||||
# base -- relative path to the pre-fabricated .h-file with general defintions and non-wycheproof vectors.
|
||||
# target -- relative path to where the finished .h-file is written.
|
||||
# crop_size_start -- number of characters removed from the end of the base file at start.
|
||||
# array_init -- string to initialize the c-header style array of testvectors.
|
||||
# formatter -- the test case formatter class to be used for this test.
|
||||
# crop_size_end -- number of characters removed from the end of the last generated test vector to close the array definiton.
|
||||
# finish -- string to re-insert at the end and finish the file. (identical to chars cropped at the start)
|
||||
# comment -- additional comments to add to the file just before defintion of the test vector array.
|
||||
aes_gcm_params = {
|
||||
'source_dir': 'source_vectors/',
|
||||
'source_file': 'aes_gcm_test.json',
|
||||
'base': '../testvectors_base/gcm-vectors_base.h',
|
||||
'target': '../testvectors/gcm-vectors.h',
|
||||
'crop_size_start': -27,
|
||||
'array_init': 'const gcm_kat_value kGcmWycheproofVectors[] = {\n',
|
||||
'formatter' : AESGCM(),
|
||||
'crop_size_end': -3,
|
||||
'finish': '#endif // gcm_vectors_h__\n',
|
||||
'comment' : ''
|
||||
}
|
||||
|
||||
chacha_poly_params = {
|
||||
'source_dir': 'source_vectors/',
|
||||
'source_file': 'chacha20_poly1305_test.json',
|
||||
'base': '../testvectors_base/chachapoly-vectors_base.h',
|
||||
'target': '../testvectors/chachapoly-vectors.h',
|
||||
'crop_size_start': -35,
|
||||
'array_init': 'const chacha_testvector kChaCha20WycheproofVectors[] = {\n',
|
||||
'formatter' : ChaChaPoly(),
|
||||
'crop_size_end': -2,
|
||||
'finish': '#endif // chachapoly_vectors_h__\n',
|
||||
'comment' : ''
|
||||
}
|
||||
|
||||
curve25519_params = {
|
||||
'source_dir': 'source_vectors/',
|
||||
'source_file': 'x25519_test.json',
|
||||
'base': '../testvectors_base/curve25519-vectors_base.h',
|
||||
'target': '../testvectors/curve25519-vectors.h',
|
||||
'crop_size_start': -34,
|
||||
'array_init': 'const curve25519_testvector kCurve25519WycheproofVectors[] = {\n',
|
||||
'formatter' : Curve25519(),
|
||||
'crop_size_end': -2,
|
||||
'finish': '#endif // curve25519_vectors_h__\n',
|
||||
'comment' : '// The public key section of the pkcs8 wrapped private key is\n\
|
||||
// filled up with 0\'s, which is not correct, but acceptable for the\n\
|
||||
// tests at this moment because validity of the public key is not checked.\n'
|
||||
}
|
||||
|
||||
def update_tests(tests):
|
||||
|
||||
remote = "https://raw.githubusercontent.com/google/wycheproof/master/testvectors/"
|
||||
for test in tests:
|
||||
subprocess.check_call(['wget', remote+test['source_file'], '-O',
|
||||
'gtests/common/wycheproof/source_vectors/' +test['source_file'],
|
||||
'--no-check-certificate'])
|
||||
|
||||
def generate_test_vectors():
|
||||
"""Generate C-header files for all supported tests."""
|
||||
all_tests = [aes_gcm_params, chacha_poly_params, curve25519_params]
|
||||
update_tests(all_tests)
|
||||
for test in all_tests:
|
||||
generate_vectors_file(test)
|
||||
|
||||
def main():
|
||||
generate_test_vectors()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,956 @@
|
|||
{
|
||||
"algorithm" : "X25519",
|
||||
"generatorVersion" : "0.4.12",
|
||||
"notes" : {
|
||||
"LowOrderPublic" : "Curve25519 or its twist contains some points of low order. This test vector contains a public key with such a point. While many libraries reject such public keys, doing so is not a strict requirement according to RFC 7748.",
|
||||
"Small public key" : "The public key is insecure and does not belong to a valid private key. Some libraries reject such keys.",
|
||||
"Twist" : "Public keys are either points on curve25519 or points on its twist. Implementations may either reject such keys or compute X25519 using the twist. If a point multiplication is performed then it is important that the result is correct, since otherwise attacks with invalid keys are possible."
|
||||
},
|
||||
"numberOfTests" : 87,
|
||||
"header" : [],
|
||||
"testGroups" : [
|
||||
{
|
||||
"curve" : "curve25519",
|
||||
"tests" : [
|
||||
{
|
||||
"tcId" : 1,
|
||||
"comment" : "normal case",
|
||||
"curve" : "curve25519",
|
||||
"public" : "9c647d9ae589b9f58fdc3ca4947efbc915c4b2e08e744a0edf469dac59c8f85a",
|
||||
"private" : "4852834d9d6b77dadeabaaf2e11dca66d19fe74993a7bec36c6e16a0983feaba",
|
||||
"shared" : "87b7f212b627f7a54ca5e0bcdaddd5389d9de6156cdbcf8ebe14ffbcfb436551",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 2,
|
||||
"comment" : "normal case",
|
||||
"curve" : "curve25519",
|
||||
"public" : "9c647d9ae589b9f58fdc3ca4947efbc915c4b2e08e744a0edf469dac59c8f85a",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "4b82bd8650ea9b81a42181840926a4ffa16434d1bf298de1db87efb5b0a9e34e",
|
||||
"result" : "valid",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 3,
|
||||
"comment" : "public key on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "63aa40c6e38346c5caf23a6df0a5e6c80889a08647e551b3563449befcfc9733",
|
||||
"private" : "588c061a50804ac488ad774ac716c3f5ba714b2712e048491379a500211998a8",
|
||||
"shared" : "b1a707519495ffffb298ff941716b06dfab87cf8d91123fe2be9a233dda22212",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 4,
|
||||
"comment" : "public key on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0f83c36fded9d32fadf4efa3ae93a90bb5cfa66893bc412c43fa7287dbb99779",
|
||||
"private" : "b05bfd32e55325d9fd648cb302848039000b390e44d521e58aab3b29a6960ba8",
|
||||
"shared" : "67dd4a6e165533534c0e3f172e4ab8576bca923a5f07b2c069b4c310ff2e935b",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 5,
|
||||
"comment" : "public key on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0b8211a2b6049097f6871c6c052d3c5fc1ba17da9e32ae458403b05bb283092a",
|
||||
"private" : "70e34bcbe1f47fbc0fddfd7c1e1aa53d57bfe0f66d243067b424bb6210bed19c",
|
||||
"shared" : "4a0638cfaa9ef1933b47f8939296a6b25be541ef7f70e844c0bcc00b134de64a",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 6,
|
||||
"comment" : "public key on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "343ac20a3b9c6a27b1008176509ad30735856ec1c8d8fcae13912d08d152f46c",
|
||||
"private" : "68c1f3a653a4cdb1d37bba94738f8b957a57beb24d646e994dc29a276aad458d",
|
||||
"shared" : "399491fce8dfab73b4f9f611de8ea0b27b28f85994250b0f475d585d042ac207",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 7,
|
||||
"comment" : "public key on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "fa695fc7be8d1be5bf704898f388c452bafdd3b8eae805f8681a8d15c2d4e142",
|
||||
"private" : "d877b26d06dff9d9f7fd4c5b3769f8cdd5b30516a5ab806be324ff3eb69ea0b2",
|
||||
"shared" : "2c4fe11d490a53861776b13b4354abd4cf5a97699db6e6c68c1626d07662f758",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 8,
|
||||
"comment" : "public key = 0",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"private" : "207494038f2bb811d47805bcdf04a2ac585ada7f2f23389bfd4658f9ddd4debc",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Small public key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 9,
|
||||
"comment" : "public key = 1",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"private" : "202e8972b61c7e61930eb9450b5070eae1c670475685541f0476217e4818cfab",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Small public key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 10,
|
||||
"comment" : "edge case on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0200000000000000000000000000000000000000000000000000000000000000",
|
||||
"private" : "38dde9f3e7b799045f9ac3793d4a9277dadeadc41bec0290f81f744f73775f84",
|
||||
"shared" : "9a2cfe84ff9c4a9739625cae4a3b82a906877a441946f8d7b3d795fe8f5d1639",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 11,
|
||||
"comment" : "edge case on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0300000000000000000000000000000000000000000000000000000000000000",
|
||||
"private" : "9857a914e3c29036fd9a442ba526b5cdcdf28216153e636c10677acab6bd6aa5",
|
||||
"shared" : "4da4e0aa072c232ee2f0fa4e519ae50b52c1edd08a534d4ef346c2e106d21d60",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 12,
|
||||
"comment" : "edge case on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ffffff030000f8ffff1f0000c0ffffff000000feffff070000f0ffff3f000000",
|
||||
"private" : "48e2130d723305ed05e6e5894d398a5e33367a8c6aac8fcdf0a88e4b42820db7",
|
||||
"shared" : "9ed10c53747f647f82f45125d3de15a1e6b824496ab40410ffcc3cfe95760f3b",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 13,
|
||||
"comment" : "edge case on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "000000fcffff070000e0ffff3f000000ffffff010000f8ffff0f0000c0ffff7f",
|
||||
"private" : "28f41011691851b3a62b641553b30d0dfddcb8fffcf53700a7be2f6a872e9fb0",
|
||||
"shared" : "cf72b4aa6aa1c9f894f4165b86109aa468517648e1f0cc70e1ab08460176506b",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 14,
|
||||
"comment" : "edge case on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffff7f",
|
||||
"private" : "18a93b6499b9f6b3225ca02fef410e0adec23532321d2d8ef1a6d602a8c65b83",
|
||||
"shared" : "5d50b62836bb69579410386cf7bb811c14bf85b1c7b17e5924c7ffea91ef9e12",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 15,
|
||||
"comment" : "edge case on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "eaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "c01d1305a1338a1fcac2ba7e2e032b427e0b04903165aca957d8d0553d8717b0",
|
||||
"shared" : "19230eb148d5d67c3c22ab1daeff80a57eae4265ce2872657b2c8099fc698e50",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 16,
|
||||
"comment" : "edge case for public key",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0400000000000000000000000000000000000000000000000000000000000000",
|
||||
"private" : "386f7f16c50731d64f82e6a170b142a4e34f31fd7768fcb8902925e7d1e21abe",
|
||||
"shared" : "0fcab5d842a078d7a71fc59b57bfb4ca0be6873b49dcdb9f44e14ae8fbdfa542",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 17,
|
||||
"comment" : "edge case for public key",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000",
|
||||
"private" : "e023a289bd5e90fa2804ddc019a05ef3e79d434bb6ea2f522ecb643a75296e95",
|
||||
"shared" : "54ce8f2275c077e3b1306a3939c5e03eef6bbb88060544758d9fef59b0bc3e4f",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 18,
|
||||
"comment" : "edge case for public key",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03",
|
||||
"private" : "68f010d62ee8d926053a361c3a75c6ea4ebdc8606ab285003a6f8f4076b01e83",
|
||||
"shared" : "f136775c5beb0af8110af10b20372332043cab752419678775a223df57c9d30d",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 19,
|
||||
"comment" : "edge case for public key",
|
||||
"curve" : "curve25519",
|
||||
"public" : "fffffffbfffffbffffdfffffdffffffffefffffefffff7fffff7ffffbfffff3f",
|
||||
"private" : "58ebcb35b0f8845caf1ec630f96576b62c4b7b6c36b29deb2cb0084651755c96",
|
||||
"shared" : "bf9affd06b844085586460962ef2146ff3d4533d9444aab006eb88cc3054407d",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 20,
|
||||
"comment" : "edge case for public key",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||
"private" : "188c4bc5b9c44b38bb658b9b2ae82d5b01015e093184b17cb7863503a783e1bb",
|
||||
"shared" : "d480de04f699cb3be0684a9cc2e31281ea0bc5a9dcc157d3d20158d46ca5246d",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 21,
|
||||
"comment" : "edge case for public key",
|
||||
"curve" : "curve25519",
|
||||
"public" : "fffffffffeffff7ffffffffffeffff7ffffffffffeffff7ffffffffffeffff7f",
|
||||
"private" : "e06c11bb2e13ce3dc7673f67f5482242909423a9ae95ee986a988d98faee23a2",
|
||||
"shared" : "4c4401cce6b51e4cb18f2790246c9bf914db667750a1cb89069092af07292276",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 22,
|
||||
"comment" : "edge case for public key",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ebffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "c0658c46dde18129293877535b1162b6f9f5414a23cf4d2cbc140a4d99da2b8f",
|
||||
"shared" : "578ba8cc2dbdc575afcf9df2b3ee6189f5337d6854c79b4ce165ea12293b3a0f",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 23,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800",
|
||||
"private" : "10255c9230a97a30a458ca284a629669293a31890cda9d147febc7d1e22d6bb1",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 24,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157",
|
||||
"private" : "78f1e8edf14481b389448dac8f59c70b038e7cf92ef2c7eff57a72466e115296",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 25,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "a0a05a3e8f9f44204d5f8059a94ac7dfc39a49ac016dd743dbfa43c5d671fd88",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 26,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "d0dbb3ed1906663f15420af31f4eaf6509d9a9949723500605ad7c1c6e7450a9",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 27,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "c0b1d0eb22b244fe3291140072cdd9d989b5f0ecd96c100feb5bca241c1d9f8f",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 28,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0000000000000000000000000000000000000000000000000000000000000080",
|
||||
"private" : "480bf45f594942a8bc0f3353c6e8b8853d77f351f1c2ca6c2d1abf8a00b4229c",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 29,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0100000000000000000000000000000000000000000000000000000000000080",
|
||||
"private" : "30f993fcf8514fc89bd8db14cd43ba0d4b2530e73c4276a05e1b145d420cedb4",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 30,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880",
|
||||
"private" : "c04974b758380e2a5b5df6eb09bb2f6b3434f982722a8e676d3da251d1b3de83",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 31,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7",
|
||||
"private" : "502a31373db32446842fe5add3e024022ea54f274182afc3d9f1bb3d39534eb5",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 32,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "90fa6417b0e37030fd6e43eff2abaef14c6793117a039cf621318ba90f4e98be",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 33,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "78ad3f26027f1c9fdd975a1613b947779bad2cf2b741ade01840885a30bb979c",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 34,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "98e23de7b1e0926ed9c87e7b14baf55f497a1d7096f93977680e44dc1c7b7b8b",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"LowOrderPublic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 35,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 36,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0100000000000000000000000000000000000000000000000000000000000000",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 37,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 38,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 39,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 40,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 41,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 42,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0000000000000000000000000000000000000000000000000000000000000080",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 43,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0100000000000000000000000000000000000000000000000000000000000080",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 44,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 45,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 46,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 47,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 48,
|
||||
"comment" : "public key with low order",
|
||||
"curve" : "curve25519",
|
||||
"public" : "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "1064a67da639a8f6df4fbea2d63358b65bca80a770712e14ea8a72df5a3313ae",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 49,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "f01e48dafac9d7bcf589cbc382c878d18bda3550589ffb5d50b523bebe329dae",
|
||||
"shared" : "bd36a0790eb883098c988b21786773de0b3a4df162282cf110de18dd484ce74b",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 50,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "288796bc5aff4b81a37501757bc0753a3c21964790d38699308debc17a6eaf8d",
|
||||
"shared" : "b4e0dd76da7b071728b61f856771aa356e57eda78a5b1655cc3820fb5f854c5c",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 51,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "98df845f6651bf1138221f119041f72b6dbc3c4ace7143d99fd55ad867480da8",
|
||||
"shared" : "6fdf6c37611dbd5304dc0f2eb7c9517eb3c50e12fd050ac6dec27071d4bfc034",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 52,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"private" : "f09498e46f02f878829e78b803d316a2ed695d0498a08abdf8276930e24edcb0",
|
||||
"shared" : "4c8fc4b1c6ab88fb21f18f6d4c810240d4e94651ba44f7a2c863cec7dc56602d",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 53,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0200000000000000000000000000000000000000000000000000000000000080",
|
||||
"private" : "1813c10a5c7f21f96e17f288c0cc37607c04c5f5aea2db134f9e2ffc66bd9db8",
|
||||
"shared" : "1cd0b28267dc541c642d6d7dca44a8b38a63736eef5c4e6501ffbbb1780c033c",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 54,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0300000000000000000000000000000000000000000000000000000000000080",
|
||||
"private" : "7857fb808653645a0beb138a64f5f4d733a45ea84c3cda11a9c06f7e7139149e",
|
||||
"shared" : "8755be01c60a7e825cff3e0e78cb3aa4333861516aa59b1c51a8b2a543dfa822",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 55,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0400000000000000000000000000000000000000000000000000000000000080",
|
||||
"private" : "e03aa842e2abc56e81e87b8b9f417b2a1e5913c723eed28d752f8d47a59f498f",
|
||||
"shared" : "54c9a1ed95e546d27822a360931dda60a1df049da6f904253c0612bbdc087476",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 56,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "f8f707b7999b18cb0d6b96124f2045972ca274bfc154ad0c87038c24c6d0d4b2",
|
||||
"shared" : "cc1f40d743cdc2230e1043daba8b75e810f1fbab7f255269bd9ebb29e6bf494f",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 57,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "dbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "a034f684fa631e1a348118c1ce4c98231f2d9eec9ba5365b4a05d69a785b0796",
|
||||
"shared" : "54998ee43a5b007bf499f078e736524400a8b5c7e9b9b43771748c7cdf880412",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 58,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "dcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "30b6c6a0f2ffa680768f992ba89e152d5bc9893d38c9119be4f767bfab6e0ca5",
|
||||
"shared" : "ead9b38efdd723637934e55ab717a7ae09eb86a21dc36a3feeb88b759e391e09",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 59,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "eaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "901b9dcf881e01e027575035d40b43bdc1c5242e030847495b0c7286469b6591",
|
||||
"shared" : "602ff40789b54b41805915fe2a6221f07a50ffc2c3fc94cf61f13d7904e88e0e",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 60,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ebffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "8046677c28fd82c9a1bdb71a1a1a34faba1225e2507fe3f54d10bd5b0d865f8e",
|
||||
"shared" : "e00ae8b143471247ba24f12c885536c3cb981b58e1e56b2baf35c12ae1f79c26",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 61,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "602f7e2f68a846b82cc269b1d48e939886ae54fd636c1fe074d710127d472491",
|
||||
"shared" : "98cb9b50dd3fc2b0d4f2d2bf7c5cfdd10c8fcd31fc40af1ad44f47c131376362",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 62,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "60887b3dc72443026ebedbbbb70665f42b87add1440e7768fbd7e8e2ce5f639d",
|
||||
"shared" : "38d6304c4a7e6d9f7959334fb5245bd2c754525d4c91db950206926234c1f633",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 63,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "78d31dfa854497d72d8def8a1b7fb006cec2d8c4924647c93814ae56faeda495",
|
||||
"shared" : "786cd54996f014a5a031ec14db812ed08355061fdb5de680a800ac521f318e23",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 64,
|
||||
"comment" : "public key >= p",
|
||||
"curve" : "curve25519",
|
||||
"public" : "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"private" : "c04c5baefa8302ddded6a4bb957761b4eb97aefa4fc3b8043085f96a5659b3a5",
|
||||
"shared" : "29ae8bc73e9b10a08b4f681c43c3e0ac1a171d31b38f1a48efba29ae639ea134",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 65,
|
||||
"comment" : "RFC 7748",
|
||||
"curve" : "curve25519",
|
||||
"public" : "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c",
|
||||
"private" : "a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44",
|
||||
"shared" : "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 66,
|
||||
"comment" : "RFC 7748",
|
||||
"curve" : "curve25519",
|
||||
"public" : "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a413",
|
||||
"private" : "4866e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba4d",
|
||||
"shared" : "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 67,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "0ab4e76380d84dde4f6833c58f2a9fb8f83bb0169b172be4b6e0592887741a36",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "0200000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 68,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "89e10d5701b4337d2d032181538b1064bd4084401ceca1fd12663a1959388000",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "0900000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 69,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "2b55d3aa4a8f80c8c0b2ae5f933e85af49beac36c2fa7394bab76c8933f8f81d",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "1000000000000000000000000000000000000000000000000000000000000000",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 70,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "63e5b1fe9601fe84385d8866b0421262f78fbfa5aff9585e626679b18547d959",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 71,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "e428f3dac17809f827a522ce32355058d07369364aa78902ee10139b9f9dd653",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "fcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 72,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "b3b50e3ed3a407b95de942ef74575b5ab8a10c09ee103544d60bdfed8138ab2b",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "f9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 73,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "213fffe93d5ea8cd242e462844029922c43c77c9e3e42f562f485d24c501a20b",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 74,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "91b232a178b3cd530932441e6139418f72172292f1da4c1834fc5ebfefb51e3f",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 75,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "045c6e11c5d332556c7822fe94ebf89b56a3878dc27ca079103058849fabcb4f",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "e5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 76,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "1ca2190b71163539063c35773bda0c9c928e9136f0620aeb093f099197b7f74e",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "e3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 77,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "f76e9010ac33c5043b2d3b76a842171000c4916222e9e85897a0aec7f6350b3c",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 78,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "bb72688d8f8aa7a39cd6060cd5c8093cdec6fe341937c3886a99346cd07faa55",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "dbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 79,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "88fddea193391c6a5933ef9b71901549447205aae9da928a6b91a352ba10f41f",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000000002",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 80,
|
||||
"comment" : "edge case for shared secret",
|
||||
"curve" : "curve25519",
|
||||
"public" : "303b392f153116cad9cc682a00ccc44c95ff0d3bbe568beb6c4e739bafdc2c68",
|
||||
"private" : "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63",
|
||||
"shared" : "0000000000000000000000000000000000000000000000000000000000008000",
|
||||
"result" : "acceptable",
|
||||
"flags" : [
|
||||
"Twist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"tcId" : 81,
|
||||
"comment" : "checking for overflow",
|
||||
"curve" : "curve25519",
|
||||
"public" : "fd300aeb40e1fa582518412b49b208a7842b1e1f056a040178ea4141534f652d",
|
||||
"private" : "c81724704000b26d31703cc97e3a378d56fad8219361c88cca8bd7c5719b12b2",
|
||||
"shared" : "b734105dc257585d73b566ccb76f062795ccbec89128e52b02f3e59639f13c46",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 82,
|
||||
"comment" : "checking for overflow",
|
||||
"curve" : "curve25519",
|
||||
"public" : "c8ef79b514d7682677bc7931e06ee5c27c9b392b4ae9484473f554e6678ecc2e",
|
||||
"private" : "c81724704000b26d31703cc97e3a378d56fad8219361c88cca8bd7c5719b12b2",
|
||||
"shared" : "647a46b6fc3f40d62141ee3cee706b4d7a9271593a7b143e8e2e2279883e4550",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 83,
|
||||
"comment" : "checking for overflow",
|
||||
"curve" : "curve25519",
|
||||
"public" : "64aeac2504144861532b7bbcb6c87d67dd4c1f07ebc2e06effb95aecc6170b2c",
|
||||
"private" : "c81724704000b26d31703cc97e3a378d56fad8219361c88cca8bd7c5719b12b2",
|
||||
"shared" : "4ff03d5fb43cd8657a3cf37c138cadcecce509e4eba089d0ef40b4e4fb946155",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 84,
|
||||
"comment" : "checking for overflow",
|
||||
"curve" : "curve25519",
|
||||
"public" : "bf68e35e9bdb7eee1b50570221860f5dcdad8acbab031b14974cc49013c49831",
|
||||
"private" : "c81724704000b26d31703cc97e3a378d56fad8219361c88cca8bd7c5719b12b2",
|
||||
"shared" : "21cee52efdbc812e1d021a4af1e1d8bc4db3c400e4d2a2c56a3926db4d99c65b",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 85,
|
||||
"comment" : "checking for overflow",
|
||||
"curve" : "curve25519",
|
||||
"public" : "5347c491331a64b43ddc683034e677f53dc32b52a52a577c15a83bf298e99f19",
|
||||
"private" : "c81724704000b26d31703cc97e3a378d56fad8219361c88cca8bd7c5719b12b2",
|
||||
"shared" : "18cb89e4e20c0c2bd324305245266c9327690bbe79acb88f5b8fb3f74eca3e52",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 86,
|
||||
"comment" : "private key == -1 (mod order)",
|
||||
"curve" : "curve25519",
|
||||
"public" : "258e04523b8d253ee65719fc6906c657192d80717edc828fa0af21686e2faa75",
|
||||
"private" : "a023cdd083ef5bb82f10d62e59e15a6800000000000000000000000000000050",
|
||||
"shared" : "258e04523b8d253ee65719fc6906c657192d80717edc828fa0af21686e2faa75",
|
||||
"result" : "valid",
|
||||
"flags" : []
|
||||
},
|
||||
{
|
||||
"tcId" : 87,
|
||||
"comment" : "private key == 1 (mod order) on twist",
|
||||
"curve" : "curve25519",
|
||||
"public" : "2eae5ec3dd494e9f2d37d258f873a8e6e9d0dbd1e383ef64d98bb91b3e0be035",
|
||||
"private" : "58083dd261ad91eff952322ec824c682ffffffffffffffffffffffffffffff5f",
|
||||
"shared" : "2eae5ec3dd494e9f2d37d258f873a8e6e9d0dbd1e383ef64d98bb91b3e0be035",
|
||||
"result" : "acceptable",
|
||||
"flags" : []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -16,17 +16,35 @@
|
|||
#include "secerr.h"
|
||||
#include "secitem.h"
|
||||
|
||||
const SEC_ASN1Template mySEC_NullTemplate[] = {
|
||||
{SEC_ASN1_NULL, 0, NULL, sizeof(SECItem)}};
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class QuickDERTest : public ::testing::Test,
|
||||
public ::testing::WithParamInterface<SECItem> {};
|
||||
struct TemplateAndInput {
|
||||
const SEC_ASN1Template* t;
|
||||
SECItem input;
|
||||
};
|
||||
|
||||
class QuickDERTest : public ::testing::Test,
|
||||
public ::testing::WithParamInterface<TemplateAndInput> {};
|
||||
|
||||
static const uint8_t kBitstringTag = 0x03;
|
||||
static const uint8_t kNullTag = 0x05;
|
||||
static const uint8_t kLongLength = 0x80;
|
||||
|
||||
const SEC_ASN1Template kBitstringTemplate[] = {
|
||||
{SEC_ASN1_BIT_STRING, 0, NULL, sizeof(SECItem)}, {0}};
|
||||
|
||||
// Empty bitstring with unused bits.
|
||||
static uint8_t kEmptyBitstringUnused[] = {kBitstringTag, 1, 1};
|
||||
|
||||
// Bitstring with 8 unused bits.
|
||||
static uint8_t kBitstring8Unused[] = {kBitstringTag, 3, 8, 0xff, 0x00};
|
||||
|
||||
// Bitstring with >8 unused bits.
|
||||
static uint8_t kBitstring9Unused[] = {kBitstringTag, 3, 9, 0xff, 0x80};
|
||||
|
||||
const SEC_ASN1Template kNullTemplate[] = {
|
||||
{SEC_ASN1_NULL, 0, NULL, sizeof(SECItem)}, {0}};
|
||||
|
||||
// Length of zero wrongly encoded as 0x80 instead of 0x00.
|
||||
static uint8_t kOverlongLength_0_0[] = {kNullTag, kLongLength | 0};
|
||||
|
||||
|
|
@ -53,14 +71,22 @@ static uint8_t kOverlongLength_16_0[] = {kNullTag, kLongLength | 0x10,
|
|||
0x00, 0x00,
|
||||
0x00, 0x00};
|
||||
|
||||
static const SECItem kInvalidDER[] = {
|
||||
{siBuffer, kOverlongLength_0_0, sizeof(kOverlongLength_0_0)},
|
||||
{siBuffer, kOverlongLength_1_0, sizeof(kOverlongLength_1_0)},
|
||||
{siBuffer, kOverlongLength_16_0, sizeof(kOverlongLength_16_0)},
|
||||
#define TI(t, x) \
|
||||
{ \
|
||||
t, { siBuffer, x, sizeof(x) } \
|
||||
}
|
||||
static const TemplateAndInput kInvalidDER[] = {
|
||||
TI(kBitstringTemplate, kEmptyBitstringUnused),
|
||||
TI(kBitstringTemplate, kBitstring8Unused),
|
||||
TI(kBitstringTemplate, kBitstring9Unused),
|
||||
TI(kNullTemplate, kOverlongLength_0_0),
|
||||
TI(kNullTemplate, kOverlongLength_1_0),
|
||||
TI(kNullTemplate, kOverlongLength_16_0),
|
||||
};
|
||||
#undef TI
|
||||
|
||||
TEST_P(QuickDERTest, InvalidLengths) {
|
||||
const SECItem& original_input(GetParam());
|
||||
const SECItem& original_input(GetParam().input);
|
||||
|
||||
ScopedSECItem copy_of_input(SECITEM_AllocItem(nullptr, nullptr, 0U));
|
||||
ASSERT_TRUE(copy_of_input);
|
||||
|
|
@ -69,11 +95,10 @@ TEST_P(QuickDERTest, InvalidLengths) {
|
|||
|
||||
PORTCheapArenaPool pool;
|
||||
PORT_InitCheapArena(&pool, DER_DEFAULT_CHUNKSIZE);
|
||||
ScopedSECItem parsed_value(SECITEM_AllocItem(nullptr, nullptr, 0U));
|
||||
ASSERT_TRUE(parsed_value);
|
||||
StackSECItem parsed_value;
|
||||
ASSERT_EQ(SECFailure,
|
||||
SEC_QuickDERDecodeItem(&pool.arena, parsed_value.get(),
|
||||
mySEC_NullTemplate, copy_of_input.get()));
|
||||
SEC_QuickDERDecodeItem(&pool.arena, &parsed_value, GetParam().t,
|
||||
copy_of_input.get()));
|
||||
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||
PORT_DestroyCheapArena(&pool);
|
||||
}
|
||||
|
|
|
|||
187
security/nss/gtests/freebl_gtest/cmac_unittests.cc
Normal file
187
security/nss/gtests/freebl_gtest/cmac_unittests.cc
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
// 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 "gtest/gtest.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
|
||||
#include "blapi.h"
|
||||
#include "secitem.h"
|
||||
#include "freebl_scoped_ptrs.h"
|
||||
|
||||
class CmacAesTest : public ::testing::Test {
|
||||
protected:
|
||||
bool Compare(const uint8_t *actual, const uint8_t *expected,
|
||||
unsigned int length) {
|
||||
return strncmp((const char *)actual, (const char *)expected, length) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CmacAesTest, CreateInvalidSize) {
|
||||
uint8_t key[1] = {0x00};
|
||||
ScopedCMACContext ctx(CMAC_Create(CMAC_AES, key, sizeof(key)));
|
||||
ASSERT_EQ(ctx, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(CmacAesTest, CreateRightSize) {
|
||||
uint8_t *key = PORT_NewArray(uint8_t, AES_128_KEY_LENGTH);
|
||||
ScopedCMACContext ctx(CMAC_Create(CMAC_AES, key, AES_128_KEY_LENGTH));
|
||||
|
||||
ASSERT_NE(ctx, nullptr);
|
||||
PORT_Free(key);
|
||||
}
|
||||
|
||||
// The following tests were taken from NIST's Cryptographic Standards and
|
||||
// Guidelines page for AES-CMAC Examples with Intermediate Values. These same
|
||||
// test vectors for AES-128 can be found in RFC 4493, Section 4.
|
||||
|
||||
static const uint8_t kNistKeys[][AES_256_KEY_LENGTH] = {
|
||||
{0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15,
|
||||
0x88, 0x09, 0xCF, 0x4F, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, 0xC8, 0x10, 0xF3,
|
||||
0x2B, 0x80, 0x90, 0x79, 0xE5, 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C,
|
||||
0x6B, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
{0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, 0x2B, 0x73, 0xAE,
|
||||
0xF0, 0x85, 0x7D, 0x77, 0x81, 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61,
|
||||
0x08, 0xD7, 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4}};
|
||||
static const size_t kNistKeyLengthsCount = PR_ARRAY_SIZE(kNistKeys);
|
||||
static const unsigned int kNistKeyLengths[kNistKeyLengthsCount] = {
|
||||
AES_128_KEY_LENGTH, AES_192_KEY_LENGTH, AES_256_KEY_LENGTH};
|
||||
|
||||
static const uint8_t kNistPlaintext[64] = {
|
||||
0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E,
|
||||
0x11, 0x73, 0x93, 0x17, 0x2A, 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03,
|
||||
0xAC, 0x9C, 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, 0x30,
|
||||
0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, 0xE5, 0xFB, 0xC1, 0x19,
|
||||
0x1A, 0x0A, 0x52, 0xEF, 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B,
|
||||
0x17, 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10};
|
||||
static const unsigned int kNistPlaintextLengths[] = {0, 16, 20, 64};
|
||||
static const size_t kNistPlaintextLengthsCount =
|
||||
PR_ARRAY_SIZE(kNistPlaintextLengths);
|
||||
|
||||
// This table contains the result of a CMAC over kNistPlaintext using keys from
|
||||
// kNistKeys. For each key, there are kNistPlaintextLengthsCount answers, all
|
||||
// listed one after the other as the input is truncated to the different sizes
|
||||
// in kNistPlaintextLengths.
|
||||
static const uint8_t kNistKnown[][AES_BLOCK_SIZE] = {
|
||||
{0xBB, 0x1D, 0x69, 0x29, 0xE9, 0x59, 0x37, 0x28, 0x7F, 0xA3, 0x7D, 0x12,
|
||||
0x9B, 0x75, 0x67, 0x46},
|
||||
{0x07, 0x0A, 0x16, 0xB4, 0x6B, 0x4D, 0x41, 0x44, 0xF7, 0x9B, 0xDD, 0x9D,
|
||||
0xD0, 0x4A, 0x28, 0x7C},
|
||||
{0x7D, 0x85, 0x44, 0x9E, 0xA6, 0xEA, 0x19, 0xC8, 0x23, 0xA7, 0xBF, 0x78,
|
||||
0x83, 0x7D, 0xFA, 0xDE},
|
||||
{0x51, 0xF0, 0xBE, 0xBF, 0x7E, 0x3B, 0x9D, 0x92, 0xFC, 0x49, 0x74, 0x17,
|
||||
0x79, 0x36, 0x3C, 0xFE},
|
||||
{0xD1, 0x7D, 0xDF, 0x46, 0xAD, 0xAA, 0xCD, 0xE5, 0x31, 0xCA, 0xC4, 0x83,
|
||||
0xDE, 0x7A, 0x93, 0x67},
|
||||
{0x9E, 0x99, 0xA7, 0xBF, 0x31, 0xE7, 0x10, 0x90, 0x06, 0x62, 0xF6, 0x5E,
|
||||
0x61, 0x7C, 0x51, 0x84},
|
||||
{0x3D, 0x75, 0xC1, 0x94, 0xED, 0x96, 0x07, 0x04, 0x44, 0xA9, 0xFA, 0x7E,
|
||||
0xC7, 0x40, 0xEC, 0xF8},
|
||||
{0xA1, 0xD5, 0xDF, 0x0E, 0xED, 0x79, 0x0F, 0x79, 0x4D, 0x77, 0x58, 0x96,
|
||||
0x59, 0xF3, 0x9A, 0x11},
|
||||
{0x02, 0x89, 0x62, 0xF6, 0x1B, 0x7B, 0xF8, 0x9E, 0xFC, 0x6B, 0x55, 0x1F,
|
||||
0x46, 0x67, 0xD9, 0x83},
|
||||
{0x28, 0xA7, 0x02, 0x3F, 0x45, 0x2E, 0x8F, 0x82, 0xBD, 0x4B, 0xF2, 0x8D,
|
||||
0x8C, 0x37, 0xC3, 0x5C},
|
||||
{0x15, 0x67, 0x27, 0xDC, 0x08, 0x78, 0x94, 0x4A, 0x02, 0x3C, 0x1F, 0xE0,
|
||||
0x3B, 0xAD, 0x6D, 0x93},
|
||||
{0xE1, 0x99, 0x21, 0x90, 0x54, 0x9F, 0x6E, 0xD5, 0x69, 0x6A, 0x2C, 0x05,
|
||||
0x6C, 0x31, 0x54, 0x10}};
|
||||
PR_STATIC_ASSERT(PR_ARRAY_SIZE(kNistKnown) ==
|
||||
kNistKeyLengthsCount * kNistPlaintextLengthsCount);
|
||||
|
||||
TEST_F(CmacAesTest, AesNistAligned) {
|
||||
for (unsigned int key_index = 0; key_index < kNistKeyLengthsCount;
|
||||
key_index++) {
|
||||
ScopedCMACContext ctx(CMAC_Create(CMAC_AES, kNistKeys[key_index],
|
||||
kNistKeyLengths[key_index]));
|
||||
ASSERT_NE(ctx, nullptr);
|
||||
|
||||
for (unsigned int plaintext_index = 0;
|
||||
plaintext_index < kNistPlaintextLengthsCount; plaintext_index++) {
|
||||
CMAC_Begin(ctx.get());
|
||||
|
||||
unsigned int known_index =
|
||||
(key_index * kNistPlaintextLengthsCount) + plaintext_index;
|
||||
CMAC_Update(ctx.get(), kNistPlaintext,
|
||||
kNistPlaintextLengths[plaintext_index]);
|
||||
|
||||
uint8_t output[AES_BLOCK_SIZE];
|
||||
CMAC_Finish(ctx.get(), output, NULL, AES_BLOCK_SIZE);
|
||||
|
||||
ASSERT_TRUE(Compare(output, kNistKnown[known_index], AES_BLOCK_SIZE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CmacAesTest, AesNistUnaligned) {
|
||||
for (unsigned int key_index = 0; key_index < kNistKeyLengthsCount;
|
||||
key_index++) {
|
||||
unsigned int key_length = kNistKeyLengths[key_index];
|
||||
ScopedCMACContext ctx(
|
||||
CMAC_Create(CMAC_AES, kNistKeys[key_index], key_length));
|
||||
ASSERT_NE(ctx, nullptr);
|
||||
|
||||
// Skip the zero-length test.
|
||||
for (unsigned int plaintext_index = 1;
|
||||
plaintext_index < kNistPlaintextLengthsCount; plaintext_index++) {
|
||||
unsigned int known_index =
|
||||
(key_index * kNistPlaintextLengthsCount) + plaintext_index;
|
||||
unsigned int plaintext_length = kNistPlaintextLengths[plaintext_index];
|
||||
|
||||
// Test all possible offsets and make sure that misaligned updates
|
||||
// produce the desired result. That is, do two updates:
|
||||
// 0 ... offset
|
||||
// offset ... len - offset
|
||||
// and ensure the result is the same as doing one update.
|
||||
for (unsigned int offset = 1; offset < plaintext_length; offset++) {
|
||||
CMAC_Begin(ctx.get());
|
||||
|
||||
CMAC_Update(ctx.get(), kNistPlaintext, offset);
|
||||
CMAC_Update(ctx.get(), kNistPlaintext + offset,
|
||||
plaintext_length - offset);
|
||||
|
||||
uint8_t output[AES_BLOCK_SIZE];
|
||||
CMAC_Finish(ctx.get(), output, NULL, AES_BLOCK_SIZE);
|
||||
|
||||
ASSERT_TRUE(Compare(output, kNistKnown[known_index], AES_BLOCK_SIZE));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CmacAesTest, AesNistTruncated) {
|
||||
for (unsigned int key_index = 0; key_index < kNistKeyLengthsCount;
|
||||
key_index++) {
|
||||
unsigned int key_length = kNistKeyLengths[key_index];
|
||||
ScopedCMACContext ctx(
|
||||
CMAC_Create(CMAC_AES, kNistKeys[key_index], key_length));
|
||||
ASSERT_TRUE(ctx != nullptr);
|
||||
|
||||
// Skip the zero-length test.
|
||||
for (unsigned int plaintext_index = 1;
|
||||
plaintext_index < kNistPlaintextLengthsCount; plaintext_index++) {
|
||||
unsigned int known_index =
|
||||
(key_index * kNistPlaintextLengthsCount) + plaintext_index;
|
||||
unsigned int plaintext_length = kNistPlaintextLengths[plaintext_index];
|
||||
|
||||
// Test truncated outputs to ensure that we always get the desired values.
|
||||
for (unsigned int out_len = 1; out_len < AES_BLOCK_SIZE; out_len++) {
|
||||
CMAC_Begin(ctx.get());
|
||||
|
||||
CMAC_Update(ctx.get(), kNistPlaintext, plaintext_length);
|
||||
|
||||
unsigned int actual_out_len = 0;
|
||||
uint8_t output[AES_BLOCK_SIZE];
|
||||
CMAC_Finish(ctx.get(), output, &actual_out_len, out_len);
|
||||
|
||||
ASSERT_TRUE(actual_out_len == out_len);
|
||||
ASSERT_TRUE(Compare(output, kNistKnown[known_index], out_len));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
|
||||
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
|
||||
'<(DEPTH)/lib/ssl/ssl.gyp:ssl',
|
||||
'<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -34,12 +35,20 @@
|
|||
'ecl_unittest.cc',
|
||||
'ghash_unittest.cc',
|
||||
'rsa_unittest.cc',
|
||||
'cmac_unittests.cc',
|
||||
'<(DEPTH)/gtests/common/gtests.cc'
|
||||
],
|
||||
'dependencies': [
|
||||
'freebl_gtest_deps',
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
],
|
||||
'conditions': [
|
||||
[ 'cc_is_gcc==1 and (target_arch=="ia32" or target_arch=="x64")', {
|
||||
'cflags_cc': [
|
||||
'-msse2',
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
{
|
||||
'target_name': 'prng_gtest',
|
||||
|
|
@ -78,7 +87,7 @@
|
|||
'defines': [
|
||||
'NSS_USE_STATIC_LIBS',
|
||||
],
|
||||
# For test builds we have to set MPI defines.
|
||||
# For static builds we have to set MPI defines.
|
||||
'conditions': [
|
||||
[ 'ct_verif==1', {
|
||||
'defines': [
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// 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 "gcm-vectors.h"
|
||||
#include "testvectors/gcm-vectors.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <memory>
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <mach/clock.h>
|
||||
|
|
@ -27,7 +28,7 @@ void gettime(struct timespec* tp) {
|
|||
tp->tv_sec = mts.tv_sec;
|
||||
tp->tv_nsec = mts.tv_nsec;
|
||||
#else
|
||||
clock_gettime(CLOCK_MONOTONIC, tp);
|
||||
ASSERT_NE(0, timespec_get(tp, TIME_UTC));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -84,8 +85,9 @@ class MPITest : public ::testing::Test {
|
|||
mp_int a;
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&a));
|
||||
ASSERT_EQ(MP_OKAY, mp_read_unsigned_octets(&a, ref.data(), ref.size()));
|
||||
uint8_t buf[len];
|
||||
ASSERT_EQ(MP_OKAY, mp_to_fixlen_octets(&a, buf, len));
|
||||
std::unique_ptr<uint8_t[]> buf(new uint8_t[len]);
|
||||
ASSERT_NE(buf, nullptr);
|
||||
ASSERT_EQ(MP_OKAY, mp_to_fixlen_octets(&a, buf.get(), len));
|
||||
size_t compare;
|
||||
if (len > ref.size()) {
|
||||
for (size_t i = 0; i < len - ref.size(); ++i) {
|
||||
|
|
@ -96,9 +98,9 @@ class MPITest : public ::testing::Test {
|
|||
compare = len;
|
||||
}
|
||||
dump("value", ref.data(), ref.size());
|
||||
dump("output", buf, len);
|
||||
ASSERT_EQ(0, memcmp(buf + len - compare, ref.data() + ref.size() - compare,
|
||||
compare))
|
||||
dump("output", buf.get(), len);
|
||||
ASSERT_EQ(0, memcmp(buf.get() + len - compare,
|
||||
ref.data() + ref.size() - compare, compare))
|
||||
<< "comparing " << compare << " octets";
|
||||
mp_clear(&a);
|
||||
}
|
||||
|
|
@ -146,6 +148,41 @@ TEST_F(MPITest, MpiCmpUnalignedTest) {
|
|||
}
|
||||
#endif
|
||||
|
||||
// The two follow tests ensure very similar mp_set_* functions are ok.
|
||||
TEST_F(MPITest, MpiSetUlong) {
|
||||
mp_int a, b, c;
|
||||
MP_DIGITS(&a) = 0;
|
||||
MP_DIGITS(&b) = 0;
|
||||
MP_DIGITS(&c) = 0;
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&a));
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&b));
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&c));
|
||||
EXPECT_EQ(MP_OKAY, mp_set_ulong(&a, 1));
|
||||
EXPECT_EQ(MP_OKAY, mp_set_ulong(&b, 0));
|
||||
EXPECT_EQ(MP_OKAY, mp_set_ulong(&c, -1));
|
||||
|
||||
mp_clear(&a);
|
||||
mp_clear(&b);
|
||||
mp_clear(&c);
|
||||
}
|
||||
|
||||
TEST_F(MPITest, MpiSetInt) {
|
||||
mp_int a, b, c;
|
||||
MP_DIGITS(&a) = 0;
|
||||
MP_DIGITS(&b) = 0;
|
||||
MP_DIGITS(&c) = 0;
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&a));
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&b));
|
||||
ASSERT_EQ(MP_OKAY, mp_init(&c));
|
||||
EXPECT_EQ(MP_OKAY, mp_set_int(&a, 1));
|
||||
EXPECT_EQ(MP_OKAY, mp_set_int(&b, 0));
|
||||
EXPECT_EQ(MP_OKAY, mp_set_int(&c, -1));
|
||||
|
||||
mp_clear(&a);
|
||||
mp_clear(&b);
|
||||
mp_clear(&c);
|
||||
}
|
||||
|
||||
TEST_F(MPITest, MpiFixlenOctetsZero) {
|
||||
std::vector<uint8_t> zero = {0};
|
||||
TestToFixedOctets(zero, 1);
|
||||
|
|
@ -253,4 +290,4 @@ TEST_F(DISABLED_MPITest, MpiCmpConstTest) {
|
|||
mp_clear(&c);
|
||||
}
|
||||
|
||||
} // nss_test
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "gtest/gtest.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
|
||||
#include "blapi.h"
|
||||
#include "secitem.h"
|
||||
|
|
|
|||
|
|
@ -24,9 +24,12 @@ NSS_SRCDIRS = \
|
|||
cryptohi_gtest \
|
||||
der_gtest \
|
||||
pk11_gtest \
|
||||
smime_gtest \
|
||||
softoken_gtest \
|
||||
ssl_gtest \
|
||||
$(SYSINIT_GTEST) \
|
||||
nss_bogo_shim \
|
||||
pkcs11testmodule \
|
||||
$(NULL)
|
||||
endif
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
'<(DEPTH)/lib/base/base.gyp:nssb',
|
||||
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
|
||||
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
|
||||
'<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix',
|
||||
'<(DEPTH)/lib/mozpkix/mozpkix.gyp:mozpkix',
|
||||
'<(DEPTH)/lib/mozpkix/mozpkix.gyp:mozpkix-testlib',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -152,10 +152,14 @@ private:
|
|||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
|
||||
Time validityBeginning, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
// All of the certificates in this test for which this is called have a
|
||||
// validity period that begins "one day before now".
|
||||
EXPECT_EQ(TimeFromEpochInSeconds(oneDayBeforeNow), validityBeginning);
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
|
@ -301,10 +305,14 @@ public:
|
|||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
|
||||
Time validityBeginning, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
// All of the certificates in this test for which this is called have a
|
||||
// validity period that begins "one day before now".
|
||||
EXPECT_EQ(TimeFromEpochInSeconds(oneDayBeforeNow), validityBeginning);
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
|
@ -321,7 +329,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
|
|
@ -442,10 +450,14 @@ public:
|
|||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
|
||||
Time validityBeginning, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
// All of the certificates in this test for which this is called have a
|
||||
// validity period that begins "one day before now".
|
||||
EXPECT_EQ(TimeFromEpochInSeconds(oneDayBeforeNow), validityBeginning);
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
|
@ -665,10 +677,14 @@ private:
|
|||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
|
||||
Time validityBeginning, Duration,
|
||||
/*optional*/ const Input*,
|
||||
/*optional*/ const Input*) override
|
||||
{
|
||||
// All of the certificates in this test for which this is called have a
|
||||
// validity period that begins "one day before now".
|
||||
EXPECT_EQ(TimeFromEpochInSeconds(oneDayBeforeNow), validityBeginning);
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
|
@ -723,7 +739,7 @@ class RevokedEndEntityTrustDomain final : public MultiplePathTrustDomain
|
|||
{
|
||||
public:
|
||||
Result CheckRevocation(EndEntityOrCA endEntityOrCA, const CertID&, Time,
|
||||
Duration, /*optional*/ const Input*,
|
||||
Time, Duration, /*optional*/ const Input*,
|
||||
/*optional*/ const Input*) override
|
||||
{
|
||||
if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
|
||||
|
|
@ -828,10 +844,14 @@ private:
|
|||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
|
||||
Time validityBeginning, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
// All of the certificates in this test for which this is called have a
|
||||
// validity period that begins "one day before now".
|
||||
EXPECT_EQ(TimeFromEpochInSeconds(oneDayBeforeNow), validityBeginning);
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ private:
|
|||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, Duration,
|
||||
/*optional*/ const Input*, /*optional*/ const Input*)
|
||||
override
|
||||
{
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ private:
|
|||
return checker.Check(issuerCert, nullptr, keepGoing);
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, Duration,
|
||||
const Input*, const Input*) override
|
||||
{
|
||||
return Success;
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ private:
|
|||
return checker.Check(derCert, nullptr, keepGoing);
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, Duration,
|
||||
const Input*, const Input*) override
|
||||
{
|
||||
return Success;
|
||||
|
|
|
|||
|
|
@ -166,8 +166,8 @@ void ASSERT_SimpleCase(uint8_t unusedBits, uint8_t bits, KeyUsage usage)
|
|||
|
||||
// Test that none of the other non-padding bits are mistaken for the given
|
||||
// key usage in the single-byte value case.
|
||||
NAMED_SIMPLE_KU(notGood, unusedBits,
|
||||
static_cast<uint8_t>((~bits >> unusedBits) << unusedBits));
|
||||
uint8_t paddingBits = (static_cast<uint8_t>(~bits) >> unusedBits) << unusedBits;
|
||||
NAMED_SIMPLE_KU(notGood, unusedBits, paddingBits);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, ¬Good, usage));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, ¬Good, usage));
|
||||
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ public:
|
|||
return Success;
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, Duration,
|
||||
/*optional*/ const Input*,
|
||||
/*optional*/ const Input*) override
|
||||
{
|
||||
|
|
|
|||
|
|
@ -191,8 +191,10 @@ TEST_F(pkixder_input_tests, ReadByteWrapAroundPointer)
|
|||
// a null pointer is undefined behavior according to the C++ language spec.,
|
||||
// but this should catch the problem on at least some compilers, if not all of
|
||||
// them.
|
||||
const uint8_t* der = nullptr;
|
||||
--der;
|
||||
uintptr_t derint = -1;
|
||||
auto der = reinterpret_cast<const uint8_t*>(derint);
|
||||
ASSERT_EQ(sizeof(der), sizeof(derint))
|
||||
<< "underflow of pointer might not work";
|
||||
Input buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 0));
|
||||
Reader input(buf);
|
||||
|
|
@ -359,6 +361,7 @@ TEST_F(pkixder_input_tests, Skip_WrapAroundPointer)
|
|||
// but this should catch the problem on at least some compilers, if not all of
|
||||
// them.
|
||||
const uint8_t* der = nullptr;
|
||||
// coverity[FORWARD_NULL]
|
||||
--der;
|
||||
Input buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 0));
|
||||
|
|
|
|||
|
|
@ -1224,3 +1224,53 @@ TEST_F(pkixder_universal_types_tests, OID)
|
|||
|
||||
ASSERT_EQ(Success, OID(reader, expectedOID));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_universal_types_tests, SkipOptionalImplicitPrimitiveTag)
|
||||
{
|
||||
const uint8_t DER_IMPLICIT_BIT_STRING_WITH_CLASS_NUMBER_1[] = {
|
||||
0x81,
|
||||
0x04,
|
||||
0x00,
|
||||
0x0A,
|
||||
0x0B,
|
||||
0x0C,
|
||||
};
|
||||
Input input(DER_IMPLICIT_BIT_STRING_WITH_CLASS_NUMBER_1);
|
||||
Reader reader(input);
|
||||
|
||||
ASSERT_EQ(Success, SkipOptionalImplicitPrimitiveTag(reader, 1));
|
||||
ASSERT_TRUE(reader.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_universal_types_tests, SkipOptionalImplicitPrimitiveTagMismatch)
|
||||
{
|
||||
const uint8_t DER_IMPLICIT_BIT_STRING_WITH_CLASS_NUMBER_1[] = {
|
||||
0x81,
|
||||
0x04,
|
||||
0x00,
|
||||
0x0A,
|
||||
0x0B,
|
||||
0x0C,
|
||||
};
|
||||
Input input(DER_IMPLICIT_BIT_STRING_WITH_CLASS_NUMBER_1);
|
||||
Reader reader(input);
|
||||
|
||||
ASSERT_EQ(Success, SkipOptionalImplicitPrimitiveTag(reader, 2));
|
||||
ASSERT_FALSE(reader.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_universal_types_tests, NoSkipOptionalImplicitConstructedTag)
|
||||
{
|
||||
const uint8_t DER_IMPLICIT_SEQUENCE_WITH_CLASS_NUMBER_1[] = {
|
||||
0xA1,
|
||||
0x03,
|
||||
0x05,
|
||||
0x01,
|
||||
0x00,
|
||||
};
|
||||
Input input(DER_IMPLICIT_SEQUENCE_WITH_CLASS_NUMBER_1);
|
||||
Reader reader(input);
|
||||
|
||||
ASSERT_EQ(Success, SkipOptionalImplicitPrimitiveTag(reader, 1));
|
||||
ASSERT_FALSE(reader.AtEnd());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ class EverythingFailsByDefaultTrustDomain : public TrustDomain {
|
|||
Result::FATAL_ERROR_LIBRARY_FAILURE);
|
||||
}
|
||||
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
|
||||
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Time, Duration,
|
||||
/*optional*/ const Input*,
|
||||
/*optional*/ const Input*) override {
|
||||
ADD_FAILURE();
|
||||
|
|
|
|||
|
|
@ -7,20 +7,32 @@ DEPTH = ../..
|
|||
MODULE = nss
|
||||
|
||||
CPPSRCS = \
|
||||
pk11_aes_gcm_unittest.cc \
|
||||
pk11_aeskeywrap_unittest.cc \
|
||||
pk11_aeskeywrappad_unittest.cc \
|
||||
pk11_cbc_unittest.cc \
|
||||
pk11_chacha20poly1305_unittest.cc \
|
||||
pk11_curve25519_unittest.cc \
|
||||
pk11_der_private_key_import_unittest.cc \
|
||||
pk11_des_unittest.cc \
|
||||
pk11_ecdsa_unittest.cc \
|
||||
pk11_encrypt_derive_unittest.cc \
|
||||
pk11_export_unittest.cc \
|
||||
pk11_find_certs_unittest.cc \
|
||||
pk11_import_unittest.cc \
|
||||
pk11_keygen.cc \
|
||||
pk11_key_unittest.cc \
|
||||
pk11_module_unittest.cc \
|
||||
pk11_pbkdf2_unittest.cc \
|
||||
pk11_prf_unittest.cc \
|
||||
pk11_prng_unittest.cc \
|
||||
pk11_rsapkcs1_unittest.cc \
|
||||
pk11_rsapss_unittest.cc \
|
||||
pk11_der_private_key_import_unittest.cc \
|
||||
pk11_seed_cbc_unittest.cc \
|
||||
$(NULL)
|
||||
|
||||
DEFINES += -DDLL_PREFIX=\"$(DLL_PREFIX)\" -DDLL_SUFFIX=\"$(DLL_SUFFIX)\"
|
||||
|
||||
INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
|
||||
-I$(CORE_DEPTH)/gtests/common \
|
||||
-I$(CORE_DEPTH)/cpputil
|
||||
|
|
@ -33,4 +45,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)
|
||||
|
||||
|
|
|
|||
91
security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc
Normal file
91
security/nss/gtests/pk11_gtest/pk11_aes_cmac_unittest.cc
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/* -*- 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 <memory>
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "secerr.h"
|
||||
#include "sechash.h"
|
||||
|
||||
#include "blapi.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class Pkcs11AesCmacTest : public ::testing::Test {
|
||||
protected:
|
||||
ScopedPK11SymKey ImportKey(CK_MECHANISM_TYPE mech, SECItem *key_item) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
if (!slot) {
|
||||
ADD_FAILURE() << "Can't get slot";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ScopedPK11SymKey result(PK11_ImportSymKey(
|
||||
slot.get(), mech, PK11_OriginUnwrap, CKA_SIGN, key_item, nullptr));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void RunTest(uint8_t *key, unsigned int key_len, uint8_t *data,
|
||||
unsigned int data_len, uint8_t *expected,
|
||||
unsigned int expected_len, CK_ULONG mechanism) {
|
||||
// Create SECItems for everything...
|
||||
std::vector<uint8_t> output(expected_len);
|
||||
SECItem key_item = {siBuffer, key, key_len};
|
||||
SECItem output_item = {siBuffer, output.data(), expected_len};
|
||||
SECItem data_item = {siBuffer, data, data_len};
|
||||
SECItem expected_item = {siBuffer, expected, expected_len};
|
||||
|
||||
// Do the PKCS #11 stuff...
|
||||
ScopedPK11SymKey p11_key = ImportKey(mechanism, &key_item);
|
||||
ASSERT_NE(nullptr, p11_key.get());
|
||||
|
||||
SECStatus ret = PK11_SignWithSymKey(p11_key.get(), CKM_AES_CMAC, NULL,
|
||||
&output_item, &data_item);
|
||||
|
||||
// Verify the result...
|
||||
ASSERT_EQ(SECSuccess, ret);
|
||||
ASSERT_EQ(0, SECITEM_CompareItem(&output_item, &expected_item));
|
||||
}
|
||||
};
|
||||
|
||||
// Sanity check of the PKCS #11 API only. Extensive tests for correctness of
|
||||
// underling CMAC implementation conducted in the following file:
|
||||
// gtests/freebl_gtest/cmac_unittests.cc
|
||||
|
||||
TEST_F(Pkcs11AesCmacTest, Aes128NistExample1) {
|
||||
uint8_t key[AES_128_KEY_LENGTH] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE,
|
||||
0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,
|
||||
0x09, 0xCF, 0x4F, 0x3C};
|
||||
uint8_t known[AES_BLOCK_SIZE] = {0xBB, 0x1D, 0x69, 0x29, 0xE9, 0x59,
|
||||
0x37, 0x28, 0x7F, 0xA3, 0x7D, 0x12,
|
||||
0x9B, 0x75, 0x67, 0x46};
|
||||
|
||||
RunTest(key, AES_128_KEY_LENGTH, NULL, 0, known, AES_BLOCK_SIZE,
|
||||
CKM_AES_CMAC);
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11AesCmacTest, General) {
|
||||
uint8_t key[AES_128_KEY_LENGTH] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE,
|
||||
0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88,
|
||||
0x09, 0xCF, 0x4F, 0x3C};
|
||||
uint8_t known[4] = {0xBB, 0x1D, 0x69, 0x29};
|
||||
|
||||
RunTest(key, AES_128_KEY_LENGTH, NULL, 0, known, 4, CKM_AES_CMAC_GENERAL);
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11AesCmacTest, InvalidKeySize) {
|
||||
uint8_t key[4] = {0x00, 0x00, 0x00, 0x00};
|
||||
SECItem key_item = {siBuffer, key, 4};
|
||||
|
||||
ScopedPK11SymKey result = ImportKey(CKM_AES_CMAC, &key_item);
|
||||
ASSERT_EQ(nullptr, result.get());
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include "nss_scoped_ptrs.h"
|
||||
|
||||
#include "gcm-vectors.h"
|
||||
#include "testvectors/gcm-vectors.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util.h"
|
||||
|
||||
|
|
@ -26,87 +26,120 @@ class Pkcs11AesGcmTest : public ::testing::TestWithParam<gcm_kat_value> {
|
|||
std::vector<uint8_t> plaintext = hex_string_to_bytes(val.plaintext);
|
||||
std::vector<uint8_t> aad = hex_string_to_bytes(val.additional_data);
|
||||
std::vector<uint8_t> result = hex_string_to_bytes(val.result);
|
||||
|
||||
bool invalid_ct = val.invalid_ct;
|
||||
bool invalid_iv = val.invalid_iv;
|
||||
std::stringstream s;
|
||||
s << "Test #" << val.test_id << " failed.";
|
||||
std::string msg = s.str();
|
||||
// Ignore GHASH-only vectors.
|
||||
if (key.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare AEAD params.
|
||||
CK_GCM_PARAMS gcmParams;
|
||||
gcmParams.pIv = iv.data();
|
||||
gcmParams.ulIvLen = iv.size();
|
||||
gcmParams.pAAD = aad.data();
|
||||
gcmParams.ulAADLen = aad.size();
|
||||
gcmParams.ulTagBits = 128;
|
||||
CK_GCM_PARAMS gcm_params;
|
||||
gcm_params.pIv = iv.data();
|
||||
gcm_params.ulIvLen = iv.size();
|
||||
gcm_params.pAAD = aad.data();
|
||||
gcm_params.ulAADLen = aad.size();
|
||||
gcm_params.ulTagBits = 128;
|
||||
|
||||
SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcmParams),
|
||||
sizeof(gcmParams)};
|
||||
SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcm_params),
|
||||
sizeof(gcm_params)};
|
||||
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
SECItem keyItem = {siBuffer, key.data(),
|
||||
static_cast<unsigned int>(key.size())};
|
||||
SECItem key_item = {siBuffer, key.data(),
|
||||
static_cast<unsigned int>(key.size())};
|
||||
|
||||
// Import key.
|
||||
ScopedPK11SymKey symKey(PK11_ImportSymKey(
|
||||
slot.get(), mech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr));
|
||||
EXPECT_TRUE(!!symKey);
|
||||
ScopedPK11SymKey sym_key(PK11_ImportSymKey(
|
||||
slot.get(), mech, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, nullptr));
|
||||
ASSERT_TRUE(!!sym_key) << msg;
|
||||
|
||||
// Encrypt with bogus parameters.
|
||||
unsigned int output_len = 0;
|
||||
std::vector<uint8_t> output(plaintext.size() + gcm_params.ulTagBits / 8);
|
||||
// "maxout" must be at least "inlen + tagBytes", or, in this case:
|
||||
// "output.size()" must be at least "plaintext.size() + tagBytes"
|
||||
gcm_params.ulTagBits = 128;
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), &output_len,
|
||||
output.size() - 10, plaintext.data(), plaintext.size());
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(0U, output_len);
|
||||
|
||||
// The valid values for tag size in AES_GCM are:
|
||||
// 32, 64, 96, 104, 112, 120 and 128.
|
||||
gcm_params.ulTagBits = 110;
|
||||
rv = PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), &output_len,
|
||||
output.size(), plaintext.data(), plaintext.size());
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(0U, output_len);
|
||||
|
||||
// Encrypt.
|
||||
unsigned int outputLen = 0;
|
||||
std::vector<uint8_t> output(plaintext.size() + gcmParams.ulTagBits / 8);
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(symKey.get(), mech, ¶ms, output.data(), &outputLen,
|
||||
output.size(), plaintext.data(), plaintext.size());
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
ASSERT_EQ(outputLen, output.size());
|
||||
gcm_params.ulTagBits = 128;
|
||||
rv = PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(), &output_len,
|
||||
output.size(), plaintext.data(), plaintext.size());
|
||||
if (invalid_iv) {
|
||||
EXPECT_EQ(SECFailure, rv) << msg;
|
||||
EXPECT_EQ(0U, output_len);
|
||||
return;
|
||||
}
|
||||
EXPECT_EQ(SECSuccess, rv) << msg;
|
||||
|
||||
ASSERT_EQ(output_len, output.size()) << msg;
|
||||
|
||||
// Check ciphertext and tag.
|
||||
EXPECT_EQ(result, output);
|
||||
if (invalid_ct) {
|
||||
EXPECT_NE(result, output) << msg;
|
||||
} else {
|
||||
EXPECT_EQ(result, output) << msg;
|
||||
}
|
||||
|
||||
// Decrypt.
|
||||
unsigned int decryptedLen = 0;
|
||||
unsigned int decrypted_len = 0;
|
||||
// The PK11 AES API is stupid, it expects an explicit IV and thus wants
|
||||
// a block more of available output memory.
|
||||
std::vector<uint8_t> decrypted(output.size());
|
||||
rv =
|
||||
PK11_Decrypt(symKey.get(), mech, ¶ms, decrypted.data(),
|
||||
&decryptedLen, decrypted.size(), output.data(), outputLen);
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
ASSERT_EQ(decryptedLen, plaintext.size());
|
||||
rv = PK11_Decrypt(sym_key.get(), mech, ¶ms, decrypted.data(),
|
||||
&decrypted_len, decrypted.size(), output.data(),
|
||||
output_len);
|
||||
EXPECT_EQ(SECSuccess, rv) << msg;
|
||||
ASSERT_EQ(decrypted_len, plaintext.size()) << msg;
|
||||
|
||||
// Check the plaintext.
|
||||
EXPECT_EQ(plaintext,
|
||||
std::vector<uint8_t>(decrypted.begin(),
|
||||
decrypted.begin() + decryptedLen));
|
||||
decrypted.begin() + decrypted_len))
|
||||
<< msg;
|
||||
}
|
||||
|
||||
SECStatus EncryptWithIV(std::vector<uint8_t>& iv) {
|
||||
// Generate a random key.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ScopedPK11SymKey symKey(
|
||||
ScopedPK11SymKey sym_key(
|
||||
PK11_KeyGen(slot.get(), mech, nullptr, 16, nullptr));
|
||||
EXPECT_TRUE(!!symKey);
|
||||
EXPECT_TRUE(!!sym_key);
|
||||
|
||||
std::vector<uint8_t> data(17);
|
||||
std::vector<uint8_t> output(33);
|
||||
std::vector<uint8_t> aad(0);
|
||||
|
||||
// Prepare AEAD params.
|
||||
CK_GCM_PARAMS gcmParams;
|
||||
gcmParams.pIv = iv.data();
|
||||
gcmParams.ulIvLen = iv.size();
|
||||
gcmParams.pAAD = aad.data();
|
||||
gcmParams.ulAADLen = aad.size();
|
||||
gcmParams.ulTagBits = 128;
|
||||
CK_GCM_PARAMS gcm_params;
|
||||
gcm_params.pIv = iv.data();
|
||||
gcm_params.ulIvLen = iv.size();
|
||||
gcm_params.pAAD = aad.data();
|
||||
gcm_params.ulAADLen = aad.size();
|
||||
gcm_params.ulTagBits = 128;
|
||||
|
||||
SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcmParams),
|
||||
sizeof(gcmParams)};
|
||||
SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&gcm_params),
|
||||
sizeof(gcm_params)};
|
||||
|
||||
// Try to encrypt.
|
||||
unsigned int outputLen = 0;
|
||||
return PK11_Encrypt(symKey.get(), mech, ¶ms, output.data(), &outputLen,
|
||||
output.size(), data.data(), data.size());
|
||||
unsigned int output_len = 0;
|
||||
return PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(),
|
||||
&output_len, output.size(), data.data(), data.size());
|
||||
}
|
||||
|
||||
const CK_MECHANISM_TYPE mech = CKM_AES_GCM;
|
||||
|
|
@ -117,19 +150,22 @@ TEST_P(Pkcs11AesGcmTest, TestVectors) { RunTest(GetParam()); }
|
|||
INSTANTIATE_TEST_CASE_P(NISTTestVector, Pkcs11AesGcmTest,
|
||||
::testing::ValuesIn(kGcmKatValues));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(WycheproofTestVector, Pkcs11AesGcmTest,
|
||||
::testing::ValuesIn(kGcmWycheproofVectors));
|
||||
|
||||
TEST_F(Pkcs11AesGcmTest, ZeroLengthIV) {
|
||||
std::vector<uint8_t> iv(0);
|
||||
EXPECT_EQ(EncryptWithIV(iv), SECFailure);
|
||||
EXPECT_EQ(SECFailure, EncryptWithIV(iv));
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11AesGcmTest, AllZeroIV) {
|
||||
std::vector<uint8_t> iv(16, 0);
|
||||
EXPECT_EQ(EncryptWithIV(iv), SECSuccess);
|
||||
EXPECT_EQ(SECSuccess, EncryptWithIV(iv));
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11AesGcmTest, TwelveByteZeroIV) {
|
||||
std::vector<uint8_t> iv(12, 0);
|
||||
EXPECT_EQ(EncryptWithIV(iv), SECSuccess);
|
||||
EXPECT_EQ(SECSuccess, EncryptWithIV(iv));
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -8,125 +8,115 @@
|
|||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
|
||||
#include "testvectors/kw-vectors.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// Test vectors from https://tools.ietf.org/html/rfc3394#section-4.1 to 4.6
|
||||
unsigned char kKEK1[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
|
||||
|
||||
unsigned char kKD1[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
|
||||
|
||||
unsigned char kC1[] = {0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
|
||||
0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
|
||||
0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5};
|
||||
|
||||
unsigned char kKEK2[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17};
|
||||
|
||||
unsigned char kC2[] = {0x96, 0x77, 0x8B, 0x25, 0xAE, 0x6C, 0xA4, 0x35,
|
||||
0xF9, 0x2B, 0x5B, 0x97, 0xC0, 0x50, 0xAE, 0xD2,
|
||||
0x46, 0x8A, 0xB8, 0xA1, 0x7A, 0xD8, 0x4E, 0x5D};
|
||||
|
||||
unsigned char kKEK3[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
|
||||
|
||||
unsigned char kC3[] = {0x64, 0xE8, 0xC3, 0xF9, 0xCE, 0x0F, 0x5B, 0xA2,
|
||||
0x63, 0xE9, 0x77, 0x79, 0x05, 0x81, 0x8A, 0x2A,
|
||||
0x93, 0xC8, 0x19, 0x1E, 0x7D, 0x6E, 0x8A, 0xE7};
|
||||
|
||||
unsigned char kKD4[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
|
||||
|
||||
unsigned char kC4[] = {0x03, 0x1D, 0x33, 0x26, 0x4E, 0x15, 0xD3, 0x32,
|
||||
0x68, 0xF2, 0x4E, 0xC2, 0x60, 0x74, 0x3E, 0xDC,
|
||||
0xE1, 0xC6, 0xC7, 0xDD, 0xEE, 0x72, 0x5A, 0x93,
|
||||
0x6B, 0xA8, 0x14, 0x91, 0x5C, 0x67, 0x62, 0xD2};
|
||||
|
||||
unsigned char kC5[] = {0xA8, 0xF9, 0xBC, 0x16, 0x12, 0xC6, 0x8B, 0x3F,
|
||||
0xF6, 0xE6, 0xF4, 0xFB, 0xE3, 0x0E, 0x71, 0xE4,
|
||||
0x76, 0x9C, 0x8B, 0x80, 0xA3, 0x2C, 0xB8, 0x95,
|
||||
0x8C, 0xD5, 0xD1, 0x7D, 0x6B, 0x25, 0x4D, 0xA1};
|
||||
|
||||
unsigned char kKD6[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
|
||||
|
||||
unsigned char kC6[] = {0x28, 0xC9, 0xF4, 0x04, 0xC4, 0xB8, 0x10, 0xF4,
|
||||
0xCB, 0xCC, 0xB3, 0x5C, 0xFB, 0x87, 0xF8, 0x26,
|
||||
0x3F, 0x57, 0x86, 0xE2, 0xD8, 0x0E, 0xD3, 0x26,
|
||||
0xCB, 0xC7, 0xF0, 0xE7, 0x1A, 0x99, 0xF4, 0x3B,
|
||||
0xFB, 0x98, 0x8B, 0x9B, 0x7A, 0x02, 0xDD, 0x21};
|
||||
|
||||
class Pkcs11AESKeyWrapTest : public ::testing::Test {
|
||||
class Pkcs11AESKeyWrapTest : public ::testing::TestWithParam<keywrap_vector> {
|
||||
protected:
|
||||
CK_MECHANISM_TYPE mechanism = CKM_NSS_AES_KEY_WRAP;
|
||||
|
||||
void WrapUnwrap(unsigned char* kek, unsigned int kekLen,
|
||||
unsigned char* keyData, unsigned int keyDataLen,
|
||||
unsigned char* expectedCiphertext) {
|
||||
unsigned char wrappedKey[40];
|
||||
unsigned int wrappedKeyLen;
|
||||
unsigned char unwrappedKey[40];
|
||||
unsigned int unwrappedKeyLen = 0;
|
||||
void WrapUnwrap(unsigned char* kek_data, unsigned int kek_len,
|
||||
unsigned char* key_data, unsigned int key_data_len,
|
||||
unsigned char* expected_ciphertext,
|
||||
unsigned int expected_ciphertext_len,
|
||||
std::map<Action, Result> tests, uint32_t test_id) {
|
||||
std::vector<unsigned char> wrapped_key(PR_MAX(1U, expected_ciphertext_len));
|
||||
std::vector<unsigned char> unwrapped_key(PR_MAX(1U, key_data_len));
|
||||
std::vector<unsigned char> zeros(PR_MAX(1U, expected_ciphertext_len));
|
||||
std::fill(zeros.begin(), zeros.end(), 0);
|
||||
unsigned int wrapped_key_len = 0;
|
||||
unsigned int unwrapped_key_len = 0;
|
||||
SECStatus rv;
|
||||
|
||||
std::stringstream s;
|
||||
s << "Test with original ID #" << test_id << " failed." << std::endl;
|
||||
std::string msg = s.str();
|
||||
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
ASSERT_NE(nullptr, slot) << msg;
|
||||
|
||||
// Import encryption key.
|
||||
SECItem keyItem = {siBuffer, kek, kekLen};
|
||||
ScopedPK11SymKey encryptionKey(
|
||||
PK11_ImportSymKey(slot.get(), CKM_NSS_AES_KEY_WRAP, PK11_OriginUnwrap,
|
||||
CKA_ENCRYPT, &keyItem, nullptr));
|
||||
EXPECT_TRUE(!!encryptionKey);
|
||||
SECItem kek_item = {siBuffer, kek_data, kek_len};
|
||||
ScopedPK11SymKey kek(PK11_ImportSymKey(slot.get(), CKM_NSS_AES_KEY_WRAP,
|
||||
PK11_OriginUnwrap, CKA_ENCRYPT,
|
||||
&kek_item, nullptr));
|
||||
EXPECT_TRUE(!!kek) << msg;
|
||||
|
||||
// Wrap key
|
||||
rv = PK11_Encrypt(encryptionKey.get(), mechanism, nullptr /* param */,
|
||||
wrappedKey, &wrappedKeyLen, sizeof(wrappedKey), keyData,
|
||||
keyDataLen);
|
||||
EXPECT_EQ(rv, SECSuccess) << "CKM_NSS_AES_KEY_WRAP encrypt failed";
|
||||
EXPECT_TRUE(!memcmp(expectedCiphertext, wrappedKey, wrappedKeyLen));
|
||||
Action test = WRAP;
|
||||
if (tests.count(test)) {
|
||||
rv = PK11_Encrypt(kek.get(), mechanism, nullptr /* param */,
|
||||
wrapped_key.data(), &wrapped_key_len,
|
||||
wrapped_key.size(), key_data, key_data_len);
|
||||
ASSERT_EQ(rv, tests[test].expect_rv) << msg;
|
||||
|
||||
// If we failed, check that output was not produced.
|
||||
if (rv == SECFailure) {
|
||||
EXPECT_TRUE(wrapped_key_len == 0);
|
||||
EXPECT_TRUE(!memcmp(wrapped_key.data(), zeros.data(), wrapped_key_len));
|
||||
}
|
||||
|
||||
if (tests[test].output_match) {
|
||||
EXPECT_EQ(expected_ciphertext_len, wrapped_key_len) << msg;
|
||||
EXPECT_TRUE(!memcmp(expected_ciphertext, wrapped_key.data(),
|
||||
expected_ciphertext_len))
|
||||
<< msg;
|
||||
} else {
|
||||
// If we produced output, verify that it doesn't match the vector
|
||||
if (wrapped_key_len) {
|
||||
EXPECT_FALSE(wrapped_key_len == expected_ciphertext_len &&
|
||||
!memcmp(wrapped_key.data(), expected_ciphertext,
|
||||
expected_ciphertext_len))
|
||||
<< msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unwrap key
|
||||
rv = PK11_Decrypt(encryptionKey.get(), mechanism, nullptr /* param */,
|
||||
unwrappedKey, &unwrappedKeyLen, sizeof(unwrappedKey),
|
||||
wrappedKey, wrappedKeyLen);
|
||||
EXPECT_EQ(rv, SECSuccess) << " CKM_NSS_AES_KEY_WRAP decrypt failed\n";
|
||||
EXPECT_TRUE(!memcmp(keyData, unwrappedKey, unwrappedKeyLen));
|
||||
test = UNWRAP;
|
||||
if (tests.count(test)) {
|
||||
rv = PK11_Decrypt(kek.get(), mechanism, nullptr /* param */,
|
||||
unwrapped_key.data(), &unwrapped_key_len,
|
||||
unwrapped_key.size(), expected_ciphertext,
|
||||
expected_ciphertext_len);
|
||||
ASSERT_EQ(rv, tests[test].expect_rv) << msg;
|
||||
|
||||
// If we failed, check that output was not produced.
|
||||
if (rv == SECFailure) {
|
||||
EXPECT_TRUE(unwrapped_key_len == 0);
|
||||
EXPECT_TRUE(
|
||||
!memcmp(unwrapped_key.data(), zeros.data(), unwrapped_key_len));
|
||||
}
|
||||
|
||||
if (tests[test].output_match) {
|
||||
EXPECT_EQ(unwrapped_key_len, key_data_len) << msg;
|
||||
EXPECT_TRUE(!memcmp(key_data, unwrapped_key.data(), key_data_len))
|
||||
<< msg;
|
||||
} else {
|
||||
// If we produced output, verify that it doesn't match the vector
|
||||
if (unwrapped_key_len) {
|
||||
EXPECT_FALSE(
|
||||
unwrapped_key_len == expected_ciphertext_len &&
|
||||
!memcmp(unwrapped_key.data(), key_data, unwrapped_key_len))
|
||||
<< msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WrapUnwrap(keywrap_vector testvector) {
|
||||
WrapUnwrap(testvector.key.data(), testvector.key.size(),
|
||||
testvector.msg.data(), testvector.msg.size(),
|
||||
testvector.ct.data(), testvector.ct.size(), testvector.tests,
|
||||
testvector.test_id);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Pkcs11AESKeyWrapTest, WrapUnwrepTest1) {
|
||||
WrapUnwrap(kKEK1, sizeof(kKEK1), kKD1, sizeof(kKD1), kC1);
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11AESKeyWrapTest, WrapUnwrepTest2) {
|
||||
WrapUnwrap(kKEK2, sizeof(kKEK2), kKD1, sizeof(kKD1), kC2);
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11AESKeyWrapTest, WrapUnwrepTest3) {
|
||||
WrapUnwrap(kKEK3, sizeof(kKEK3), kKD1, sizeof(kKD1), kC3);
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11AESKeyWrapTest, WrapUnwrepTest4) {
|
||||
WrapUnwrap(kKEK2, sizeof(kKEK2), kKD4, sizeof(kKD4), kC4);
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11AESKeyWrapTest, WrapUnwrepTest5) {
|
||||
WrapUnwrap(kKEK3, sizeof(kKEK3), kKD4, sizeof(kKD4), kC5);
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11AESKeyWrapTest, WrapUnwrepTest6) {
|
||||
WrapUnwrap(kKEK3, sizeof(kKEK3), kKD6, sizeof(kKD6), kC6);
|
||||
}
|
||||
TEST_P(Pkcs11AESKeyWrapTest, TestVectors) { WrapUnwrap(GetParam()); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Pkcs11WycheproofAESKWTest, Pkcs11AESKeyWrapTest,
|
||||
::testing::ValuesIn(kWycheproofAesKWVectors));
|
||||
} /* nss_test */
|
||||
|
|
|
|||
415
security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc
Normal file
415
security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
/* -*- 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 <memory>
|
||||
#include "gtest/gtest.h"
|
||||
#include "nss.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "pk11pub.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class Pkcs11AESKeyWrapPadTest : public ::testing::Test {};
|
||||
|
||||
// Encrypt an ephemeral EC key (U2F use case)
|
||||
TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapECKey) {
|
||||
const uint32_t kwrappedBufLen = 256;
|
||||
const uint32_t kPublicKeyLen = 65;
|
||||
const uint32_t kOidLen = 65;
|
||||
unsigned char param_buf[kOidLen];
|
||||
unsigned char unwrap_buf[kPublicKeyLen];
|
||||
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
|
||||
SECItem ecdsa_params = {siBuffer, param_buf, sizeof(param_buf)};
|
||||
SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
|
||||
ASSERT_NE(oid_data, nullptr);
|
||||
ecdsa_params.data[0] = SEC_ASN1_OBJECT_ID;
|
||||
ecdsa_params.data[1] = oid_data->oid.len;
|
||||
memcpy(ecdsa_params.data + 2, oid_data->oid.data, oid_data->oid.len);
|
||||
ecdsa_params.len = oid_data->oid.len + 2;
|
||||
|
||||
SECKEYPublicKey* pub_tmp;
|
||||
ScopedSECKEYPublicKey pub_key;
|
||||
ScopedSECKEYPrivateKey priv_key(
|
||||
PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &ecdsa_params,
|
||||
&pub_tmp, PR_FALSE, PR_TRUE, nullptr));
|
||||
ASSERT_NE(nullptr, priv_key);
|
||||
ASSERT_NE(nullptr, pub_tmp);
|
||||
pub_key.reset(pub_tmp);
|
||||
|
||||
// Generate a KEK.
|
||||
ScopedPK11SymKey kek(
|
||||
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
|
||||
ASSERT_NE(nullptr, kek);
|
||||
|
||||
// Wrap the key
|
||||
ScopedSECItem wrapped(::SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen));
|
||||
ScopedSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, nullptr));
|
||||
|
||||
SECStatus rv = PK11_WrapPrivKey(slot.get(), kek.get(), priv_key.get(),
|
||||
CKM_NSS_AES_KEY_WRAP_PAD, param.get(),
|
||||
wrapped.get(), nullptr);
|
||||
ASSERT_EQ(rv, SECSuccess);
|
||||
|
||||
SECItem pubKey = {siBuffer, unwrap_buf, kPublicKeyLen};
|
||||
CK_ATTRIBUTE_TYPE usages[] = {CKA_SIGN};
|
||||
int usageCount = 1;
|
||||
|
||||
ScopedSECKEYPrivateKey unwrapped(
|
||||
PK11_UnwrapPrivKey(slot.get(), kek.get(), CKM_NSS_AES_KEY_WRAP_PAD,
|
||||
param.get(), wrapped.get(), nullptr, &pubKey, false,
|
||||
true, CKK_EC, usages, usageCount, nullptr));
|
||||
ASSERT_EQ(0, PORT_GetError());
|
||||
ASSERT_TRUE(!!unwrapped);
|
||||
}
|
||||
|
||||
// Encrypt an ephemeral RSA key
|
||||
TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRsaKey) {
|
||||
const uint32_t kwrappedBufLen = 648;
|
||||
unsigned char unwrap_buf[kwrappedBufLen];
|
||||
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
|
||||
PK11RSAGenParams rsa_param;
|
||||
rsa_param.keySizeInBits = 1024;
|
||||
rsa_param.pe = 65537L;
|
||||
|
||||
SECKEYPublicKey* pub_tmp;
|
||||
ScopedSECKEYPublicKey pub_key;
|
||||
ScopedSECKEYPrivateKey priv_key(
|
||||
PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsa_param,
|
||||
&pub_tmp, PR_FALSE, PR_FALSE, nullptr));
|
||||
ASSERT_NE(nullptr, priv_key);
|
||||
ASSERT_NE(nullptr, pub_tmp);
|
||||
pub_key.reset(pub_tmp);
|
||||
|
||||
// Generate a KEK.
|
||||
ScopedPK11SymKey kek(
|
||||
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
|
||||
ASSERT_NE(nullptr, kek);
|
||||
|
||||
// Wrap the key
|
||||
ScopedSECItem wrapped(::SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen));
|
||||
ScopedSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, nullptr));
|
||||
|
||||
SECStatus rv = PK11_WrapPrivKey(slot.get(), kek.get(), priv_key.get(),
|
||||
CKM_NSS_AES_KEY_WRAP_PAD, param.get(),
|
||||
wrapped.get(), nullptr);
|
||||
ASSERT_EQ(rv, SECSuccess);
|
||||
|
||||
SECItem pubKey = {siBuffer, unwrap_buf, kwrappedBufLen};
|
||||
CK_ATTRIBUTE_TYPE usages[] = {CKA_SIGN};
|
||||
int usageCount = 1;
|
||||
|
||||
ScopedSECKEYPrivateKey unwrapped(
|
||||
PK11_UnwrapPrivKey(slot.get(), kek.get(), CKM_NSS_AES_KEY_WRAP_PAD,
|
||||
param.get(), wrapped.get(), nullptr, &pubKey, false,
|
||||
false, CKK_EC, usages, usageCount, nullptr));
|
||||
ASSERT_EQ(0, PORT_GetError());
|
||||
ASSERT_TRUE(!!unwrapped);
|
||||
|
||||
ScopedSECItem priv_key_data(
|
||||
PK11_ExportDERPrivateKeyInfo(priv_key.get(), nullptr));
|
||||
ScopedSECItem unwrapped_data(
|
||||
PK11_ExportDERPrivateKeyInfo(unwrapped.get(), nullptr));
|
||||
EXPECT_TRUE(!!priv_key_data);
|
||||
EXPECT_TRUE(!!unwrapped_data);
|
||||
ASSERT_EQ(priv_key_data->len, unwrapped_data->len);
|
||||
ASSERT_EQ(
|
||||
0, memcmp(priv_key_data->data, unwrapped_data->data, priv_key_data->len));
|
||||
}
|
||||
|
||||
// Wrap a random that's a multiple of the block size, and compare the unwrap
|
||||
// result.
|
||||
TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_EvenBlock) {
|
||||
const uint32_t kInputKeyLen = 128;
|
||||
uint32_t out_len = 0;
|
||||
std::vector<unsigned char> input_key(kInputKeyLen);
|
||||
std::vector<unsigned char> wrapped_key(
|
||||
kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
|
||||
std::vector<unsigned char> unwrapped_key(
|
||||
kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
|
||||
|
||||
// Generate input key material
|
||||
SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size());
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
// Generate a KEK.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
ScopedPK11SymKey kek(
|
||||
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
|
||||
ASSERT_NE(nullptr, kek);
|
||||
|
||||
// Wrap the key
|
||||
rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
wrapped_key.data(), &out_len,
|
||||
static_cast<unsigned int>(wrapped_key.size()),
|
||||
input_key.data(),
|
||||
static_cast<unsigned int>(input_key.size()));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
unwrapped_key.data(), &out_len,
|
||||
static_cast<unsigned int>(unwrapped_key.size()),
|
||||
wrapped_key.data(), out_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_EQ(input_key.size(), out_len);
|
||||
ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len));
|
||||
}
|
||||
|
||||
// Wrap a random that's NOT a multiple of the block size, and compare the unwrap
|
||||
// result.
|
||||
TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_OddBlock1) {
|
||||
const uint32_t kInputKeyLen = 65;
|
||||
uint32_t out_len = 0;
|
||||
std::vector<unsigned char> input_key(kInputKeyLen);
|
||||
std::vector<unsigned char> wrapped_key(
|
||||
kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
|
||||
std::vector<unsigned char> unwrapped_key(
|
||||
kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
|
||||
|
||||
// Generate input key material
|
||||
SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size());
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
// Generate a KEK.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
ScopedPK11SymKey kek(
|
||||
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
|
||||
ASSERT_NE(nullptr, kek);
|
||||
|
||||
// Wrap the key
|
||||
rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
wrapped_key.data(), &out_len,
|
||||
static_cast<unsigned int>(wrapped_key.size()),
|
||||
input_key.data(),
|
||||
static_cast<unsigned int>(input_key.size()));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
unwrapped_key.data(), &out_len,
|
||||
static_cast<unsigned int>(unwrapped_key.size()),
|
||||
wrapped_key.data(), out_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_EQ(input_key.size(), out_len);
|
||||
ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len));
|
||||
}
|
||||
|
||||
// Wrap a random that's NOT a multiple of the block size, and compare the unwrap
|
||||
// result.
|
||||
TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_OddBlock2) {
|
||||
const uint32_t kInputKeyLen = 63;
|
||||
uint32_t out_len = 0;
|
||||
std::vector<unsigned char> input_key(kInputKeyLen);
|
||||
std::vector<unsigned char> wrapped_key(
|
||||
kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
|
||||
std::vector<unsigned char> unwrapped_key(
|
||||
kInputKeyLen + AES_BLOCK_SIZE); // One block of padding
|
||||
|
||||
// Generate input key material
|
||||
SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size());
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
// Generate a KEK.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
ScopedPK11SymKey kek(
|
||||
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
|
||||
ASSERT_NE(nullptr, kek);
|
||||
|
||||
// Wrap the key
|
||||
rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
wrapped_key.data(), &out_len, wrapped_key.size(),
|
||||
input_key.data(), input_key.size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
unwrapped_key.data(), &out_len,
|
||||
static_cast<unsigned int>(unwrapped_key.size()),
|
||||
wrapped_key.data(), out_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_EQ(input_key.size(), out_len);
|
||||
ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len));
|
||||
}
|
||||
|
||||
// Invalid long padding (over the block size, but otherwise valid)
|
||||
TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_PaddingTooLong) {
|
||||
const uint32_t kInputKeyLen = 32;
|
||||
uint32_t out_len = 0;
|
||||
|
||||
// Apply our own padding
|
||||
const unsigned char buf[32] = {
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
|
||||
std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
|
||||
std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
|
||||
|
||||
// Generate a KEK.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
ScopedPK11SymKey kek(
|
||||
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
|
||||
ASSERT_NE(nullptr, kek);
|
||||
|
||||
// Wrap the key
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding
|
||||
/* param */ nullptr, wrapped_key.data(), &out_len,
|
||||
wrapped_key.size(), buf, sizeof(buf));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
unwrapped_key.data(), &out_len,
|
||||
static_cast<unsigned int>(unwrapped_key.size()),
|
||||
wrapped_key.data(), out_len);
|
||||
ASSERT_EQ(SECFailure, rv);
|
||||
}
|
||||
|
||||
// Invalid 0-length padding (there should be a full block if the message doesn't
|
||||
// need to be padded)
|
||||
TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_NoPadding) {
|
||||
const uint32_t kInputKeyLen = 32;
|
||||
uint32_t out_len = 0;
|
||||
|
||||
// Apply our own padding
|
||||
const unsigned char buf[32] = {0};
|
||||
std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
|
||||
std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
|
||||
|
||||
// Generate a KEK.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
ScopedPK11SymKey kek(
|
||||
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
|
||||
ASSERT_NE(nullptr, kek);
|
||||
|
||||
// Wrap the key
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding
|
||||
/* param */ nullptr, wrapped_key.data(), &out_len,
|
||||
wrapped_key.size(), buf, sizeof(buf));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
unwrapped_key.data(), &out_len,
|
||||
static_cast<unsigned int>(unwrapped_key.size()),
|
||||
wrapped_key.data(), out_len);
|
||||
ASSERT_EQ(SECFailure, rv);
|
||||
}
|
||||
|
||||
// Invalid padding
|
||||
TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_BadPadding1) {
|
||||
const uint32_t kInputKeyLen = 32;
|
||||
uint32_t out_len = 0;
|
||||
|
||||
// Apply our own padding
|
||||
const unsigned char buf[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08,
|
||||
0x08, 0x08, 0x08, 0x08}; // Check all 8 bytes
|
||||
std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
|
||||
std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
|
||||
|
||||
// Generate a KEK.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
ScopedPK11SymKey kek(
|
||||
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
|
||||
ASSERT_NE(nullptr, kek);
|
||||
|
||||
// Wrap the key
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding
|
||||
/* param */ nullptr, wrapped_key.data(), &out_len,
|
||||
wrapped_key.size(), buf, sizeof(buf));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
unwrapped_key.data(), &out_len,
|
||||
static_cast<unsigned int>(unwrapped_key.size()),
|
||||
wrapped_key.data(), out_len);
|
||||
ASSERT_EQ(SECFailure, rv);
|
||||
}
|
||||
|
||||
// Invalid padding
|
||||
TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_BadPadding2) {
|
||||
const uint32_t kInputKeyLen = 32;
|
||||
uint32_t out_len = 0;
|
||||
|
||||
// Apply our own padding
|
||||
const unsigned char
|
||||
buf[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x02}; // Check first loop repeat
|
||||
std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
|
||||
std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
|
||||
|
||||
// Generate a KEK.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
ScopedPK11SymKey kek(
|
||||
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
|
||||
ASSERT_NE(nullptr, kek);
|
||||
|
||||
// Wrap the key
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding
|
||||
/* param */ nullptr, wrapped_key.data(), &out_len,
|
||||
wrapped_key.size(), buf, sizeof(buf));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
unwrapped_key.data(), &out_len,
|
||||
static_cast<unsigned int>(unwrapped_key.size()),
|
||||
wrapped_key.data(), out_len);
|
||||
ASSERT_EQ(SECFailure, rv);
|
||||
}
|
||||
|
||||
// Minimum valid padding
|
||||
TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_ShortValidPadding) {
|
||||
const uint32_t kInputKeyLen = 32;
|
||||
uint32_t out_len = 0;
|
||||
|
||||
// Apply our own padding
|
||||
const unsigned char buf[kInputKeyLen] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; // Minimum
|
||||
std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
|
||||
std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
|
||||
|
||||
// Generate a KEK.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
ScopedPK11SymKey kek(
|
||||
PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
|
||||
ASSERT_NE(nullptr, kek);
|
||||
|
||||
// Wrap the key
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP, // Don't apply more padding
|
||||
/* param */ nullptr, wrapped_key.data(), &out_len,
|
||||
wrapped_key.size(), buf, sizeof(buf));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
|
||||
unwrapped_key.data(), &out_len,
|
||||
static_cast<unsigned int>(unwrapped_key.size()),
|
||||
wrapped_key.data(), out_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_EQ(kInputKeyLen - 1, out_len);
|
||||
ASSERT_EQ(0, memcmp(buf, unwrapped_key.data(), out_len));
|
||||
}
|
||||
|
||||
} /* nss_test */
|
||||
558
security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc
Normal file
558
security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc
Normal file
|
|
@ -0,0 +1,558 @@
|
|||
/* -*- 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 <memory>
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "secerr.h"
|
||||
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
static const uint8_t kInput[99] = {1, 2, 3};
|
||||
static const uint8_t kKeyData[24] = {'K', 'E', 'Y'};
|
||||
|
||||
static SECItem* GetIv() {
|
||||
static const uint8_t kIvData[16] = {'I', 'V'};
|
||||
static const SECItem kIv = {siBuffer, const_cast<uint8_t*>(kIvData),
|
||||
static_cast<unsigned int>(sizeof(kIvData))};
|
||||
return const_cast<SECItem*>(&kIv);
|
||||
}
|
||||
|
||||
class Pkcs11CbcPadTest : public ::testing::TestWithParam<CK_MECHANISM_TYPE> {
|
||||
protected:
|
||||
bool is_padded() const {
|
||||
switch (GetParam()) {
|
||||
case CKM_AES_CBC_PAD:
|
||||
case CKM_DES3_CBC_PAD:
|
||||
return true;
|
||||
|
||||
case CKM_AES_CBC:
|
||||
case CKM_DES3_CBC:
|
||||
return false;
|
||||
|
||||
default:
|
||||
ADD_FAILURE() << "Unknown mechanism " << GetParam();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t GetUnpaddedMechanism() const {
|
||||
switch (GetParam()) {
|
||||
case CKM_AES_CBC_PAD:
|
||||
return CKM_AES_CBC;
|
||||
case CKM_DES3_CBC_PAD:
|
||||
return CKM_DES3_CBC;
|
||||
default:
|
||||
ADD_FAILURE() << "Unknown padded mechanism " << GetParam();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t block_size() const {
|
||||
return static_cast<size_t>(PK11_GetBlockSize(GetParam(), nullptr));
|
||||
}
|
||||
|
||||
size_t GetInputLen(CK_ATTRIBUTE_TYPE op) const {
|
||||
if (is_padded() && op == CKA_ENCRYPT) {
|
||||
// Anything goes for encryption when padded.
|
||||
return sizeof(kInput);
|
||||
}
|
||||
|
||||
// Otherwise, use a strict multiple of the block size.
|
||||
size_t block_count = sizeof(kInput) / block_size();
|
||||
EXPECT_LT(1U, block_count) << "need 2 blocks for tests";
|
||||
return block_count * block_size();
|
||||
}
|
||||
|
||||
ScopedPK11SymKey MakeKey(CK_ATTRIBUTE_TYPE op) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
EXPECT_NE(nullptr, slot);
|
||||
if (!slot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int key_len = 0;
|
||||
switch (GetParam()) {
|
||||
case CKM_AES_CBC_PAD:
|
||||
case CKM_AES_CBC:
|
||||
key_len = 16; // This doesn't do AES-256 to keep it simple.
|
||||
break;
|
||||
|
||||
case CKM_DES3_CBC_PAD:
|
||||
case CKM_DES3_CBC:
|
||||
key_len = 24;
|
||||
break;
|
||||
|
||||
default:
|
||||
ADD_FAILURE() << "Unknown mechanism " << GetParam();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SECItem key_item = {siBuffer, const_cast<uint8_t*>(kKeyData), key_len};
|
||||
PK11SymKey* p = PK11_ImportSymKey(slot.get(), GetParam(), PK11_OriginUnwrap,
|
||||
op, &key_item, nullptr);
|
||||
EXPECT_NE(nullptr, p);
|
||||
return ScopedPK11SymKey(p);
|
||||
}
|
||||
|
||||
ScopedPK11Context MakeContext(CK_ATTRIBUTE_TYPE op) {
|
||||
ScopedPK11SymKey k = MakeKey(op);
|
||||
PK11Context* ctx =
|
||||
PK11_CreateContextBySymKey(GetParam(), op, k.get(), GetIv());
|
||||
EXPECT_NE(nullptr, ctx);
|
||||
return ScopedPK11Context(ctx);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, EncryptDecrypt) {
|
||||
uint8_t encrypted[sizeof(kInput) + 64]; // Allow for padding and expansion.
|
||||
size_t input_len = GetInputLen(CKA_ENCRYPT);
|
||||
|
||||
ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
|
||||
unsigned int encrypted_len = 0;
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(ek.get(), GetParam(), GetIv(), encrypted, &encrypted_len,
|
||||
sizeof(encrypted), kInput, input_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_LE(input_len, static_cast<size_t>(encrypted_len));
|
||||
|
||||
// Though the decrypted result can't be larger than the input we provided,
|
||||
// NSS needs extra space to put the padding in.
|
||||
uint8_t decrypted[sizeof(kInput) + 64];
|
||||
unsigned int decrypted_len = 0;
|
||||
ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
|
||||
rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted, &decrypted_len,
|
||||
sizeof(decrypted), encrypted, encrypted_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_EQ(input_len, static_cast<size_t>(decrypted_len));
|
||||
EXPECT_EQ(0, memcmp(kInput, decrypted, input_len));
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, ContextEncryptDecrypt) {
|
||||
uint8_t encrypted[sizeof(kInput) + 64]; // Allow for padding and expansion.
|
||||
size_t input_len = GetInputLen(CKA_ENCRYPT);
|
||||
|
||||
ScopedPK11Context ectx = MakeContext(CKA_ENCRYPT);
|
||||
int encrypted_len = 0;
|
||||
SECStatus rv = PK11_CipherOp(ectx.get(), encrypted, &encrypted_len,
|
||||
sizeof(encrypted), kInput, input_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_LE(0, encrypted_len); // Stupid signed parameters.
|
||||
|
||||
unsigned int final_len = 0;
|
||||
rv = PK11_CipherFinal(ectx.get(), encrypted + encrypted_len, &final_len,
|
||||
sizeof(encrypted) - encrypted_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
encrypted_len += final_len;
|
||||
EXPECT_LE(input_len, static_cast<size_t>(encrypted_len));
|
||||
|
||||
uint8_t decrypted[sizeof(kInput) + 64];
|
||||
int decrypted_len = 0;
|
||||
ScopedPK11Context dctx = MakeContext(CKA_DECRYPT);
|
||||
rv = PK11_CipherOp(dctx.get(), decrypted, &decrypted_len, sizeof(decrypted),
|
||||
encrypted, encrypted_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_LE(0, decrypted_len);
|
||||
|
||||
rv = PK11_CipherFinal(dctx.get(), decrypted + decrypted_len, &final_len,
|
||||
sizeof(decrypted) - decrypted_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
decrypted_len += final_len;
|
||||
EXPECT_EQ(input_len, static_cast<size_t>(decrypted_len));
|
||||
EXPECT_EQ(0, memcmp(kInput, decrypted, input_len));
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, ContextEncryptDecryptTwoParts) {
|
||||
uint8_t encrypted[sizeof(kInput) + 64];
|
||||
size_t input_len = GetInputLen(CKA_ENCRYPT);
|
||||
|
||||
ScopedPK11Context ectx = MakeContext(CKA_ENCRYPT);
|
||||
int first_len = 0;
|
||||
SECStatus rv = PK11_CipherOp(ectx.get(), encrypted, &first_len,
|
||||
sizeof(encrypted), kInput, block_size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_LE(0, first_len);
|
||||
|
||||
int second_len = 0;
|
||||
rv = PK11_CipherOp(ectx.get(), encrypted + first_len, &second_len,
|
||||
sizeof(encrypted) - first_len, kInput + block_size(),
|
||||
input_len - block_size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_LE(0, second_len);
|
||||
|
||||
unsigned int final_len = 0;
|
||||
rv = PK11_CipherFinal(ectx.get(), encrypted + first_len + second_len,
|
||||
&final_len, sizeof(encrypted) - first_len - second_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
unsigned int encrypted_len = first_len + second_len + final_len;
|
||||
ASSERT_LE(input_len, static_cast<size_t>(encrypted_len));
|
||||
|
||||
// Now decrypt this in a similar fashion.
|
||||
uint8_t decrypted[sizeof(kInput) + 64];
|
||||
ScopedPK11Context dctx = MakeContext(CKA_DECRYPT);
|
||||
rv = PK11_CipherOp(dctx.get(), decrypted, &first_len, sizeof(decrypted),
|
||||
encrypted, block_size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_LE(0, first_len);
|
||||
|
||||
rv = PK11_CipherOp(dctx.get(), decrypted + first_len, &second_len,
|
||||
sizeof(decrypted) - first_len, encrypted + block_size(),
|
||||
encrypted_len - block_size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_LE(0, second_len);
|
||||
|
||||
unsigned int decrypted_len = 0;
|
||||
rv = PK11_CipherFinal(dctx.get(), decrypted + first_len + second_len,
|
||||
&decrypted_len,
|
||||
sizeof(decrypted) - first_len - second_len);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
decrypted_len += first_len + second_len;
|
||||
EXPECT_EQ(input_len, static_cast<size_t>(decrypted_len));
|
||||
EXPECT_EQ(0, memcmp(kInput, decrypted, input_len));
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, FailDecryptSimple) {
|
||||
ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
|
||||
uint8_t output[sizeof(kInput) + 64];
|
||||
unsigned int output_len = 999;
|
||||
SECStatus rv =
|
||||
PK11_Decrypt(dk.get(), GetParam(), GetIv(), output, &output_len,
|
||||
sizeof(output), kInput, GetInputLen(CKA_DECRYPT));
|
||||
if (is_padded()) {
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(999U, output_len);
|
||||
} else {
|
||||
// Unpadded decryption can't really fail.
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, FailEncryptSimple) {
|
||||
ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
|
||||
uint8_t output[3]; // Too small for anything.
|
||||
unsigned int output_len = 333;
|
||||
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(ek.get(), GetParam(), GetIv(), output, &output_len,
|
||||
sizeof(output), kInput, GetInputLen(CKA_ENCRYPT));
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(333U, output_len);
|
||||
}
|
||||
|
||||
// It's a bit of a lie to put this in pk11_cbc_unittest, since we
|
||||
// also test bounds checking in other modes. There doesn't seem
|
||||
// to be an appropriately-generic place elsewhere.
|
||||
TEST_F(Pkcs11CbcPadTest, FailEncryptShortParam) {
|
||||
SECStatus rv = SECFailure;
|
||||
uint8_t encrypted[sizeof(kInput)];
|
||||
unsigned int encrypted_len = 0;
|
||||
size_t input_len = AES_BLOCK_SIZE;
|
||||
|
||||
// CK_GCM_PARAMS is the largest param struct used across AES modes
|
||||
uint8_t param_buf[sizeof(CK_GCM_PARAMS)];
|
||||
SECItem param = {siBuffer, param_buf, sizeof(param_buf)};
|
||||
SECItem key_item = {siBuffer, const_cast<uint8_t*>(kKeyData), 16};
|
||||
|
||||
// Setup (we use the ECB key for other modes)
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ASSERT_NE(nullptr, slot);
|
||||
ScopedPK11SymKey key(PK11_ImportSymKey(slot.get(), CKM_AES_ECB,
|
||||
PK11_OriginUnwrap, CKA_ENCRYPT,
|
||||
&key_item, nullptr));
|
||||
ASSERT_TRUE(key.get());
|
||||
|
||||
// CTR should have a CK_AES_CTR_PARAMS
|
||||
param.len = sizeof(CK_AES_CTR_PARAMS) - 1;
|
||||
rv = PK11_Encrypt(key.get(), CKM_AES_CTR, ¶m, encrypted, &encrypted_len,
|
||||
sizeof(encrypted), kInput, input_len);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
|
||||
param.len++;
|
||||
reinterpret_cast<CK_AES_CTR_PARAMS*>(param.data)->ulCounterBits = 32;
|
||||
rv = PK11_Encrypt(key.get(), CKM_AES_CTR, ¶m, encrypted, &encrypted_len,
|
||||
sizeof(encrypted), kInput, input_len);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
// GCM should have a CK_GCM_PARAMS
|
||||
param.len = sizeof(CK_GCM_PARAMS) - 1;
|
||||
rv = PK11_Encrypt(key.get(), CKM_AES_GCM, ¶m, encrypted, &encrypted_len,
|
||||
sizeof(encrypted), kInput, input_len);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
|
||||
param.len++;
|
||||
reinterpret_cast<CK_GCM_PARAMS*>(param.data)->pIv = param_buf;
|
||||
reinterpret_cast<CK_GCM_PARAMS*>(param.data)->ulIvLen = 12;
|
||||
reinterpret_cast<CK_GCM_PARAMS*>(param.data)->pAAD = nullptr;
|
||||
reinterpret_cast<CK_GCM_PARAMS*>(param.data)->ulAADLen = 0;
|
||||
reinterpret_cast<CK_GCM_PARAMS*>(param.data)->ulTagBits = 128;
|
||||
rv = PK11_Encrypt(key.get(), CKM_AES_GCM, ¶m, encrypted, &encrypted_len,
|
||||
sizeof(encrypted), kInput, input_len);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
// CBC should have a 16B IV
|
||||
param.len = AES_BLOCK_SIZE - 1;
|
||||
rv = PK11_Encrypt(key.get(), CKM_AES_CBC, ¶m, encrypted, &encrypted_len,
|
||||
sizeof(encrypted), kInput, input_len);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
|
||||
param.len++;
|
||||
rv = PK11_Encrypt(key.get(), CKM_AES_CBC, ¶m, encrypted, &encrypted_len,
|
||||
sizeof(encrypted), kInput, input_len);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
// CTS
|
||||
param.len = AES_BLOCK_SIZE - 1;
|
||||
rv = PK11_Encrypt(key.get(), CKM_AES_CTS, ¶m, encrypted, &encrypted_len,
|
||||
sizeof(encrypted), kInput, input_len);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
|
||||
param.len++;
|
||||
rv = PK11_Encrypt(key.get(), CKM_AES_CTS, ¶m, encrypted, &encrypted_len,
|
||||
sizeof(encrypted), kInput, input_len);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, ContextFailDecryptSimple) {
|
||||
ScopedPK11Context dctx = MakeContext(CKA_DECRYPT);
|
||||
uint8_t output[sizeof(kInput) + 64];
|
||||
int output_len = 77;
|
||||
|
||||
SECStatus rv = PK11_CipherOp(dctx.get(), output, &output_len, sizeof(output),
|
||||
kInput, GetInputLen(CKA_DECRYPT));
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
EXPECT_LE(0, output_len) << "this is not an AEAD, so content leaks";
|
||||
|
||||
unsigned int final_len = 88;
|
||||
rv = PK11_CipherFinal(dctx.get(), output, &final_len, sizeof(output));
|
||||
if (is_padded()) {
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
ASSERT_EQ(88U, final_len) << "final_len should be untouched";
|
||||
} else {
|
||||
// Unpadded decryption can't really fail.
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, ContextFailDecryptInvalidBlockSize) {
|
||||
ScopedPK11Context dctx = MakeContext(CKA_DECRYPT);
|
||||
uint8_t output[sizeof(kInput) + 64];
|
||||
int output_len = 888;
|
||||
|
||||
SECStatus rv = PK11_CipherOp(dctx.get(), output, &output_len, sizeof(output),
|
||||
kInput, GetInputLen(CKA_DECRYPT) - 1);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
// Because PK11_CipherOp is partial, it can return data on failure.
|
||||
// This means that it needs to reset its output length to 0 when it starts.
|
||||
EXPECT_EQ(0, output_len) << "output_len is reset";
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_PaddingTooLong) {
|
||||
if (!is_padded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Padding that's over the block size
|
||||
const std::vector<uint8_t> input = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
|
||||
std::vector<uint8_t> encrypted(input.size());
|
||||
uint32_t encrypted_len = 0;
|
||||
|
||||
ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
|
||||
SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(),
|
||||
encrypted.data(), &encrypted_len,
|
||||
encrypted.size(), input.data(), input.size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_EQ(input.size(), encrypted_len);
|
||||
|
||||
std::vector<uint8_t> decrypted(input.size());
|
||||
uint32_t decrypted_len = 0;
|
||||
ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
|
||||
rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(),
|
||||
&decrypted_len, decrypted.size(), encrypted.data(),
|
||||
encrypted_len);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(0U, decrypted_len);
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_ShortPadding1) {
|
||||
if (!is_padded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Padding that's one byte short
|
||||
const std::vector<uint8_t> input = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
|
||||
std::vector<uint8_t> encrypted(input.size());
|
||||
uint32_t encrypted_len = 0;
|
||||
|
||||
ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
|
||||
SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(),
|
||||
encrypted.data(), &encrypted_len,
|
||||
encrypted.size(), input.data(), input.size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_EQ(input.size(), encrypted_len);
|
||||
|
||||
std::vector<uint8_t> decrypted(input.size());
|
||||
uint32_t decrypted_len = 0;
|
||||
ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
|
||||
rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(),
|
||||
&decrypted_len, decrypted.size(), encrypted.data(),
|
||||
encrypted_len);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(0U, decrypted_len);
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_ShortPadding2) {
|
||||
if (!is_padded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Padding that's one byte short
|
||||
const std::vector<uint8_t> input = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02};
|
||||
std::vector<uint8_t> encrypted(input.size());
|
||||
uint32_t encrypted_len = 0;
|
||||
|
||||
ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
|
||||
SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(),
|
||||
encrypted.data(), &encrypted_len,
|
||||
encrypted.size(), input.data(), input.size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_EQ(input.size(), encrypted_len);
|
||||
|
||||
std::vector<uint8_t> decrypted(input.size());
|
||||
uint32_t decrypted_len = 0;
|
||||
ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
|
||||
rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(),
|
||||
&decrypted_len, decrypted.size(), encrypted.data(),
|
||||
encrypted_len);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(0U, decrypted_len);
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_ZeroLengthPadding) {
|
||||
if (!is_padded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Padding of length zero
|
||||
const std::vector<uint8_t> input = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
std::vector<uint8_t> encrypted(input.size());
|
||||
uint32_t encrypted_len = 0;
|
||||
|
||||
ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
|
||||
SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(),
|
||||
encrypted.data(), &encrypted_len,
|
||||
encrypted.size(), input.data(), input.size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_EQ(input.size(), encrypted_len);
|
||||
|
||||
std::vector<uint8_t> decrypted(input.size());
|
||||
uint32_t decrypted_len = 0;
|
||||
ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
|
||||
rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(),
|
||||
&decrypted_len, decrypted.size(), encrypted.data(),
|
||||
encrypted_len);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(0U, decrypted_len);
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_OverflowPadding) {
|
||||
if (!is_padded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Padding that's much longer than block size
|
||||
const std::vector<uint8_t> input = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
std::vector<uint8_t> encrypted(input.size());
|
||||
uint32_t encrypted_len = 0;
|
||||
|
||||
ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
|
||||
SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(),
|
||||
encrypted.data(), &encrypted_len,
|
||||
encrypted.size(), input.data(), input.size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_EQ(input.size(), encrypted_len);
|
||||
|
||||
std::vector<uint8_t> decrypted(input.size());
|
||||
uint32_t decrypted_len = 0;
|
||||
ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
|
||||
rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(),
|
||||
&decrypted_len, decrypted.size(), encrypted.data(),
|
||||
encrypted_len);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(0U, decrypted_len);
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_ShortValidPadding) {
|
||||
if (!is_padded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Minimal valid padding
|
||||
const std::vector<uint8_t> input = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
|
||||
std::vector<uint8_t> encrypted(input.size());
|
||||
uint32_t encrypted_len = 0;
|
||||
|
||||
ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
|
||||
SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedMechanism(), GetIv(),
|
||||
encrypted.data(), &encrypted_len,
|
||||
encrypted.size(), input.data(), input.size());
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
EXPECT_EQ(input.size(), encrypted_len);
|
||||
|
||||
std::vector<uint8_t> decrypted(input.size());
|
||||
uint32_t decrypted_len = 0;
|
||||
ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
|
||||
rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(),
|
||||
&decrypted_len, decrypted.size(), encrypted.data(),
|
||||
encrypted_len);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
EXPECT_EQ(input.size() - 1, decrypted_len);
|
||||
EXPECT_EQ(0, memcmp(decrypted.data(), input.data(), decrypted_len));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(EncryptDecrypt, Pkcs11CbcPadTest,
|
||||
::testing::Values(CKM_AES_CBC_PAD, CKM_AES_CBC,
|
||||
CKM_DES3_CBC_PAD, CKM_DES3_CBC));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -8,114 +8,31 @@
|
|||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "sechash.h"
|
||||
#include "secerr.h"
|
||||
|
||||
#include "cpputil.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
|
||||
#include "testvectors/chachapoly-vectors.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// ChaCha20/Poly1305 Test Vector 1, RFC 7539
|
||||
// <http://tools.ietf.org/html/rfc7539#section-2.8.2>
|
||||
const uint8_t kTestVector1Data[] = {
|
||||
0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47,
|
||||
0x65, 0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
|
||||
0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66,
|
||||
0x20, 0x27, 0x39, 0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
|
||||
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79,
|
||||
0x6f, 0x75, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
|
||||
0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20,
|
||||
0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
|
||||
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20,
|
||||
0x62, 0x65, 0x20, 0x69, 0x74, 0x2e};
|
||||
const uint8_t kTestVector1AAD[] = {0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1,
|
||||
0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7};
|
||||
const uint8_t kTestVector1Key[] = {
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a,
|
||||
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
|
||||
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f};
|
||||
const uint8_t kTestVector1IV[] = {0x07, 0x00, 0x00, 0x00, 0x40, 0x41,
|
||||
0x42, 0x43, 0x44, 0x45, 0x46, 0x47};
|
||||
const uint8_t kTestVector1CT[] = {
|
||||
0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc,
|
||||
0x53, 0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
|
||||
0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e,
|
||||
0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
|
||||
0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6,
|
||||
0x7e, 0xcd, 0x3b, 0x36, 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
|
||||
0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4,
|
||||
0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
|
||||
0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65,
|
||||
0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16, 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09,
|
||||
0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91};
|
||||
static const CK_MECHANISM_TYPE kMech = CKM_NSS_CHACHA20_POLY1305;
|
||||
static const CK_MECHANISM_TYPE kMechXor = CKM_NSS_CHACHA20_CTR;
|
||||
// Some test data for simple tests.
|
||||
static const uint8_t kKeyData[32] = {'k'};
|
||||
static const uint8_t kCtrNonce[16] = {'c', 0, 0, 0, 'n'};
|
||||
static const uint8_t kData[16] = {'d'};
|
||||
|
||||
// ChaCha20/Poly1305 Test Vector 2, RFC 7539
|
||||
// <http://tools.ietf.org/html/rfc7539#appendix-A.5>
|
||||
const uint8_t kTestVector2Data[] = {
|
||||
0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61,
|
||||
0x66, 0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66,
|
||||
0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20,
|
||||
0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20,
|
||||
0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x6f, 0x66, 0x20, 0x73,
|
||||
0x69, 0x78, 0x20, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e,
|
||||
0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x75, 0x70, 0x64,
|
||||
0x61, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63,
|
||||
0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f, 0x62, 0x73, 0x6f, 0x6c,
|
||||
0x65, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65,
|
||||
0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20,
|
||||
0x61, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e,
|
||||
0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x61, 0x70, 0x70,
|
||||
0x72, 0x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20,
|
||||
0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74,
|
||||
0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72,
|
||||
0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6d, 0x61, 0x74,
|
||||
0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20,
|
||||
0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6d, 0x20, 0x6f, 0x74,
|
||||
0x68, 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20,
|
||||
0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x69, 0x6e, 0x20,
|
||||
0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80,
|
||||
0x9d};
|
||||
const uint8_t kTestVector2AAD[] = {0xf3, 0x33, 0x88, 0x86, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x4e, 0x91};
|
||||
const uint8_t kTestVector2Key[] = {
|
||||
0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, 0xf3, 0x33, 0x88,
|
||||
0x86, 0x04, 0xf6, 0xb5, 0xf0, 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b,
|
||||
0x80, 0x09, 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0};
|
||||
const uint8_t kTestVector2IV[] = {0x00, 0x00, 0x00, 0x00, 0x01, 0x02,
|
||||
0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
||||
const uint8_t kTestVector2CT[] = {
|
||||
0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4, 0x60, 0xf0, 0x62, 0xc7,
|
||||
0x9b, 0xe6, 0x43, 0xbd, 0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89,
|
||||
0xf1, 0x08, 0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2, 0x4c, 0x6c, 0xfc, 0x18,
|
||||
0x75, 0x5d, 0x43, 0xee, 0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0,
|
||||
0xbd, 0xb7, 0xb7, 0x3c, 0x32, 0x1b, 0x01, 0x00, 0xd4, 0xf0, 0x3b, 0x7f,
|
||||
0x35, 0x58, 0x94, 0xcf, 0x33, 0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce,
|
||||
0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b, 0x94, 0x81, 0x14, 0xad, 0x17, 0x6e,
|
||||
0x00, 0x8d, 0x33, 0xbd, 0x60, 0xf9, 0x82, 0xb1, 0xff, 0x37, 0xc8, 0x55,
|
||||
0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61, 0xc1, 0x86, 0x32, 0x4e,
|
||||
0x2b, 0x35, 0x06, 0x38, 0x36, 0x06, 0x90, 0x7b, 0x6a, 0x7c, 0x02, 0xb0,
|
||||
0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4, 0xb9, 0x16, 0x6c, 0x76,
|
||||
0x7b, 0x80, 0x4d, 0x46, 0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4, 0xe9,
|
||||
0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e, 0xe2, 0x82, 0xa1, 0xb0,
|
||||
0xa0, 0x6c, 0x52, 0x3e, 0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15,
|
||||
0x5b, 0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a, 0x0d, 0x07, 0x2b, 0x04,
|
||||
0xb3, 0x56, 0x4e, 0xea, 0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a,
|
||||
0x0b, 0xb2, 0x31, 0x60, 0x53, 0xfa, 0x76, 0x99, 0x19, 0x55, 0xeb, 0xd6,
|
||||
0x31, 0x59, 0x43, 0x4e, 0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10,
|
||||
0x73, 0xa6, 0x72, 0x76, 0x27, 0x09, 0x7a, 0x10, 0x49, 0xe6, 0x17, 0xd9,
|
||||
0x1d, 0x36, 0x10, 0x94, 0xfa, 0x68, 0xf0, 0xff, 0x77, 0x98, 0x71, 0x30,
|
||||
0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04, 0xdf, 0x99, 0x7b, 0x71, 0x4d,
|
||||
0x6c, 0x6f, 0x2c, 0x29, 0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70,
|
||||
0x9b, 0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb, 0x22, 0x39, 0x23, 0x36,
|
||||
0xfe, 0xa1, 0x85, 0x1f, 0x38};
|
||||
|
||||
class Pkcs11ChaCha20Poly1305Test : public ::testing::Test {
|
||||
class Pkcs11ChaCha20Poly1305Test
|
||||
: public ::testing::TestWithParam<chaChaTestVector> {
|
||||
public:
|
||||
void EncryptDecrypt(PK11SymKey* symKey, const uint8_t* data, size_t data_len,
|
||||
const uint8_t* aad, size_t aad_len, const uint8_t* iv,
|
||||
size_t iv_len, const uint8_t* ct = nullptr,
|
||||
size_t ct_len = 0) {
|
||||
void EncryptDecrypt(const ScopedPK11SymKey& key, const bool invalid_iv,
|
||||
const bool invalid_tag, const uint8_t* data,
|
||||
size_t data_len, const uint8_t* aad, size_t aad_len,
|
||||
const uint8_t* iv, size_t iv_len,
|
||||
const uint8_t* ct = nullptr, size_t ct_len = 0) {
|
||||
// Prepare AEAD params.
|
||||
CK_NSS_AEAD_PARAMS aead_params;
|
||||
aead_params.pNonce = toUcharPtr(iv);
|
||||
|
|
@ -127,135 +44,261 @@ class Pkcs11ChaCha20Poly1305Test : public ::testing::Test {
|
|||
SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&aead_params),
|
||||
sizeof(aead_params)};
|
||||
|
||||
// Encrypt with bad parameters.
|
||||
unsigned int encrypted_len = 0;
|
||||
std::vector<uint8_t> encrypted(data_len + aead_params.ulTagLen);
|
||||
aead_params.ulTagLen = 158072;
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(key.get(), kMech, ¶ms, encrypted.data(),
|
||||
&encrypted_len, encrypted.size(), data, data_len);
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(0U, encrypted_len);
|
||||
aead_params.ulTagLen = 16;
|
||||
|
||||
// Encrypt.
|
||||
unsigned int outputLen = 0;
|
||||
std::vector<uint8_t> output(data_len + aead_params.ulTagLen);
|
||||
SECStatus rv = PK11_Encrypt(symKey, mech, ¶ms, &output[0], &outputLen,
|
||||
output.size(), data, data_len);
|
||||
rv = PK11_Encrypt(key.get(), kMech, ¶ms, encrypted.data(),
|
||||
&encrypted_len, encrypted.size(), data, data_len);
|
||||
|
||||
// Return if encryption failure was expected due to invalid IV.
|
||||
// Without valid ciphertext, all further tests can be skipped.
|
||||
if (invalid_iv) {
|
||||
EXPECT_EQ(rv, SECFailure);
|
||||
EXPECT_EQ(0U, encrypted_len)
|
||||
<< "encrypted_len is unmodified after failure";
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
EXPECT_EQ(encrypted.size(), static_cast<size_t>(encrypted_len));
|
||||
|
||||
// Check ciphertext and tag.
|
||||
if (ct) {
|
||||
EXPECT_TRUE(!memcmp(ct, &output[0], outputLen));
|
||||
ASSERT_EQ(ct_len, encrypted_len);
|
||||
EXPECT_TRUE(!memcmp(ct, encrypted.data(), encrypted.size()) !=
|
||||
invalid_tag);
|
||||
}
|
||||
|
||||
// Decrypt.
|
||||
unsigned int decryptedLen = 0;
|
||||
std::vector<uint8_t> decrypted(data_len);
|
||||
rv = PK11_Decrypt(symKey, mech, ¶ms, &decrypted[0], &decryptedLen,
|
||||
decrypted.size(), &output[0], outputLen);
|
||||
// Get the *estimated* plaintext length. This value should
|
||||
// never be zero as it could lead to a NULL outPtr being
|
||||
// passed to a subsequent decryption call (for AEAD we
|
||||
// must authenticate even when the pt is zero-length).
|
||||
unsigned int decrypt_bytes_needed = 0;
|
||||
rv = PK11_Decrypt(key.get(), kMech, ¶ms, nullptr, &decrypt_bytes_needed,
|
||||
0, encrypted.data(), encrypted_len);
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
EXPECT_GT(decrypt_bytes_needed, data_len);
|
||||
|
||||
// Now decrypt it
|
||||
std::vector<uint8_t> decrypted(decrypt_bytes_needed);
|
||||
unsigned int decrypted_len = 0;
|
||||
rv = PK11_Decrypt(key.get(), kMech, ¶ms, decrypted.data(),
|
||||
&decrypted_len, decrypted.size(), encrypted.data(),
|
||||
encrypted.size());
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
|
||||
// Check the plaintext.
|
||||
EXPECT_TRUE(!memcmp(data, &decrypted[0], decryptedLen));
|
||||
ASSERT_EQ(data_len, decrypted_len);
|
||||
EXPECT_TRUE(!memcmp(data, decrypted.data(), decrypted_len));
|
||||
|
||||
// Decrypt with bogus data.
|
||||
{
|
||||
std::vector<uint8_t> bogusCiphertext(output);
|
||||
bogusCiphertext[0] ^= 0xff;
|
||||
rv = PK11_Decrypt(symKey, mech, ¶ms, &decrypted[0], &decryptedLen,
|
||||
decrypted.size(), &bogusCiphertext[0], outputLen);
|
||||
EXPECT_NE(rv, SECSuccess);
|
||||
// Skip if there's no data to modify.
|
||||
if (encrypted_len > 0) {
|
||||
decrypted_len = 0;
|
||||
std::vector<uint8_t> bogus_ciphertext(encrypted);
|
||||
bogus_ciphertext[0] ^= 0xff;
|
||||
rv = PK11_Decrypt(key.get(), kMech, ¶ms, decrypted.data(),
|
||||
&decrypted_len, decrypted.size(),
|
||||
bogus_ciphertext.data(), encrypted_len);
|
||||
EXPECT_EQ(rv, SECFailure);
|
||||
EXPECT_EQ(0U, decrypted_len);
|
||||
}
|
||||
|
||||
// Decrypt with bogus tag.
|
||||
{
|
||||
std::vector<uint8_t> bogusTag(output);
|
||||
bogusTag[outputLen - 1] ^= 0xff;
|
||||
rv = PK11_Decrypt(symKey, mech, ¶ms, &decrypted[0], &decryptedLen,
|
||||
decrypted.size(), &bogusTag[0], outputLen);
|
||||
EXPECT_NE(rv, SECSuccess);
|
||||
// Skip if there's no tag to modify.
|
||||
if (encrypted_len > 0) {
|
||||
decrypted_len = 0;
|
||||
std::vector<uint8_t> bogus_tag(encrypted);
|
||||
bogus_tag[encrypted_len - 1] ^= 0xff;
|
||||
rv = PK11_Decrypt(key.get(), kMech, ¶ms, decrypted.data(),
|
||||
&decrypted_len, decrypted.size(), bogus_tag.data(),
|
||||
encrypted_len);
|
||||
EXPECT_EQ(rv, SECFailure);
|
||||
EXPECT_EQ(0U, decrypted_len);
|
||||
}
|
||||
|
||||
// Decrypt with bogus IV.
|
||||
{
|
||||
SECItem bogusParams(params);
|
||||
// iv_len == 0 is invalid and should be caught earlier.
|
||||
// Still skip, if there's no IV to modify.
|
||||
if (iv_len != 0) {
|
||||
decrypted_len = 0;
|
||||
SECItem bogus_params(params);
|
||||
CK_NSS_AEAD_PARAMS bogusAeadParams(aead_params);
|
||||
bogusParams.data = reinterpret_cast<unsigned char*>(&bogusAeadParams);
|
||||
bogus_params.data = reinterpret_cast<unsigned char*>(&bogusAeadParams);
|
||||
|
||||
std::vector<uint8_t> bogusIV(iv, iv + iv_len);
|
||||
bogusAeadParams.pNonce = toUcharPtr(&bogusIV[0]);
|
||||
bogusAeadParams.pNonce = toUcharPtr(bogusIV.data());
|
||||
bogusIV[0] ^= 0xff;
|
||||
|
||||
rv = PK11_Decrypt(symKey, mech, &bogusParams, &decrypted[0],
|
||||
&decryptedLen, data_len, &output[0], outputLen);
|
||||
EXPECT_NE(rv, SECSuccess);
|
||||
rv = PK11_Decrypt(key.get(), kMech, &bogus_params, decrypted.data(),
|
||||
&decrypted_len, data_len, encrypted.data(),
|
||||
encrypted.size());
|
||||
EXPECT_EQ(rv, SECFailure);
|
||||
EXPECT_EQ(0U, decrypted_len);
|
||||
}
|
||||
|
||||
// Decrypt with bogus additional data.
|
||||
{
|
||||
SECItem bogusParams(params);
|
||||
CK_NSS_AEAD_PARAMS bogusAeadParams(aead_params);
|
||||
bogusParams.data = reinterpret_cast<unsigned char*>(&bogusAeadParams);
|
||||
// Skip when AAD was empty and can't be modified.
|
||||
// Alternatively we could generate random aad.
|
||||
if (aad_len != 0) {
|
||||
decrypted_len = 0;
|
||||
SECItem bogus_params(params);
|
||||
CK_NSS_AEAD_PARAMS bogus_aead_params(aead_params);
|
||||
bogus_params.data = reinterpret_cast<unsigned char*>(&bogus_aead_params);
|
||||
|
||||
std::vector<uint8_t> bogusAAD(aad, aad + aad_len);
|
||||
bogusAeadParams.pAAD = toUcharPtr(&bogusAAD[0]);
|
||||
bogusAAD[0] ^= 0xff;
|
||||
std::vector<uint8_t> bogus_aad(aad, aad + aad_len);
|
||||
bogus_aead_params.pAAD = toUcharPtr(bogus_aad.data());
|
||||
bogus_aad[0] ^= 0xff;
|
||||
|
||||
rv = PK11_Decrypt(symKey, mech, &bogusParams, &decrypted[0],
|
||||
&decryptedLen, data_len, &output[0], outputLen);
|
||||
EXPECT_NE(rv, SECSuccess);
|
||||
rv = PK11_Decrypt(key.get(), kMech, &bogus_params, decrypted.data(),
|
||||
&decrypted_len, data_len, encrypted.data(),
|
||||
encrypted.size());
|
||||
EXPECT_EQ(rv, SECFailure);
|
||||
EXPECT_EQ(0U, decrypted_len);
|
||||
}
|
||||
}
|
||||
|
||||
void EncryptDecrypt(const uint8_t* key, size_t key_len, const uint8_t* data,
|
||||
size_t data_len, const uint8_t* aad, size_t aad_len,
|
||||
const uint8_t* iv, size_t iv_len, const uint8_t* ct,
|
||||
size_t ct_len) {
|
||||
void EncryptDecrypt(const chaChaTestVector testvector) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
SECItem keyItem = {siBuffer, toUcharPtr(key),
|
||||
static_cast<unsigned int>(key_len)};
|
||||
SECItem keyItem = {siBuffer, toUcharPtr(testvector.Key.data()),
|
||||
static_cast<unsigned int>(testvector.Key.size())};
|
||||
|
||||
// Import key.
|
||||
ScopedPK11SymKey symKey(PK11_ImportSymKey(
|
||||
slot.get(), mech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr));
|
||||
EXPECT_TRUE(!!symKey);
|
||||
ScopedPK11SymKey key(PK11_ImportSymKey(slot.get(), kMech, PK11_OriginUnwrap,
|
||||
CKA_ENCRYPT, &keyItem, nullptr));
|
||||
EXPECT_TRUE(!!key);
|
||||
|
||||
// Check.
|
||||
EncryptDecrypt(symKey.get(), data, data_len, aad, aad_len, iv, iv_len, ct,
|
||||
ct_len);
|
||||
EncryptDecrypt(key, testvector.invalidIV, testvector.invalidTag,
|
||||
testvector.Data.data(), testvector.Data.size(),
|
||||
testvector.AAD.data(), testvector.AAD.size(),
|
||||
testvector.IV.data(), testvector.IV.size(),
|
||||
testvector.CT.data(), testvector.CT.size());
|
||||
}
|
||||
|
||||
protected:
|
||||
CK_MECHANISM_TYPE mech = CKM_NSS_CHACHA20_POLY1305;
|
||||
};
|
||||
|
||||
#define ENCRYPT_DECRYPT(v) \
|
||||
EncryptDecrypt(v##Key, sizeof(v##Key), v##Data, sizeof(v##Data), v##AAD, \
|
||||
sizeof(v##AAD), v##IV, sizeof(v##IV), v##CT, sizeof(v##CT));
|
||||
|
||||
TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateEncryptDecrypt) {
|
||||
// Generate a random key.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ScopedPK11SymKey symKey(PK11_KeyGen(slot.get(), mech, nullptr, 32, nullptr));
|
||||
EXPECT_TRUE(!!symKey);
|
||||
ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
|
||||
EXPECT_TRUE(!!key);
|
||||
|
||||
// Generate random data.
|
||||
std::vector<uint8_t> data(512);
|
||||
SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), &data[0], data.size());
|
||||
std::vector<uint8_t> input(512);
|
||||
SECStatus rv =
|
||||
PK11_GenerateRandomOnSlot(slot.get(), input.data(), input.size());
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
|
||||
// Generate random AAD.
|
||||
std::vector<uint8_t> aad(16);
|
||||
rv = PK11_GenerateRandomOnSlot(slot.get(), &aad[0], aad.size());
|
||||
rv = PK11_GenerateRandomOnSlot(slot.get(), aad.data(), aad.size());
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
|
||||
// Generate random IV.
|
||||
std::vector<uint8_t> iv(12);
|
||||
rv = PK11_GenerateRandomOnSlot(slot.get(), &iv[0], iv.size());
|
||||
rv = PK11_GenerateRandomOnSlot(slot.get(), iv.data(), iv.size());
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
|
||||
// Check.
|
||||
EncryptDecrypt(symKey.get(), &data[0], data.size(), &aad[0], aad.size(),
|
||||
&iv[0], iv.size());
|
||||
EncryptDecrypt(key, false, false, input.data(), input.size(), aad.data(),
|
||||
aad.size(), iv.data(), iv.size());
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11ChaCha20Poly1305Test, CheckTestVector1) {
|
||||
ENCRYPT_DECRYPT(kTestVector1);
|
||||
TEST_F(Pkcs11ChaCha20Poly1305Test, Xor) {
|
||||
static const uint8_t kExpected[sizeof(kData)] = {
|
||||
0xd8, 0x15, 0xd3, 0xb3, 0xe9, 0x34, 0x3b, 0x7a,
|
||||
0x24, 0xf6, 0x5f, 0xd7, 0x95, 0x3d, 0xd3, 0x51};
|
||||
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
SECItem keyItem = {siBuffer, toUcharPtr(kKeyData),
|
||||
static_cast<unsigned int>(sizeof(kKeyData))};
|
||||
ScopedPK11SymKey key(PK11_ImportSymKey(
|
||||
slot.get(), kMechXor, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr));
|
||||
EXPECT_TRUE(!!key);
|
||||
|
||||
SECItem ctrNonceItem = {siBuffer, toUcharPtr(kCtrNonce),
|
||||
static_cast<unsigned int>(sizeof(kCtrNonce))};
|
||||
uint8_t encrypted[sizeof(kData)];
|
||||
unsigned int encrypted_len = 88; // This should be overwritten.
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
|
||||
&encrypted_len, sizeof(encrypted), kData, sizeof(kData));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(encrypted_len));
|
||||
EXPECT_EQ(0, memcmp(kExpected, encrypted, sizeof(kExpected)));
|
||||
|
||||
// Decrypting has the same effect.
|
||||
rv = PK11_Decrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
|
||||
&encrypted_len, sizeof(encrypted), kData, sizeof(kData));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len));
|
||||
EXPECT_EQ(0, memcmp(kExpected, encrypted, sizeof(kExpected)));
|
||||
|
||||
// Operating in reverse too.
|
||||
rv = PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
|
||||
&encrypted_len, sizeof(encrypted), kExpected,
|
||||
sizeof(kExpected));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(encrypted_len));
|
||||
EXPECT_EQ(0, memcmp(kData, encrypted, sizeof(kData)));
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11ChaCha20Poly1305Test, CheckTestVector2) {
|
||||
ENCRYPT_DECRYPT(kTestVector2);
|
||||
// This test just ensures that a key can be generated for use with the XOR
|
||||
// function. The result is random and therefore cannot be checked.
|
||||
TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateXor) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
|
||||
EXPECT_TRUE(!!key);
|
||||
|
||||
SECItem ctrNonceItem = {siBuffer, toUcharPtr(kCtrNonce),
|
||||
static_cast<unsigned int>(sizeof(kCtrNonce))};
|
||||
uint8_t encrypted[sizeof(kData)];
|
||||
unsigned int encrypted_len = 88; // This should be overwritten.
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
|
||||
&encrypted_len, sizeof(encrypted), kData, sizeof(kData));
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len));
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11ChaCha20Poly1305Test, XorInvalidParams) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
|
||||
EXPECT_TRUE(!!key);
|
||||
|
||||
SECItem ctrNonceItem = {siBuffer, toUcharPtr(kCtrNonce),
|
||||
static_cast<unsigned int>(sizeof(kCtrNonce)) - 1};
|
||||
uint8_t encrypted[sizeof(kData)];
|
||||
unsigned int encrypted_len = 88;
|
||||
SECStatus rv =
|
||||
PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
|
||||
&encrypted_len, sizeof(encrypted), kData, sizeof(kData));
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
|
||||
ctrNonceItem.data = nullptr;
|
||||
rv = PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
|
||||
&encrypted_len, sizeof(encrypted), kData, sizeof(kData));
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_P(Pkcs11ChaCha20Poly1305Test, TestVectors) { EncryptDecrypt(GetParam()); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(NSSTestVector, Pkcs11ChaCha20Poly1305Test,
|
||||
::testing::ValuesIn(kChaCha20Vectors));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(WycheproofTestVector, Pkcs11ChaCha20Poly1305Test,
|
||||
::testing::ValuesIn(kChaCha20WycheproofVectors));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -5,111 +5,122 @@
|
|||
#include <memory>
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
|
||||
#include "prerror.h"
|
||||
#include "cpputil.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
|
||||
#include "testvectors/curve25519-vectors.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// <https://tools.ietf.org/html/rfc7748#section-6.1>
|
||||
const uint8_t kPkcs8[] = {
|
||||
0x30, 0x67, 0x02, 0x01, 0x00, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48,
|
||||
0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda,
|
||||
0x47, 0x0f, 0x01, 0x04, 0x4c, 0x30, 0x4a, 0x02, 0x01, 0x01, 0x04, 0x20,
|
||||
0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, 0x3c, 0x16, 0xc1, 0x72,
|
||||
0x51, 0xb2, 0x66, 0x45, 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a,
|
||||
0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a, 0xa1, 0x23, 0x03, 0x21,
|
||||
0x00, 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, 0x74, 0x8b, 0x7d,
|
||||
0xdc, 0xb4, 0x3e, 0xf7, 0x5a, 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a,
|
||||
0xf4, 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a};
|
||||
const uint8_t kSpki[] = {
|
||||
0x30, 0x39, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||
0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01,
|
||||
0x03, 0x21, 0x00, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3,
|
||||
0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b,
|
||||
0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f};
|
||||
const uint8_t kSecret[] = {0x4a, 0x5d, 0x9d, 0x5b, 0xa4, 0xce, 0x2d, 0xe1,
|
||||
0x72, 0x8e, 0x3b, 0xf4, 0x80, 0x35, 0x0f, 0x25,
|
||||
0xe0, 0x7e, 0x21, 0xc9, 0x47, 0xd1, 0x9e, 0x33,
|
||||
0x76, 0xf0, 0x9b, 0x3c, 0x1e, 0x16, 0x17, 0x42};
|
||||
|
||||
// A public key that's too short (31 bytes).
|
||||
const uint8_t kSpkiShort[] = {
|
||||
0x30, 0x38, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||
0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01,
|
||||
0x03, 0x20, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3, 0x5b,
|
||||
0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b, 0x78,
|
||||
0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f};
|
||||
|
||||
// A public key that's too long (33 bytes).
|
||||
const uint8_t kSpkiLong[] = {
|
||||
0x30, 0x3a, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||
0x01, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01,
|
||||
0x03, 0x22, 0x00, 0xde, 0x9e, 0xdb, 0x7d, 0x7b, 0x7d, 0xc1, 0xb4, 0xd3,
|
||||
0x5b, 0x61, 0xc2, 0xec, 0xe4, 0x35, 0x37, 0x3f, 0x83, 0x43, 0xc8, 0x5b,
|
||||
0x78, 0x67, 0x4d, 0xad, 0xfc, 0x7e, 0x14, 0x6f, 0x88, 0x2b, 0x4f, 0x34};
|
||||
|
||||
class Pkcs11Curve25519Test : public ::testing::Test {
|
||||
class Pkcs11Curve25519Test
|
||||
: public ::testing::TestWithParam<curve25519_testvector> {
|
||||
protected:
|
||||
void Derive(const uint8_t* pkcs8, size_t pkcs8_len, const uint8_t* spki,
|
||||
size_t spki_len, const uint8_t* secret, size_t secret_len,
|
||||
bool expect_success) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
ASSERT_TRUE(slot);
|
||||
|
||||
SECItem pkcs8Item = {siBuffer, toUcharPtr(pkcs8),
|
||||
static_cast<unsigned int>(pkcs8_len)};
|
||||
SECItem pkcs8_item = {siBuffer, toUcharPtr(pkcs8),
|
||||
static_cast<unsigned int>(pkcs8_len)};
|
||||
|
||||
SECKEYPrivateKey* key = nullptr;
|
||||
SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
|
||||
slot.get(), &pkcs8Item, nullptr, nullptr, false, false, KU_ALL, &key,
|
||||
slot.get(), &pkcs8_item, nullptr, nullptr, false, false, KU_ALL, &key,
|
||||
nullptr);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
ScopedSECKEYPrivateKey privKey(key);
|
||||
ASSERT_TRUE(privKey);
|
||||
ScopedSECKEYPrivateKey priv_key_sess(key);
|
||||
ASSERT_TRUE(priv_key_sess);
|
||||
|
||||
SECItem spkiItem = {siBuffer, toUcharPtr(spki),
|
||||
static_cast<unsigned int>(spki_len)};
|
||||
SECItem spki_item = {siBuffer, toUcharPtr(spki),
|
||||
static_cast<unsigned int>(spki_len)};
|
||||
|
||||
ScopedCERTSubjectPublicKeyInfo certSpki(
|
||||
SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
|
||||
ASSERT_TRUE(certSpki);
|
||||
ScopedCERTSubjectPublicKeyInfo cert_spki(
|
||||
SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
|
||||
if (!expect_success && !cert_spki) {
|
||||
return;
|
||||
}
|
||||
ASSERT_TRUE(cert_spki);
|
||||
|
||||
ScopedSECKEYPublicKey pubKey(SECKEY_ExtractPublicKey(certSpki.get()));
|
||||
ASSERT_TRUE(pubKey);
|
||||
ScopedSECKEYPublicKey pub_key_remote(
|
||||
SECKEY_ExtractPublicKey(cert_spki.get()));
|
||||
ASSERT_TRUE(pub_key_remote);
|
||||
|
||||
ScopedPK11SymKey symKey(PK11_PubDeriveWithKDF(
|
||||
privKey.get(), pubKey.get(), false, nullptr, nullptr, CKM_ECDH1_DERIVE,
|
||||
CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr, nullptr));
|
||||
EXPECT_EQ(expect_success, !!symKey);
|
||||
// sym_key_sess = ECDH(session_import(private_test), public_test)
|
||||
ScopedPK11SymKey sym_key_sess(PK11_PubDeriveWithKDF(
|
||||
priv_key_sess.get(), pub_key_remote.get(), false, nullptr, nullptr,
|
||||
CKM_ECDH1_DERIVE, CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr,
|
||||
nullptr));
|
||||
ASSERT_EQ(expect_success, !!sym_key_sess);
|
||||
|
||||
if (expect_success) {
|
||||
rv = PK11_ExtractKeyValue(symKey.get());
|
||||
rv = PK11_ExtractKeyValue(sym_key_sess.get());
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
SECItem* keyData = PK11_GetKeyData(symKey.get());
|
||||
EXPECT_EQ(secret_len, keyData->len);
|
||||
EXPECT_EQ(memcmp(keyData->data, secret, secret_len), 0);
|
||||
SECItem* key_data = PK11_GetKeyData(sym_key_sess.get());
|
||||
EXPECT_EQ(secret_len, key_data->len);
|
||||
EXPECT_EQ(memcmp(key_data->data, secret, secret_len), 0);
|
||||
|
||||
// Perform wrapped export on the imported private, import it as
|
||||
// permanent, and verify we derive the same shared secret
|
||||
static const uint8_t pw[] = "pw";
|
||||
SECItem pwItem = {siBuffer, toUcharPtr(pw), sizeof(pw)};
|
||||
ScopedSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo(
|
||||
slot.get(), SEC_OID_AES_256_CBC, &pwItem, priv_key_sess.get(), 1,
|
||||
nullptr));
|
||||
ASSERT_NE(nullptr, epki) << "PK11_ExportEncryptedPrivKeyInfo failed: "
|
||||
<< PORT_ErrorToName(PORT_GetError());
|
||||
|
||||
ScopedSECKEYPublicKey pub_key_local(
|
||||
SECKEY_ConvertToPublicKey(priv_key_sess.get()));
|
||||
|
||||
SECKEYPrivateKey* priv_key_tok = nullptr;
|
||||
rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
|
||||
slot.get(), epki.get(), &pwItem, nullptr,
|
||||
&pub_key_local->u.ec.publicValue, PR_TRUE, PR_TRUE, ecKey, 0,
|
||||
&priv_key_tok, nullptr);
|
||||
ASSERT_EQ(SECSuccess, rv) << "PK11_ImportEncryptedPrivateKeyInfo failed "
|
||||
<< PORT_ErrorToName(PORT_GetError());
|
||||
ASSERT_TRUE(priv_key_tok);
|
||||
|
||||
// sym_key_tok = ECDH(token_import(export(private_test)),
|
||||
// public_test)
|
||||
ScopedPK11SymKey sym_key_tok(PK11_PubDeriveWithKDF(
|
||||
priv_key_tok, pub_key_remote.get(), false, nullptr, nullptr,
|
||||
CKM_ECDH1_DERIVE, CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr,
|
||||
nullptr));
|
||||
EXPECT_TRUE(sym_key_tok);
|
||||
|
||||
if (sym_key_tok) {
|
||||
rv = PK11_ExtractKeyValue(sym_key_tok.get());
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
key_data = PK11_GetKeyData(sym_key_tok.get());
|
||||
EXPECT_EQ(secret_len, key_data->len);
|
||||
EXPECT_EQ(memcmp(key_data->data, secret, secret_len), 0);
|
||||
}
|
||||
rv = PK11_DeleteTokenPrivateKey(priv_key_tok, true);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Derive(const curve25519_testvector testvector) {
|
||||
Derive(testvector.private_key.data(), testvector.private_key.size(),
|
||||
testvector.public_key.data(), testvector.public_key.size(),
|
||||
testvector.secret.data(), testvector.secret.size(),
|
||||
testvector.valid);
|
||||
};
|
||||
};
|
||||
|
||||
TEST_F(Pkcs11Curve25519Test, DeriveSharedSecret) {
|
||||
Derive(kPkcs8, sizeof(kPkcs8), kSpki, sizeof(kSpki), kSecret, sizeof(kSecret),
|
||||
true);
|
||||
}
|
||||
TEST_P(Pkcs11Curve25519Test, TestVectors) { Derive(GetParam()); }
|
||||
|
||||
TEST_F(Pkcs11Curve25519Test, DeriveSharedSecretShort) {
|
||||
Derive(kPkcs8, sizeof(kPkcs8), kSpkiShort, sizeof(kSpkiShort), nullptr, 0,
|
||||
false);
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(NSSTestVector, Pkcs11Curve25519Test,
|
||||
::testing::ValuesIn(kCurve25519Vectors));
|
||||
|
||||
TEST_F(Pkcs11Curve25519Test, DeriveSharedSecretLong) {
|
||||
Derive(kPkcs8, sizeof(kPkcs8), kSpkiLong, sizeof(kSpkiLong), nullptr, 0,
|
||||
false);
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(WycheproofTestVector, Pkcs11Curve25519Test,
|
||||
::testing::ValuesIn(kCurve25519WycheproofVectors));
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -15,6 +15,20 @@
|
|||
|
||||
namespace nss_test {
|
||||
|
||||
const std::vector<uint8_t> kValidP256Key = {
|
||||
0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
|
||||
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
|
||||
0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
|
||||
0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57,
|
||||
0x67, 0xb1, 0xd6, 0x93, 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12,
|
||||
0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21, 0xa1, 0x44, 0x03, 0x42,
|
||||
0x00, 0x04, 0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31, 0xc9, 0x61,
|
||||
0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68, 0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61,
|
||||
0xfa, 0x6c, 0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6, 0x79, 0x03,
|
||||
0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99, 0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28,
|
||||
0xbc, 0x64, 0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51, 0x77, 0xa3,
|
||||
0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99};
|
||||
|
||||
const std::vector<uint8_t> kValidRSAKey = {
|
||||
// 512-bit RSA private key (PKCS#8)
|
||||
0x30, 0x82, 0x01, 0x54, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
|
||||
|
|
@ -73,38 +87,76 @@ const std::vector<uint8_t> kInvalidZeroLengthKey = {
|
|||
|
||||
class DERPrivateKeyImportTest : public ::testing::Test {
|
||||
public:
|
||||
bool ParsePrivateKey(const std::vector<uint8_t>& data) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
EXPECT_TRUE(slot);
|
||||
|
||||
bool ParsePrivateKey(const std::vector<uint8_t>& data, bool expect_success) {
|
||||
SECKEYPrivateKey* key = nullptr;
|
||||
SECStatus rv = SECFailure;
|
||||
std::string nick_str =
|
||||
::testing::UnitTest::GetInstance()->current_test_info()->name() +
|
||||
std::to_string(rand());
|
||||
SECItem item = {siBuffer, const_cast<unsigned char*>(data.data()),
|
||||
(unsigned int)data.size()};
|
||||
static_cast<unsigned int>(data.size())};
|
||||
SECItem nick = {siBuffer, reinterpret_cast<unsigned char*>(
|
||||
const_cast<char*>(nick_str.data())),
|
||||
static_cast<unsigned int>(nick_str.length())};
|
||||
|
||||
SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
|
||||
slot.get(), &item, nullptr, nullptr, false, false, KU_ALL, &key,
|
||||
nullptr);
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
EXPECT_TRUE(slot);
|
||||
if (!slot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PK11_NeedUserInit(slot.get())) {
|
||||
if (PK11_InitPin(slot.get(), nullptr, nullptr) != SECSuccess) {
|
||||
EXPECT_EQ(rv, SECSuccess) << "PK11_InitPin failed";
|
||||
}
|
||||
}
|
||||
rv = PK11_Authenticate(slot.get(), PR_TRUE, nullptr);
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
|
||||
rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
|
||||
slot.get(), &item, &nick, nullptr, true, false, KU_ALL, &key, nullptr);
|
||||
EXPECT_EQ(rv == SECSuccess, key != nullptr);
|
||||
SECKEY_DestroyPrivateKey(key);
|
||||
|
||||
if (expect_success) {
|
||||
// Try to find the key via its label
|
||||
ScopedSECKEYPrivateKeyList list(PK11_ListPrivKeysInSlot(
|
||||
slot.get(), const_cast<char*>(nick_str.c_str()), nullptr));
|
||||
EXPECT_FALSE(!list);
|
||||
}
|
||||
|
||||
if (key) {
|
||||
rv = PK11_DeleteTokenPrivateKey(key, true);
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
|
||||
// PK11_DeleteTokenPrivateKey leaves an errorCode set when there's
|
||||
// no cert. This is expected, so clear it.
|
||||
if (PORT_GetError() == SSL_ERROR_NO_CERTIFICATE) {
|
||||
PORT_SetError(0);
|
||||
}
|
||||
}
|
||||
|
||||
return rv == SECSuccess;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DERPrivateKeyImportTest, ImportPrivateRSAKey) {
|
||||
EXPECT_TRUE(ParsePrivateKey(kValidRSAKey));
|
||||
EXPECT_FALSE(PORT_GetError());
|
||||
EXPECT_TRUE(ParsePrivateKey(kValidRSAKey, true));
|
||||
EXPECT_FALSE(PORT_GetError()) << PORT_GetError();
|
||||
}
|
||||
|
||||
TEST_F(DERPrivateKeyImportTest, ImportEcdsaKey) {
|
||||
EXPECT_TRUE(ParsePrivateKey(kValidP256Key, true));
|
||||
EXPECT_FALSE(PORT_GetError()) << PORT_GetError();
|
||||
}
|
||||
|
||||
TEST_F(DERPrivateKeyImportTest, ImportInvalidPrivateKey) {
|
||||
EXPECT_FALSE(ParsePrivateKey(kInvalidLengthKey));
|
||||
EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_DER);
|
||||
EXPECT_FALSE(ParsePrivateKey(kInvalidLengthKey, false));
|
||||
EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_DER) << PORT_GetError();
|
||||
}
|
||||
|
||||
TEST_F(DERPrivateKeyImportTest, ImportZeroLengthPrivateKey) {
|
||||
EXPECT_FALSE(ParsePrivateKey(kInvalidZeroLengthKey));
|
||||
EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_KEY);
|
||||
EXPECT_FALSE(ParsePrivateKey(kInvalidZeroLengthKey, false));
|
||||
EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_KEY) << PORT_GetError();
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
65
security/nss/gtests/pk11_gtest/pk11_des_unittest.cc
Normal file
65
security/nss/gtests/pk11_gtest/pk11_des_unittest.cc
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- 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 <memory>
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
|
||||
#include "nss_scoped_ptrs.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class Pkcs11DesTest : public ::testing::Test {
|
||||
protected:
|
||||
SECStatus EncryptWithIV(std::vector<uint8_t>& iv,
|
||||
const CK_MECHANISM_TYPE mech) {
|
||||
// Generate a random key.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ScopedPK11SymKey sym_key(
|
||||
PK11_KeyGen(slot.get(), mech, nullptr, 8, nullptr));
|
||||
EXPECT_TRUE(!!sym_key);
|
||||
|
||||
std::vector<uint8_t> data(16);
|
||||
std::vector<uint8_t> output(16);
|
||||
|
||||
SECItem params = {siBuffer, iv.data(),
|
||||
static_cast<unsigned int>(iv.size())};
|
||||
|
||||
// Try to encrypt.
|
||||
unsigned int output_len = 0;
|
||||
return PK11_Encrypt(sym_key.get(), mech, ¶ms, output.data(),
|
||||
&output_len, output.size(), data.data(), data.size());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Pkcs11DesTest, ZeroLengthIV) {
|
||||
std::vector<uint8_t> iv(0);
|
||||
EXPECT_EQ(SECFailure, EncryptWithIV(iv, CKM_DES_CBC));
|
||||
EXPECT_EQ(SECFailure, EncryptWithIV(iv, CKM_DES3_CBC));
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11DesTest, IVTooShort) {
|
||||
std::vector<uint8_t> iv(7);
|
||||
EXPECT_EQ(SECFailure, EncryptWithIV(iv, CKM_DES_CBC));
|
||||
EXPECT_EQ(SECFailure, EncryptWithIV(iv, CKM_DES3_CBC));
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11DesTest, WrongLengthIV) {
|
||||
// We tolerate IVs > 8
|
||||
std::vector<uint8_t> iv(15, 0);
|
||||
EXPECT_EQ(SECSuccess, EncryptWithIV(iv, CKM_DES_CBC));
|
||||
EXPECT_EQ(SECSuccess, EncryptWithIV(iv, CKM_DES3_CBC));
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11DesTest, AllGood) {
|
||||
std::vector<uint8_t> iv(8, 0);
|
||||
EXPECT_EQ(SECSuccess, EncryptWithIV(iv, CKM_DES_CBC));
|
||||
EXPECT_EQ(SECSuccess, EncryptWithIV(iv, CKM_DES3_CBC));
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -45,6 +45,11 @@ static const Pkcs11EcdsaTestParams kEcdsaVectors[] = {
|
|||
DataBuffer(kP256Spki, sizeof(kP256Spki)),
|
||||
DataBuffer(kP256Data, sizeof(kP256Data)),
|
||||
DataBuffer(kP256Signature, sizeof(kP256Signature))}},
|
||||
{SEC_OID_SHA256,
|
||||
{DataBuffer(kP256Pkcs8ZeroPad, sizeof(kP256Pkcs8ZeroPad)),
|
||||
DataBuffer(kP256SpkiZeroPad, sizeof(kP256SpkiZeroPad)),
|
||||
DataBuffer(kP256DataZeroPad, sizeof(kP256DataZeroPad)),
|
||||
DataBuffer(kP256SignatureZeroPad, sizeof(kP256SignatureZeroPad))}},
|
||||
{SEC_OID_SHA384,
|
||||
{DataBuffer(kP384Pkcs8, sizeof(kP384Pkcs8)),
|
||||
DataBuffer(kP384Spki, sizeof(kP384Spki)),
|
||||
|
|
|
|||
|
|
@ -130,6 +130,38 @@ const uint8_t kP521Signature[] = {
|
|||
0xd8, 0xb8, 0xc3, 0x7f, 0xf0, 0x77, 0x7b, 0x1a, 0x20, 0xf8, 0xcc, 0xb1,
|
||||
0xdc, 0xcc, 0x43, 0x99, 0x7f, 0x1e, 0xe0, 0xe4, 0x4d, 0xa4, 0xa6, 0x7a};
|
||||
|
||||
// ECDSA P256 test case with a leading zero in the private key
|
||||
const uint8_t kP256Pkcs8ZeroPad[] = {
|
||||
0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
|
||||
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
|
||||
0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
|
||||
0x00, 0x16, 0x40, 0x71, 0x99, 0xe3, 0x07, 0xaa, 0xdc, 0x98, 0x0b, 0x21,
|
||||
0x62, 0xce, 0x66, 0x1f, 0xe4, 0x1a, 0x86, 0x9a, 0x23, 0x33, 0xf6, 0x72,
|
||||
0xb4, 0xa3, 0xdc, 0x3b, 0x50, 0xba, 0x20, 0xce, 0xa1, 0x44, 0x03, 0x42,
|
||||
0x00, 0x04, 0x53, 0x11, 0x9a, 0x86, 0xa0, 0xc2, 0x99, 0x4f, 0xa6, 0xf8,
|
||||
0x08, 0xf8, 0x61, 0x01, 0x0e, 0x6b, 0x04, 0x9c, 0xd8, 0x15, 0x63, 0x2e,
|
||||
0xd1, 0x38, 0x00, 0x10, 0xee, 0xe4, 0xc9, 0x11, 0xff, 0x05, 0xba, 0xd6,
|
||||
0xcd, 0x94, 0xea, 0x00, 0xec, 0x85, 0x26, 0x2c, 0xbd, 0x4d, 0x85, 0xbd,
|
||||
0x20, 0xce, 0xa5, 0xb1, 0x3f, 0x4d, 0x82, 0x9b, 0x9f, 0x28, 0x2e, 0xd3,
|
||||
0x8a, 0x87, 0x1f, 0x89, 0xf8, 0x02};
|
||||
const uint8_t kP256SpkiZeroPad[] = {
|
||||
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||
0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
|
||||
0x42, 0x00, 0x04, 0x53, 0x11, 0x9a, 0x86, 0xa0, 0xc2, 0x99, 0x4f, 0xa6,
|
||||
0xf8, 0x08, 0xf8, 0x61, 0x01, 0x0e, 0x6b, 0x04, 0x9c, 0xd8, 0x15, 0x63,
|
||||
0x2e, 0xd1, 0x38, 0x00, 0x10, 0xee, 0xe4, 0xc9, 0x11, 0xff, 0x05, 0xba,
|
||||
0xd6, 0xcd, 0x94, 0xea, 0x00, 0xec, 0x85, 0x26, 0x2c, 0xbd, 0x4d, 0x85,
|
||||
0xbd, 0x20, 0xce, 0xa5, 0xb1, 0x3f, 0x4d, 0x82, 0x9b, 0x9f, 0x28, 0x2e,
|
||||
0xd3, 0x8a, 0x87, 0x1f, 0x89, 0xf8, 0x02};
|
||||
const uint8_t kP256DataZeroPad[] = {'s', 'a', 'm', 'p', 'l', 'e'};
|
||||
const uint8_t kP256SignatureZeroPad[] = {
|
||||
0xa6, 0xf4, 0xe4, 0xa8, 0x3f, 0x03, 0x59, 0x89, 0x60, 0x53, 0xe7,
|
||||
0xdc, 0xb5, 0xbe, 0x78, 0xaf, 0xc1, 0xca, 0xc0, 0x65, 0xba, 0xa4,
|
||||
0x3c, 0xf1, 0xe4, 0xae, 0xe3, 0xba, 0x22, 0x3d, 0xac, 0x9d, 0x6d,
|
||||
0x1b, 0x26, 0x00, 0xcf, 0x47, 0xa1, 0xe1, 0x04, 0x21, 0x8d, 0x0b,
|
||||
0xbb, 0x16, 0xfa, 0x3e, 0x59, 0x32, 0x01, 0xb0, 0x45, 0x3e, 0x27,
|
||||
0xa4, 0xc4, 0xfd, 0x31, 0xc9, 0x1a, 0x8e, 0x74, 0xd8};
|
||||
|
||||
// ECDSA test vectors, SPKI and PKCS#8 edge cases.
|
||||
const uint8_t kP256Pkcs8NoCurveOIDOrAlgorithmParams[] = {
|
||||
0x30, 0x7d, 0x02, 0x01, 0x00, 0x30, 0x09, 0x06, 0x07, 0x2a, 0x86, 0x48,
|
||||
|
|
|
|||
547
security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc
Normal file
547
security/nss/gtests/pk11_gtest/pk11_find_certs_unittest.cc
Normal file
|
|
@ -0,0 +1,547 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=4 et sw=4 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 <string.h>
|
||||
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "prenv.h"
|
||||
#include "prerror.h"
|
||||
#include "secmod.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// These test certificates were generated using pycert/pykey from
|
||||
// mozilla-central (https://hg.mozilla.org/mozilla-central/file/ ...
|
||||
// 9968319230a74eb8c1953444a0e6973c7500a9f8/security/manager/ssl/ ...
|
||||
// tests/unit/pycert.py).
|
||||
|
||||
// issuer:test cert
|
||||
// subject:test cert
|
||||
// issuerKey:secp256r1
|
||||
// subjectKey:secp256r1
|
||||
// serialNumber:1
|
||||
const std::vector<uint8_t> kTestCert1DER = {
|
||||
0x30, 0x82, 0x01, 0x1D, 0x30, 0x81, 0xC2, 0xA0, 0x03, 0x02, 0x01, 0x02,
|
||||
0x02, 0x01, 0x01, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
|
||||
0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10,
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20,
|
||||
0x63, 0x65, 0x72, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x37,
|
||||
0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x18,
|
||||
0x0F, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x5A, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
|
||||
0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x65,
|
||||
0x72, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE,
|
||||
0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01,
|
||||
0x07, 0x03, 0x42, 0x00, 0x04, 0x4F, 0xBF, 0xBB, 0xBB, 0x61, 0xE0, 0xF8,
|
||||
0xF9, 0xB1, 0xA6, 0x0A, 0x59, 0xAC, 0x87, 0x04, 0xE2, 0xEC, 0x05, 0x0B,
|
||||
0x42, 0x3E, 0x3C, 0xF7, 0x2E, 0x92, 0x3F, 0x2C, 0x4F, 0x79, 0x4B, 0x45,
|
||||
0x5C, 0x2A, 0x69, 0xD2, 0x33, 0x45, 0x6C, 0x36, 0xC4, 0x11, 0x9D, 0x07,
|
||||
0x06, 0xE0, 0x0E, 0xED, 0xC8, 0xD1, 0x93, 0x90, 0xD7, 0x99, 0x1B, 0x7B,
|
||||
0x2D, 0x07, 0xA3, 0x04, 0xEA, 0xA0, 0x4A, 0xA6, 0xC0, 0x30, 0x0D, 0x06,
|
||||
0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00,
|
||||
0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x5C, 0x75, 0x51, 0x9F, 0x13,
|
||||
0x11, 0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20, 0xA3, 0xBC, 0x06, 0x30, 0x91,
|
||||
0xFF, 0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64, 0xEC, 0xFD, 0xCB, 0x42, 0x80,
|
||||
0x0A, 0x70, 0xE6, 0x02, 0x20, 0x11, 0xFA, 0xA2, 0xCA, 0x06, 0xF3, 0xBC,
|
||||
0x5F, 0x8A, 0xCA, 0x17, 0x63, 0x36, 0x87, 0xCF, 0x8D, 0x5C, 0xA0, 0x56,
|
||||
0x84, 0x44, 0x61, 0xB2, 0x33, 0x42, 0x07, 0x58, 0x9F, 0x0C, 0x9E, 0x49,
|
||||
0x83,
|
||||
};
|
||||
|
||||
// issuer:test cert
|
||||
// subject:test cert
|
||||
// issuerKey:secp256r1
|
||||
// subjectKey:secp256r1
|
||||
// serialNumber:2
|
||||
const std::vector<uint8_t> kTestCert2DER = {
|
||||
0x30, 0x82, 0x01, 0x1E, 0x30, 0x81, 0xC2, 0xA0, 0x03, 0x02, 0x01, 0x02,
|
||||
0x02, 0x01, 0x02, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
|
||||
0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10,
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20,
|
||||
0x63, 0x65, 0x72, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x37,
|
||||
0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x18,
|
||||
0x0F, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x5A, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03,
|
||||
0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x65,
|
||||
0x72, 0x74, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE,
|
||||
0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01,
|
||||
0x07, 0x03, 0x42, 0x00, 0x04, 0x4F, 0xBF, 0xBB, 0xBB, 0x61, 0xE0, 0xF8,
|
||||
0xF9, 0xB1, 0xA6, 0x0A, 0x59, 0xAC, 0x87, 0x04, 0xE2, 0xEC, 0x05, 0x0B,
|
||||
0x42, 0x3E, 0x3C, 0xF7, 0x2E, 0x92, 0x3F, 0x2C, 0x4F, 0x79, 0x4B, 0x45,
|
||||
0x5C, 0x2A, 0x69, 0xD2, 0x33, 0x45, 0x6C, 0x36, 0xC4, 0x11, 0x9D, 0x07,
|
||||
0x06, 0xE0, 0x0E, 0xED, 0xC8, 0xD1, 0x93, 0x90, 0xD7, 0x99, 0x1B, 0x7B,
|
||||
0x2D, 0x07, 0xA3, 0x04, 0xEA, 0xA0, 0x4A, 0xA6, 0xC0, 0x30, 0x0D, 0x06,
|
||||
0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00,
|
||||
0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20, 0x5C, 0x75, 0x51, 0x9F, 0x13,
|
||||
0x11, 0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20, 0xA3, 0xBC, 0x06, 0x30, 0x91,
|
||||
0xFF, 0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64, 0xEC, 0xFD, 0xCB, 0x42, 0x80,
|
||||
0x0A, 0x70, 0xE6, 0x02, 0x21, 0x00, 0xF6, 0x5E, 0x42, 0xC7, 0x54, 0x40,
|
||||
0x81, 0xE9, 0x4C, 0x16, 0x48, 0xB1, 0x39, 0x0A, 0xA0, 0xE2, 0x8C, 0x23,
|
||||
0xAA, 0xC5, 0xBB, 0xAC, 0xEB, 0x9B, 0x15, 0x0B, 0x2F, 0xB7, 0xF5, 0x85,
|
||||
0xB2, 0x54,
|
||||
};
|
||||
|
||||
const std::vector<uint8_t> kTestCertSubjectDER = {
|
||||
0x30, 0x14, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03,
|
||||
0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74,
|
||||
};
|
||||
|
||||
// issuer:test cert
|
||||
// subject:unrelated subject DN
|
||||
// issuerKey:secp256r1
|
||||
// subjectKey:secp256r1
|
||||
// serialNumber:3
|
||||
const std::vector<uint8_t> kUnrelatedTestCertDER = {
|
||||
0x30, 0x82, 0x01, 0x28, 0x30, 0x81, 0xCD, 0xA0, 0x03, 0x02, 0x01, 0x02,
|
||||
0x02, 0x01, 0x03, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
|
||||
0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10,
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20,
|
||||
0x63, 0x65, 0x72, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x37,
|
||||
0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x18,
|
||||
0x0F, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x5A, 0x30, 0x1F, 0x31, 0x1D, 0x30, 0x1B, 0x06, 0x03,
|
||||
0x55, 0x04, 0x03, 0x0C, 0x14, 0x75, 0x6E, 0x72, 0x65, 0x6C, 0x61, 0x74,
|
||||
0x65, 0x64, 0x20, 0x73, 0x75, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x44,
|
||||
0x4E, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
|
||||
0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07,
|
||||
0x03, 0x42, 0x00, 0x04, 0x4F, 0xBF, 0xBB, 0xBB, 0x61, 0xE0, 0xF8, 0xF9,
|
||||
0xB1, 0xA6, 0x0A, 0x59, 0xAC, 0x87, 0x04, 0xE2, 0xEC, 0x05, 0x0B, 0x42,
|
||||
0x3E, 0x3C, 0xF7, 0x2E, 0x92, 0x3F, 0x2C, 0x4F, 0x79, 0x4B, 0x45, 0x5C,
|
||||
0x2A, 0x69, 0xD2, 0x33, 0x45, 0x6C, 0x36, 0xC4, 0x11, 0x9D, 0x07, 0x06,
|
||||
0xE0, 0x0E, 0xED, 0xC8, 0xD1, 0x93, 0x90, 0xD7, 0x99, 0x1B, 0x7B, 0x2D,
|
||||
0x07, 0xA3, 0x04, 0xEA, 0xA0, 0x4A, 0xA6, 0xC0, 0x30, 0x0D, 0x06, 0x09,
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03,
|
||||
0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x5C, 0x75, 0x51, 0x9F, 0x13, 0x11,
|
||||
0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20, 0xA3, 0xBC, 0x06, 0x30, 0x91, 0xFF,
|
||||
0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64, 0xEC, 0xFD, 0xCB, 0x42, 0x80, 0x0A,
|
||||
0x70, 0xE6, 0x02, 0x20, 0x0F, 0x1A, 0x04, 0xC2, 0xF8, 0xBA, 0xC2, 0x94,
|
||||
0x26, 0x6E, 0xBC, 0x91, 0x7D, 0xDB, 0x75, 0x7B, 0xE8, 0xA3, 0x4F, 0x69,
|
||||
0x1B, 0xF3, 0x1F, 0x2C, 0xCE, 0x82, 0x67, 0xC9, 0x5B, 0xBB, 0xBA, 0x0A,
|
||||
};
|
||||
|
||||
class PK11FindCertsTestBase : public ::testing::Test {
|
||||
protected:
|
||||
PK11FindCertsTestBase()
|
||||
: m_slot(nullptr), test_cert_db_dir_("PK11FindCertsTestBase-") {}
|
||||
|
||||
virtual void SetUp() {
|
||||
std::string test_cert_db_path(test_cert_db_dir_.GetPath());
|
||||
const char* test_name =
|
||||
::testing::UnitTest::GetInstance()->current_test_info()->name();
|
||||
std::string mod_spec = "configDir='sql:";
|
||||
mod_spec.append(test_cert_db_path);
|
||||
mod_spec.append("' tokenDescription='");
|
||||
mod_spec.append(test_name);
|
||||
mod_spec.append("'");
|
||||
m_slot = SECMOD_OpenUserDB(mod_spec.c_str());
|
||||
ASSERT_NE(m_slot, nullptr);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
ASSERT_EQ(SECMOD_CloseUserDB(m_slot), SECSuccess);
|
||||
PK11_FreeSlot(m_slot);
|
||||
std::string test_cert_db_path(test_cert_db_dir_.GetPath());
|
||||
ASSERT_EQ(0, unlink((test_cert_db_path + "/cert9.db").c_str()));
|
||||
ASSERT_EQ(0, unlink((test_cert_db_path + "/key4.db").c_str()));
|
||||
}
|
||||
|
||||
PK11SlotInfo* m_slot;
|
||||
ScopedUniqueDirectory test_cert_db_dir_;
|
||||
};
|
||||
|
||||
class PK11FindRawCertsBySubjectTest : public PK11FindCertsTestBase {};
|
||||
|
||||
// If we don't have any certificates, we shouldn't get any when we search for
|
||||
// them.
|
||||
TEST_F(PK11FindRawCertsBySubjectTest, TestNoCertsImportedNoCertsFound) {
|
||||
SECItem subject_item = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestCertSubjectDER.data()),
|
||||
(unsigned int)kTestCertSubjectDER.size()};
|
||||
CERTCertificateList* certificates = nullptr;
|
||||
SECStatus rv =
|
||||
PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates);
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
EXPECT_EQ(certificates, nullptr);
|
||||
}
|
||||
|
||||
// If we have one certificate but it has an unrelated subject DN, we shouldn't
|
||||
// get it when we search.
|
||||
TEST_F(PK11FindRawCertsBySubjectTest, TestOneCertImportedNoCertsFound) {
|
||||
char cert_nickname[] = "Unrelated Cert";
|
||||
SECItem cert_item = {siBuffer,
|
||||
const_cast<unsigned char*>(kUnrelatedTestCertDER.data()),
|
||||
(unsigned int)kUnrelatedTestCertDER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE,
|
||||
cert_nickname, false),
|
||||
SECSuccess);
|
||||
|
||||
SECItem subject_item = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestCertSubjectDER.data()),
|
||||
(unsigned int)kTestCertSubjectDER.size()};
|
||||
CERTCertificateList* certificates = nullptr;
|
||||
SECStatus rv =
|
||||
PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates);
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
EXPECT_EQ(certificates, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(PK11FindRawCertsBySubjectTest, TestMultipleMatchingCertsFound) {
|
||||
char cert1_nickname[] = "Test Cert 1";
|
||||
SECItem cert1_item = {siBuffer,
|
||||
const_cast<unsigned char*>(kTestCert1DER.data()),
|
||||
(unsigned int)kTestCert1DER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE,
|
||||
cert1_nickname, false),
|
||||
SECSuccess);
|
||||
char cert2_nickname[] = "Test Cert 2";
|
||||
SECItem cert2_item = {siBuffer,
|
||||
const_cast<unsigned char*>(kTestCert2DER.data()),
|
||||
(unsigned int)kTestCert2DER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert2_item, CK_INVALID_HANDLE,
|
||||
cert2_nickname, false),
|
||||
SECSuccess);
|
||||
char unrelated_cert_nickname[] = "Unrelated Test Cert";
|
||||
SECItem unrelated_cert_item = {
|
||||
siBuffer, const_cast<unsigned char*>(kUnrelatedTestCertDER.data()),
|
||||
(unsigned int)kUnrelatedTestCertDER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &unrelated_cert_item, CK_INVALID_HANDLE,
|
||||
unrelated_cert_nickname, false),
|
||||
SECSuccess);
|
||||
|
||||
CERTCertificateList* certificates = nullptr;
|
||||
SECItem subject_item = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestCertSubjectDER.data()),
|
||||
(unsigned int)kTestCertSubjectDER.size()};
|
||||
SECStatus rv =
|
||||
PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates);
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
ASSERT_NE(certificates, nullptr);
|
||||
ScopedCERTCertificateList scoped_certificates(certificates);
|
||||
ASSERT_EQ(scoped_certificates->len, 2);
|
||||
|
||||
std::vector<uint8_t> found_cert1(
|
||||
scoped_certificates->certs[0].data,
|
||||
scoped_certificates->certs[0].data + scoped_certificates->certs[0].len);
|
||||
std::vector<uint8_t> found_cert2(
|
||||
scoped_certificates->certs[1].data,
|
||||
scoped_certificates->certs[1].data + scoped_certificates->certs[1].len);
|
||||
EXPECT_TRUE(found_cert1 == kTestCert1DER || found_cert1 == kTestCert2DER);
|
||||
EXPECT_TRUE(found_cert2 == kTestCert1DER || found_cert2 == kTestCert2DER);
|
||||
EXPECT_TRUE(found_cert1 != found_cert2);
|
||||
}
|
||||
|
||||
// If we try to search the internal slots, we won't find the certificate we just
|
||||
// imported (because it's on a different slot).
|
||||
TEST_F(PK11FindRawCertsBySubjectTest, TestNoCertsOnInternalSlots) {
|
||||
char cert1_nickname[] = "Test Cert 1";
|
||||
SECItem cert1_item = {siBuffer,
|
||||
const_cast<unsigned char*>(kTestCert1DER.data()),
|
||||
(unsigned int)kTestCert1DER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE,
|
||||
cert1_nickname, false),
|
||||
SECSuccess);
|
||||
|
||||
SECItem subject_item = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestCertSubjectDER.data()),
|
||||
(unsigned int)kTestCertSubjectDER.size()};
|
||||
CERTCertificateList* internal_key_slot_certificates = nullptr;
|
||||
ScopedPK11SlotInfo internal_key_slot(PK11_GetInternalKeySlot());
|
||||
SECStatus rv = PK11_FindRawCertsWithSubject(
|
||||
internal_key_slot.get(), &subject_item, &internal_key_slot_certificates);
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
EXPECT_EQ(internal_key_slot_certificates, nullptr);
|
||||
|
||||
CERTCertificateList* internal_slot_certificates = nullptr;
|
||||
ScopedPK11SlotInfo internal_slot(PK11_GetInternalSlot());
|
||||
rv = PK11_FindRawCertsWithSubject(internal_slot.get(), &subject_item,
|
||||
&internal_slot_certificates);
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
EXPECT_EQ(internal_slot_certificates, nullptr);
|
||||
}
|
||||
|
||||
// issuer:test cert
|
||||
// subject:(empty - this had to be done by hand as pycert doesn't support this)
|
||||
// issuerKey:secp256r1
|
||||
// subjectKey:secp256r1
|
||||
// serialNumber:4
|
||||
const std::vector<uint8_t> kEmptySubjectCertDER = {
|
||||
0x30, 0x82, 0x01, 0x09, 0x30, 0x81, 0xAE, 0xA0, 0x03, 0x02, 0x01, 0x02,
|
||||
0x02, 0x01, 0x04, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
|
||||
0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x14, 0x31, 0x12, 0x30, 0x10,
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20,
|
||||
0x63, 0x65, 0x72, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31, 0x37,
|
||||
0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x18,
|
||||
0x0F, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x5A, 0x30, 0x00, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
|
||||
0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48,
|
||||
0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4F, 0xBF, 0xBB,
|
||||
0xBB, 0x61, 0xE0, 0xF8, 0xF9, 0xB1, 0xA6, 0x0A, 0x59, 0xAC, 0x87, 0x04,
|
||||
0xE2, 0xEC, 0x05, 0x0B, 0x42, 0x3E, 0x3C, 0xF7, 0x2E, 0x92, 0x3F, 0x2C,
|
||||
0x4F, 0x79, 0x4B, 0x45, 0x5C, 0x2A, 0x69, 0xD2, 0x33, 0x45, 0x6C, 0x36,
|
||||
0xC4, 0x11, 0x9D, 0x07, 0x06, 0xE0, 0x0E, 0xED, 0xC8, 0xD1, 0x93, 0x90,
|
||||
0xD7, 0x99, 0x1B, 0x7B, 0x2D, 0x07, 0xA3, 0x04, 0xEA, 0xA0, 0x4A, 0xA6,
|
||||
0xC0, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
|
||||
0x01, 0x0B, 0x05, 0x00, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x5C,
|
||||
0x75, 0x51, 0x9F, 0x13, 0x11, 0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20, 0xA3,
|
||||
0xBC, 0x06, 0x30, 0x91, 0xFF, 0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64, 0xEC,
|
||||
0xFD, 0xCB, 0x42, 0x80, 0x0A, 0x70, 0xE6, 0x02, 0x20, 0x31, 0x1B, 0x92,
|
||||
0xAA, 0xA8, 0xB7, 0x51, 0x52, 0x7B, 0x64, 0xD6, 0xF7, 0x2F, 0x0C, 0xFB,
|
||||
0xBB, 0xD5, 0xDF, 0x86, 0xA3, 0x97, 0x96, 0x60, 0x42, 0xDA, 0xD4, 0xA8,
|
||||
0x5F, 0x2F, 0xA4, 0xDE, 0x7C};
|
||||
|
||||
std::vector<uint8_t> kEmptySubjectDER = {0x30, 0x00};
|
||||
|
||||
// This certificate has the smallest possible subject. Finding it should work.
|
||||
TEST_F(PK11FindRawCertsBySubjectTest, TestFindEmptySubject) {
|
||||
char empty_subject_cert_nickname[] = "Empty Subject Cert";
|
||||
SECItem empty_subject_cert_item = {
|
||||
siBuffer, const_cast<unsigned char*>(kEmptySubjectCertDER.data()),
|
||||
(unsigned int)kEmptySubjectCertDER.size()};
|
||||
ASSERT_EQ(
|
||||
PK11_ImportDERCert(m_slot, &empty_subject_cert_item, CK_INVALID_HANDLE,
|
||||
empty_subject_cert_nickname, false),
|
||||
SECSuccess);
|
||||
|
||||
SECItem subject_item = {siBuffer,
|
||||
const_cast<unsigned char*>(kEmptySubjectDER.data()),
|
||||
(unsigned int)kEmptySubjectDER.size()};
|
||||
CERTCertificateList* certificates = nullptr;
|
||||
SECStatus rv =
|
||||
PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates);
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
ASSERT_NE(certificates, nullptr);
|
||||
ScopedCERTCertificateList scoped_certificates(certificates);
|
||||
ASSERT_EQ(scoped_certificates->len, 1);
|
||||
|
||||
std::vector<uint8_t> found_cert(
|
||||
scoped_certificates->certs[0].data,
|
||||
scoped_certificates->certs[0].data + scoped_certificates->certs[0].len);
|
||||
EXPECT_EQ(found_cert, kEmptySubjectCertDER);
|
||||
}
|
||||
|
||||
// Searching for a zero-length subject doesn't make sense (the minimum subject
|
||||
// is the SEQUENCE tag followed by a length byte of 0), but it shouldn't cause
|
||||
// problems.
|
||||
TEST_F(PK11FindRawCertsBySubjectTest, TestSearchForNullSubject) {
|
||||
char cert1_nickname[] = "Test Cert 1";
|
||||
SECItem cert1_item = {siBuffer,
|
||||
const_cast<unsigned char*>(kTestCert1DER.data()),
|
||||
(unsigned int)kTestCert1DER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE,
|
||||
cert1_nickname, false),
|
||||
SECSuccess);
|
||||
|
||||
SECItem subject_item = {siBuffer, nullptr, 0};
|
||||
CERTCertificateList* certificates = nullptr;
|
||||
SECStatus rv =
|
||||
PK11_FindRawCertsWithSubject(m_slot, &subject_item, &certificates);
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
EXPECT_EQ(certificates, nullptr);
|
||||
}
|
||||
|
||||
class PK11GetCertsMatchingPrivateKeyTest : public PK11FindCertsTestBase {};
|
||||
|
||||
// This is the private secp256r1 key corresponding to the above test
|
||||
// certificates.
|
||||
const std::vector<uint8_t> kTestPrivateKeyInfoDER = {
|
||||
0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
|
||||
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
|
||||
0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
|
||||
0x21, 0x91, 0x40, 0x3d, 0x57, 0x10, 0xbf, 0x15, 0xa2, 0x65, 0x81, 0x8c,
|
||||
0xd4, 0x2e, 0xd6, 0xfe, 0xdf, 0x09, 0xad, 0xd9, 0x2d, 0x78, 0xb1, 0x8e,
|
||||
0x7a, 0x1e, 0x9f, 0xeb, 0x95, 0x52, 0x47, 0x02, 0xa1, 0x44, 0x03, 0x42,
|
||||
0x00, 0x04, 0x4f, 0xbf, 0xbb, 0xbb, 0x61, 0xe0, 0xf8, 0xf9, 0xb1, 0xa6,
|
||||
0x0a, 0x59, 0xac, 0x87, 0x04, 0xe2, 0xec, 0x05, 0x0b, 0x42, 0x3e, 0x3c,
|
||||
0xf7, 0x2e, 0x92, 0x3f, 0x2c, 0x4f, 0x79, 0x4b, 0x45, 0x5c, 0x2a, 0x69,
|
||||
0xd2, 0x33, 0x45, 0x6c, 0x36, 0xc4, 0x11, 0x9d, 0x07, 0x06, 0xe0, 0x0e,
|
||||
0xed, 0xc8, 0xd1, 0x93, 0x90, 0xd7, 0x99, 0x1b, 0x7b, 0x2d, 0x07, 0xa3,
|
||||
0x04, 0xea, 0xa0, 0x4a, 0xa6, 0xc0,
|
||||
};
|
||||
|
||||
// issuer:test cert (different key)
|
||||
// subject:test cert (different key)
|
||||
// issuerKey:secp256k1
|
||||
// subjectKey:secp256k1
|
||||
// serialNumber:1
|
||||
const std::vector<uint8_t> kTestCertWithOtherKeyDER = {
|
||||
0x30, 0x82, 0x01, 0x3a, 0x30, 0x81, 0xdf, 0xa0, 0x03, 0x02, 0x01, 0x02,
|
||||
0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x24, 0x31, 0x22, 0x30, 0x20,
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x74, 0x65, 0x73, 0x74, 0x20,
|
||||
0x63, 0x65, 0x72, 0x74, 0x20, 0x28, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72,
|
||||
0x65, 0x6e, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x30, 0x22, 0x18, 0x0f,
|
||||
0x32, 0x30, 0x31, 0x37, 0x31, 0x31, 0x32, 0x37, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x32, 0x30, 0x30, 0x32, 0x30,
|
||||
0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x24, 0x31, 0x22,
|
||||
0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x74, 0x65, 0x73,
|
||||
0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x20, 0x28, 0x64, 0x69, 0x66, 0x66,
|
||||
0x65, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x6b, 0x65, 0x79, 0x29, 0x30, 0x56,
|
||||
0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
|
||||
0x05, 0x2b, 0x81, 0x04, 0x00, 0x0a, 0x03, 0x42, 0x00, 0x04, 0x35, 0xee,
|
||||
0x7c, 0x72, 0x89, 0xd8, 0xfe, 0xf7, 0xa8, 0x6a, 0xfe, 0x5d, 0xa6, 0x6d,
|
||||
0x8b, 0xc2, 0xeb, 0xb6, 0xa8, 0x54, 0x3f, 0xd2, 0xfe, 0xad, 0x08, 0x9f,
|
||||
0x45, 0xce, 0x7a, 0xcd, 0x0f, 0xa6, 0x43, 0x82, 0xa9, 0x50, 0x0c, 0x41,
|
||||
0xda, 0xd7, 0x70, 0xff, 0xd4, 0xb5, 0x11, 0xbf, 0x4b, 0x49, 0x2e, 0xb1,
|
||||
0x23, 0x88, 0x00, 0xc3, 0x2c, 0x4f, 0x76, 0xc7, 0x3a, 0x3f, 0x32, 0x94,
|
||||
0xe7, 0xc5, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
||||
0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x47, 0x00, 0x30, 0x44, 0x02, 0x20,
|
||||
0x63, 0x59, 0x02, 0x01, 0x89, 0xd7, 0x3e, 0x5b, 0xff, 0xd1, 0x16, 0x4e,
|
||||
0xe3, 0xe2, 0x0a, 0xe0, 0x4a, 0xd8, 0x75, 0xaf, 0x77, 0x5c, 0x93, 0x60,
|
||||
0xba, 0x10, 0x1f, 0x97, 0xdd, 0x27, 0x2d, 0x24, 0x02, 0x20, 0x1e, 0xa0,
|
||||
0x7b, 0xee, 0x90, 0x9b, 0x5f, 0x2c, 0x49, 0xd6, 0x61, 0xda, 0x31, 0x14,
|
||||
0xb1, 0xa4, 0x0d, 0x2d, 0x90, 0x2b, 0x70, 0xd8, 0x6b, 0x07, 0x64, 0x27,
|
||||
0xa5, 0x2e, 0xfe, 0xca, 0x6e, 0xe6,
|
||||
};
|
||||
|
||||
// If there are no certs at all, we'll get back a null list.
|
||||
TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestNoCertsAtAll) {
|
||||
SECItem private_key_info = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()),
|
||||
(unsigned int)kTestPrivateKeyInfoDER.size(),
|
||||
};
|
||||
SECKEYPrivateKey* priv_key = nullptr;
|
||||
ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
|
||||
m_slot, &private_key_info, nullptr, nullptr, false, false,
|
||||
KU_ALL, &priv_key, nullptr),
|
||||
SECSuccess);
|
||||
ASSERT_NE(priv_key, nullptr);
|
||||
ScopedSECKEYPrivateKey scoped_priv_key(priv_key);
|
||||
ScopedCERTCertList certs(
|
||||
PK11_GetCertsMatchingPrivateKey(scoped_priv_key.get()));
|
||||
ASSERT_TRUE(CERT_LIST_EMPTY(certs));
|
||||
}
|
||||
|
||||
// If there are no certs for the private key, we'll get back a null list.
|
||||
TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestNoCertsForKey) {
|
||||
SECItem private_key_info = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()),
|
||||
(unsigned int)kTestPrivateKeyInfoDER.size(),
|
||||
};
|
||||
SECKEYPrivateKey* priv_key = nullptr;
|
||||
ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
|
||||
m_slot, &private_key_info, nullptr, nullptr, false, false,
|
||||
KU_ALL, &priv_key, nullptr),
|
||||
SECSuccess);
|
||||
ASSERT_NE(priv_key, nullptr);
|
||||
ScopedSECKEYPrivateKey scoped_priv_key(priv_key);
|
||||
|
||||
char cert_nickname[] = "Test Cert With Other Key";
|
||||
SECItem cert_item = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestCertWithOtherKeyDER.data()),
|
||||
(unsigned int)kTestCertWithOtherKeyDER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE,
|
||||
cert_nickname, false),
|
||||
SECSuccess);
|
||||
|
||||
ScopedCERTCertList certs(
|
||||
PK11_GetCertsMatchingPrivateKey(scoped_priv_key.get()));
|
||||
ASSERT_TRUE(CERT_LIST_EMPTY(certs));
|
||||
}
|
||||
|
||||
void CheckCertListForSubjects(
|
||||
ScopedCERTCertList& list,
|
||||
const std::vector<const char*>& expected_subjects) {
|
||||
ASSERT_NE(list.get(), nullptr);
|
||||
ASSERT_NE(expected_subjects.size(), 0ul);
|
||||
for (const auto& expected_subject : expected_subjects) {
|
||||
size_t list_length = 0;
|
||||
bool found = false;
|
||||
for (CERTCertListNode* n = CERT_LIST_HEAD(list); !CERT_LIST_END(n, list);
|
||||
n = CERT_LIST_NEXT(n)) {
|
||||
list_length++;
|
||||
if (strcmp(n->cert->subjectName, expected_subject) == 0) {
|
||||
ASSERT_FALSE(found);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(found);
|
||||
ASSERT_EQ(list_length, expected_subjects.size());
|
||||
}
|
||||
}
|
||||
|
||||
// We should only get back certs that actually match the private key.
|
||||
TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestOneCertForKey) {
|
||||
SECItem private_key_info = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()),
|
||||
(unsigned int)kTestPrivateKeyInfoDER.size(),
|
||||
};
|
||||
SECKEYPrivateKey* priv_key = nullptr;
|
||||
ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
|
||||
m_slot, &private_key_info, nullptr, nullptr, false, false,
|
||||
KU_ALL, &priv_key, nullptr),
|
||||
SECSuccess);
|
||||
ASSERT_NE(priv_key, nullptr);
|
||||
ScopedSECKEYPrivateKey scoped_priv_key(priv_key);
|
||||
|
||||
char cert1_nickname[] = "Test Cert 1";
|
||||
SECItem cert1_item = {siBuffer,
|
||||
const_cast<unsigned char*>(kTestCert1DER.data()),
|
||||
(unsigned int)kTestCert1DER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE,
|
||||
cert1_nickname, false),
|
||||
SECSuccess);
|
||||
|
||||
char cert_nickname[] = "Test Cert With Other Key";
|
||||
SECItem cert_item = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestCertWithOtherKeyDER.data()),
|
||||
(unsigned int)kTestCertWithOtherKeyDER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE,
|
||||
cert_nickname, false),
|
||||
SECSuccess);
|
||||
|
||||
ScopedCERTCertList certs(
|
||||
PK11_GetCertsMatchingPrivateKey(scoped_priv_key.get()));
|
||||
CheckCertListForSubjects(certs, {"CN=test cert"});
|
||||
}
|
||||
|
||||
// We should be able to get back all certs that match the private key.
|
||||
TEST_F(PK11GetCertsMatchingPrivateKeyTest, TestTwoCertsForKey) {
|
||||
SECItem private_key_info = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestPrivateKeyInfoDER.data()),
|
||||
(unsigned int)kTestPrivateKeyInfoDER.size(),
|
||||
};
|
||||
SECKEYPrivateKey* priv_key = nullptr;
|
||||
ASSERT_EQ(PK11_ImportDERPrivateKeyInfoAndReturnKey(
|
||||
m_slot, &private_key_info, nullptr, nullptr, false, false,
|
||||
KU_ALL, &priv_key, nullptr),
|
||||
SECSuccess);
|
||||
ASSERT_NE(priv_key, nullptr);
|
||||
ScopedSECKEYPrivateKey scoped_priv_key(priv_key);
|
||||
|
||||
char cert1_nickname[] = "Test Cert 1";
|
||||
SECItem cert1_item = {siBuffer,
|
||||
const_cast<unsigned char*>(kTestCert1DER.data()),
|
||||
(unsigned int)kTestCert1DER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert1_item, CK_INVALID_HANDLE,
|
||||
cert1_nickname, false),
|
||||
SECSuccess);
|
||||
char cert2_nickname[] = "Test Cert 2 (same key, different subject)";
|
||||
SECItem cert2_item = {
|
||||
siBuffer, const_cast<unsigned char*>(kUnrelatedTestCertDER.data()),
|
||||
(unsigned int)kUnrelatedTestCertDER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert2_item, CK_INVALID_HANDLE,
|
||||
cert2_nickname, false),
|
||||
SECSuccess);
|
||||
|
||||
char cert_nickname[] = "Test Cert With Other Key";
|
||||
SECItem cert_item = {
|
||||
siBuffer, const_cast<unsigned char*>(kTestCertWithOtherKeyDER.data()),
|
||||
(unsigned int)kTestCertWithOtherKeyDER.size()};
|
||||
ASSERT_EQ(PK11_ImportDERCert(m_slot, &cert_item, CK_INVALID_HANDLE,
|
||||
cert_nickname, false),
|
||||
SECSuccess);
|
||||
|
||||
ScopedCERTCertList certs(
|
||||
PK11_GetCertsMatchingPrivateKey(scoped_priv_key.get()));
|
||||
CheckCertListForSubjects(certs, {"CN=test cert", "CN=unrelated subject DN"});
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -11,39 +11,50 @@
|
|||
'target_name': 'pk11_gtest',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'pk11_aeskeywrap_unittest.cc',
|
||||
'pk11_aes_cmac_unittest.cc',
|
||||
'pk11_aes_gcm_unittest.cc',
|
||||
'pk11_aeskeywrap_unittest.cc',
|
||||
'pk11_aeskeywrappad_unittest.cc',
|
||||
'pk11_cbc_unittest.cc',
|
||||
'pk11_chacha20poly1305_unittest.cc',
|
||||
'pk11_cipherop_unittest.cc',
|
||||
'pk11_curve25519_unittest.cc',
|
||||
'pk11_der_private_key_import_unittest.cc',
|
||||
'pk11_des_unittest.cc',
|
||||
'pk11_ecdsa_unittest.cc',
|
||||
'pk11_encrypt_derive_unittest.cc',
|
||||
'pk11_find_certs_unittest.cc',
|
||||
'pk11_import_unittest.cc',
|
||||
'pk11_keygen.cc',
|
||||
'pk11_key_unittest.cc',
|
||||
'pk11_module_unittest.cc',
|
||||
'pk11_pbkdf2_unittest.cc',
|
||||
'pk11_prf_unittest.cc',
|
||||
'pk11_prng_unittest.cc',
|
||||
'pk11_rsapkcs1_unittest.cc',
|
||||
'pk11_rsapss_unittest.cc',
|
||||
'pk11_der_private_key_import_unittest.cc',
|
||||
'pk11_seed_cbc_unittest.cc',
|
||||
'<(DEPTH)/gtests/common/gtests.cc'
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
'<(DEPTH)/lib/util/util.gyp:nssutil3',
|
||||
'<(DEPTH)/cpputil/cpputil.gyp:cpputil',
|
||||
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
|
||||
'<(DEPTH)/lib/util/util.gyp:nssutil3',
|
||||
],
|
||||
'conditions': [
|
||||
[ 'test_build==1', {
|
||||
[ 'static_libs==1', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/lib/base/base.gyp:nssb',
|
||||
'<(DEPTH)/lib/certdb/certdb.gyp:certdb',
|
||||
'<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
|
||||
'<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
|
||||
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
|
||||
'<(DEPTH)/lib/nss/nss.gyp:nss_static',
|
||||
'<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
|
||||
'<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
|
||||
'<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
|
||||
'<(DEPTH)/lib/certdb/certdb.gyp:certdb',
|
||||
'<(DEPTH)/lib/base/base.gyp:nssb',
|
||||
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
|
||||
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
|
||||
'<(DEPTH)/lib/ssl/ssl.gyp:ssl',
|
||||
'<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix',
|
||||
],
|
||||
}, {
|
||||
'dependencies': [
|
||||
|
|
@ -54,6 +65,12 @@
|
|||
],
|
||||
}
|
||||
],
|
||||
'target_defaults': {
|
||||
'defines': [
|
||||
'DLL_PREFIX=\"<(dll_prefix)\"',
|
||||
'DLL_SUFFIX=\"<(dll_suffix)\"'
|
||||
]
|
||||
},
|
||||
'variables': {
|
||||
'module': 'nss'
|
||||
}
|
||||
|
|
|
|||
281
security/nss/gtests/pk11_gtest/pk11_import_unittest.cc
Normal file
281
security/nss/gtests/pk11_gtest/pk11_import_unittest.cc
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/* -*- 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 <memory>
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pk11pqg.h"
|
||||
#include "prerror.h"
|
||||
#include "secoid.h"
|
||||
|
||||
#include "cpputil.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "databuffer.h"
|
||||
#include "pk11_keygen.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// This deleter deletes a set of objects, unlike the deleter on
|
||||
// ScopedPK11GenericObject, which only deletes one.
|
||||
struct PK11GenericObjectsDeleter {
|
||||
void operator()(PK11GenericObject* objs) {
|
||||
if (objs) {
|
||||
PK11_DestroyGenericObjects(objs);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Pk11KeyImportTestBase : public ::testing::Test {
|
||||
public:
|
||||
Pk11KeyImportTestBase() = default;
|
||||
virtual ~Pk11KeyImportTestBase() = default;
|
||||
|
||||
void SetUp() override {
|
||||
slot_.reset(PK11_GetInternalKeySlot());
|
||||
ASSERT_TRUE(slot_);
|
||||
|
||||
static const uint8_t pw[] = "pw";
|
||||
SECItem pwItem = {siBuffer, toUcharPtr(pw), sizeof(pw)};
|
||||
password_.reset(SECITEM_DupItem(&pwItem));
|
||||
}
|
||||
|
||||
void Test(const Pkcs11KeyPairGenerator& generator) {
|
||||
// Generate a key and export it.
|
||||
KeyType key_type = nullKey;
|
||||
ScopedSECKEYEncryptedPrivateKeyInfo key_info;
|
||||
ScopedSECItem public_value;
|
||||
GenerateAndExport(generator, &key_type, &key_info, &public_value);
|
||||
|
||||
// Note: NSS is currently unable export wrapped DH keys, so this doesn't
|
||||
// test those beyond generate and verify.
|
||||
if (key_type == dhKey) {
|
||||
return;
|
||||
}
|
||||
ASSERT_NE(nullptr, public_value);
|
||||
ASSERT_NE(nullptr, key_info);
|
||||
|
||||
// Now import the encrypted key.
|
||||
static const uint8_t nick[] = "nick";
|
||||
SECItem nickname = {siBuffer, toUcharPtr(nick), sizeof(nick)};
|
||||
SECKEYPrivateKey* priv_tmp;
|
||||
SECStatus rv = PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
|
||||
slot_.get(), key_info.get(), password_.get(), &nickname,
|
||||
public_value.get(), PR_TRUE, PR_TRUE, key_type, 0, &priv_tmp, NULL);
|
||||
ASSERT_EQ(SECSuccess, rv) << "PK11_ImportEncryptedPrivateKeyInfo failed "
|
||||
<< PORT_ErrorToName(PORT_GetError());
|
||||
ScopedSECKEYPrivateKey priv_key(priv_tmp);
|
||||
ASSERT_NE(nullptr, priv_key);
|
||||
|
||||
CheckForPublicKey(priv_key, public_value.get());
|
||||
}
|
||||
|
||||
private:
|
||||
SECItem GetPublicComponent(ScopedSECKEYPublicKey& pub_key) {
|
||||
SECItem null = {siBuffer, NULL, 0};
|
||||
switch (SECKEY_GetPublicKeyType(pub_key.get())) {
|
||||
case rsaKey:
|
||||
case rsaPssKey:
|
||||
case rsaOaepKey:
|
||||
return pub_key->u.rsa.modulus;
|
||||
case keaKey:
|
||||
return pub_key->u.kea.publicValue;
|
||||
case dsaKey:
|
||||
return pub_key->u.dsa.publicValue;
|
||||
case dhKey:
|
||||
return pub_key->u.dh.publicValue;
|
||||
case ecKey:
|
||||
return pub_key->u.ec.publicValue;
|
||||
case fortezzaKey: /* depricated */
|
||||
case nullKey:
|
||||
/* didn't use default here so we can catch new key types at compile time
|
||||
*/
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
void CheckForPublicKey(const ScopedSECKEYPrivateKey& priv_key,
|
||||
const SECItem* expected_public) {
|
||||
// Verify the public key exists.
|
||||
StackSECItem priv_id;
|
||||
KeyType type = SECKEY_GetPrivateKeyType(priv_key.get());
|
||||
SECStatus rv = PK11_ReadRawAttribute(PK11_TypePrivKey, priv_key.get(),
|
||||
CKA_ID, &priv_id);
|
||||
ASSERT_EQ(SECSuccess, rv) << "Couldn't read CKA_ID from private key: "
|
||||
<< PORT_ErrorToName(PORT_GetError());
|
||||
|
||||
CK_ATTRIBUTE_TYPE value_type = CKA_VALUE;
|
||||
switch (type) {
|
||||
case rsaKey:
|
||||
value_type = CKA_MODULUS;
|
||||
break;
|
||||
|
||||
case dhKey:
|
||||
case dsaKey:
|
||||
value_type = CKA_VALUE;
|
||||
break;
|
||||
|
||||
case ecKey:
|
||||
value_type = CKA_EC_POINT;
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL() << "unknown key type";
|
||||
}
|
||||
|
||||
// Scan public key objects until we find one with the same CKA_ID as
|
||||
// priv_key
|
||||
std::unique_ptr<PK11GenericObject, PK11GenericObjectsDeleter> objs(
|
||||
PK11_FindGenericObjects(slot_.get(), CKO_PUBLIC_KEY));
|
||||
ASSERT_NE(nullptr, objs);
|
||||
for (PK11GenericObject* obj = objs.get(); obj != nullptr;
|
||||
obj = PK11_GetNextGenericObject(obj)) {
|
||||
StackSECItem pub_id;
|
||||
rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_ID, &pub_id);
|
||||
if (rv != SECSuccess) {
|
||||
// Can't read CKA_ID from object.
|
||||
continue;
|
||||
}
|
||||
if (!SECITEM_ItemsAreEqual(&priv_id, &pub_id)) {
|
||||
// This isn't the object we're looking for.
|
||||
continue;
|
||||
}
|
||||
|
||||
StackSECItem token;
|
||||
rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, CKA_TOKEN, &token);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
ASSERT_EQ(1U, token.len);
|
||||
ASSERT_NE(0, token.data[0]);
|
||||
|
||||
StackSECItem raw_value;
|
||||
SECItem decoded_value;
|
||||
rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj, value_type, &raw_value);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
SECItem value = raw_value;
|
||||
|
||||
// Decode the EC_POINT and check the output against expected.
|
||||
// CKA_EC_POINT isn't stable, see Bug 1520649.
|
||||
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
|
||||
ASSERT_TRUE(arena);
|
||||
if (value_type == CKA_EC_POINT) {
|
||||
// If this fails due to the noted inconsistency, we may need to
|
||||
// check the whole raw_value, or remove a leading UNCOMPRESSED_POINT tag
|
||||
rv = SEC_QuickDERDecodeItem(arena.get(), &decoded_value,
|
||||
SEC_ASN1_GET(SEC_OctetStringTemplate),
|
||||
&raw_value);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
value = decoded_value;
|
||||
}
|
||||
ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &value))
|
||||
<< "expected: "
|
||||
<< DataBuffer(expected_public->data, expected_public->len)
|
||||
<< std::endl
|
||||
<< "actual: " << DataBuffer(value.data, value.len) << std::endl;
|
||||
|
||||
// Finally, convert the private to public and ensure it matches.
|
||||
ScopedSECKEYPublicKey pub_key(SECKEY_ConvertToPublicKey(priv_key.get()));
|
||||
ASSERT_TRUE(pub_key);
|
||||
SECItem converted_public = GetPublicComponent(pub_key);
|
||||
ASSERT_TRUE(converted_public.len != 0);
|
||||
|
||||
ASSERT_TRUE(SECITEM_ItemsAreEqual(expected_public, &converted_public))
|
||||
<< "expected: "
|
||||
<< DataBuffer(expected_public->data, expected_public->len)
|
||||
<< std::endl
|
||||
<< "actual: "
|
||||
<< DataBuffer(converted_public.data, converted_public.len)
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateAndExport(const Pkcs11KeyPairGenerator& generator,
|
||||
KeyType* key_type,
|
||||
ScopedSECKEYEncryptedPrivateKeyInfo* key_info,
|
||||
ScopedSECItem* public_value) {
|
||||
ScopedSECKEYPrivateKey priv_key;
|
||||
ScopedSECKEYPublicKey pub_key;
|
||||
generator.GenerateKey(&priv_key, &pub_key);
|
||||
ASSERT_TRUE(priv_key);
|
||||
|
||||
// Save the public value, which we will need on import */
|
||||
SECItem* pub_val;
|
||||
KeyType t = SECKEY_GetPublicKeyType(pub_key.get());
|
||||
switch (t) {
|
||||
case rsaKey:
|
||||
pub_val = &pub_key->u.rsa.modulus;
|
||||
break;
|
||||
case dhKey:
|
||||
pub_val = &pub_key->u.dh.publicValue;
|
||||
break;
|
||||
case dsaKey:
|
||||
pub_val = &pub_key->u.dsa.publicValue;
|
||||
break;
|
||||
case ecKey:
|
||||
pub_val = &pub_key->u.ec.publicValue;
|
||||
break;
|
||||
default:
|
||||
FAIL() << "Unknown key type";
|
||||
}
|
||||
|
||||
CheckForPublicKey(priv_key, pub_val);
|
||||
|
||||
*key_type = t;
|
||||
// Note: NSS is currently unable export wrapped DH keys, so this doesn't
|
||||
// test those beyond generate and verify.
|
||||
if (t == dhKey) {
|
||||
return;
|
||||
}
|
||||
public_value->reset(SECITEM_DupItem(pub_val));
|
||||
|
||||
// Wrap and export the key.
|
||||
ScopedSECKEYEncryptedPrivateKeyInfo epki(PK11_ExportEncryptedPrivKeyInfo(
|
||||
slot_.get(), SEC_OID_AES_256_CBC, password_.get(), priv_key.get(), 1,
|
||||
nullptr));
|
||||
ASSERT_NE(nullptr, epki) << "PK11_ExportEncryptedPrivKeyInfo failed: "
|
||||
<< PORT_ErrorToName(PORT_GetError());
|
||||
|
||||
key_info->swap(epki);
|
||||
}
|
||||
|
||||
ScopedPK11SlotInfo slot_;
|
||||
ScopedSECItem password_;
|
||||
};
|
||||
|
||||
class Pk11KeyImportTest
|
||||
: public Pk11KeyImportTestBase,
|
||||
public ::testing::WithParamInterface<CK_MECHANISM_TYPE> {
|
||||
public:
|
||||
Pk11KeyImportTest() = default;
|
||||
virtual ~Pk11KeyImportTest() = default;
|
||||
};
|
||||
|
||||
TEST_P(Pk11KeyImportTest, GenerateExportImport) {
|
||||
Test(Pkcs11KeyPairGenerator(GetParam()));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Pk11KeyImportTest, Pk11KeyImportTest,
|
||||
::testing::Values(CKM_RSA_PKCS_KEY_PAIR_GEN,
|
||||
CKM_DSA_KEY_PAIR_GEN,
|
||||
CKM_DH_PKCS_KEY_PAIR_GEN));
|
||||
|
||||
class Pk11KeyImportTestEC : public Pk11KeyImportTestBase,
|
||||
public ::testing::WithParamInterface<SECOidTag> {
|
||||
public:
|
||||
Pk11KeyImportTestEC() = default;
|
||||
virtual ~Pk11KeyImportTestEC() = default;
|
||||
};
|
||||
|
||||
TEST_P(Pk11KeyImportTestEC, GenerateExportImport) {
|
||||
Test(Pkcs11KeyPairGenerator(CKM_EC_KEY_PAIR_GEN, GetParam()));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Pk11KeyImportTestEC, Pk11KeyImportTestEC,
|
||||
::testing::Values(SEC_OID_SECG_EC_SECP256R1,
|
||||
SEC_OID_SECG_EC_SECP384R1,
|
||||
SEC_OID_SECG_EC_SECP521R1,
|
||||
SEC_OID_CURVE25519));
|
||||
|
||||
} // namespace nss_test
|
||||
80
security/nss/gtests/pk11_gtest/pk11_key_unittest.cc
Normal file
80
security/nss/gtests/pk11_gtest/pk11_key_unittest.cc
Normal file
|
|
@ -0,0 +1,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 <memory>
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pk11pqg.h"
|
||||
#include "prerror.h"
|
||||
#include "secoid.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "pk11_keygen.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class Pkcs11NullKeyTestBase : public ::testing::Test {
|
||||
protected:
|
||||
// This constructs a key pair, then erases the public value from the public
|
||||
// key. NSS should reject this.
|
||||
void Test(const Pkcs11KeyPairGenerator& generator,
|
||||
CK_MECHANISM_TYPE dh_mech) {
|
||||
ScopedSECKEYPrivateKey priv;
|
||||
ScopedSECKEYPublicKey pub;
|
||||
generator.GenerateKey(&priv, &pub);
|
||||
ASSERT_TRUE(priv);
|
||||
|
||||
// These don't leak because they are allocated to the arena associated with
|
||||
// the public key.
|
||||
SECItem* pub_val = nullptr;
|
||||
switch (SECKEY_GetPublicKeyType(pub.get())) {
|
||||
case rsaKey:
|
||||
pub_val = &pub->u.rsa.modulus;
|
||||
break;
|
||||
|
||||
case dsaKey:
|
||||
pub_val = &pub->u.dsa.publicValue;
|
||||
break;
|
||||
|
||||
case dhKey:
|
||||
pub_val = &pub->u.dh.publicValue;
|
||||
break;
|
||||
|
||||
case ecKey:
|
||||
pub_val = &pub->u.ec.publicValue;
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL() << "Unknown key type " << SECKEY_GetPublicKeyType(pub.get());
|
||||
}
|
||||
pub_val->data = nullptr;
|
||||
pub_val->len = 0;
|
||||
|
||||
ScopedPK11SymKey symKey(PK11_PubDeriveWithKDF(
|
||||
priv.get(), pub.get(), false, nullptr, nullptr, dh_mech,
|
||||
CKM_SHA512_HMAC, CKA_DERIVE, 0, CKD_NULL, nullptr, nullptr));
|
||||
ASSERT_FALSE(symKey);
|
||||
}
|
||||
};
|
||||
|
||||
class Pkcs11DhNullKeyTest : public Pkcs11NullKeyTestBase {};
|
||||
TEST_F(Pkcs11DhNullKeyTest, UseNullPublicValue) {
|
||||
Test(Pkcs11KeyPairGenerator(CKM_DH_PKCS_KEY_PAIR_GEN), CKM_DH_PKCS_DERIVE);
|
||||
}
|
||||
|
||||
class Pkcs11EcdhNullKeyTest : public Pkcs11NullKeyTestBase,
|
||||
public ::testing::WithParamInterface<SECOidTag> {
|
||||
};
|
||||
TEST_P(Pkcs11EcdhNullKeyTest, UseNullPublicValue) {
|
||||
Test(Pkcs11KeyPairGenerator(CKM_EC_KEY_PAIR_GEN, GetParam()),
|
||||
CKM_ECDH1_DERIVE);
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(Pkcs11EcdhNullKeyTest, Pkcs11EcdhNullKeyTest,
|
||||
::testing::Values(SEC_OID_SECG_EC_SECP256R1,
|
||||
SEC_OID_SECG_EC_SECP384R1,
|
||||
SEC_OID_SECG_EC_SECP521R1,
|
||||
SEC_OID_CURVE25519));
|
||||
|
||||
} // namespace nss_test
|
||||
143
security/nss/gtests/pk11_gtest/pk11_keygen.cc
Normal file
143
security/nss/gtests/pk11_gtest/pk11_keygen.cc
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/* 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 "pk11_keygen.h"
|
||||
|
||||
#include "pk11pub.h"
|
||||
#include "pk11pqg.h"
|
||||
#include "prerror.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class ParamHolder {
|
||||
public:
|
||||
virtual void* get() = 0;
|
||||
virtual ~ParamHolder() = default;
|
||||
|
||||
protected:
|
||||
ParamHolder() = default;
|
||||
};
|
||||
|
||||
void Pkcs11KeyPairGenerator::GenerateKey(ScopedSECKEYPrivateKey* priv_key,
|
||||
ScopedSECKEYPublicKey* pub_key) const {
|
||||
// This function returns if an assertion fails, so don't leak anything.
|
||||
priv_key->reset(nullptr);
|
||||
pub_key->reset(nullptr);
|
||||
|
||||
auto params = MakeParams();
|
||||
ASSERT_NE(nullptr, params);
|
||||
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
ASSERT_TRUE(slot);
|
||||
|
||||
SECKEYPublicKey* pub_tmp;
|
||||
ScopedSECKEYPrivateKey priv_tmp(PK11_GenerateKeyPair(
|
||||
slot.get(), mech_, params->get(), &pub_tmp, PR_FALSE, PR_TRUE, nullptr));
|
||||
ASSERT_NE(nullptr, priv_tmp) << "PK11_GenerateKeyPair failed: "
|
||||
<< PORT_ErrorToName(PORT_GetError());
|
||||
ASSERT_NE(nullptr, pub_tmp);
|
||||
|
||||
priv_key->swap(priv_tmp);
|
||||
pub_key->reset(pub_tmp);
|
||||
}
|
||||
|
||||
class RsaParamHolder : public ParamHolder {
|
||||
public:
|
||||
RsaParamHolder() : params_({1024, 0x010001}) {}
|
||||
~RsaParamHolder() = default;
|
||||
|
||||
void* get() override { return ¶ms_; }
|
||||
|
||||
private:
|
||||
PK11RSAGenParams params_;
|
||||
};
|
||||
|
||||
class PqgParamHolder : public ParamHolder {
|
||||
public:
|
||||
PqgParamHolder(PQGParams* params) : params_(params) {}
|
||||
~PqgParamHolder() = default;
|
||||
|
||||
void* get() override { return params_.get(); }
|
||||
|
||||
private:
|
||||
ScopedPQGParams params_;
|
||||
};
|
||||
|
||||
class DhParamHolder : public PqgParamHolder {
|
||||
public:
|
||||
DhParamHolder(PQGParams* params)
|
||||
: PqgParamHolder(params),
|
||||
params_({nullptr, params->prime, params->base}) {}
|
||||
~DhParamHolder() = default;
|
||||
|
||||
void* get() override { return ¶ms_; }
|
||||
|
||||
private:
|
||||
SECKEYDHParams params_;
|
||||
};
|
||||
|
||||
class EcParamHolder : public ParamHolder {
|
||||
public:
|
||||
EcParamHolder(SECOidTag curve_oid) {
|
||||
SECOidData* curve = SECOID_FindOIDByTag(curve_oid);
|
||||
EXPECT_NE(nullptr, curve);
|
||||
|
||||
size_t plen = curve->oid.len + 2;
|
||||
extra_.reset(new uint8_t[plen]);
|
||||
extra_[0] = SEC_ASN1_OBJECT_ID;
|
||||
extra_[1] = static_cast<uint8_t>(curve->oid.len);
|
||||
memcpy(&extra_[2], curve->oid.data, curve->oid.len);
|
||||
|
||||
ec_params_ = {siBuffer, extra_.get(), static_cast<unsigned int>(plen)};
|
||||
}
|
||||
~EcParamHolder() = default;
|
||||
|
||||
void* get() override { return &ec_params_; }
|
||||
|
||||
private:
|
||||
SECKEYECParams ec_params_;
|
||||
std::unique_ptr<uint8_t[]> extra_;
|
||||
};
|
||||
|
||||
std::unique_ptr<ParamHolder> Pkcs11KeyPairGenerator::MakeParams() const {
|
||||
switch (mech_) {
|
||||
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
||||
std::cerr << "Generate RSA pair" << std::endl;
|
||||
return std::unique_ptr<ParamHolder>(new RsaParamHolder());
|
||||
|
||||
case CKM_DSA_KEY_PAIR_GEN:
|
||||
case CKM_DH_PKCS_KEY_PAIR_GEN: {
|
||||
PQGParams* pqg_params = nullptr;
|
||||
PQGVerify* pqg_verify = nullptr;
|
||||
const unsigned int key_size = 1024;
|
||||
SECStatus rv = PK11_PQG_ParamGenV2(key_size, 0, key_size / 16,
|
||||
&pqg_params, &pqg_verify);
|
||||
if (rv != SECSuccess) {
|
||||
ADD_FAILURE() << "PK11_PQG_ParamGenV2 failed";
|
||||
return nullptr;
|
||||
}
|
||||
EXPECT_NE(nullptr, pqg_verify);
|
||||
EXPECT_NE(nullptr, pqg_params);
|
||||
PK11_PQG_DestroyVerify(pqg_verify);
|
||||
if (mech_ == CKM_DSA_KEY_PAIR_GEN) {
|
||||
std::cerr << "Generate DSA pair" << std::endl;
|
||||
return std::unique_ptr<ParamHolder>(new PqgParamHolder(pqg_params));
|
||||
}
|
||||
std::cerr << "Generate DH pair" << std::endl;
|
||||
return std::unique_ptr<ParamHolder>(new DhParamHolder(pqg_params));
|
||||
}
|
||||
|
||||
case CKM_EC_KEY_PAIR_GEN:
|
||||
std::cerr << "Generate EC pair on " << curve_ << std::endl;
|
||||
return std::unique_ptr<ParamHolder>(new EcParamHolder(curve_));
|
||||
|
||||
default:
|
||||
ADD_FAILURE() << "unknown OID " << mech_;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
34
security/nss/gtests/pk11_gtest/pk11_keygen.h
Normal file
34
security/nss/gtests/pk11_gtest/pk11_keygen.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* 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 "nss.h"
|
||||
#include "secoid.h"
|
||||
|
||||
#include "nss_scoped_ptrs.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class ParamHolder;
|
||||
|
||||
class Pkcs11KeyPairGenerator {
|
||||
public:
|
||||
Pkcs11KeyPairGenerator(CK_MECHANISM_TYPE mech, SECOidTag curve_oid)
|
||||
: mech_(mech), curve_(curve_oid) {}
|
||||
Pkcs11KeyPairGenerator(CK_MECHANISM_TYPE mech)
|
||||
: Pkcs11KeyPairGenerator(mech, SEC_OID_UNKNOWN) {}
|
||||
|
||||
CK_MECHANISM_TYPE mechanism() const { return mech_; }
|
||||
SECOidTag curve() const { return curve_; }
|
||||
|
||||
void GenerateKey(ScopedSECKEYPrivateKey* priv_key,
|
||||
ScopedSECKEYPublicKey* pub_key) const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<ParamHolder> MakeParams() const;
|
||||
|
||||
CK_MECHANISM_TYPE mech_;
|
||||
SECOidTag curve_;
|
||||
};
|
||||
|
||||
} // namespace nss_test
|
||||
84
security/nss/gtests/pk11_gtest/pk11_module_unittest.cc
Normal file
84
security/nss/gtests/pk11_gtest/pk11_module_unittest.cc
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- 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 <memory>
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "prerror.h"
|
||||
#include "prsystem.h"
|
||||
#include "secoid.h"
|
||||
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "databuffer.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class Pkcs11ModuleTest : public ::testing::Test {
|
||||
public:
|
||||
Pkcs11ModuleTest() {}
|
||||
|
||||
void SetUp() override {
|
||||
ASSERT_EQ(SECSuccess, SECMOD_AddNewModule("Pkcs11ModuleTest", DLL_PREFIX
|
||||
"pkcs11testmodule." DLL_SUFFIX,
|
||||
0, 0))
|
||||
<< PORT_ErrorToName(PORT_GetError());
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
int type;
|
||||
ASSERT_EQ(SECSuccess, SECMOD_DeleteModule("Pkcs11ModuleTest", &type));
|
||||
ASSERT_EQ(SECMOD_EXTERNAL, type);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Pkcs11ModuleTest, LoadUnload) {
|
||||
ScopedSECMODModule module(SECMOD_FindModule("Pkcs11ModuleTest"));
|
||||
EXPECT_NE(nullptr, module);
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11ModuleTest, ListSlots) {
|
||||
ScopedPK11SlotList slots(
|
||||
PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, nullptr));
|
||||
EXPECT_NE(nullptr, slots);
|
||||
|
||||
PK11SlotListElement* element = PK11_GetFirstSafe(slots.get());
|
||||
EXPECT_NE(nullptr, element);
|
||||
|
||||
// These tokens are always present.
|
||||
const std::vector<std::string> kSlotsWithToken = {
|
||||
"NSS Internal Cryptographic Services",
|
||||
"NSS User Private Key and Certificate Services",
|
||||
"Test PKCS11 Public Certs Slot", "Test PKCS11 Slot 二"};
|
||||
std::vector<std::string> foundSlots;
|
||||
|
||||
do {
|
||||
std::string name = PK11_GetSlotName(element->slot);
|
||||
foundSlots.push_back(name);
|
||||
std::cerr << "loaded slot: " << name << std::endl;
|
||||
} while ((element = PK11_GetNextSafe(slots.get(), element, PR_FALSE)) !=
|
||||
nullptr);
|
||||
|
||||
std::sort(foundSlots.begin(), foundSlots.end());
|
||||
EXPECT_TRUE(std::equal(kSlotsWithToken.begin(), kSlotsWithToken.end(),
|
||||
foundSlots.begin()));
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11ModuleTest, PublicCertificatesToken) {
|
||||
const std::string kRegularToken = "Test PKCS11 Tokeñ 2 Label";
|
||||
const std::string kPublicCertificatesToken = "Test PKCS11 Public Certs Token";
|
||||
|
||||
ScopedPK11SlotInfo slot1(PK11_FindSlotByName(kRegularToken.c_str()));
|
||||
EXPECT_NE(nullptr, slot1);
|
||||
EXPECT_FALSE(PK11_IsFriendly(slot1.get()));
|
||||
|
||||
ScopedPK11SlotInfo slot2(
|
||||
PK11_FindSlotByName(kPublicCertificatesToken.c_str()));
|
||||
EXPECT_NE(nullptr, slot2);
|
||||
EXPECT_TRUE(PK11_IsFriendly(slot2.get()));
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -22,53 +22,102 @@ class Pkcs11Pbkdf2Test : public ::testing::Test {
|
|||
public:
|
||||
void Derive(std::vector<uint8_t>& derived, SECOidTag hash_alg) {
|
||||
// Shared between test vectors.
|
||||
const unsigned int iterations = 4096;
|
||||
const unsigned int kIterations = 4096;
|
||||
std::string pass("passwordPASSWORDpassword");
|
||||
std::string salt("saltSALTsaltSALTsaltSALTsaltSALTsalt");
|
||||
|
||||
// Derivation must succeed with the right values.
|
||||
EXPECT_TRUE(DeriveBytes(pass, salt, derived, hash_alg, iterations));
|
||||
EXPECT_TRUE(DeriveBytes(pass, salt, derived, hash_alg, kIterations));
|
||||
|
||||
// Derivation must fail when the password is bogus.
|
||||
std::string bogusPass("PasswordPASSWORDpassword");
|
||||
EXPECT_FALSE(DeriveBytes(bogusPass, salt, derived, hash_alg, iterations));
|
||||
std::string bogus_pass("PasswordPASSWORDpassword");
|
||||
EXPECT_FALSE(DeriveBytes(bogus_pass, salt, derived, hash_alg, kIterations));
|
||||
|
||||
// Derivation must fail when the salt is bogus.
|
||||
std::string bogusSalt("SaltSALTsaltSALTsaltSALTsaltSALTsalt");
|
||||
EXPECT_FALSE(DeriveBytes(pass, bogusSalt, derived, hash_alg, iterations));
|
||||
std::string bogus_salt("SaltSALTsaltSALTsaltSALTsaltSALTsalt");
|
||||
EXPECT_FALSE(DeriveBytes(pass, bogus_salt, derived, hash_alg, kIterations));
|
||||
|
||||
// Derivation must fail when using the wrong hash function.
|
||||
SECOidTag next_hash_alg = static_cast<SECOidTag>(hash_alg + 1);
|
||||
EXPECT_FALSE(DeriveBytes(pass, salt, derived, next_hash_alg, iterations));
|
||||
EXPECT_FALSE(DeriveBytes(pass, salt, derived, next_hash_alg, kIterations));
|
||||
|
||||
// Derivation must fail when using the wrong number of iterations.
|
||||
EXPECT_FALSE(DeriveBytes(pass, salt, derived, hash_alg, iterations + 1));
|
||||
// Derivation must fail when using the wrong number of kIterations.
|
||||
EXPECT_FALSE(DeriveBytes(pass, salt, derived, hash_alg, kIterations + 1));
|
||||
}
|
||||
|
||||
void KeySizes(SECOidTag hash_alg) {
|
||||
// These tests will only validate the controls around the key sizes.
|
||||
// The resulting key is tested above, with valid key sizes.
|
||||
const unsigned int kIterations = 10;
|
||||
std::string pass("passwordPASSWORDpassword");
|
||||
std::string salt("saltSALTsaltSALTsaltSALTsaltSALTsalt");
|
||||
|
||||
// Derivation must fail when using key sizes bigger than MAX_KEY_LEN.
|
||||
const int big_key_size = 768;
|
||||
EXPECT_FALSE(KeySizeParam(pass, salt, big_key_size, hash_alg, kIterations));
|
||||
|
||||
// Zero is acceptable as key size and will be managed internally.
|
||||
const int zero_key_size = 0;
|
||||
EXPECT_TRUE(KeySizeParam(pass, salt, zero_key_size, hash_alg, kIterations));
|
||||
|
||||
// -1 will be set to 0 internally and this means that the key size will be
|
||||
// obtained from the template. If the template doesn't have this defined,
|
||||
// it must fail.
|
||||
const int minus_key_size = -1;
|
||||
EXPECT_FALSE(
|
||||
KeySizeParam(pass, salt, minus_key_size, hash_alg, kIterations));
|
||||
|
||||
// Lower than -1 is not allowed, as -1 means no keyLen defined.
|
||||
const int negative_key_size = -10;
|
||||
EXPECT_FALSE(
|
||||
KeySizeParam(pass, salt, negative_key_size, hash_alg, kIterations));
|
||||
}
|
||||
|
||||
private:
|
||||
bool DeriveBytes(std::string& pass, std::string& salt,
|
||||
std::vector<uint8_t>& derived, SECOidTag hash_alg,
|
||||
unsigned int iterations) {
|
||||
SECItem passItem = {siBuffer, ToUcharPtr(pass),
|
||||
static_cast<unsigned int>(pass.length())};
|
||||
SECItem saltItem = {siBuffer, ToUcharPtr(salt),
|
||||
static_cast<unsigned int>(salt.length())};
|
||||
unsigned int kIterations) {
|
||||
SECItem pass_item = {siBuffer, ToUcharPtr(pass),
|
||||
static_cast<unsigned int>(pass.length())};
|
||||
SECItem salt_item = {siBuffer, ToUcharPtr(salt),
|
||||
static_cast<unsigned int>(salt.length())};
|
||||
|
||||
// Set up PBKDF2 params.
|
||||
ScopedSECAlgorithmID alg_id(
|
||||
PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, hash_alg, hash_alg,
|
||||
derived.size(), iterations, &saltItem));
|
||||
derived.size(), kIterations, &salt_item));
|
||||
|
||||
// Derive.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ScopedPK11SymKey symKey(
|
||||
PK11_PBEKeyGen(slot.get(), alg_id.get(), &passItem, false, nullptr));
|
||||
ScopedPK11SymKey sym_key(
|
||||
PK11_PBEKeyGen(slot.get(), alg_id.get(), &pass_item, false, nullptr));
|
||||
|
||||
SECStatus rv = PK11_ExtractKeyValue(symKey.get());
|
||||
SECStatus rv = PK11_ExtractKeyValue(sym_key.get());
|
||||
EXPECT_EQ(rv, SECSuccess);
|
||||
|
||||
SECItem* keyData = PK11_GetKeyData(symKey.get());
|
||||
return !memcmp(&derived[0], keyData->data, keyData->len);
|
||||
SECItem* key_data = PK11_GetKeyData(sym_key.get());
|
||||
return !memcmp(&derived[0], key_data->data, key_data->len);
|
||||
}
|
||||
|
||||
bool KeySizeParam(std::string& pass, std::string& salt, const int key_size,
|
||||
SECOidTag hash_alg, unsigned int kIterations) {
|
||||
SECItem pass_item = {siBuffer, ToUcharPtr(pass),
|
||||
static_cast<unsigned int>(pass.length())};
|
||||
SECItem salt_item = {siBuffer, ToUcharPtr(salt),
|
||||
static_cast<unsigned int>(salt.length())};
|
||||
|
||||
// Set up PBKDF2 params.
|
||||
ScopedSECAlgorithmID alg_id(
|
||||
PK11_CreatePBEV2AlgorithmID(SEC_OID_PKCS5_PBKDF2, hash_alg, hash_alg,
|
||||
key_size, kIterations, &salt_item));
|
||||
|
||||
// Try to generate a key with the defined params.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ScopedPK11SymKey sym_key(
|
||||
PK11_PBEKeyGen(slot.get(), alg_id.get(), &pass_item, false, nullptr));
|
||||
|
||||
// Should be nullptr if fail.
|
||||
return sym_key.get();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -93,4 +142,9 @@ TEST_F(Pkcs11Pbkdf2Test, DeriveKnown2) {
|
|||
Derive(derived, SEC_OID_HMAC_SHA256);
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11Pbkdf2Test, KeyLenSizes) {
|
||||
// The size controls are regardless of the algorithms.
|
||||
KeySizes(SEC_OID_HMAC_SHA256);
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -93,6 +93,20 @@ TEST_F(Pkcs11RsaPssTest, GenerateAndSignAndVerify) {
|
|||
EXPECT_EQ(rv, SECFailure);
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11RsaPssTest, NoLeakWithInvalidExponent) {
|
||||
// Attempt to generate an RSA key with a public exponent of 1. This should
|
||||
// fail, but it shouldn't leak memory.
|
||||
PK11RSAGenParams rsaGenParams = {1024, 0x01};
|
||||
|
||||
// Generate RSA key pair.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
SECKEYPublicKey* pubKey = nullptr;
|
||||
SECKEYPrivateKey* privKey =
|
||||
PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaGenParams,
|
||||
&pubKey, false, false, nullptr);
|
||||
EXPECT_FALSE(privKey);
|
||||
EXPECT_FALSE(pubKey);
|
||||
}
|
||||
class Pkcs11RsaPssVectorTest
|
||||
: public Pkcs11RsaPssTest,
|
||||
public ::testing::WithParamInterface<Pkcs11SignatureTestParams> {};
|
||||
|
|
|
|||
71
security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc
Normal file
71
security/nss/gtests/pk11_gtest/pk11_seed_cbc_unittest.cc
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/* -*- 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 <memory>
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "secerr.h"
|
||||
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace nss_test {
|
||||
class Pkcs11SeedCbcTest : public ::testing::Test {
|
||||
protected:
|
||||
enum class Action { Encrypt, Decrypt };
|
||||
|
||||
SECStatus EncryptDecryptSeed(Action action, unsigned int input_size,
|
||||
unsigned int output_size) {
|
||||
// Generate a random key.
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
ScopedPK11SymKey sym_key(
|
||||
PK11_KeyGen(slot.get(), kMech, nullptr, 16, nullptr));
|
||||
EXPECT_TRUE(!!sym_key);
|
||||
|
||||
std::vector<uint8_t> data(input_size);
|
||||
std::vector<uint8_t> init_vector(16);
|
||||
std::vector<uint8_t> output(output_size);
|
||||
SECItem params = {siBuffer, init_vector.data(),
|
||||
(unsigned int)init_vector.size()};
|
||||
|
||||
// Try to encrypt/decrypt.
|
||||
unsigned int output_len = 0;
|
||||
if (action == Action::Encrypt) {
|
||||
return PK11_Encrypt(sym_key.get(), kMech, ¶ms, output.data(),
|
||||
&output_len, output_size, data.data(), data.size());
|
||||
} else {
|
||||
return PK11_Decrypt(sym_key.get(), kMech, ¶ms, output.data(),
|
||||
&output_len, output_size, data.data(), data.size());
|
||||
}
|
||||
}
|
||||
const CK_MECHANISM_TYPE kMech = CKM_SEED_CBC;
|
||||
};
|
||||
|
||||
// The intention here is to test the arguments of these functions
|
||||
// The resulted content is already tested in EncryptDeriveTests.
|
||||
// SEED_CBC needs an IV of 16 bytes.
|
||||
// The input data size must be multiple of 16.
|
||||
// If not, some padding should be added.
|
||||
// The output size must be at least the size of input data.
|
||||
TEST_F(Pkcs11SeedCbcTest, SeedCBC_ValidArgs) {
|
||||
EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Encrypt, 16, 16));
|
||||
EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Decrypt, 16, 16));
|
||||
// No problem if maxLen is bigger than input data.
|
||||
EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Encrypt, 16, 32));
|
||||
EXPECT_EQ(SECSuccess, EncryptDecryptSeed(Action::Decrypt, 16, 32));
|
||||
}
|
||||
|
||||
TEST_F(Pkcs11SeedCbcTest, SeedCBC_InvalidArgs) {
|
||||
// maxLen lower than input data.
|
||||
EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Encrypt, 16, 10));
|
||||
EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Decrypt, 16, 10));
|
||||
// input data not multiple of SEED_BLOCK_SIZE (16)
|
||||
EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Encrypt, 17, 32));
|
||||
EXPECT_EQ(SECFailure, EncryptDecryptSeed(Action::Decrypt, 17, 32));
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -59,6 +59,9 @@ class Pk11SignatureTest : public ::testing::Test {
|
|||
|
||||
ScopedCERTSubjectPublicKeyInfo certSpki(
|
||||
SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
|
||||
if (!certSpki) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ScopedSECKEYPublicKey(SECKEY_ExtractPublicKey(certSpki.get()));
|
||||
}
|
||||
|
|
|
|||
45
security/nss/gtests/pkcs11testmodule/Makefile
Normal file
45
security/nss/gtests/pkcs11testmodule/Makefile
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#! 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 config.mk
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/rules.mk
|
||||
|
||||
#######################################################################
|
||||
# (6) Execute "component" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
|
||||
#######################################################################
|
||||
# (7) Execute "local" rules. (OPTIONAL). #
|
||||
#######################################################################
|
||||
|
||||
export:: private_export
|
||||
16
security/nss/gtests/pkcs11testmodule/config.mk
Normal file
16
security/nss/gtests/pkcs11testmodule/config.mk
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# 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/.
|
||||
|
||||
# can't do this in manifest.mn because OS_TARGET isn't defined there.
|
||||
ifeq (,$(filter-out WIN%,$(OS_TARGET)))
|
||||
|
||||
# don't want the 32 in the shared library name
|
||||
SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
|
||||
IMPORT_LIBRARY = $(OBJDIR)/$(IMPORT_LIB_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION)$(IMPORT_LIB_SUFFIX)
|
||||
|
||||
RES = $(OBJDIR)/$(LIBRARY_NAME).res
|
||||
RESNAME = $(LIBRARY_NAME).rc
|
||||
|
||||
endif
|
||||
22
security/nss/gtests/pkcs11testmodule/manifest.mn
Normal file
22
security/nss/gtests/pkcs11testmodule/manifest.mn
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# 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 = ../..
|
||||
DEPTH = ../..
|
||||
MODULE = nss
|
||||
|
||||
CPPSRCS = \
|
||||
pkcs11testmodule.cpp \
|
||||
$(NULL)
|
||||
|
||||
INCLUDES += -I$(CORE_DEPTH)/cpputil
|
||||
|
||||
REQUIRES = cpputil
|
||||
|
||||
MAPFILE = $(OBJDIR)/pkcs11testmodule.def
|
||||
|
||||
LIBRARY_NAME = pkcs11testmodule
|
||||
|
||||
EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)cpputil.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
658
security/nss/gtests/pkcs11testmodule/pkcs11testmodule.cpp
Normal file
658
security/nss/gtests/pkcs11testmodule/pkcs11testmodule.cpp
Normal file
|
|
@ -0,0 +1,658 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
// This is a testing PKCS #11 module that simulates a token being inserted and
|
||||
// removed from a slot every 50ms. This is achieved mainly in
|
||||
// Test_C_WaitForSlotEvent. If the application that loaded this module calls
|
||||
// C_WaitForSlotEvent, this module waits for 50ms and returns, having changed
|
||||
// its internal state to report that the token has either been inserted or
|
||||
// removed, as appropriate.
|
||||
// This module also provides an alternate token that is always present for tests
|
||||
// that don't want the cyclic behavior described above.
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h> // for Sleep
|
||||
#else
|
||||
# include <unistd.h> // for usleep
|
||||
#endif
|
||||
|
||||
#include "pkcs11t.h"
|
||||
|
||||
#undef CK_DECLARE_FUNCTION
|
||||
|
||||
#ifdef _WIN32
|
||||
#define CK_DECLARE_FUNCTION(rtype, func) extern rtype __declspec(dllexport) func
|
||||
#else
|
||||
#define CK_DECLARE_FUNCTION(rtype, func) extern rtype func
|
||||
#endif
|
||||
|
||||
#include "pkcs11.h"
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
# include <prtypes.h>
|
||||
# define static_assert(condition, message) PR_STATIC_ASSERT(condition)
|
||||
#endif
|
||||
|
||||
CK_RV Test_C_Initialize(CK_VOID_PTR) { return CKR_OK; }
|
||||
|
||||
CK_RV Test_C_Finalize(CK_VOID_PTR) { return CKR_OK; }
|
||||
|
||||
static const CK_VERSION CryptokiVersion = {2, 2};
|
||||
static const CK_VERSION TestLibraryVersion = {0, 0};
|
||||
static const char TestLibraryDescription[] = "Test PKCS11 Library";
|
||||
static const char TestManufacturerID[] = "Test PKCS11 Manufacturer ID";
|
||||
|
||||
/* The dest buffer is one in the CK_INFO or CK_TOKEN_INFO structs.
|
||||
* Those buffers are padded with spaces. DestSize corresponds to the declared
|
||||
* size for those buffers (e.g. 32 for `char foo[32]`).
|
||||
* The src buffer is a string literal. SrcSize includes the string
|
||||
* termination character (e.g. 4 for `const char foo[] = "foo"` */
|
||||
template <size_t DestSize, size_t SrcSize>
|
||||
void CopyString(unsigned char (&dest)[DestSize], const char (&src)[SrcSize]) {
|
||||
static_assert(DestSize >= SrcSize - 1, "DestSize >= SrcSize - 1");
|
||||
memcpy(dest, src, SrcSize - 1);
|
||||
memset(dest + SrcSize - 1, ' ', DestSize - SrcSize + 1);
|
||||
}
|
||||
|
||||
CK_RV Test_C_GetInfo(CK_INFO_PTR pInfo) {
|
||||
if (!pInfo) {
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
pInfo->cryptokiVersion = CryptokiVersion;
|
||||
CopyString(pInfo->manufacturerID, TestManufacturerID);
|
||||
pInfo->flags = 0; // must be 0
|
||||
CopyString(pInfo->libraryDescription, TestLibraryDescription);
|
||||
pInfo->libraryVersion = TestLibraryVersion;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV Test_C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR) { return CKR_OK; }
|
||||
|
||||
static int tokenPresent = 0;
|
||||
|
||||
// The token in slot 4 has 2 objects. Both of them are profile object
|
||||
// and identified by object ID 1 or 2.
|
||||
static bool readingProfile = false;
|
||||
static const CK_PROFILE_ID profiles[] = {CKP_PUBLIC_CERTIFICATES_TOKEN,
|
||||
CKP_BASELINE_PROVIDER};
|
||||
static int profileIndex = 0;
|
||||
|
||||
CK_RV Test_C_GetSlotList(CK_BBOOL limitToTokensPresent,
|
||||
CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) {
|
||||
if (!pulCount) {
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
CK_SLOT_ID slots[4];
|
||||
CK_ULONG slotCount = 0;
|
||||
|
||||
// We always return slot 2 and 4.
|
||||
slots[slotCount++] = 2;
|
||||
slots[slotCount++] = 4;
|
||||
|
||||
// Slot 1 is a removable slot where a token is present if
|
||||
// tokenPresent = CK_TRUE.
|
||||
if (tokenPresent || !limitToTokensPresent) {
|
||||
slots[slotCount++] = 1;
|
||||
}
|
||||
|
||||
// Slot 3 is a removable slot which never has a token.
|
||||
if (!limitToTokensPresent) {
|
||||
slots[slotCount++] = 3;
|
||||
}
|
||||
|
||||
if (pSlotList) {
|
||||
if (*pulCount < slotCount) {
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
memcpy(pSlotList, slots, sizeof(CK_SLOT_ID) * slotCount);
|
||||
}
|
||||
|
||||
*pulCount = slotCount;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
static const char TestSlotDescription[] = "Test PKCS11 Slot";
|
||||
static const char TestSlot2Description[] = "Test PKCS11 Slot 二";
|
||||
static const char TestSlot3Description[] = "Empty PKCS11 Slot";
|
||||
static const char TestSlot4Description[] = "Test PKCS11 Public Certs Slot";
|
||||
|
||||
CK_RV Test_C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) {
|
||||
if (!pInfo) {
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
switch (slotID) {
|
||||
case 1:
|
||||
CopyString(pInfo->slotDescription, TestSlotDescription);
|
||||
pInfo->flags =
|
||||
(tokenPresent ? CKF_TOKEN_PRESENT : 0) | CKF_REMOVABLE_DEVICE;
|
||||
break;
|
||||
case 2:
|
||||
CopyString(pInfo->slotDescription, TestSlot2Description);
|
||||
pInfo->flags = CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE;
|
||||
break;
|
||||
case 3:
|
||||
CopyString(pInfo->slotDescription, TestSlot3Description);
|
||||
pInfo->flags = CKF_REMOVABLE_DEVICE;
|
||||
break;
|
||||
case 4:
|
||||
CopyString(pInfo->slotDescription, TestSlot4Description);
|
||||
pInfo->flags = CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE;
|
||||
break;
|
||||
default:
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
CopyString(pInfo->manufacturerID, TestManufacturerID);
|
||||
pInfo->hardwareVersion = TestLibraryVersion;
|
||||
pInfo->firmwareVersion = TestLibraryVersion;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
// Deliberately include énye to ensure we're handling encoding correctly.
|
||||
// The PKCS #11 base specification v2.20 specifies that strings be encoded
|
||||
// as UTF-8.
|
||||
static const char TestTokenLabel[] = "Test PKCS11 Tokeñ Label";
|
||||
static const char TestToken2Label[] = "Test PKCS11 Tokeñ 2 Label";
|
||||
static const char TestToken4Label[] = "Test PKCS11 Public Certs Token";
|
||||
static const char TestTokenModel[] = "Test Model";
|
||||
|
||||
CK_RV Test_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) {
|
||||
if (!pInfo) {
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
switch (slotID) {
|
||||
case 1:
|
||||
CopyString(pInfo->label, TestTokenLabel);
|
||||
break;
|
||||
case 2:
|
||||
CopyString(pInfo->label, TestToken2Label);
|
||||
break;
|
||||
case 4:
|
||||
CopyString(pInfo->label, TestToken4Label);
|
||||
break;
|
||||
default:
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
CopyString(pInfo->manufacturerID, TestManufacturerID);
|
||||
CopyString(pInfo->model, TestTokenModel);
|
||||
memset(pInfo->serialNumber, 0, sizeof(pInfo->serialNumber));
|
||||
pInfo->flags = CKF_TOKEN_INITIALIZED;
|
||||
pInfo->ulMaxSessionCount = 1;
|
||||
pInfo->ulSessionCount = 0;
|
||||
pInfo->ulMaxRwSessionCount = 1;
|
||||
pInfo->ulRwSessionCount = 0;
|
||||
pInfo->ulMaxPinLen = 4;
|
||||
pInfo->ulMinPinLen = 4;
|
||||
pInfo->ulTotalPublicMemory = 1024;
|
||||
pInfo->ulFreePublicMemory = 1024;
|
||||
pInfo->ulTotalPrivateMemory = 1024;
|
||||
pInfo->ulFreePrivateMemory = 1024;
|
||||
pInfo->hardwareVersion = TestLibraryVersion;
|
||||
pInfo->firmwareVersion = TestLibraryVersion;
|
||||
memset(pInfo->utcTime, 0, sizeof(pInfo->utcTime));
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV Test_C_GetMechanismList(CK_SLOT_ID, CK_MECHANISM_TYPE_PTR,
|
||||
CK_ULONG_PTR pulCount) {
|
||||
if (!pulCount) {
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
*pulCount = 0;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV Test_C_GetMechanismInfo(CK_SLOT_ID, CK_MECHANISM_TYPE,
|
||||
CK_MECHANISM_INFO_PTR) {
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV Test_C_InitToken(CK_SLOT_ID, CK_UTF8CHAR_PTR, CK_ULONG, CK_UTF8CHAR_PTR) {
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV Test_C_InitPIN(CK_SESSION_HANDLE, CK_UTF8CHAR_PTR, CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_SetPIN(CK_SESSION_HANDLE, CK_UTF8CHAR_PTR, CK_ULONG,
|
||||
CK_UTF8CHAR_PTR, CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS, CK_VOID_PTR, CK_NOTIFY,
|
||||
CK_SESSION_HANDLE_PTR phSession) {
|
||||
switch (slotID) {
|
||||
case 1:
|
||||
*phSession = 1;
|
||||
break;
|
||||
case 2:
|
||||
*phSession = 2;
|
||||
break;
|
||||
case 4:
|
||||
*phSession = 4;
|
||||
break;
|
||||
default:
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV Test_C_CloseSession(CK_SESSION_HANDLE) { return CKR_OK; }
|
||||
|
||||
CK_RV Test_C_CloseAllSessions(CK_SLOT_ID) { return CKR_OK; }
|
||||
|
||||
CK_RV Test_C_GetSessionInfo(CK_SESSION_HANDLE hSession,
|
||||
CK_SESSION_INFO_PTR pInfo) {
|
||||
if (!pInfo) {
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
switch (hSession) {
|
||||
case 1:
|
||||
pInfo->slotID = 1;
|
||||
break;
|
||||
case 2:
|
||||
pInfo->slotID = 2;
|
||||
break;
|
||||
case 4:
|
||||
pInfo->slotID = 4;
|
||||
break;
|
||||
default:
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
pInfo->state = CKS_RO_PUBLIC_SESSION;
|
||||
pInfo->flags = CKF_SERIAL_SESSION;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV Test_C_GetOperationState(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_SetOperationState(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
|
||||
CK_OBJECT_HANDLE, CK_OBJECT_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_Login(CK_SESSION_HANDLE, CK_USER_TYPE, CK_UTF8CHAR_PTR, CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_Logout(CK_SESSION_HANDLE) { return CKR_FUNCTION_NOT_SUPPORTED; }
|
||||
|
||||
CK_RV Test_C_CreateObject(CK_SESSION_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG,
|
||||
CK_OBJECT_HANDLE_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_CopyObject(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR,
|
||||
CK_ULONG, CK_OBJECT_HANDLE_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DestroyObject(CK_SESSION_HANDLE, CK_OBJECT_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_GetObjectSize(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_GetAttributeValue(CK_SESSION_HANDLE hSession,
|
||||
CK_OBJECT_HANDLE hObject,
|
||||
CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) {
|
||||
if (hSession == 4) {
|
||||
assert(hObject >= 1 &&
|
||||
hObject - 1 < sizeof(profiles) / sizeof(profiles[0]));
|
||||
for (CK_ULONG count = 0; count < ulCount; count++) {
|
||||
if (pTemplate[count].type == CKA_PROFILE_ID) {
|
||||
if (pTemplate[count].pValue) {
|
||||
assert(pTemplate[count].ulValueLen == sizeof(CK_ULONG));
|
||||
CK_ULONG value = profiles[hObject - 1];
|
||||
memcpy(pTemplate[count].pValue, &value, sizeof(value));
|
||||
} else {
|
||||
pTemplate[count].ulValueLen = sizeof(CK_ULONG);
|
||||
}
|
||||
} else {
|
||||
pTemplate[count].ulValueLen = (CK_ULONG)-1;
|
||||
}
|
||||
}
|
||||
return CKR_OK;
|
||||
}
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_SetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE,
|
||||
CK_ATTRIBUTE_PTR, CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_FindObjectsInit(CK_SESSION_HANDLE hSession,
|
||||
CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) {
|
||||
// Slot 4
|
||||
if (hSession == 4) {
|
||||
for (CK_ULONG count = 0; count < ulCount; count++) {
|
||||
CK_ATTRIBUTE attribute = pTemplate[count];
|
||||
if (attribute.type == CKA_CLASS) {
|
||||
assert(attribute.ulValueLen == sizeof(CK_ULONG));
|
||||
|
||||
CK_ULONG value;
|
||||
memcpy(&value, attribute.pValue, attribute.ulValueLen);
|
||||
if (value == CKO_PROFILE) {
|
||||
readingProfile = true;
|
||||
profileIndex = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV Test_C_FindObjects(CK_SESSION_HANDLE hSession,
|
||||
CK_OBJECT_HANDLE_PTR phObject,
|
||||
CK_ULONG ulMaxObjectCount,
|
||||
CK_ULONG_PTR pulObjectCount) {
|
||||
if (readingProfile) {
|
||||
assert(hSession == 4);
|
||||
CK_ULONG count = ulMaxObjectCount;
|
||||
size_t remaining = sizeof(profiles) / sizeof(profiles[0]) - profileIndex;
|
||||
if (count > remaining) {
|
||||
count = remaining;
|
||||
}
|
||||
for (CK_ULONG i = 0; i < count; i++) {
|
||||
phObject[i] = i + 1;
|
||||
}
|
||||
profileIndex += count;
|
||||
*pulObjectCount = count;
|
||||
} else {
|
||||
*pulObjectCount = 0;
|
||||
}
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV Test_C_FindObjectsFinal(CK_SESSION_HANDLE hSession) {
|
||||
readingProfile = false;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV Test_C_EncryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
|
||||
CK_OBJECT_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_Encrypt(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
|
||||
CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_EncryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
|
||||
CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_EncryptFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DecryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
|
||||
CK_OBJECT_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_Decrypt(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
|
||||
CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DecryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
|
||||
CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DecryptFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DigestInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_Digest(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
|
||||
CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DigestUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DigestKey(CK_SESSION_HANDLE, CK_OBJECT_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DigestFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_SignInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_Sign(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
|
||||
CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_SignUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_SignFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_SignRecoverInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
|
||||
CK_OBJECT_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_SignRecover(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
|
||||
CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_VerifyInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_Verify(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
|
||||
CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_VerifyUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_VerifyFinal(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_VerifyRecoverInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
|
||||
CK_OBJECT_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_VerifyRecover(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
|
||||
CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DigestEncryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
|
||||
CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DecryptDigestUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
|
||||
CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_SignEncryptUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
|
||||
CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DecryptVerifyUpdate(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
|
||||
CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_GenerateKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR,
|
||||
CK_ULONG, CK_OBJECT_HANDLE_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_GenerateKeyPair(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
|
||||
CK_ATTRIBUTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR,
|
||||
CK_ULONG, CK_OBJECT_HANDLE_PTR,
|
||||
CK_OBJECT_HANDLE_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_WrapKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE,
|
||||
CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_UnwrapKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE,
|
||||
CK_BYTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG,
|
||||
CK_OBJECT_HANDLE_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_DeriveKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE,
|
||||
CK_ATTRIBUTE_PTR, CK_ULONG, CK_OBJECT_HANDLE_PTR) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_SeedRandom(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_GenerateRandom(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_GetFunctionStatus(CK_SESSION_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_CancelFunction(CK_SESSION_HANDLE) {
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
CK_RV Test_C_WaitForSlotEvent(CK_FLAGS, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR) {
|
||||
#ifdef _WIN32
|
||||
Sleep(50); // Sleep takes the duration argument as milliseconds
|
||||
#else
|
||||
usleep(50000); // usleep takes the duration argument as microseconds
|
||||
#endif
|
||||
*pSlot = 1;
|
||||
tokenPresent = !tokenPresent;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
static CK_FUNCTION_LIST FunctionList = {{2, 2},
|
||||
Test_C_Initialize,
|
||||
Test_C_Finalize,
|
||||
Test_C_GetInfo,
|
||||
Test_C_GetFunctionList,
|
||||
Test_C_GetSlotList,
|
||||
Test_C_GetSlotInfo,
|
||||
Test_C_GetTokenInfo,
|
||||
Test_C_GetMechanismList,
|
||||
Test_C_GetMechanismInfo,
|
||||
Test_C_InitToken,
|
||||
Test_C_InitPIN,
|
||||
Test_C_SetPIN,
|
||||
Test_C_OpenSession,
|
||||
Test_C_CloseSession,
|
||||
Test_C_CloseAllSessions,
|
||||
Test_C_GetSessionInfo,
|
||||
Test_C_GetOperationState,
|
||||
Test_C_SetOperationState,
|
||||
Test_C_Login,
|
||||
Test_C_Logout,
|
||||
Test_C_CreateObject,
|
||||
Test_C_CopyObject,
|
||||
Test_C_DestroyObject,
|
||||
Test_C_GetObjectSize,
|
||||
Test_C_GetAttributeValue,
|
||||
Test_C_SetAttributeValue,
|
||||
Test_C_FindObjectsInit,
|
||||
Test_C_FindObjects,
|
||||
Test_C_FindObjectsFinal,
|
||||
Test_C_EncryptInit,
|
||||
Test_C_Encrypt,
|
||||
Test_C_EncryptUpdate,
|
||||
Test_C_EncryptFinal,
|
||||
Test_C_DecryptInit,
|
||||
Test_C_Decrypt,
|
||||
Test_C_DecryptUpdate,
|
||||
Test_C_DecryptFinal,
|
||||
Test_C_DigestInit,
|
||||
Test_C_Digest,
|
||||
Test_C_DigestUpdate,
|
||||
Test_C_DigestKey,
|
||||
Test_C_DigestFinal,
|
||||
Test_C_SignInit,
|
||||
Test_C_Sign,
|
||||
Test_C_SignUpdate,
|
||||
Test_C_SignFinal,
|
||||
Test_C_SignRecoverInit,
|
||||
Test_C_SignRecover,
|
||||
Test_C_VerifyInit,
|
||||
Test_C_Verify,
|
||||
Test_C_VerifyUpdate,
|
||||
Test_C_VerifyFinal,
|
||||
Test_C_VerifyRecoverInit,
|
||||
Test_C_VerifyRecover,
|
||||
Test_C_DigestEncryptUpdate,
|
||||
Test_C_DecryptDigestUpdate,
|
||||
Test_C_SignEncryptUpdate,
|
||||
Test_C_DecryptVerifyUpdate,
|
||||
Test_C_GenerateKey,
|
||||
Test_C_GenerateKeyPair,
|
||||
Test_C_WrapKey,
|
||||
Test_C_UnwrapKey,
|
||||
Test_C_DeriveKey,
|
||||
Test_C_SeedRandom,
|
||||
Test_C_GenerateRandom,
|
||||
Test_C_GetFunctionStatus,
|
||||
Test_C_CancelFunction,
|
||||
Test_C_WaitForSlotEvent};
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
|
||||
CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) {
|
||||
*ppFunctionList = &FunctionList;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
;+NSS_3.48 { # NSS 3.48 release
|
||||
;+ global:
|
||||
LIBRARY pkcs11testmodule ;-
|
||||
EXPORTS ;-
|
||||
C_GetFunctionList;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
25
security/nss/gtests/pkcs11testmodule/pkcs11testmodule.gyp
Normal file
25
security/nss/gtests/pkcs11testmodule/pkcs11testmodule.gyp
Normal file
|
|
@ -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',
|
||||
'../common/gtest.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'pkcs11testmodule',
|
||||
'type': 'shared_library',
|
||||
'sources': [
|
||||
'pkcs11testmodule.cpp',
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
'<(DEPTH)/cpputil/cpputil.gyp:cpputil',
|
||||
],
|
||||
}
|
||||
],
|
||||
'variables': {
|
||||
'module': 'nss'
|
||||
}
|
||||
}
|
||||
60
security/nss/gtests/pkcs11testmodule/pkcs11testmodule.rc
Normal file
60
security/nss/gtests/pkcs11testmodule/pkcs11testmodule.rc
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/* 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 <winver.h>
|
||||
|
||||
#define MY_LIBNAME "pkcs11testmodule"
|
||||
#define MY_FILEDESCRIPTION "NSS PKCS #11 Test Module"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define MY_DEBUG_STR " (debug)"
|
||||
#define MY_FILEFLAGS_1 VS_FF_DEBUG
|
||||
#else
|
||||
#define MY_DEBUG_STR ""
|
||||
#define MY_FILEFLAGS_1 0x0L
|
||||
#endif
|
||||
#define MY_FILEFLAGS_2 MY_FILEFLAGS_1
|
||||
|
||||
#ifdef WINNT
|
||||
#define MY_FILEOS VOS_NT_WINDOWS32
|
||||
#else
|
||||
#define MY_FILEOS VOS__WINDOWS32
|
||||
#endif
|
||||
|
||||
#define MY_INTERNAL_NAME MY_LIBNAME
|
||||
#define MY_VERSION "0"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version-information resource
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 0,0,0,0
|
||||
PRODUCTVERSION 0,0,0,0
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
FILEFLAGS MY_FILEFLAGS_2
|
||||
FILEOS MY_FILEOS
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE 0x0L // not used
|
||||
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0" // Lang=US English, CharSet=Unicode
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Mozilla Foundation\0"
|
||||
VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0"
|
||||
VALUE "FileVersion", MY_VERSION "\0"
|
||||
VALUE "InternalName", MY_INTERNAL_NAME "\0"
|
||||
VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0"
|
||||
VALUE "ProductName", "Network Security Services\0"
|
||||
VALUE "ProductVersion", MY_VERSION "\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
43
security/nss/gtests/smime_gtest/Makefile
Normal file
43
security/nss/gtests/smime_gtest/Makefile
Normal file
|
|
@ -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 ../common/gtest.mk
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/rules.mk
|
||||
|
||||
#######################################################################
|
||||
# (6) Execute "component" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
||||
|
||||
#######################################################################
|
||||
# (7) Execute "local" rules. (OPTIONAL). #
|
||||
#######################################################################
|
||||
22
security/nss/gtests/smime_gtest/manifest.mn
Normal file
22
security/nss/gtests/smime_gtest/manifest.mn
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# 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 = ../..
|
||||
DEPTH = ../..
|
||||
MODULE = nss
|
||||
|
||||
CPPSRCS = \
|
||||
smime_unittest.cc \
|
||||
$(NULL)
|
||||
|
||||
INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
|
||||
-I$(CORE_DEPTH)/gtests/common \
|
||||
-I$(CORE_DEPTH)/cpputil
|
||||
|
||||
REQUIRES = nspr gtest
|
||||
|
||||
PROGRAM = smime_gtest
|
||||
|
||||
EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) $(EXTRA_OBJS) \
|
||||
$(DIST)/lib/$(LIB_PREFIX)gtestutil.$(LIB_SUFFIX)
|
||||
30
security/nss/gtests/smime_gtest/smime_gtest.gyp
Normal file
30
security/nss/gtests/smime_gtest/smime_gtest.gyp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# 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',
|
||||
'../common/gtest.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'smime_gtest',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'smime_unittest.cc',
|
||||
'<(DEPTH)/gtests/common/gtests.cc'
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
|
||||
'<(DEPTH)/lib/util/util.gyp:nssutil3',
|
||||
'<(DEPTH)/lib/nss/nss.gyp:nss3',
|
||||
'<(DEPTH)/lib/smime/smime.gyp:smime',
|
||||
'<(DEPTH)/lib/ssl/ssl.gyp:ssl3',
|
||||
]
|
||||
}
|
||||
],
|
||||
'variables': {
|
||||
'module': 'nss'
|
||||
}
|
||||
}
|
||||
137
security/nss/gtests/smime_gtest/smime_unittest.cc
Normal file
137
security/nss/gtests/smime_gtest/smime_unittest.cc
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/* -*- 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 <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "scoped_ptrs_smime.h"
|
||||
#include "smime.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// See bug 1507174; this is a CMS serialization (RFC 5652) that claims to be
|
||||
// 12336 bytes long, which ensures CMS validates the streaming decoder's
|
||||
// incorrect length.
|
||||
static const unsigned char kHugeLenAsn1[] = {
|
||||
0x30, 0x82, 0x30, 0x30, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
|
||||
0x0D, 0x01, 0x07, 0x02, 0xA0, 0x82, 0x02, 0x30, 0x30, 0x30, 0x02,
|
||||
0x01, 0x30, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0x0B, 0x06,
|
||||
0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x05};
|
||||
|
||||
// secp256r1 signature with no certs and no attrs
|
||||
static unsigned char kValidSignature[] = {
|
||||
0x30, 0x81, 0xFE, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
|
||||
0x07, 0x02, 0xA0, 0x81, 0xF0, 0x30, 0x81, 0xED, 0x02, 0x01, 0x01, 0x31,
|
||||
0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x01, 0x05, 0x00, 0x30, 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
|
||||
0xF7, 0x0D, 0x01, 0x07, 0x01, 0x31, 0x81, 0xC9, 0x30, 0x81, 0xC6, 0x02,
|
||||
0x01, 0x01, 0x30, 0x5D, 0x30, 0x45, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03,
|
||||
0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
|
||||
0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x53, 0x6F, 0x6D, 0x65, 0x2D, 0x53,
|
||||
0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x04,
|
||||
0x0A, 0x0C, 0x18, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, 0x74, 0x20,
|
||||
0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
|
||||
0x4C, 0x74, 0x64, 0x02, 0x14, 0x6B, 0x22, 0xCA, 0x91, 0xE0, 0x71, 0x97,
|
||||
0xEB, 0x45, 0x0D, 0x68, 0xC0, 0xD4, 0xB6, 0xE9, 0x45, 0x38, 0x4C, 0xDD,
|
||||
0xA3, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x01, 0x05, 0x00, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE,
|
||||
0x3D, 0x04, 0x03, 0x02, 0x04, 0x47, 0x30, 0x45, 0x02, 0x20, 0x48, 0xEB,
|
||||
0xE6, 0xBA, 0xFC, 0xFD, 0x83, 0xB3, 0xA2, 0xB5, 0x59, 0x35, 0x0C, 0xA1,
|
||||
0x31, 0x0E, 0x2F, 0xE3, 0x8D, 0x81, 0xD8, 0xF5, 0x33, 0xE4, 0x83, 0x87,
|
||||
0xB1, 0xFD, 0x43, 0x9D, 0x95, 0x7D, 0x02, 0x21, 0x00, 0xD0, 0x05, 0x0E,
|
||||
0x05, 0xA6, 0x80, 0x3C, 0x1A, 0xFE, 0x51, 0xFC, 0x4D, 0x1A, 0x25, 0x05,
|
||||
0x78, 0xB5, 0x42, 0xF5, 0xDE, 0x4E, 0x8A, 0xF8, 0xE3, 0xD8, 0x52, 0xDC,
|
||||
0x2B, 0x73, 0x80, 0x4A, 0x1A};
|
||||
|
||||
// See bug 1507135; this is a CMS signature that contains only the OID
|
||||
static unsigned char kTruncatedSignature[] = {0x30, 0x0B, 0x06, 0x09, 0x2A,
|
||||
0x86, 0x48, 0x86, 0xF7, 0x0D,
|
||||
0x01, 0x07, 0x02};
|
||||
|
||||
// secp256r1 signature that's truncated by one byte.
|
||||
static unsigned char kSlightlyTruncatedSignature[] = {
|
||||
0x30, 0x81, 0xFE, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
|
||||
0x07, 0x02, 0xA0, 0x81, 0xF0, 0x30, 0x81, 0xED, 0x02, 0x01, 0x01, 0x31,
|
||||
0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x01, 0x05, 0x00, 0x30, 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
|
||||
0xF7, 0x0D, 0x01, 0x07, 0x01, 0x31, 0x81, 0xC9, 0x30, 0x81, 0xC6, 0x02,
|
||||
0x01, 0x01, 0x30, 0x5D, 0x30, 0x45, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03,
|
||||
0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
|
||||
0x03, 0x55, 0x04, 0x08, 0x0C, 0x0A, 0x53, 0x6F, 0x6D, 0x65, 0x2D, 0x53,
|
||||
0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x04,
|
||||
0x0A, 0x0C, 0x18, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, 0x74, 0x20,
|
||||
0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
|
||||
0x4C, 0x74, 0x64, 0x02, 0x14, 0x6B, 0x22, 0xCA, 0x91, 0xE0, 0x71, 0x97,
|
||||
0xEB, 0x45, 0x0D, 0x68, 0xC0, 0xD4, 0xB6, 0xE9, 0x45, 0x38, 0x4C, 0xDD,
|
||||
0xA3, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x01, 0x05, 0x00, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE,
|
||||
0x3D, 0x04, 0x03, 0x02, 0x04, 0x47, 0x30, 0x45, 0x02, 0x20, 0x48, 0xEB,
|
||||
0xE6, 0xBA, 0xFC, 0xFD, 0x83, 0xB3, 0xA2, 0xB5, 0x59, 0x35, 0x0C, 0xA1,
|
||||
0x31, 0x0E, 0x2F, 0xE3, 0x8D, 0x81, 0xD8, 0xF5, 0x33, 0xE4, 0x83, 0x87,
|
||||
0xB1, 0xFD, 0x43, 0x9D, 0x95, 0x7D, 0x02, 0x21, 0x00, 0xD0, 0x05, 0x0E,
|
||||
0x05, 0xA6, 0x80, 0x3C, 0x1A, 0xFE, 0x51, 0xFC, 0x4D, 0x1A, 0x25, 0x05,
|
||||
0x78, 0xB5, 0x42, 0xF5, 0xDE, 0x4E, 0x8A, 0xF8, 0xE3, 0xD8, 0x52, 0xDC,
|
||||
0x2B, 0x73, 0x80, 0x4A};
|
||||
|
||||
class SMimeTest : public ::testing::Test {};
|
||||
|
||||
TEST_F(SMimeTest, InvalidDER) {
|
||||
PK11SymKey* bulk_key = nullptr;
|
||||
NSSCMSDecoderContext* dcx =
|
||||
NSS_CMSDecoder_Start(nullptr, nullptr, nullptr, /* content callback */
|
||||
nullptr, nullptr, /* password callback */
|
||||
nullptr, /* key callback */
|
||||
bulk_key);
|
||||
ASSERT_NE(nullptr, dcx);
|
||||
EXPECT_EQ(SECSuccess, NSS_CMSDecoder_Update(
|
||||
dcx, reinterpret_cast<const char*>(kHugeLenAsn1),
|
||||
sizeof(kHugeLenAsn1)));
|
||||
EXPECT_EQ(nullptr, bulk_key);
|
||||
ASSERT_FALSE(NSS_CMSDecoder_Finish(dcx));
|
||||
}
|
||||
|
||||
TEST_F(SMimeTest, IsSignedValid) {
|
||||
SECItem sig_der_item = {siBuffer, kValidSignature, sizeof(kValidSignature)};
|
||||
|
||||
ScopedNSSCMSMessage cms_msg(NSS_CMSMessage_CreateFromDER(
|
||||
&sig_der_item, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
|
||||
|
||||
ASSERT_TRUE(cms_msg);
|
||||
|
||||
ASSERT_TRUE(NSS_CMSMessage_IsSigned(cms_msg.get()));
|
||||
}
|
||||
|
||||
TEST_F(SMimeTest, TruncatedCmsSignature) {
|
||||
SECItem sig_der_item = {siBuffer, kTruncatedSignature,
|
||||
sizeof(kTruncatedSignature)};
|
||||
|
||||
ScopedNSSCMSMessage cms_msg(NSS_CMSMessage_CreateFromDER(
|
||||
&sig_der_item, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
|
||||
|
||||
ASSERT_TRUE(cms_msg);
|
||||
|
||||
ASSERT_FALSE(NSS_CMSMessage_IsSigned(cms_msg.get()));
|
||||
}
|
||||
|
||||
TEST_F(SMimeTest, SlightlyTruncatedCmsSignature) {
|
||||
SECItem sig_der_item = {siBuffer, kSlightlyTruncatedSignature,
|
||||
sizeof(kSlightlyTruncatedSignature)};
|
||||
|
||||
ScopedNSSCMSMessage cms_msg(NSS_CMSMessage_CreateFromDER(
|
||||
&sig_der_item, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
|
||||
|
||||
ASSERT_FALSE(cms_msg);
|
||||
|
||||
ASSERT_FALSE(NSS_CMSMessage_IsSigned(cms_msg.get()));
|
||||
}
|
||||
|
||||
TEST_F(SMimeTest, IsSignedNull) {
|
||||
ASSERT_FALSE(NSS_CMSMessage_IsSigned(nullptr));
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -6,12 +6,22 @@ CORE_DEPTH = ../..
|
|||
DEPTH = ../..
|
||||
MODULE = nss
|
||||
|
||||
DEFINES += -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" -DDLL_PREFIX=\"$(DLL_PREFIX)\"
|
||||
|
||||
include $(CORE_DEPTH)/coreconf/arch.mk
|
||||
ifneq ($(OS_ARCH),WINNT)
|
||||
DB_TESTS = \
|
||||
softoken_nssckbi_testlib_gtest.cc
|
||||
endif
|
||||
|
||||
CPPSRCS = \
|
||||
softoken_gtest.cc \
|
||||
$(DB_TESTS) \
|
||||
$(NULL)
|
||||
|
||||
INCLUDES += \
|
||||
-I$(CORE_DEPTH)/gtests/google_test/gtest/include \
|
||||
-I$(CORE_DEPTH)/gtests/common \
|
||||
-I$(CORE_DEPTH)/cpputil \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,104 +1,20 @@
|
|||
#include <cstdlib>
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <codecvt>
|
||||
#endif
|
||||
|
||||
#include "cert.h"
|
||||
#include "certdb.h"
|
||||
#include "nspr.h"
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "secmod.h"
|
||||
#include "secerr.h"
|
||||
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "util.h"
|
||||
|
||||
#define GTEST_HAS_RTTI 0
|
||||
#include "gtest/gtest.h"
|
||||
#include <fstream>
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// Given a prefix, attempts to create a unique directory that the user can do
|
||||
// work in without impacting other tests. For example, if given the prefix
|
||||
// "scratch", a directory like "scratch05c17b25" will be created in the current
|
||||
// working directory (or the location specified by NSS_GTEST_WORKDIR, if
|
||||
// defined).
|
||||
// Upon destruction, the implementation will attempt to delete the directory.
|
||||
// However, no attempt is made to first remove files in the directory - the
|
||||
// user is responsible for this. If the directory is not empty, deleting it will
|
||||
// fail.
|
||||
// Statistically, it is technically possible to fail to create a unique
|
||||
// directory name, but this is extremely unlikely given the expected workload of
|
||||
// this implementation.
|
||||
class ScopedUniqueDirectory {
|
||||
public:
|
||||
explicit ScopedUniqueDirectory(const std::string &prefix);
|
||||
|
||||
// NB: the directory must be empty upon destruction
|
||||
~ScopedUniqueDirectory() { assert(rmdir(mPath.c_str()) == 0); }
|
||||
|
||||
const std::string &GetPath() { return mPath; }
|
||||
const std::string &GetUTF8Path() { return mUTF8Path; }
|
||||
|
||||
private:
|
||||
static const int RETRY_LIMIT = 5;
|
||||
static void GenerateRandomName(/*in/out*/ std::string &prefix);
|
||||
static bool TryMakingDirectory(/*in/out*/ std::string &prefix);
|
||||
|
||||
std::string mPath;
|
||||
std::string mUTF8Path;
|
||||
};
|
||||
|
||||
ScopedUniqueDirectory::ScopedUniqueDirectory(const std::string &prefix) {
|
||||
std::string path;
|
||||
const char *workingDirectory = PR_GetEnvSecure("NSS_GTEST_WORKDIR");
|
||||
if (workingDirectory) {
|
||||
path.assign(workingDirectory);
|
||||
}
|
||||
path.append(prefix);
|
||||
for (int i = 0; i < RETRY_LIMIT; i++) {
|
||||
std::string pathCopy(path);
|
||||
// TryMakingDirectory will modify its input. If it fails, we want to throw
|
||||
// away the modified result.
|
||||
if (TryMakingDirectory(pathCopy)) {
|
||||
mPath.assign(pathCopy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(mPath.length() > 0);
|
||||
#if defined(_WIN32)
|
||||
// sqldb always uses UTF-8 regardless of the current system locale.
|
||||
DWORD len =
|
||||
MultiByteToWideChar(CP_ACP, 0, mPath.data(), mPath.size(), nullptr, 0);
|
||||
std::vector<wchar_t> buf(len, L'\0');
|
||||
MultiByteToWideChar(CP_ACP, 0, mPath.data(), mPath.size(), buf.data(),
|
||||
buf.size());
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
mUTF8Path = converter.to_bytes(std::wstring(buf.begin(), buf.end()));
|
||||
#else
|
||||
mUTF8Path = mPath;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ScopedUniqueDirectory::GenerateRandomName(std::string &prefix) {
|
||||
std::stringstream ss;
|
||||
ss << prefix;
|
||||
// RAND_MAX is at least 32767.
|
||||
ss << std::setfill('0') << std::setw(4) << std::hex << rand() << rand();
|
||||
// This will overwrite the value of prefix. This is a little inefficient, but
|
||||
// at least it makes the code simple.
|
||||
ss >> prefix;
|
||||
}
|
||||
|
||||
bool ScopedUniqueDirectory::TryMakingDirectory(std::string &prefix) {
|
||||
GenerateRandomName(prefix);
|
||||
#if defined(_WIN32)
|
||||
return _mkdir(prefix.c_str()) == 0;
|
||||
#else
|
||||
return mkdir(prefix.c_str(), 0777) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
class SoftokenTest : public ::testing::Test {
|
||||
protected:
|
||||
SoftokenTest() : mNSSDBDir("SoftokenTest.d-") {}
|
||||
|
|
@ -205,6 +121,27 @@ TEST_F(SoftokenTest, CreateObjectChangePassword) {
|
|||
EXPECT_EQ(nullptr, obj);
|
||||
}
|
||||
|
||||
// The size limit for a password is 500 characters as defined in pkcs11i.h
|
||||
TEST_F(SoftokenTest, CreateObjectChangeToBigPassword) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
ASSERT_TRUE(slot);
|
||||
EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
|
||||
EXPECT_EQ(
|
||||
SECSuccess,
|
||||
PK11_ChangePW(slot.get(), "",
|
||||
"rUIFIFr2bxKnbJbitsfkyqttpk6vCJzlYMNxcxXcaN37gSZKbLk763X7iR"
|
||||
"yeVNWZHQ02lSF69HYjzTyPW3318ZD0DBFMMbALZ8ZPZP73CIo5uIQlaowV"
|
||||
"IbP8eOhRYtGUqoLGlcIFNEYogV8Q3GN58VeBMs0KxrIOvPQ9s8SnYYkqvt"
|
||||
"zzgntmAvCgvk64x6eQf0okHwegd5wi6m0WVJytEepWXkP9J629FSa5kNT8"
|
||||
"FvL3jvslkiImzTNuTvl32fQDXXMSc8vVk5Q3mH7trMZM0VDdwHWYERjHbz"
|
||||
"kGxFgp0VhediHx7p9kkz6H6ac4et9sW4UkTnN7xhYc1Zr17wRSk2heQtcX"
|
||||
"oZJGwuzhiKm8A8wkuVxms6zO56P4JORIk8oaUW6lyNTLo2kWWnTA"));
|
||||
EXPECT_EQ(SECSuccess, PK11_Logout(slot.get()));
|
||||
ScopedPK11GenericObject obj(PK11_CreateGenericObject(
|
||||
slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
|
||||
EXPECT_EQ(nullptr, obj);
|
||||
}
|
||||
|
||||
TEST_F(SoftokenTest, CreateObjectChangeToEmptyPassword) {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
ASSERT_TRUE(slot);
|
||||
|
|
@ -221,6 +158,76 @@ TEST_F(SoftokenTest, CreateObjectChangeToEmptyPassword) {
|
|||
EXPECT_NE(nullptr, obj);
|
||||
}
|
||||
|
||||
// We should be able to read CRLF, LF and CR.
|
||||
// During the Initialization of the NSS Database, is called a function to load
|
||||
// PKCS11 modules defined in pkcs11.txt. This file is read to get the
|
||||
// specifications, parse them and load the modules. Here we are ensuring that
|
||||
// the parsing will work correctly, independent of the breaking line format of
|
||||
// pkcs11.txt file, which could vary depending where it was created.
|
||||
// If the parsing is not well interpreted, the database cannot initialize.
|
||||
TEST_F(SoftokenTest, CreateObjectReadBreakLine) {
|
||||
const std::string path = mNSSDBDir.GetPath();
|
||||
const std::string dbname_in = path + "/pkcs11.txt";
|
||||
const std::string dbname_out_cr = path + "/pkcs11_cr.txt";
|
||||
const std::string dbname_out_crlf = path + "/pkcs11_crlf.txt";
|
||||
const std::string dbname_out_lf = path + "/pkcs11_lf.txt";
|
||||
|
||||
std::ifstream in(dbname_in);
|
||||
ASSERT_TRUE(in);
|
||||
std::ofstream out_cr(dbname_out_cr);
|
||||
ASSERT_TRUE(out_cr);
|
||||
std::ofstream out_crlf(dbname_out_crlf);
|
||||
ASSERT_TRUE(out_crlf);
|
||||
std::ofstream out_lf(dbname_out_lf);
|
||||
ASSERT_TRUE(out_lf);
|
||||
|
||||
// Database should be correctly initialized by Setup()
|
||||
ASSERT_TRUE(NSS_IsInitialized());
|
||||
ASSERT_EQ(SECSuccess, NSS_Shutdown());
|
||||
|
||||
// Prepare the file formats with CR, CRLF and LF
|
||||
for (std::string line; getline(in, line);) {
|
||||
out_cr << line << "\r";
|
||||
out_crlf << line << "\r\n";
|
||||
out_lf << line << "\n";
|
||||
}
|
||||
in.close();
|
||||
out_cr.close();
|
||||
out_crlf.close();
|
||||
out_lf.close();
|
||||
|
||||
// Change the pkcs11.txt to CR format.
|
||||
ASSERT_TRUE(!remove(dbname_in.c_str()));
|
||||
ASSERT_TRUE(!rename(dbname_out_cr.c_str(), dbname_in.c_str()));
|
||||
|
||||
// Try to initialize with CR format.
|
||||
std::string nssInitArg("sql:");
|
||||
nssInitArg.append(mNSSDBDir.GetUTF8Path());
|
||||
ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
|
||||
NSS_INIT_NOROOTINIT));
|
||||
ASSERT_TRUE(NSS_IsInitialized());
|
||||
ASSERT_EQ(SECSuccess, NSS_Shutdown());
|
||||
|
||||
// Change the pkcs11.txt to CRLF format.
|
||||
ASSERT_TRUE(!remove(dbname_in.c_str()));
|
||||
ASSERT_TRUE(!rename(dbname_out_crlf.c_str(), dbname_in.c_str()));
|
||||
|
||||
// Try to initialize with CRLF format.
|
||||
ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
|
||||
NSS_INIT_NOROOTINIT));
|
||||
ASSERT_TRUE(NSS_IsInitialized());
|
||||
ASSERT_EQ(SECSuccess, NSS_Shutdown());
|
||||
|
||||
// Change the pkcs11.txt to LF format.
|
||||
ASSERT_TRUE(!remove(dbname_in.c_str()));
|
||||
ASSERT_TRUE(!rename(dbname_out_lf.c_str(), dbname_in.c_str()));
|
||||
|
||||
// Try to initialize with LF format.
|
||||
ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
|
||||
NSS_INIT_NOROOTINIT));
|
||||
ASSERT_TRUE(NSS_IsInitialized());
|
||||
}
|
||||
|
||||
class SoftokenNonAsciiTest : public SoftokenTest {
|
||||
protected:
|
||||
SoftokenNonAsciiTest() : SoftokenTest("SoftokenTest.\xF7-") {}
|
||||
|
|
@ -351,6 +358,100 @@ TEST_F(SoftokenNoDBTest, NeedUserInitNoDB) {
|
|||
ASSERT_EQ(SECSuccess, NSS_Shutdown());
|
||||
}
|
||||
|
||||
#ifndef NSS_FIPS_DISABLED
|
||||
|
||||
class SoftokenFipsTest : public SoftokenTest {
|
||||
protected:
|
||||
SoftokenFipsTest() : SoftokenTest("SoftokenFipsTest.d-") {}
|
||||
|
||||
virtual void SetUp() {
|
||||
SoftokenTest::SetUp();
|
||||
|
||||
// Turn on FIPS mode (code borrowed from FipsMode in modutil/pk11.c)
|
||||
char *internal_name;
|
||||
ASSERT_FALSE(PK11_IsFIPS());
|
||||
internal_name = PR_smprintf("%s", SECMOD_GetInternalModule()->commonName);
|
||||
ASSERT_EQ(SECSuccess, SECMOD_DeleteInternalModule(internal_name));
|
||||
PR_smprintf_free(internal_name);
|
||||
ASSERT_TRUE(PK11_IsFIPS());
|
||||
}
|
||||
};
|
||||
|
||||
const std::vector<std::string> kFipsPasswordCases[] = {
|
||||
// FIPS level1 -> level1 -> level1
|
||||
{"", "", ""},
|
||||
// FIPS level1 -> level1 -> level2
|
||||
{"", "", "strong-_123"},
|
||||
// FIXME: this should work: FIPS level1 -> level2 -> level2
|
||||
// {"", "strong-_123", "strong-_456"},
|
||||
// FIPS level2 -> level2 -> level2
|
||||
{"strong-_123", "strong-_456", "strong-_123"}};
|
||||
|
||||
const std::vector<std::string> kFipsPasswordBadCases[] = {
|
||||
// FIPS level1 -> level2 -> level1
|
||||
{"", "strong-_123", ""},
|
||||
// FIPS level2 -> level1 -> level1
|
||||
{"strong-_123", ""},
|
||||
// FIPS level2 -> level2 -> level1
|
||||
{"strong-_123", "strong-_456", ""},
|
||||
// initialize with a weak password
|
||||
{"weak"},
|
||||
// FIPS level1 -> weak password
|
||||
{"", "weak"},
|
||||
// FIPS level2 -> weak password
|
||||
{"strong-_123", "weak"}};
|
||||
|
||||
class SoftokenFipsPasswordTest
|
||||
: public SoftokenFipsTest,
|
||||
public ::testing::WithParamInterface<std::vector<std::string>> {};
|
||||
|
||||
class SoftokenFipsBadPasswordTest
|
||||
: public SoftokenFipsTest,
|
||||
public ::testing::WithParamInterface<std::vector<std::string>> {};
|
||||
|
||||
TEST_P(SoftokenFipsPasswordTest, SetPassword) {
|
||||
const std::vector<std::string> &passwords = GetParam();
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
ASSERT_TRUE(slot);
|
||||
|
||||
auto it = passwords.begin();
|
||||
auto prev_it = it;
|
||||
EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, (*it).c_str()));
|
||||
for (it++; it != passwords.end(); it++, prev_it++) {
|
||||
EXPECT_EQ(SECSuccess,
|
||||
PK11_ChangePW(slot.get(), (*prev_it).c_str(), (*it).c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(SoftokenFipsBadPasswordTest, SetBadPassword) {
|
||||
const std::vector<std::string> &passwords = GetParam();
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
ASSERT_TRUE(slot);
|
||||
|
||||
auto it = passwords.begin();
|
||||
auto prev_it = it;
|
||||
SECStatus rv = PK11_InitPin(slot.get(), nullptr, (*it).c_str());
|
||||
if (it + 1 == passwords.end())
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
else
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
for (it++; it != passwords.end(); it++, prev_it++) {
|
||||
rv = PK11_ChangePW(slot.get(), (*prev_it).c_str(), (*it).c_str());
|
||||
if (it + 1 == passwords.end())
|
||||
EXPECT_EQ(SECFailure, rv);
|
||||
else
|
||||
EXPECT_EQ(SECSuccess, rv);
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(FipsPasswordCases, SoftokenFipsPasswordTest,
|
||||
::testing::ValuesIn(kFipsPasswordCases));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(BadFipsPasswordCases, SoftokenFipsBadPasswordTest,
|
||||
::testing::ValuesIn(kFipsPasswordBadCases));
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace nss_test
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
'type': 'executable',
|
||||
'sources': [
|
||||
'softoken_gtest.cc',
|
||||
'softoken_nssckbi_testlib_gtest.cc',
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
|
|
@ -19,7 +20,7 @@
|
|||
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
|
||||
],
|
||||
'conditions': [
|
||||
[ 'test_build==1', {
|
||||
[ 'static_libs==1', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/lib/nss/nss.gyp:nss_static',
|
||||
'<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
|
||||
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
|
||||
'<(DEPTH)/lib/ssl/ssl.gyp:ssl',
|
||||
'<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix',
|
||||
],
|
||||
}, {
|
||||
'dependencies': [
|
||||
|
|
@ -43,6 +45,10 @@
|
|||
'target_defaults': {
|
||||
'include_dirs': [
|
||||
'../../lib/util'
|
||||
],
|
||||
'defines': [
|
||||
'DLL_PREFIX=\"<(dll_prefix)\"',
|
||||
'DLL_SUFFIX=\"<(dll_suffix)\"'
|
||||
]
|
||||
},
|
||||
'variables': {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
#include "cert.h"
|
||||
#include "certdb.h"
|
||||
#include "nspr.h"
|
||||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "secerr.h"
|
||||
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "util.h"
|
||||
|
||||
#define GTEST_HAS_RTTI 0
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class SoftokenBuiltinsTest : public ::testing::Test {
|
||||
protected:
|
||||
SoftokenBuiltinsTest() : nss_db_dir_("SoftokenBuiltinsTest.d-") {}
|
||||
SoftokenBuiltinsTest(const std::string &prefix) : nss_db_dir_(prefix) {}
|
||||
|
||||
virtual void SetUp() {
|
||||
std::string nss_init_arg("sql:");
|
||||
nss_init_arg.append(nss_db_dir_.GetUTF8Path());
|
||||
ASSERT_EQ(SECSuccess, NSS_Initialize(nss_init_arg.c_str(), "", "",
|
||||
SECMOD_DB, NSS_INIT_NOROOTINIT));
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
ASSERT_EQ(SECSuccess, NSS_Shutdown());
|
||||
const std::string &nss_db_dir_path = nss_db_dir_.GetPath();
|
||||
ASSERT_EQ(0, unlink((nss_db_dir_path + "/cert9.db").c_str()));
|
||||
ASSERT_EQ(0, unlink((nss_db_dir_path + "/key4.db").c_str()));
|
||||
ASSERT_EQ(0, unlink((nss_db_dir_path + "/pkcs11.txt").c_str()));
|
||||
}
|
||||
|
||||
virtual void LoadModule() {
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
|
||||
ASSERT_TRUE(slot);
|
||||
EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
|
||||
SECStatus result = SECMOD_AddNewModule(
|
||||
"Builtins-testlib", DLL_PREFIX "nssckbi-testlib." DLL_SUFFIX, 0, 0);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
}
|
||||
|
||||
ScopedUniqueDirectory nss_db_dir_;
|
||||
};
|
||||
|
||||
// The next tests in this class are used to test the Distrust Fields.
|
||||
// More details about these fields in lib/ckfw/builtins/README.
|
||||
TEST_F(SoftokenBuiltinsTest, CheckNoDistrustFields) {
|
||||
const char *kCertNickname =
|
||||
"Builtin Object Token:Distrust Fields Test - no_distrust";
|
||||
LoadModule();
|
||||
|
||||
CERTCertDBHandle *cert_handle = CERT_GetDefaultCertDB();
|
||||
ASSERT_TRUE(cert_handle);
|
||||
ScopedCERTCertificate cert(
|
||||
CERT_FindCertByNickname(cert_handle, kCertNickname));
|
||||
ASSERT_TRUE(cert);
|
||||
|
||||
EXPECT_EQ(PR_FALSE,
|
||||
PK11_HasAttributeSet(cert->slot, cert->pkcs11ID,
|
||||
CKA_NSS_SERVER_DISTRUST_AFTER, PR_FALSE));
|
||||
EXPECT_EQ(PR_FALSE,
|
||||
PK11_HasAttributeSet(cert->slot, cert->pkcs11ID,
|
||||
CKA_NSS_EMAIL_DISTRUST_AFTER, PR_FALSE));
|
||||
ASSERT_FALSE(cert->distrust);
|
||||
}
|
||||
|
||||
TEST_F(SoftokenBuiltinsTest, CheckOkDistrustFields) {
|
||||
const char *kCertNickname =
|
||||
"Builtin Object Token:Distrust Fields Test - ok_distrust";
|
||||
LoadModule();
|
||||
|
||||
CERTCertDBHandle *cert_handle = CERT_GetDefaultCertDB();
|
||||
ASSERT_TRUE(cert_handle);
|
||||
ScopedCERTCertificate cert(
|
||||
CERT_FindCertByNickname(cert_handle, kCertNickname));
|
||||
ASSERT_TRUE(cert);
|
||||
|
||||
const char *kExpectedDERValueServer = "200617000000Z";
|
||||
const char *kExpectedDERValueEmail = "071014085320Z";
|
||||
// When a valid timestamp is encoded, the result length is exactly 13.
|
||||
const unsigned int kDistrustFieldSize = 13;
|
||||
|
||||
ASSERT_TRUE(cert->distrust);
|
||||
ASSERT_EQ(kDistrustFieldSize, cert->distrust->serverDistrustAfter.len);
|
||||
ASSERT_NE(nullptr, cert->distrust->serverDistrustAfter.data);
|
||||
EXPECT_TRUE(!memcmp(kExpectedDERValueServer,
|
||||
cert->distrust->serverDistrustAfter.data,
|
||||
kDistrustFieldSize));
|
||||
|
||||
ASSERT_EQ(kDistrustFieldSize, cert->distrust->emailDistrustAfter.len);
|
||||
ASSERT_NE(nullptr, cert->distrust->emailDistrustAfter.data);
|
||||
EXPECT_TRUE(!memcmp(kExpectedDERValueEmail,
|
||||
cert->distrust->emailDistrustAfter.data,
|
||||
kDistrustFieldSize));
|
||||
}
|
||||
|
||||
TEST_F(SoftokenBuiltinsTest, CheckInvalidDistrustFields) {
|
||||
const char *kCertNickname =
|
||||
"Builtin Object Token:Distrust Fields Test - err_distrust";
|
||||
LoadModule();
|
||||
|
||||
CERTCertDBHandle *cert_handle = CERT_GetDefaultCertDB();
|
||||
ASSERT_TRUE(cert_handle);
|
||||
ScopedCERTCertificate cert(
|
||||
CERT_FindCertByNickname(cert_handle, kCertNickname));
|
||||
ASSERT_TRUE(cert);
|
||||
|
||||
// The field should never be set to TRUE in production, we are just
|
||||
// testing if this field is readable, even if set to TRUE.
|
||||
EXPECT_EQ(PR_TRUE,
|
||||
PK11_HasAttributeSet(cert->slot, cert->pkcs11ID,
|
||||
CKA_NSS_SERVER_DISTRUST_AFTER, PR_FALSE));
|
||||
// If something other than CK_BBOOL CK_TRUE, it will be considered FALSE
|
||||
// Here, there is an OCTAL value, but with unexpected content (1 digit less).
|
||||
EXPECT_EQ(PR_FALSE,
|
||||
PK11_HasAttributeSet(cert->slot, cert->pkcs11ID,
|
||||
CKA_NSS_EMAIL_DISTRUST_AFTER, PR_FALSE));
|
||||
ASSERT_FALSE(cert->distrust);
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -36,6 +36,12 @@ CPPSRCS := $(filter-out $(shell grep -l '^TEST_F' $(CPPSRCS)), $(CPPSRCS))
|
|||
CFLAGS += -DNSS_DISABLE_TLS_1_3
|
||||
endif
|
||||
|
||||
ifdef NSS_ALLOW_SSLKEYLOGFILE
|
||||
SSLKEYLOGFILE_FILES = ssl_keylog_unittest.cc
|
||||
else
|
||||
SSLKEYLOGFILE_FILES = $(NULL)
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
#######################################################################
|
||||
|
|
|
|||
|
|
@ -12,6 +12,48 @@
|
|||
#include "seccomon.h"
|
||||
#include "selfencrypt.h"
|
||||
|
||||
SECStatus SSLInt_TweakChannelInfoForDC(PRFileDesc *fd, PRBool changeAuthKeyBits,
|
||||
PRBool changeScheme) {
|
||||
if (!fd) {
|
||||
return SECFailure;
|
||||
}
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// Just toggle so we'll always have a valid value.
|
||||
if (changeScheme) {
|
||||
ss->sec.signatureScheme = (ss->sec.signatureScheme == ssl_sig_ed25519)
|
||||
? ssl_sig_ecdsa_secp256r1_sha256
|
||||
: ssl_sig_ed25519;
|
||||
}
|
||||
if (changeAuthKeyBits) {
|
||||
ss->sec.authKeyBits = ss->sec.authKeyBits ? ss->sec.authKeyBits * 2 : 384;
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus SSLInt_GetHandshakeRandoms(PRFileDesc *fd, SSL3Random client_random,
|
||||
SSL3Random server_random) {
|
||||
if (!fd) {
|
||||
return SECFailure;
|
||||
}
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (client_random) {
|
||||
memcpy(client_random, ss->ssl3.hs.client_random, sizeof(SSL3Random));
|
||||
}
|
||||
if (server_random) {
|
||||
memcpy(server_random, ss->ssl3.hs.server_random, sizeof(SSL3Random));
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd) {
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
|
|
@ -109,9 +151,10 @@ void SSLInt_PrintCipherSpecs(const char *label, PRFileDesc *fd) {
|
|||
}
|
||||
}
|
||||
|
||||
/* Force a timer expiry by backdating when all active timers were started. We
|
||||
* could set the remaining time to 0 but then backoff would not work properly if
|
||||
* we decide to test it. */
|
||||
/* DTLS timers are separate from the time that the rest of the stack uses.
|
||||
* Force a timer expiry by backdating when all active timers were started.
|
||||
* We could set the remaining time to 0 but then backoff would not work properly
|
||||
* if we decide to test it. */
|
||||
SECStatus SSLInt_ShiftDtlsTimers(PRFileDesc *fd, PRIntervalTime shift) {
|
||||
size_t i;
|
||||
sslSocket *ss = ssl_FindSocket(fd);
|
||||
|
|
@ -297,42 +340,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;
|
||||
}
|
||||
|
||||
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size) {
|
||||
sslSocket *ss;
|
||||
|
||||
|
|
@ -356,20 +363,14 @@ SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size) {
|
|||
return SECSuccess;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ SECStatus SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd);
|
|||
SECStatus SSLInt_UpdateSSLv2ClientRandom(PRFileDesc *fd, uint8_t *rnd,
|
||||
size_t rnd_len, uint8_t *msg,
|
||||
size_t msg_len);
|
||||
|
||||
SECStatus SSLInt_GetHandshakeRandoms(PRFileDesc *fd, SSL3Random client_random,
|
||||
SSL3Random server_random);
|
||||
PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext);
|
||||
void SSLInt_ClearSelfEncryptKey();
|
||||
void SSLInt_SetSelfEncryptMacKey(PK11SymKey *key);
|
||||
|
|
@ -39,18 +40,9 @@ 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);
|
||||
void SSLInt_SetTicketLifetime(uint32_t lifetime);
|
||||
SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending);
|
||||
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size);
|
||||
void SSLInt_RolloverAntiReplay(void);
|
||||
SECStatus SSLInt_TweakChannelInfoForDC(PRFileDesc *fd, PRBool changeAuthKeyBits,
|
||||
PRBool changeScheme);
|
||||
|
||||
#endif // ndef libssl_internals_h_
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@ CPPSRCS = \
|
|||
ssl_agent_unittest.cc \
|
||||
ssl_auth_unittest.cc \
|
||||
ssl_cert_ext_unittest.cc \
|
||||
ssl_cipherorder_unittest.cc \
|
||||
ssl_ciphersuite_unittest.cc \
|
||||
ssl_custext_unittest.cc \
|
||||
ssl_damage_unittest.cc \
|
||||
ssl_debug_env_unittest.cc \
|
||||
ssl_dhe_unittest.cc \
|
||||
ssl_drop_unittest.cc \
|
||||
ssl_ecdh_unittest.cc \
|
||||
|
|
@ -31,11 +33,12 @@ CPPSRCS = \
|
|||
ssl_gather_unittest.cc \
|
||||
ssl_gtest.cc \
|
||||
ssl_hrr_unittest.cc \
|
||||
ssl_keylog_unittest.cc \
|
||||
ssl_keyupdate_unittest.cc \
|
||||
ssl_loopback_unittest.cc \
|
||||
ssl_misc_unittest.cc \
|
||||
ssl_primitive_unittest.cc \
|
||||
ssl_record_unittest.cc \
|
||||
ssl_recordsep_unittest.cc \
|
||||
ssl_recordsize_unittest.cc \
|
||||
ssl_resumption_unittest.cc \
|
||||
ssl_renegotiation_unittest.cc \
|
||||
|
|
@ -52,7 +55,9 @@ CPPSRCS = \
|
|||
tls_hkdf_unittest.cc \
|
||||
tls_filter.cc \
|
||||
tls_protect.cc \
|
||||
tls_subcerts_unittest.cc \
|
||||
tls_esni_unittest.cc \
|
||||
$(SSLKEYLOGFILE_FILES) \
|
||||
$(NULL)
|
||||
|
||||
INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
|
||||
|
|
|
|||
|
|
@ -45,11 +45,40 @@ TEST_P(TlsConnectTls13, ZeroRttServerRejectByOption) {
|
|||
SendReceive();
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ZeroRttApplicationReject) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
|
||||
auto reject_0rtt = [](PRBool firstHello, const PRUint8* clientToken,
|
||||
unsigned int clientTokenLen, PRUint8* appToken,
|
||||
unsigned int* appTokenLen, unsigned int appTokenMax,
|
||||
void* arg) {
|
||||
auto* called = reinterpret_cast<bool*>(arg);
|
||||
*called = true;
|
||||
|
||||
EXPECT_TRUE(firstHello);
|
||||
EXPECT_EQ(0U, clientTokenLen);
|
||||
return ssl_hello_retry_reject_0rtt;
|
||||
};
|
||||
|
||||
bool cb_run = false;
|
||||
EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(server_->ssl_fd(),
|
||||
reject_0rtt, &cb_run));
|
||||
ZeroRttSendReceive(true, false);
|
||||
Handshake();
|
||||
EXPECT_TRUE(cb_run);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ZeroRttApparentReplayAfterRestart) {
|
||||
// The test fixtures call SSL_SetupAntiReplay() in SetUp(). This results in
|
||||
// 0-RTT being rejected until at least one window passes. SetupFor0Rtt()
|
||||
// forces a rollover of the anti-replay filters, which clears this state.
|
||||
// Here, we do the setup manually here without that forced rollover.
|
||||
// The test fixtures enable anti-replay in SetUp(). This results in 0-RTT
|
||||
// being rejected until at least one window passes. SetupFor0Rtt() forces a
|
||||
// rollover of the anti-replay filters, which clears that state and allows
|
||||
// 0-RTT to work. Make the first connection manually to avoid that rollover
|
||||
// and cause 0-RTT to be rejected.
|
||||
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
|
|
@ -106,7 +135,7 @@ class TlsZeroRttReplayTest : public TlsConnectTls13 {
|
|||
SendReceive();
|
||||
|
||||
if (rollover) {
|
||||
SSLInt_RolloverAntiReplay();
|
||||
RolloverAntiReplay();
|
||||
}
|
||||
|
||||
// Now replay that packet against the server.
|
||||
|
|
@ -184,20 +213,21 @@ TEST_P(TlsConnectTls13, ZeroRttServerOnly) {
|
|||
CheckKeys();
|
||||
}
|
||||
|
||||
// A small sleep after sending the ClientHello means that the ticket age that
|
||||
// arrives at the server is too low. With a small tolerance for variation in
|
||||
// ticket age (which is determined by the |window| parameter that is passed to
|
||||
// SSL_SetupAntiReplay()), the server then rejects early data.
|
||||
// Advancing time after sending the ClientHello means that the ticket age that
|
||||
// arrives at the server is too low. The server then rejects early data if this
|
||||
// delay exceeds half the anti-replay window.
|
||||
TEST_P(TlsConnectTls13, ZeroRttRejectOldTicket) {
|
||||
static const PRTime kWindow = 10 * PR_USEC_PER_SEC;
|
||||
ResetAntiReplay(kWindow);
|
||||
SetupForZeroRtt();
|
||||
|
||||
Reset();
|
||||
StartConnect();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
EXPECT_EQ(SECSuccess, SSL_SetupAntiReplay(1, 1, 3));
|
||||
SSLInt_RolloverAntiReplay(); // Make sure to flush replay state.
|
||||
SSLInt_RolloverAntiReplay();
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, false, []() {
|
||||
PR_Sleep(PR_MillisecondsToInterval(10));
|
||||
ZeroRttSendReceive(true, false, [this]() {
|
||||
AdvanceTime(1 + kWindow / 2);
|
||||
return true;
|
||||
});
|
||||
Handshake();
|
||||
|
|
@ -212,13 +242,15 @@ TEST_P(TlsConnectTls13, ZeroRttRejectOldTicket) {
|
|||
// small tolerance for variation in ticket age and the ticket will appear to
|
||||
// arrive prematurely, causing the server to reject early data.
|
||||
TEST_P(TlsConnectTls13, ZeroRttRejectPrematureTicket) {
|
||||
static const PRTime kWindow = 10 * PR_USEC_PER_SEC;
|
||||
ResetAntiReplay(kWindow);
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
server_->Set0RttEnabled(true);
|
||||
StartConnect();
|
||||
client_->Handshake(); // ClientHello
|
||||
server_->Handshake(); // ServerHello
|
||||
PR_Sleep(PR_MillisecondsToInterval(10));
|
||||
AdvanceTime(1 + kWindow / 2);
|
||||
Handshake(); // Remainder of handshake
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
|
|
@ -227,9 +259,6 @@ TEST_P(TlsConnectTls13, ZeroRttRejectPrematureTicket) {
|
|||
Reset();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
EXPECT_EQ(SECSuccess, SSL_SetupAntiReplay(1, 1, 3));
|
||||
SSLInt_RolloverAntiReplay(); // Make sure to flush replay state.
|
||||
SSLInt_RolloverAntiReplay();
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ExpectEarlyDataAccepted(false);
|
||||
StartConnect();
|
||||
|
|
@ -649,6 +678,351 @@ TEST_P(TlsConnectTls13, ZeroRttOrdering) {
|
|||
EXPECT_EQ(2U, step);
|
||||
}
|
||||
|
||||
// Early data remains available after the handshake completes for TLS.
|
||||
TEST_F(TlsConnectStreamTls13, ZeroRttLateReadTls) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
client_->Handshake(); // ClientHello
|
||||
|
||||
// Write some early data.
|
||||
const uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
PRInt32 rv = PR_Write(client_->ssl_fd(), data, sizeof(data));
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), rv);
|
||||
|
||||
// Consume the ClientHello and generate ServerHello..Finished.
|
||||
server_->Handshake();
|
||||
|
||||
// Read some of the data.
|
||||
std::vector<uint8_t> small_buffer(1 + sizeof(data) / 2);
|
||||
rv = PR_Read(server_->ssl_fd(), small_buffer.data(), small_buffer.size());
|
||||
EXPECT_EQ(static_cast<PRInt32>(small_buffer.size()), rv);
|
||||
EXPECT_EQ(0, memcmp(data, small_buffer.data(), small_buffer.size()));
|
||||
|
||||
Handshake(); // Complete the handshake.
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
|
||||
// After the handshake, it should be possible to read the remainder.
|
||||
uint8_t big_buf[100];
|
||||
rv = PR_Read(server_->ssl_fd(), big_buf, sizeof(big_buf));
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - small_buffer.size()), rv);
|
||||
EXPECT_EQ(0, memcmp(&data[small_buffer.size()], big_buf,
|
||||
sizeof(data) - small_buffer.size()));
|
||||
|
||||
// And that's all there is to read.
|
||||
rv = PR_Read(server_->ssl_fd(), big_buf, sizeof(big_buf));
|
||||
EXPECT_GT(0, rv);
|
||||
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
|
||||
}
|
||||
|
||||
// Early data that arrives before the handshake can be read after the handshake
|
||||
// is complete.
|
||||
TEST_F(TlsConnectDatagram13, ZeroRttLateReadDtls) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
client_->Handshake(); // ClientHello
|
||||
|
||||
// Write some early data.
|
||||
const uint8_t data[] = {1, 2, 3};
|
||||
PRInt32 written = PR_Write(client_->ssl_fd(), data, sizeof(data));
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written);
|
||||
|
||||
Handshake(); // Complete the handshake.
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
|
||||
// Reading at the server should return the early data, which was buffered.
|
||||
uint8_t buf[sizeof(data) + 1] = {0};
|
||||
PRInt32 read = PR_Read(server_->ssl_fd(), buf, sizeof(buf));
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), read);
|
||||
EXPECT_EQ(0, memcmp(data, buf, sizeof(data)));
|
||||
}
|
||||
|
||||
class PacketHolder : public PacketFilter {
|
||||
public:
|
||||
PacketHolder() = default;
|
||||
|
||||
virtual Action Filter(const DataBuffer& input, DataBuffer* output) {
|
||||
packet_ = input;
|
||||
Disable();
|
||||
return DROP;
|
||||
}
|
||||
|
||||
const DataBuffer& packet() const { return packet_; }
|
||||
|
||||
private:
|
||||
DataBuffer packet_;
|
||||
};
|
||||
|
||||
// Early data that arrives late is discarded for DTLS.
|
||||
TEST_F(TlsConnectDatagram13, ZeroRttLateArrivalDtls) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
client_->Handshake(); // ClientHello
|
||||
|
||||
// Write some early data. Twice, so that we can read bits of it.
|
||||
const uint8_t data[] = {1, 2, 3};
|
||||
PRInt32 written = PR_Write(client_->ssl_fd(), data, sizeof(data));
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written);
|
||||
|
||||
// Block and capture the next packet.
|
||||
auto holder = std::make_shared<PacketHolder>();
|
||||
client_->SetFilter(holder);
|
||||
written = PR_Write(client_->ssl_fd(), data, sizeof(data));
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written);
|
||||
EXPECT_FALSE(holder->enabled()) << "the filter should disable itself";
|
||||
|
||||
// Consume the ClientHello and generate ServerHello..Finished.
|
||||
server_->Handshake();
|
||||
|
||||
// Read some of the data.
|
||||
std::vector<uint8_t> small_buffer(sizeof(data));
|
||||
PRInt32 read =
|
||||
PR_Read(server_->ssl_fd(), small_buffer.data(), small_buffer.size());
|
||||
|
||||
EXPECT_EQ(static_cast<PRInt32>(small_buffer.size()), read);
|
||||
EXPECT_EQ(0, memcmp(data, small_buffer.data(), small_buffer.size()));
|
||||
|
||||
Handshake(); // Complete the handshake.
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
|
||||
server_->SendDirect(holder->packet());
|
||||
|
||||
// Reading now should return nothing, even though a valid packet was
|
||||
// delivered.
|
||||
read = PR_Read(server_->ssl_fd(), small_buffer.data(), small_buffer.size());
|
||||
EXPECT_GT(0, read);
|
||||
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
|
||||
}
|
||||
|
||||
// Early data reads in TLS should be coalesced.
|
||||
TEST_F(TlsConnectStreamTls13, ZeroRttCoalesceReadTls) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
client_->Handshake(); // ClientHello
|
||||
|
||||
// Write some early data. In two writes.
|
||||
const uint8_t data[] = {1, 2, 3, 4, 5, 6};
|
||||
PRInt32 written = PR_Write(client_->ssl_fd(), data, 1);
|
||||
EXPECT_EQ(1, written);
|
||||
|
||||
written = PR_Write(client_->ssl_fd(), data + 1, sizeof(data) - 1);
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - 1), written);
|
||||
|
||||
// Consume the ClientHello and generate ServerHello..Finished.
|
||||
server_->Handshake();
|
||||
|
||||
// Read all of the data.
|
||||
std::vector<uint8_t> buffer(sizeof(data));
|
||||
PRInt32 read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size());
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), read);
|
||||
EXPECT_EQ(0, memcmp(data, buffer.data(), sizeof(data)));
|
||||
|
||||
Handshake(); // Complete the handshake.
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
}
|
||||
|
||||
// Early data reads in DTLS should not be coalesced.
|
||||
TEST_F(TlsConnectDatagram13, ZeroRttNoCoalesceReadDtls) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
client_->Handshake(); // ClientHello
|
||||
|
||||
// Write some early data. In two writes.
|
||||
const uint8_t data[] = {1, 2, 3, 4, 5, 6};
|
||||
PRInt32 written = PR_Write(client_->ssl_fd(), data, 1);
|
||||
EXPECT_EQ(1, written);
|
||||
|
||||
written = PR_Write(client_->ssl_fd(), data + 1, sizeof(data) - 1);
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - 1), written);
|
||||
|
||||
// Consume the ClientHello and generate ServerHello..Finished.
|
||||
server_->Handshake();
|
||||
|
||||
// Try to read all of the data.
|
||||
std::vector<uint8_t> buffer(sizeof(data));
|
||||
PRInt32 read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size());
|
||||
EXPECT_EQ(1, read);
|
||||
EXPECT_EQ(0, memcmp(data, buffer.data(), 1));
|
||||
|
||||
// Read the remainder.
|
||||
read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size());
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data) - 1), read);
|
||||
EXPECT_EQ(0, memcmp(data + 1, buffer.data(), sizeof(data) - 1));
|
||||
|
||||
Handshake(); // Complete the handshake.
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
}
|
||||
|
||||
// Early data reads in DTLS should fail if the buffer is too small.
|
||||
TEST_F(TlsConnectDatagram13, ZeroRttShortReadDtls) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
client_->Handshake(); // ClientHello
|
||||
|
||||
// Write some early data. In two writes.
|
||||
const uint8_t data[] = {1, 2, 3, 4, 5, 6};
|
||||
PRInt32 written = PR_Write(client_->ssl_fd(), data, sizeof(data));
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), written);
|
||||
|
||||
// Consume the ClientHello and generate ServerHello..Finished.
|
||||
server_->Handshake();
|
||||
|
||||
// Try to read all of the data into a small buffer.
|
||||
std::vector<uint8_t> buffer(sizeof(data));
|
||||
PRInt32 read = PR_Read(server_->ssl_fd(), buffer.data(), 1);
|
||||
EXPECT_GT(0, read);
|
||||
EXPECT_EQ(SSL_ERROR_RX_SHORT_DTLS_READ, PORT_GetError());
|
||||
|
||||
// Read again with more space.
|
||||
read = PR_Read(server_->ssl_fd(), buffer.data(), buffer.size());
|
||||
EXPECT_EQ(static_cast<PRInt32>(sizeof(data)), read);
|
||||
EXPECT_EQ(0, memcmp(data, buffer.data(), sizeof(data)));
|
||||
|
||||
Handshake(); // Complete the handshake.
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
}
|
||||
|
||||
// There are few ways in which TLS uses the clock and most of those operate on
|
||||
// timescales that would be ridiculous to wait for in a test. This is the one
|
||||
// test we have that uses the real clock. It tests that time passes by checking
|
||||
// that a small sleep results in rejection of early data. 0-RTT has a
|
||||
// configurable timer, which makes it ideal for this.
|
||||
TEST_F(TlsConnectStreamTls13, TimePassesByDefault) {
|
||||
// Calling EnsureTlsSetup() replaces the time function on client and server,
|
||||
// and sets up anti-replay, which we don't want, so initialize each directly.
|
||||
client_->EnsureTlsSetup();
|
||||
server_->EnsureTlsSetup();
|
||||
// StartConnect() calls EnsureTlsSetup(), so avoid that too.
|
||||
client_->StartConnect();
|
||||
server_->StartConnect();
|
||||
|
||||
// Set a tiny anti-replay window. This has to be at least 2 milliseconds to
|
||||
// have any chance of being relevant as that is the smallest window that we
|
||||
// can detect. Anything smaller rounds to zero.
|
||||
static const unsigned int kTinyWindowMs = 5;
|
||||
ResetAntiReplay(static_cast<PRTime>(kTinyWindowMs * PR_USEC_PER_MSEC));
|
||||
server_->SetAntiReplayContext(anti_replay_);
|
||||
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
server_->Set0RttEnabled(true);
|
||||
Handshake();
|
||||
CheckConnected();
|
||||
SendReceive(); // Absorb a session ticket.
|
||||
CheckKeys();
|
||||
|
||||
// Clear the first window.
|
||||
PR_Sleep(PR_MillisecondsToInterval(kTinyWindowMs));
|
||||
|
||||
Reset();
|
||||
client_->EnsureTlsSetup();
|
||||
server_->EnsureTlsSetup();
|
||||
client_->StartConnect();
|
||||
server_->StartConnect();
|
||||
|
||||
// Early data is rejected by the server only if time passes for it as well.
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, false, []() {
|
||||
// Sleep long enough that we minimize the risk of our RTT estimation being
|
||||
// duped by stutters in test execution. This is very long to allow for
|
||||
// flaky and low-end hardware, especially what our CI runs on.
|
||||
PR_Sleep(PR_MillisecondsToInterval(1000));
|
||||
return true;
|
||||
});
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(false);
|
||||
CheckConnected();
|
||||
}
|
||||
|
||||
// Test that SSL_CreateAntiReplayContext doesn't pass bad inputs.
|
||||
TEST_F(TlsConnectStreamTls13, BadAntiReplayArgs) {
|
||||
SSLAntiReplayContext* p;
|
||||
// Zero or negative window.
|
||||
EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, -1, 1, 1, &p));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 0, 1, 1, &p));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
// Zero k.
|
||||
EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 1, 0, 1, &p));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
// Zero bits.
|
||||
EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 1, 1, 0, &p));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
EXPECT_EQ(SECFailure, SSL_CreateAntiReplayContext(0, 1, 1, 1, nullptr));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
|
||||
// Prove that these parameters do work, even if they are useless..
|
||||
EXPECT_EQ(SECSuccess, SSL_CreateAntiReplayContext(0, 1, 1, 1, &p));
|
||||
ASSERT_NE(nullptr, p);
|
||||
ScopedSSLAntiReplayContext ctx(p);
|
||||
|
||||
// The socket isn't a client or server until later, so configuring a client
|
||||
// should work OK.
|
||||
client_->EnsureTlsSetup();
|
||||
EXPECT_EQ(SECSuccess, SSL_SetAntiReplayContext(client_->ssl_fd(), ctx.get()));
|
||||
EXPECT_EQ(SECSuccess, SSL_SetAntiReplayContext(client_->ssl_fd(), nullptr));
|
||||
}
|
||||
|
||||
// See also TlsConnectGenericResumption.ResumeServerIncompatibleCipher
|
||||
TEST_P(TlsConnectTls13, ZeroRttDifferentCompatibleCipher) {
|
||||
EnsureTlsSetup();
|
||||
server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
// Change the ciphersuite. Resumption is OK because the hash is the same, but
|
||||
// early data will be rejected.
|
||||
server_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
|
||||
StartConnect();
|
||||
ZeroRttSendReceive(true, false);
|
||||
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(false);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
}
|
||||
|
||||
// See also TlsConnectGenericResumption.ResumeServerIncompatibleCipher
|
||||
TEST_P(TlsConnectTls13, ZeroRttDifferentIncompatibleCipher) {
|
||||
EnsureTlsSetup();
|
||||
server_->EnableSingleCipher(TLS_AES_256_GCM_SHA384);
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
// Resumption is rejected because the hash is different.
|
||||
server_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256);
|
||||
ExpectResumption(RESUME_NONE);
|
||||
|
||||
StartConnect();
|
||||
ZeroRttSendReceive(true, false);
|
||||
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(false);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
}
|
||||
|
||||
#ifndef NSS_DISABLE_TLS_1_3
|
||||
INSTANTIATE_TEST_CASE_P(Tls13ZeroRttReplayTest, TlsZeroRttReplayTest,
|
||||
TlsConnectTestBase::kTlsVariantsAll);
|
||||
|
|
|
|||
|
|
@ -176,14 +176,434 @@ TEST_P(TlsConnectGeneric, ClientAuth) {
|
|||
CheckKeys();
|
||||
}
|
||||
|
||||
// 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
|
||||
// then gets an alert from the server. The test harness
|
||||
// doesn't handle this right yet.
|
||||
TEST_P(TlsConnectStream, DISABLED_ClientAuthRequiredRejected) {
|
||||
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()));
|
||||
ASSERT_NE(nullptr, cert1.get());
|
||||
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
ASSERT_NE(nullptr, cert2.get());
|
||||
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()));
|
||||
ASSERT_NE(nullptr, cert1.get());
|
||||
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
ASSERT_NE(nullptr, cert2.get());
|
||||
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()));
|
||||
ASSERT_NE(nullptr, cert3.get());
|
||||
ScopedCERTCertificate cert4(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
ASSERT_NE(nullptr, cert4.get());
|
||||
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, PostHandshakeAuthBeforeKeyUpdate) {
|
||||
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());
|
||||
// Send KeyUpdate.
|
||||
EXPECT_EQ(SECFailure, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
|
||||
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthDuringClientKeyUpdate) {
|
||||
client_->SetupClientAuth();
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
|
||||
Connect();
|
||||
CheckEpochs(3, 3);
|
||||
// Send CertificateRequest from server.
|
||||
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
|
||||
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
|
||||
// Send KeyUpdate from client.
|
||||
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_TRUE));
|
||||
server_->SendData(50); // server sends CertificateRequest
|
||||
client_->SendData(50); // client sends KeyUpdate
|
||||
server_->ReadBytes(50); // server receives KeyUpdate and defers response
|
||||
CheckEpochs(4, 3);
|
||||
client_->ReadBytes(50); // client receives CertificateRequest
|
||||
client_->SendData(
|
||||
50); // client sends Certificate, CertificateVerify, Finished
|
||||
server_->ReadBytes(
|
||||
50); // server receives Certificate, CertificateVerify, Finished
|
||||
client_->CheckEpochs(3, 4);
|
||||
server_->CheckEpochs(4, 4);
|
||||
server_->SendData(50); // server sends KeyUpdate
|
||||
client_->ReadBytes(50); // client receives KeyUpdate
|
||||
client_->CheckEpochs(4, 4);
|
||||
}
|
||||
|
||||
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);
|
||||
ConnectExpectFail();
|
||||
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()));
|
||||
ASSERT_NE(nullptr, cert1.get());
|
||||
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
ASSERT_NE(nullptr, cert2.get());
|
||||
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()));
|
||||
ASSERT_NE(nullptr, cert3.get());
|
||||
ScopedCERTCertificate cert4(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
ASSERT_NE(nullptr, cert4.get());
|
||||
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));
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_OptionSet(server_->ssl_fd(), SSL_REQUIRE_CERTIFICATE,
|
||||
SSL_REQUIRE_ALWAYS));
|
||||
// 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); // send Certificate Request
|
||||
client_->ReadBytes(50); // read Certificate Request
|
||||
client_->SendData(50); // send empty Certificate+Finished
|
||||
server_->ExpectSendAlert(kTlsAlertCertificateRequired);
|
||||
server_->ReadBytes(50); // read empty Certificate+Finished
|
||||
server_->ExpectReadWriteError();
|
||||
server_->SendData(50); // send alert
|
||||
// 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()));
|
||||
}
|
||||
|
||||
// Check if post-handshake auth still works when session tickets are enabled:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1553443
|
||||
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthWithSessionTicketsEnabled) {
|
||||
EnsureTlsSetup();
|
||||
client_->SetupClientAuth();
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
|
||||
SSL_ENABLE_SESSION_TICKETS, PR_TRUE));
|
||||
EXPECT_EQ(SECSuccess, SSL_OptionSet(server_->ssl_fd(),
|
||||
SSL_ENABLE_SESSION_TICKETS, PR_TRUE));
|
||||
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_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(1U, called);
|
||||
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
|
||||
ASSERT_NE(nullptr, cert1.get());
|
||||
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
|
||||
ASSERT_NE(nullptr, cert2.get());
|
||||
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGenericPre13, ClientAuthRequiredRejected) {
|
||||
server_->RequestClientAuth(true);
|
||||
ConnectExpectAlert(server_, kTlsAlertBadCertificate);
|
||||
client_->CheckErrorCode(SSL_ERROR_BAD_CERT_ALERT);
|
||||
server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
|
||||
}
|
||||
|
||||
// In TLS 1.3, the client will claim that the connection is done and then
|
||||
// receive the alert afterwards. So drive the handshake manually.
|
||||
TEST_P(TlsConnectTls13, ClientAuthRequiredRejected) {
|
||||
server_->RequestClientAuth(true);
|
||||
StartConnect();
|
||||
client_->Handshake(); // CH
|
||||
server_->Handshake(); // SH.. (no resumption)
|
||||
client_->Handshake(); // Next message
|
||||
ASSERT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
|
||||
ExpectAlert(server_, kTlsAlertCertificateRequired);
|
||||
server_->Handshake(); // Alert
|
||||
server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
|
||||
client_->Handshake(); // Receive Alert
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, ClientAuthRequestedRejected) {
|
||||
|
|
@ -219,7 +639,9 @@ static void CheckSigScheme(std::shared_ptr<TlsHandshakeRecorder>& capture,
|
|||
EXPECT_EQ(expected_scheme, static_cast<uint16_t>(scheme));
|
||||
|
||||
ScopedCERTCertificate remote_cert(SSL_PeerCertificate(peer->ssl_fd()));
|
||||
ASSERT_NE(nullptr, remote_cert.get());
|
||||
ScopedSECKEYPublicKey remote_key(CERT_ExtractPublicKey(remote_cert.get()));
|
||||
ASSERT_NE(nullptr, remote_key.get());
|
||||
EXPECT_EQ(expected_size, SECKEY_PublicKeyStrengthInBits(remote_key.get()));
|
||||
}
|
||||
|
||||
|
|
@ -273,9 +695,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,
|
||||
|
|
@ -342,6 +762,59 @@ TEST_P(TlsConnectTls12, ClientAuthInconsistentPssSignatureScheme) {
|
|||
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureScheme) {
|
||||
static const SSLSignatureScheme kSignatureScheme[] = {
|
||||
ssl_sig_rsa_pkcs1_sha256, ssl_sig_rsa_pss_rsae_sha256};
|
||||
|
||||
Reset(TlsAgent::kServerRsa, "rsa");
|
||||
client_->SetSignatureSchemes(kSignatureScheme,
|
||||
PR_ARRAY_SIZE(kSignatureScheme));
|
||||
server_->SetSignatureSchemes(kSignatureScheme,
|
||||
PR_ARRAY_SIZE(kSignatureScheme));
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
|
||||
auto capture_cert_verify = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
client_, kTlsHandshakeCertificateVerify);
|
||||
capture_cert_verify->EnableDecryption();
|
||||
|
||||
Connect();
|
||||
CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pss_rsae_sha256,
|
||||
1024);
|
||||
}
|
||||
|
||||
// Client should refuse to connect without a usable signature scheme.
|
||||
TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureSchemeOnly) {
|
||||
static const SSLSignatureScheme kSignatureScheme[] = {
|
||||
ssl_sig_rsa_pkcs1_sha256};
|
||||
|
||||
Reset(TlsAgent::kServerRsa, "rsa");
|
||||
client_->SetSignatureSchemes(kSignatureScheme,
|
||||
PR_ARRAY_SIZE(kSignatureScheme));
|
||||
client_->SetupClientAuth();
|
||||
client_->StartConnect();
|
||||
client_->Handshake();
|
||||
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
|
||||
}
|
||||
|
||||
// Though the client has a usable signature scheme, when a certificate is
|
||||
// requested, it can't produce one.
|
||||
TEST_P(TlsConnectTls13, ClientAuthPkcs1AndEcdsaScheme) {
|
||||
static const SSLSignatureScheme kSignatureScheme[] = {
|
||||
ssl_sig_rsa_pkcs1_sha256, ssl_sig_ecdsa_secp256r1_sha256};
|
||||
|
||||
Reset(TlsAgent::kServerRsa, "rsa");
|
||||
client_->SetSignatureSchemes(kSignatureScheme,
|
||||
PR_ARRAY_SIZE(kSignatureScheme));
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
|
||||
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
||||
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
}
|
||||
|
||||
class TlsZeroCertificateRequestSigAlgsFilter : public TlsHandshakeFilter {
|
||||
public:
|
||||
TlsZeroCertificateRequestSigAlgsFilter(const std::shared_ptr<TlsAgent>& a)
|
||||
|
|
@ -552,7 +1025,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,15 +1038,16 @@ 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);
|
||||
client_->CheckErrorCode(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls12Plus, RequestClientAuthWithSha384) {
|
||||
TEST_P(TlsConnectTls12, RequestClientAuthWithSha384) {
|
||||
server_->SetSignatureSchemes(kSignatureSchemeRsaSha384,
|
||||
PR_ARRAY_SIZE(kSignatureSchemeRsaSha384));
|
||||
server_->RequestClientAuth(false);
|
||||
|
|
@ -888,11 +1364,11 @@ TEST_P(TlsConnectGeneric, AuthFailImmediate) {
|
|||
}
|
||||
|
||||
static const SSLExtraServerCertData ServerCertDataRsaPkcs1Decrypt = {
|
||||
ssl_auth_rsa_decrypt, nullptr, nullptr, nullptr};
|
||||
ssl_auth_rsa_decrypt, nullptr, nullptr, nullptr, nullptr, nullptr};
|
||||
static const SSLExtraServerCertData ServerCertDataRsaPkcs1Sign = {
|
||||
ssl_auth_rsa_sign, nullptr, nullptr, nullptr};
|
||||
ssl_auth_rsa_sign, nullptr, nullptr, nullptr, nullptr, nullptr};
|
||||
static const SSLExtraServerCertData ServerCertDataRsaPss = {
|
||||
ssl_auth_rsa_pss, nullptr, nullptr, nullptr};
|
||||
ssl_auth_rsa_pss, nullptr, nullptr, nullptr, nullptr, nullptr};
|
||||
|
||||
// Test RSA cert with usage=[signature, encipherment].
|
||||
TEST_F(TlsAgentStreamTestServer, ConfigureCertRsaPkcs1SignAndKEX) {
|
||||
|
|
@ -972,6 +1448,109 @@ TEST_F(TlsAgentStreamTestServer, ConfigureCertRsaPss) {
|
|||
&ServerCertDataRsaPss));
|
||||
}
|
||||
|
||||
// A server should refuse to even start a handshake with
|
||||
// misconfigured certificate and signature scheme.
|
||||
TEST_P(TlsConnectTls12Plus, MisconfiguredCertScheme) {
|
||||
Reset(TlsAgent::kServerDsa);
|
||||
static const SSLSignatureScheme kScheme[] = {ssl_sig_ecdsa_secp256r1_sha256};
|
||||
server_->SetSignatureSchemes(kScheme, PR_ARRAY_SIZE(kScheme));
|
||||
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
||||
if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
// TLS 1.2 disables cipher suites, which leads to a different error.
|
||||
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
} else {
|
||||
server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
|
||||
}
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
}
|
||||
|
||||
// In TLS 1.2, disabling an EC group causes ECDSA to be invalid.
|
||||
TEST_P(TlsConnectTls12, Tls12CertDisabledGroup) {
|
||||
Reset(TlsAgent::kServerEcdsa256);
|
||||
static const std::vector<SSLNamedGroup> k25519 = {ssl_grp_ec_curve25519};
|
||||
server_->ConfigNamedGroups(k25519);
|
||||
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
||||
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
}
|
||||
|
||||
// In TLS 1.3, ECDSA configuration only depends on the signature scheme.
|
||||
TEST_P(TlsConnectTls13, Tls13CertDisabledGroup) {
|
||||
Reset(TlsAgent::kServerEcdsa256);
|
||||
static const std::vector<SSLNamedGroup> k25519 = {ssl_grp_ec_curve25519};
|
||||
server_->ConfigNamedGroups(k25519);
|
||||
Connect();
|
||||
}
|
||||
|
||||
// A client should refuse to even start a handshake with only DSA.
|
||||
TEST_P(TlsConnectTls13, Tls13DsaOnlyClient) {
|
||||
static const SSLSignatureScheme kDsa[] = {ssl_sig_dsa_sha256};
|
||||
client_->SetSignatureSchemes(kDsa, PR_ARRAY_SIZE(kDsa));
|
||||
client_->StartConnect();
|
||||
client_->Handshake();
|
||||
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, Tls13DsaOnlyServer) {
|
||||
Reset(TlsAgent::kServerDsa);
|
||||
static const SSLSignatureScheme kDsa[] = {ssl_sig_dsa_sha256};
|
||||
server_->SetSignatureSchemes(kDsa, PR_ARRAY_SIZE(kDsa));
|
||||
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
||||
server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, Tls13Pkcs1OnlyClient) {
|
||||
static const SSLSignatureScheme kPkcs1[] = {ssl_sig_rsa_pkcs1_sha256};
|
||||
client_->SetSignatureSchemes(kPkcs1, PR_ARRAY_SIZE(kPkcs1));
|
||||
client_->StartConnect();
|
||||
client_->Handshake();
|
||||
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, Tls13Pkcs1OnlyServer) {
|
||||
static const SSLSignatureScheme kPkcs1[] = {ssl_sig_rsa_pkcs1_sha256};
|
||||
server_->SetSignatureSchemes(kPkcs1, PR_ARRAY_SIZE(kPkcs1));
|
||||
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
||||
server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, Tls13DsaIsNotAdvertisedClient) {
|
||||
EnsureTlsSetup();
|
||||
static const SSLSignatureScheme kSchemes[] = {ssl_sig_dsa_sha256,
|
||||
ssl_sig_rsa_pss_rsae_sha256};
|
||||
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
auto capture =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
|
||||
Connect();
|
||||
// We should only have the one signature algorithm advertised.
|
||||
static const uint8_t kExpectedExt[] = {0, 2, ssl_sig_rsa_pss_rsae_sha256 >> 8,
|
||||
ssl_sig_rsa_pss_rsae_sha256 & 0xff};
|
||||
ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
|
||||
capture->extension());
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls13, Tls13DsaIsNotAdvertisedServer) {
|
||||
EnsureTlsSetup();
|
||||
static const SSLSignatureScheme kSchemes[] = {ssl_sig_dsa_sha256,
|
||||
ssl_sig_rsa_pss_rsae_sha256};
|
||||
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
|
||||
auto capture = MakeTlsFilter<TlsExtensionCapture>(
|
||||
server_, ssl_signature_algorithms_xtn, true);
|
||||
capture->SetHandshakeTypes({kTlsHandshakeCertificateRequest});
|
||||
capture->EnableDecryption();
|
||||
server_->RequestClientAuth(false); // So we get a CertificateRequest.
|
||||
Connect();
|
||||
// We should only have the one signature algorithm advertised.
|
||||
static const uint8_t kExpectedExt[] = {0, 2, ssl_sig_rsa_pss_rsae_sha256 >> 8,
|
||||
ssl_sig_rsa_pss_rsae_sha256 & 0xff};
|
||||
ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
|
||||
capture->extension());
|
||||
}
|
||||
|
||||
// variant, version, certificate, auth type, signature scheme
|
||||
typedef std::tuple<SSLProtocolVariant, uint16_t, std::string, SSLAuthType,
|
||||
SSLSignatureScheme>
|
||||
|
|
@ -1033,12 +1612,21 @@ TEST_P(TlsSignatureSchemeConfiguration, SignatureSchemeConfigBoth) {
|
|||
INSTANTIATE_TEST_CASE_P(
|
||||
SignatureSchemeRsa, TlsSignatureSchemeConfiguration,
|
||||
::testing::Combine(
|
||||
TlsConnectTestBase::kTlsVariantsAll, TlsConnectTestBase::kTlsV12Plus,
|
||||
TlsConnectTestBase::kTlsVariantsAll, TlsConnectTestBase::kTlsV12,
|
||||
::testing::Values(TlsAgent::kServerRsaSign),
|
||||
::testing::Values(ssl_auth_rsa_sign),
|
||||
::testing::Values(ssl_sig_rsa_pkcs1_sha256, ssl_sig_rsa_pkcs1_sha384,
|
||||
ssl_sig_rsa_pkcs1_sha512, ssl_sig_rsa_pss_rsae_sha256,
|
||||
ssl_sig_rsa_pss_rsae_sha384)));
|
||||
// RSASSA-PKCS1-v1_5 is not allowed to be used in TLS 1.3
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SignatureSchemeRsaTls13, TlsSignatureSchemeConfiguration,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV13,
|
||||
::testing::Values(TlsAgent::kServerRsaSign),
|
||||
::testing::Values(ssl_auth_rsa_sign),
|
||||
::testing::Values(ssl_sig_rsa_pss_rsae_sha256,
|
||||
ssl_sig_rsa_pss_rsae_sha384)));
|
||||
// PSS with SHA-512 needs a bigger key to work.
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
SignatureSchemeBigRsa, TlsSignatureSchemeConfiguration,
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ class SignedCertificateTimestampsExtractor {
|
|||
}
|
||||
|
||||
void assertTimestamps(const DataBuffer& timestamps) {
|
||||
EXPECT_TRUE(auth_timestamps_);
|
||||
ASSERT_NE(nullptr, auth_timestamps_);
|
||||
EXPECT_EQ(timestamps, *auth_timestamps_);
|
||||
|
||||
EXPECT_TRUE(handshake_timestamps_);
|
||||
ASSERT_NE(nullptr, handshake_timestamps_);
|
||||
EXPECT_EQ(timestamps, *handshake_timestamps_);
|
||||
|
||||
const SECItem* current =
|
||||
|
|
@ -64,8 +64,8 @@ static const uint8_t kSctValue[] = {0x01, 0x23, 0x45, 0x67, 0x89};
|
|||
static const SECItem kSctItem = {siBuffer, const_cast<uint8_t*>(kSctValue),
|
||||
sizeof(kSctValue)};
|
||||
static const DataBuffer kSctBuffer(kSctValue, sizeof(kSctValue));
|
||||
static const SSLExtraServerCertData kExtraSctData = {ssl_auth_null, nullptr,
|
||||
nullptr, &kSctItem};
|
||||
static const SSLExtraServerCertData kExtraSctData = {
|
||||
ssl_auth_null, nullptr, nullptr, &kSctItem, nullptr, nullptr};
|
||||
|
||||
// Test timestamps extraction during a successful handshake.
|
||||
TEST_P(TlsConnectGenericPre13, SignedCertificateTimestampsLegacy) {
|
||||
|
|
@ -147,8 +147,8 @@ static const SECItem kOcspItems[] = {
|
|||
{siBuffer, const_cast<uint8_t*>(kOcspValue2), sizeof(kOcspValue2)}};
|
||||
static const SECItemArray kOcspResponses = {const_cast<SECItem*>(kOcspItems),
|
||||
PR_ARRAY_SIZE(kOcspItems)};
|
||||
const static SSLExtraServerCertData kOcspExtraData = {ssl_auth_null, nullptr,
|
||||
&kOcspResponses, nullptr};
|
||||
const static SSLExtraServerCertData kOcspExtraData = {
|
||||
ssl_auth_null, nullptr, &kOcspResponses, nullptr, nullptr, nullptr};
|
||||
|
||||
TEST_P(TlsConnectGeneric, NoOcsp) {
|
||||
EnsureTlsSetup();
|
||||
|
|
@ -224,7 +224,7 @@ TEST_P(TlsConnectGeneric, OcspHugeSuccess) {
|
|||
const SECItemArray hugeOcspResponses = {const_cast<SECItem*>(hugeOcspItems),
|
||||
PR_ARRAY_SIZE(hugeOcspItems)};
|
||||
const SSLExtraServerCertData hugeOcspExtraData = {
|
||||
ssl_auth_null, nullptr, &hugeOcspResponses, nullptr};
|
||||
ssl_auth_null, nullptr, &hugeOcspResponses, nullptr, nullptr, nullptr};
|
||||
|
||||
// The value should be available during the AuthCertificateCallback
|
||||
client_->SetAuthCertificateCallback([&](TlsAgent* agent, bool checksig,
|
||||
|
|
|
|||
241
security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc
Normal file
241
security/nss/gtests/ssl_gtest/ssl_cipherorder_unittest.cc
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
/* -*- 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 "ssl.h"
|
||||
#include "sslerr.h"
|
||||
#include "sslproto.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "tls_connect.h"
|
||||
#include "tls_filter.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
class TlsCipherOrderTest : public TlsConnectTestBase {
|
||||
protected:
|
||||
virtual void ConfigureTLS() {
|
||||
EnsureTlsSetup();
|
||||
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
}
|
||||
|
||||
virtual SECStatus BuildTestLists(std::vector<uint16_t> &cs_initial_list,
|
||||
std::vector<uint16_t> &cs_new_list) {
|
||||
// This is the current CipherSuites order of enabled CipherSuites as defined
|
||||
// in ssl3con.c
|
||||
const PRUint16 *kCipherSuites = SSL_GetImplementedCiphers();
|
||||
|
||||
for (unsigned int i = 0; i < kNumImplementedCiphers; i++) {
|
||||
PRBool pref = PR_FALSE, policy = PR_FALSE;
|
||||
SECStatus rv;
|
||||
rv = SSL_CipherPolicyGet(kCipherSuites[i], &policy);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
rv = SSL_CipherPrefGetDefault(kCipherSuites[i], &pref);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (pref && policy) {
|
||||
cs_initial_list.push_back(kCipherSuites[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// We will test set function with the first 15 enabled ciphers.
|
||||
const PRUint16 kNumCiphersToSet = 15;
|
||||
for (unsigned int i = 0; i < kNumCiphersToSet; i++) {
|
||||
cs_new_list.push_back(cs_initial_list[i]);
|
||||
}
|
||||
cs_new_list[0] = cs_initial_list[1];
|
||||
cs_new_list[1] = cs_initial_list[0];
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
public:
|
||||
TlsCipherOrderTest() : TlsConnectTestBase(ssl_variant_stream, 0) {}
|
||||
const unsigned int kNumImplementedCiphers = SSL_GetNumImplementedCiphers();
|
||||
};
|
||||
|
||||
const PRUint16 kCSUnsupported[] = {20196, 10101};
|
||||
const PRUint16 kNumCSUnsupported = PR_ARRAY_SIZE(kCSUnsupported);
|
||||
const PRUint16 kCSEmpty[] = {0};
|
||||
|
||||
// Get the active CipherSuites odered as they were compiled
|
||||
TEST_F(TlsCipherOrderTest, CipherOrderGet) {
|
||||
std::vector<uint16_t> initial_cs_order;
|
||||
std::vector<uint16_t> new_cs_order;
|
||||
SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ConfigureTLS();
|
||||
|
||||
std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
|
||||
unsigned int current_num_active_cs = 0;
|
||||
result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(),
|
||||
¤t_num_active_cs);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ASSERT_EQ(current_num_active_cs, initial_cs_order.size());
|
||||
for (unsigned int i = 0; i < initial_cs_order.size(); i++) {
|
||||
EXPECT_EQ(initial_cs_order[i], current_cs_order[i]);
|
||||
}
|
||||
// Get the chosen CipherSuite during the Handshake without any modification.
|
||||
Connect();
|
||||
SSLChannelInfo channel;
|
||||
result = SSL_GetChannelInfo(client_->ssl_fd(), &channel, sizeof channel);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
EXPECT_EQ(channel.cipherSuite, initial_cs_order[0]);
|
||||
}
|
||||
|
||||
// The "server" used for gtests honor only its ciphersuites order.
|
||||
// So, we apply the new set for the server instead of client.
|
||||
// This is enough to test the effect of SSL_CipherSuiteOrderSet function.
|
||||
TEST_F(TlsCipherOrderTest, CipherOrderSet) {
|
||||
std::vector<uint16_t> initial_cs_order;
|
||||
std::vector<uint16_t> new_cs_order;
|
||||
SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ConfigureTLS();
|
||||
|
||||
// change the server_ ciphersuites order.
|
||||
result = SSL_CipherSuiteOrderSet(server_->ssl_fd(), new_cs_order.data(),
|
||||
new_cs_order.size());
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
|
||||
// The function expect an array. We are using vector for VStudio
|
||||
// compatibility.
|
||||
std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
|
||||
unsigned int current_num_active_cs = 0;
|
||||
result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(),
|
||||
¤t_num_active_cs);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ASSERT_EQ(current_num_active_cs, new_cs_order.size());
|
||||
for (unsigned int i = 0; i < new_cs_order.size(); i++) {
|
||||
ASSERT_EQ(new_cs_order[i], current_cs_order[i]);
|
||||
}
|
||||
|
||||
Connect();
|
||||
SSLChannelInfo channel;
|
||||
// changes in server_ order reflect in client chosen ciphersuite.
|
||||
result = SSL_GetChannelInfo(client_->ssl_fd(), &channel, sizeof channel);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
EXPECT_EQ(channel.cipherSuite, new_cs_order[0]);
|
||||
}
|
||||
|
||||
// Duplicate socket configuration from a model.
|
||||
TEST_F(TlsCipherOrderTest, CipherOrderCopySocket) {
|
||||
std::vector<uint16_t> initial_cs_order;
|
||||
std::vector<uint16_t> new_cs_order;
|
||||
SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ConfigureTLS();
|
||||
|
||||
// Use the existing sockets for this test.
|
||||
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(),
|
||||
new_cs_order.size());
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
|
||||
std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
|
||||
unsigned int current_num_active_cs = 0;
|
||||
result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(),
|
||||
¤t_num_active_cs);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ASSERT_EQ(current_num_active_cs, initial_cs_order.size());
|
||||
for (unsigned int i = 0; i < current_num_active_cs; i++) {
|
||||
ASSERT_EQ(initial_cs_order[i], current_cs_order[i]);
|
||||
}
|
||||
|
||||
// Import/Duplicate configurations from client_ to server_
|
||||
PRFileDesc *rv = SSL_ImportFD(client_->ssl_fd(), server_->ssl_fd());
|
||||
EXPECT_NE(nullptr, rv);
|
||||
|
||||
result = SSL_CipherSuiteOrderGet(server_->ssl_fd(), current_cs_order.data(),
|
||||
¤t_num_active_cs);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ASSERT_EQ(current_num_active_cs, new_cs_order.size());
|
||||
for (unsigned int i = 0; i < new_cs_order.size(); i++) {
|
||||
EXPECT_EQ(new_cs_order.data()[i], current_cs_order[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// If the infomed num of elements is lower than the actual list size, only the
|
||||
// first "informed num" elements will be considered. The rest is ignored.
|
||||
TEST_F(TlsCipherOrderTest, CipherOrderSetLower) {
|
||||
std::vector<uint16_t> initial_cs_order;
|
||||
std::vector<uint16_t> new_cs_order;
|
||||
SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ConfigureTLS();
|
||||
|
||||
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(),
|
||||
new_cs_order.size() - 1);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
|
||||
std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
|
||||
unsigned int current_num_active_cs = 0;
|
||||
result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(),
|
||||
¤t_num_active_cs);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ASSERT_EQ(current_num_active_cs, new_cs_order.size() - 1);
|
||||
for (unsigned int i = 0; i < new_cs_order.size() - 1; i++) {
|
||||
ASSERT_EQ(new_cs_order.data()[i], current_cs_order[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Testing Errors Controls
|
||||
TEST_F(TlsCipherOrderTest, CipherOrderSetControls) {
|
||||
std::vector<uint16_t> initial_cs_order;
|
||||
std::vector<uint16_t> new_cs_order;
|
||||
SECStatus result = BuildTestLists(initial_cs_order, new_cs_order);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ConfigureTLS();
|
||||
|
||||
// Create a new vector with diplicated entries
|
||||
std::vector<uint16_t> repeated_cs_order(SSL_GetNumImplementedCiphers() + 1);
|
||||
std::copy(initial_cs_order.begin(), initial_cs_order.end(),
|
||||
repeated_cs_order.begin());
|
||||
repeated_cs_order[0] = repeated_cs_order[1];
|
||||
|
||||
// Repeated ciphersuites in the list
|
||||
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), repeated_cs_order.data(),
|
||||
initial_cs_order.size());
|
||||
EXPECT_EQ(result, SECFailure);
|
||||
|
||||
// Zero size for the sent list
|
||||
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(), 0);
|
||||
EXPECT_EQ(result, SECFailure);
|
||||
|
||||
// Wrong size, greater than actual
|
||||
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), new_cs_order.data(),
|
||||
SSL_GetNumImplementedCiphers() + 1);
|
||||
EXPECT_EQ(result, SECFailure);
|
||||
|
||||
// Wrong ciphersuites, not implemented
|
||||
result = SSL_CipherSuiteOrderSet(client_->ssl_fd(), kCSUnsupported,
|
||||
kNumCSUnsupported);
|
||||
EXPECT_EQ(result, SECFailure);
|
||||
|
||||
// Null list
|
||||
result =
|
||||
SSL_CipherSuiteOrderSet(client_->ssl_fd(), nullptr, new_cs_order.size());
|
||||
EXPECT_EQ(result, SECFailure);
|
||||
|
||||
// Empty list
|
||||
result =
|
||||
SSL_CipherSuiteOrderSet(client_->ssl_fd(), kCSEmpty, new_cs_order.size());
|
||||
EXPECT_EQ(result, SECFailure);
|
||||
|
||||
// Confirm that the controls are working, as the current ciphersuites
|
||||
// remained untouched
|
||||
std::vector<uint16_t> current_cs_order(SSL_GetNumImplementedCiphers() + 1);
|
||||
unsigned int current_num_active_cs = 0;
|
||||
result = SSL_CipherSuiteOrderGet(client_->ssl_fd(), current_cs_order.data(),
|
||||
¤t_num_active_cs);
|
||||
ASSERT_EQ(result, SECSuccess);
|
||||
ASSERT_EQ(current_num_active_cs, initial_cs_order.size());
|
||||
for (unsigned int i = 0; i < initial_cs_order.size(); i++) {
|
||||
ASSERT_EQ(initial_cs_order[i], current_cs_order[i]);
|
||||
}
|
||||
}
|
||||
} // namespace nss_test
|
||||
|
|
@ -56,6 +56,9 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
|
|||
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
std::vector<SSLNamedGroup> groups = {group_};
|
||||
if (cert_group_ != ssl_grp_none) {
|
||||
groups.push_back(cert_group_);
|
||||
}
|
||||
client_->ConfigNamedGroups(groups);
|
||||
server_->ConfigNamedGroups(groups);
|
||||
kea_type_ = SSLInt_GetKEAType(group_);
|
||||
|
|
@ -68,41 +71,48 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
|
|||
virtual void SetupCertificate() {
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
switch (sig_scheme_) {
|
||||
case ssl_sig_rsa_pkcs1_sha256:
|
||||
case ssl_sig_rsa_pkcs1_sha384:
|
||||
case ssl_sig_rsa_pkcs1_sha512:
|
||||
case ssl_sig_rsa_pss_rsae_sha256:
|
||||
std::cerr << "Signature scheme: rsa_pss_rsae_sha256" << std::endl;
|
||||
Reset(TlsAgent::kServerRsaSign);
|
||||
auth_type_ = ssl_auth_rsa_sign;
|
||||
break;
|
||||
case ssl_sig_rsa_pss_rsae_sha256:
|
||||
case ssl_sig_rsa_pss_rsae_sha384:
|
||||
std::cerr << "Signature scheme: rsa_pss_rsae_sha384" << std::endl;
|
||||
Reset(TlsAgent::kServerRsaSign);
|
||||
auth_type_ = ssl_auth_rsa_sign;
|
||||
break;
|
||||
case ssl_sig_rsa_pss_rsae_sha512:
|
||||
// You can't fit SHA-512 PSS in a 1024-bit key.
|
||||
std::cerr << "Signature scheme: rsa_pss_rsae_sha512" << std::endl;
|
||||
Reset(TlsAgent::kRsa2048);
|
||||
auth_type_ = ssl_auth_rsa_sign;
|
||||
break;
|
||||
case ssl_sig_rsa_pss_pss_sha256:
|
||||
std::cerr << "Signature scheme: rsa_pss_pss_sha256" << std::endl;
|
||||
Reset(TlsAgent::kServerRsaPss);
|
||||
auth_type_ = ssl_auth_rsa_pss;
|
||||
break;
|
||||
case ssl_sig_rsa_pss_pss_sha384:
|
||||
std::cerr << "Signature scheme: rsa_pss_pss_sha384" << std::endl;
|
||||
Reset("rsa_pss384");
|
||||
auth_type_ = ssl_auth_rsa_pss;
|
||||
break;
|
||||
case ssl_sig_rsa_pss_pss_sha512:
|
||||
std::cerr << "Signature scheme: rsa_pss_pss_sha512" << std::endl;
|
||||
Reset("rsa_pss512");
|
||||
auth_type_ = ssl_auth_rsa_pss;
|
||||
break;
|
||||
case ssl_sig_ecdsa_secp256r1_sha256:
|
||||
std::cerr << "Signature scheme: ecdsa_secp256r1_sha256" << std::endl;
|
||||
Reset(TlsAgent::kServerEcdsa256);
|
||||
auth_type_ = ssl_auth_ecdsa;
|
||||
cert_group_ = ssl_grp_ec_secp256r1;
|
||||
break;
|
||||
case ssl_sig_ecdsa_secp384r1_sha384:
|
||||
std::cerr << "Signature scheme: ecdsa_secp384r1_sha384" << std::endl;
|
||||
Reset(TlsAgent::kServerEcdsa384);
|
||||
auth_type_ = ssl_auth_ecdsa;
|
||||
cert_group_ = ssl_grp_ec_secp384r1;
|
||||
break;
|
||||
default:
|
||||
ADD_FAILURE() << "Unsupported signature scheme: " << sig_scheme_;
|
||||
|
|
@ -118,9 +128,11 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
|
|||
break;
|
||||
case ssl_auth_ecdsa:
|
||||
Reset(TlsAgent::kServerEcdsa256);
|
||||
cert_group_ = ssl_grp_ec_secp256r1;
|
||||
break;
|
||||
case ssl_auth_ecdh_ecdsa:
|
||||
Reset(TlsAgent::kServerEcdhEcdsa);
|
||||
cert_group_ = ssl_grp_ec_secp256r1;
|
||||
break;
|
||||
case ssl_auth_ecdh_rsa:
|
||||
Reset(TlsAgent::kServerEcdhRsa);
|
||||
|
|
@ -198,6 +210,7 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
|
|||
SSLAuthType auth_type_;
|
||||
SSLKEAType kea_type_;
|
||||
SSLNamedGroup group_;
|
||||
SSLNamedGroup cert_group_ = ssl_grp_none;
|
||||
SSLSignatureScheme sig_scheme_;
|
||||
SSLCipherSuiteInfo csinfo_;
|
||||
};
|
||||
|
|
@ -330,6 +343,12 @@ static SSLSignatureScheme kSignatureSchemesParamsArr[] = {
|
|||
ssl_sig_rsa_pss_pss_sha256, ssl_sig_rsa_pss_pss_sha384,
|
||||
ssl_sig_rsa_pss_pss_sha512};
|
||||
|
||||
static SSLSignatureScheme kSignatureSchemesParamsArrTls13[] = {
|
||||
ssl_sig_ecdsa_secp256r1_sha256, ssl_sig_ecdsa_secp384r1_sha384,
|
||||
ssl_sig_rsa_pss_rsae_sha256, ssl_sig_rsa_pss_rsae_sha384,
|
||||
ssl_sig_rsa_pss_rsae_sha512, ssl_sig_rsa_pss_pss_sha256,
|
||||
ssl_sig_rsa_pss_pss_sha384, ssl_sig_rsa_pss_pss_sha512};
|
||||
|
||||
INSTANTIATE_CIPHER_TEST_P(RC4, Stream, V10ToV12, kDummyNamedGroupParams,
|
||||
kDummySignatureSchemesParams,
|
||||
TLS_RSA_WITH_RC4_128_SHA,
|
||||
|
|
@ -394,7 +413,7 @@ INSTANTIATE_CIPHER_TEST_P(
|
|||
#ifndef NSS_DISABLE_TLS_1_3
|
||||
INSTANTIATE_CIPHER_TEST_P(TLS13, All, V13,
|
||||
::testing::ValuesIn(kFasterDHEGroups),
|
||||
::testing::ValuesIn(kSignatureSchemesParamsArr),
|
||||
::testing::ValuesIn(kSignatureSchemesParamsArrTls13),
|
||||
TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256,
|
||||
TLS_AES_256_GCM_SHA384);
|
||||
INSTANTIATE_CIPHER_TEST_P(TLS13AllGroups, All, V13,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
53
security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc
Normal file
53
security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- 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 <cstdlib>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "gtest_utils.h"
|
||||
#include "tls_connect.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
extern "C" {
|
||||
extern FILE* ssl_trace_iob;
|
||||
|
||||
#ifdef NSS_ALLOW_SSLKEYLOGFILE
|
||||
extern FILE* ssl_keylog_iob;
|
||||
#endif
|
||||
}
|
||||
|
||||
// These tests ensure that when the associated environment variables are unset
|
||||
// that the lazily-initialized defaults are what they are supposed to be.
|
||||
|
||||
#ifdef DEBUG
|
||||
TEST_P(TlsConnectGeneric, DebugEnvTraceFileNotSet) {
|
||||
char* ev = PR_GetEnvSecure("SSLDEBUGFILE");
|
||||
if (ev && ev[0]) {
|
||||
// note: should use GTEST_SKIP when GTest gets updated to support it
|
||||
return;
|
||||
}
|
||||
|
||||
Connect();
|
||||
EXPECT_EQ(stderr, ssl_trace_iob);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NSS_ALLOW_SSLKEYLOGFILE
|
||||
TEST_P(TlsConnectGeneric, DebugEnvKeylogFileNotSet) {
|
||||
char* ev = PR_GetEnvSecure("SSLKEYLOGFILE");
|
||||
if (ev && ev[0]) {
|
||||
// note: should use GTEST_SKIP when GTest gets updated to support it
|
||||
return;
|
||||
}
|
||||
|
||||
Connect();
|
||||
EXPECT_EQ(nullptr, ssl_keylog_iob);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -682,4 +682,100 @@ TEST_P(TlsConnectTls12, ConnectInconsistentSigAlgDHE) {
|
|||
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
||||
}
|
||||
|
||||
static void CheckSkeSigScheme(
|
||||
std::shared_ptr<TlsHandshakeRecorder>& capture_ske,
|
||||
uint16_t expected_scheme) {
|
||||
TlsParser parser(capture_ske->buffer());
|
||||
EXPECT_TRUE(parser.SkipVariable(2)) << " read dh_p";
|
||||
EXPECT_TRUE(parser.SkipVariable(2)) << " read dh_q";
|
||||
EXPECT_TRUE(parser.SkipVariable(2)) << " read dh_Ys";
|
||||
|
||||
uint32_t tmp;
|
||||
EXPECT_TRUE(parser.Read(&tmp, 2)) << " read sig_scheme";
|
||||
EXPECT_EQ(expected_scheme, static_cast<uint16_t>(tmp));
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls12, ConnectSigAlgEnabledByPolicyDhe) {
|
||||
EnableOnlyDheCiphers();
|
||||
|
||||
const std::vector<SSLSignatureScheme> schemes = {ssl_sig_rsa_pkcs1_sha1,
|
||||
ssl_sig_rsa_pkcs1_sha384};
|
||||
|
||||
EnsureTlsSetup();
|
||||
client_->SetSignatureSchemes(schemes.data(), schemes.size());
|
||||
server_->SetSignatureSchemes(schemes.data(), schemes.size());
|
||||
auto capture_ske = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
server_, kTlsHandshakeServerKeyExchange);
|
||||
|
||||
StartConnect();
|
||||
client_->Handshake(); // Send ClientHello
|
||||
|
||||
// Enable SHA-1 by policy.
|
||||
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, NSS_USE_ALG_IN_SSL_KX, 0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
||||
0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
Handshake(); // Remainder of handshake
|
||||
// The server should now report that it is connected
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
|
||||
|
||||
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha1);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls12, ConnectSigAlgDisabledByPolicyDhe) {
|
||||
EnableOnlyDheCiphers();
|
||||
|
||||
const std::vector<SSLSignatureScheme> schemes = {ssl_sig_rsa_pkcs1_sha1,
|
||||
ssl_sig_rsa_pkcs1_sha384};
|
||||
|
||||
EnsureTlsSetup();
|
||||
client_->SetSignatureSchemes(schemes.data(), schemes.size());
|
||||
server_->SetSignatureSchemes(schemes.data(), schemes.size());
|
||||
auto capture_ske = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
server_, kTlsHandshakeServerKeyExchange);
|
||||
|
||||
StartConnect();
|
||||
client_->Handshake(); // Send ClientHello
|
||||
|
||||
// Disable SHA-1 by policy after sending ClientHello so that CH
|
||||
// includes SHA-1 signature scheme.
|
||||
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, 0, NSS_USE_ALG_IN_SSL_KX);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
||||
0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
Handshake(); // Remainder of handshake
|
||||
// The server should now report that it is connected
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
|
||||
|
||||
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha384);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectPre12, ConnectSigAlgDisabledByPolicyDhePre12) {
|
||||
EnableOnlyDheCiphers();
|
||||
|
||||
EnsureTlsSetup();
|
||||
StartConnect();
|
||||
client_->Handshake(); // Send ClientHello
|
||||
|
||||
// Disable SHA-1 by policy. This will cause the connection fail as
|
||||
// TLS 1.1 or earlier uses combined SHA-1 + MD5 signature.
|
||||
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, 0, NSS_USE_ALG_IN_SSL_KX);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
||||
0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
server_->ExpectSendAlert(kTlsAlertHandshakeFailure);
|
||||
client_->ExpectReceiveAlert(kTlsAlertHandshakeFailure);
|
||||
|
||||
// Remainder of handshake
|
||||
Handshake();
|
||||
|
||||
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -666,6 +666,80 @@ TEST_P(TlsConnectTls12, ConnectIncorrectSigAlg) {
|
|||
client_->CheckErrorCode(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
|
||||
}
|
||||
|
||||
static void CheckSkeSigScheme(
|
||||
std::shared_ptr<TlsHandshakeRecorder> &capture_ske,
|
||||
uint16_t expected_scheme) {
|
||||
TlsParser parser(capture_ske->buffer());
|
||||
uint32_t tmp = 0;
|
||||
EXPECT_TRUE(parser.Read(&tmp, 1)) << " read curve_type";
|
||||
EXPECT_EQ(3U, tmp) << "curve type has to be 3";
|
||||
EXPECT_TRUE(parser.Skip(2)) << " read namedcurve";
|
||||
EXPECT_TRUE(parser.SkipVariable(1)) << " read public";
|
||||
|
||||
EXPECT_TRUE(parser.Read(&tmp, 2)) << " read sig_scheme";
|
||||
EXPECT_EQ(expected_scheme, static_cast<uint16_t>(tmp));
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls12, ConnectSigAlgEnabledByPolicy) {
|
||||
EnsureTlsSetup();
|
||||
client_->DisableAllCiphers();
|
||||
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
||||
|
||||
const std::vector<SSLSignatureScheme> schemes = {ssl_sig_rsa_pkcs1_sha1,
|
||||
ssl_sig_rsa_pkcs1_sha384};
|
||||
|
||||
client_->SetSignatureSchemes(schemes.data(), schemes.size());
|
||||
server_->SetSignatureSchemes(schemes.data(), schemes.size());
|
||||
auto capture_ske = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
server_, kTlsHandshakeServerKeyExchange);
|
||||
|
||||
StartConnect();
|
||||
client_->Handshake(); // Send ClientHello
|
||||
|
||||
// Enable SHA-1 by policy.
|
||||
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, NSS_USE_ALG_IN_SSL_KX, 0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
||||
0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
Handshake(); // Remainder of handshake
|
||||
// The server should now report that it is connected
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
|
||||
|
||||
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha1);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectTls12, ConnectSigAlgDisabledByPolicy) {
|
||||
EnsureTlsSetup();
|
||||
client_->DisableAllCiphers();
|
||||
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
||||
|
||||
const std::vector<SSLSignatureScheme> schemes = {ssl_sig_rsa_pkcs1_sha1,
|
||||
ssl_sig_rsa_pkcs1_sha384};
|
||||
|
||||
client_->SetSignatureSchemes(schemes.data(), schemes.size());
|
||||
server_->SetSignatureSchemes(schemes.data(), schemes.size());
|
||||
auto capture_ske = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
server_, kTlsHandshakeServerKeyExchange);
|
||||
|
||||
StartConnect();
|
||||
client_->Handshake(); // Send ClientHello
|
||||
|
||||
// Disable SHA-1 by policy.
|
||||
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, 0, NSS_USE_ALG_IN_SSL_KX);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
||||
0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
Handshake(); // Remainder of handshake
|
||||
// The server should now report that it is connected
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
|
||||
|
||||
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha384);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV11Plus));
|
||||
|
|
|
|||
|
|
@ -436,14 +436,14 @@ TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsOddLength) {
|
|||
}
|
||||
|
||||
TEST_F(TlsExtensionTest13Stream, SignatureAlgorithmsPrecedingGarbage) {
|
||||
// 31 unknown signature algorithms followed by sha-256, rsa
|
||||
// 31 unknown signature algorithms followed by sha-256, rsa-pss
|
||||
const uint8_t val[] = {
|
||||
0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x01};
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x04};
|
||||
DataBuffer extension(val, sizeof(val));
|
||||
MakeTlsFilter<TlsExtensionReplacer>(client_, ssl_signature_algorithms_xtn,
|
||||
extension);
|
||||
|
|
@ -482,6 +482,73 @@ TEST_P(TlsExtensionTestGeneric, SupportedCurvesTrailingData) {
|
|||
client_, ssl_elliptic_curves_xtn, extension));
|
||||
}
|
||||
|
||||
TEST_P(TlsExtensionTest12, SupportedCurvesDisableX25519) {
|
||||
// Disable session resumption.
|
||||
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
|
||||
|
||||
// Ensure that we can enable its use in the key exchange.
|
||||
SECStatus rv =
|
||||
NSS_SetAlgorithmPolicy(SEC_OID_CURVE25519, NSS_USE_ALG_IN_SSL_KX, 0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
||||
0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
auto capture1 =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_elliptic_curves_xtn);
|
||||
Connect();
|
||||
|
||||
EXPECT_TRUE(capture1->captured());
|
||||
const DataBuffer& ext1 = capture1->extension();
|
||||
|
||||
uint32_t count;
|
||||
ASSERT_TRUE(ext1.Read(0, 2, &count));
|
||||
|
||||
// Whether or not we've seen x25519 offered in this handshake.
|
||||
bool seen1_x25519 = false;
|
||||
for (size_t offset = 2; offset <= count; offset++) {
|
||||
uint32_t val;
|
||||
ASSERT_TRUE(ext1.Read(offset, 2, &val));
|
||||
if (val == ssl_grp_ec_curve25519) {
|
||||
seen1_x25519 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(seen1_x25519);
|
||||
|
||||
// Ensure that we can disable its use in the key exchange.
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_CURVE25519, 0, NSS_USE_ALG_IN_SSL_KX);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
||||
0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
// Clean up after the last run.
|
||||
Reset();
|
||||
auto capture2 =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_elliptic_curves_xtn);
|
||||
Connect();
|
||||
|
||||
EXPECT_TRUE(capture2->captured());
|
||||
const DataBuffer& ext2 = capture2->extension();
|
||||
|
||||
ASSERT_TRUE(ext2.Read(0, 2, &count));
|
||||
|
||||
// Whether or not we've seen x25519 offered in this handshake.
|
||||
bool seen2_x25519 = false;
|
||||
for (size_t offset = 2; offset <= count; offset++) {
|
||||
uint32_t val;
|
||||
ASSERT_TRUE(ext2.Read(offset, 2, &val));
|
||||
|
||||
if (val == ssl_grp_ec_curve25519) {
|
||||
seen2_x25519 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_FALSE(seen2_x25519);
|
||||
}
|
||||
|
||||
TEST_P(TlsExtensionTestPre13, SupportedPointsEmpty) {
|
||||
const uint8_t val[] = {0x00};
|
||||
DataBuffer extension(val, sizeof(val));
|
||||
|
|
@ -547,6 +614,56 @@ TEST_P(TlsExtensionTest12, SignatureAlgorithmConfiguration) {
|
|||
}
|
||||
}
|
||||
|
||||
// This only works on TLS 1.2, since it relies on DSA.
|
||||
TEST_P(TlsExtensionTest12, SignatureAlgorithmDisableDSA) {
|
||||
const std::vector<SSLSignatureScheme> schemes = {
|
||||
ssl_sig_dsa_sha1, ssl_sig_dsa_sha256, ssl_sig_dsa_sha384,
|
||||
ssl_sig_dsa_sha512, ssl_sig_rsa_pss_rsae_sha256};
|
||||
|
||||
// Connect with DSA enabled by policy.
|
||||
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE,
|
||||
NSS_USE_ALG_IN_SSL_KX, 0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
||||
0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
Reset(TlsAgent::kServerDsa);
|
||||
auto capture1 =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
|
||||
client_->SetSignatureSchemes(schemes.data(), schemes.size());
|
||||
Connect();
|
||||
|
||||
// Check if all the signature algorithms are advertised.
|
||||
EXPECT_TRUE(capture1->captured());
|
||||
const DataBuffer& ext1 = capture1->extension();
|
||||
EXPECT_EQ(2U + 2U * schemes.size(), ext1.len());
|
||||
|
||||
// Connect with DSA disabled by policy.
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_ANSIX9_DSA_SIGNATURE, 0,
|
||||
NSS_USE_ALG_IN_SSL_KX);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
||||
0);
|
||||
ASSERT_EQ(SECSuccess, rv);
|
||||
|
||||
Reset(TlsAgent::kServerDsa);
|
||||
auto capture2 =
|
||||
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
|
||||
client_->SetSignatureSchemes(schemes.data(), schemes.size());
|
||||
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
||||
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
||||
|
||||
// Check if no DSA algorithms are advertised.
|
||||
EXPECT_TRUE(capture2->captured());
|
||||
const DataBuffer& ext2 = capture2->extension();
|
||||
EXPECT_EQ(2U + 2U, ext2.len());
|
||||
uint32_t v = 0;
|
||||
EXPECT_TRUE(ext2.Read(2, 2, &v));
|
||||
EXPECT_EQ(ssl_sig_rsa_pss_rsae_sha256, v);
|
||||
}
|
||||
|
||||
// Temporary test to verify that we choke on an empty ClientKeyShare.
|
||||
// This test will fail when we implement HelloRetryRequest.
|
||||
TEST_P(TlsExtensionTest13, EmptyClientKeyShare) {
|
||||
|
|
@ -1121,6 +1238,10 @@ INSTANTIATE_TEST_CASE_P(
|
|||
INSTANTIATE_TEST_CASE_P(ExtensionDatagramOnly, TlsExtensionTestDtls,
|
||||
TlsConnectTestBase::kTlsV11Plus);
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ExtensionTls12, TlsExtensionTest12,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV12));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ExtensionTls12Plus, TlsExtensionTest12Plus,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
||||
TlsConnectTestBase::kTlsV12Plus));
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace nss_test {
|
|||
const uint8_t kShortEmptyFinished[8] = {0};
|
||||
const uint8_t kLongEmptyFinished[128] = {0};
|
||||
|
||||
class TlsFuzzTest : public ::testing::Test {};
|
||||
class TlsFuzzTest : public TlsConnectGeneric {};
|
||||
|
||||
// Record the application data stream.
|
||||
class TlsApplicationDataRecorder : public TlsRecordFilter {
|
||||
|
|
@ -46,16 +46,9 @@ class TlsApplicationDataRecorder : public TlsRecordFilter {
|
|||
DataBuffer buffer_;
|
||||
};
|
||||
|
||||
// Ensure that ssl_Time() returns a constant value.
|
||||
FUZZ_F(TlsFuzzTest, SSL_Time_Constant) {
|
||||
PRUint32 now = ssl_TimeSec();
|
||||
PR_Sleep(PR_SecondsToInterval(2));
|
||||
EXPECT_EQ(ssl_TimeSec(), now);
|
||||
}
|
||||
|
||||
// Check that due to the deterministic PRNG we derive
|
||||
// the same master secret in two consecutive TLS sessions.
|
||||
FUZZ_P(TlsConnectGeneric, DeterministicExporter) {
|
||||
FUZZ_P(TlsFuzzTest, DeterministicExporter) {
|
||||
const char kLabel[] = "label";
|
||||
std::vector<unsigned char> out1(32), out2(32);
|
||||
|
||||
|
|
@ -95,7 +88,7 @@ FUZZ_P(TlsConnectGeneric, DeterministicExporter) {
|
|||
|
||||
// Check that due to the deterministic RNG two consecutive
|
||||
// TLS sessions will have the exact same transcript.
|
||||
FUZZ_P(TlsConnectGeneric, DeterministicTranscript) {
|
||||
FUZZ_P(TlsFuzzTest, DeterministicTranscript) {
|
||||
// Make sure we have RSA blinding params.
|
||||
Connect();
|
||||
|
||||
|
|
@ -130,9 +123,7 @@ FUZZ_P(TlsConnectGeneric, DeterministicTranscript) {
|
|||
// with all supported TLS versions, STREAM and DGRAM.
|
||||
// Check that records are NOT encrypted.
|
||||
// Check that records don't have a MAC.
|
||||
FUZZ_P(TlsConnectGeneric, ConnectSendReceive_NullCipher) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
FUZZ_P(TlsFuzzTest, ConnectSendReceive_NullCipher) {
|
||||
// Set up app data filters.
|
||||
auto client_recorder = MakeTlsFilter<TlsApplicationDataRecorder>(client_);
|
||||
auto server_recorder = MakeTlsFilter<TlsApplicationDataRecorder>(server_);
|
||||
|
|
@ -157,7 +148,7 @@ FUZZ_P(TlsConnectGeneric, ConnectSendReceive_NullCipher) {
|
|||
}
|
||||
|
||||
// Check that an invalid Finished message doesn't abort the connection.
|
||||
FUZZ_P(TlsConnectGeneric, BogusClientFinished) {
|
||||
FUZZ_P(TlsFuzzTest, BogusClientFinished) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
MakeTlsFilter<TlsInspectorReplaceHandshakeMessage>(
|
||||
|
|
@ -168,7 +159,7 @@ FUZZ_P(TlsConnectGeneric, BogusClientFinished) {
|
|||
}
|
||||
|
||||
// Check that an invalid Finished message doesn't abort the connection.
|
||||
FUZZ_P(TlsConnectGeneric, BogusServerFinished) {
|
||||
FUZZ_P(TlsFuzzTest, BogusServerFinished) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
MakeTlsFilter<TlsInspectorReplaceHandshakeMessage>(
|
||||
|
|
@ -179,7 +170,7 @@ FUZZ_P(TlsConnectGeneric, BogusServerFinished) {
|
|||
}
|
||||
|
||||
// Check that an invalid server auth signature doesn't abort the connection.
|
||||
FUZZ_P(TlsConnectGeneric, BogusServerAuthSignature) {
|
||||
FUZZ_P(TlsFuzzTest, BogusServerAuthSignature) {
|
||||
EnsureTlsSetup();
|
||||
uint8_t msg_type = version_ == SSL_LIBRARY_VERSION_TLS_1_3
|
||||
? kTlsHandshakeCertificateVerify
|
||||
|
|
@ -190,7 +181,7 @@ FUZZ_P(TlsConnectGeneric, BogusServerAuthSignature) {
|
|||
}
|
||||
|
||||
// Check that an invalid client auth signature doesn't abort the connection.
|
||||
FUZZ_P(TlsConnectGeneric, BogusClientAuthSignature) {
|
||||
FUZZ_P(TlsFuzzTest, BogusClientAuthSignature) {
|
||||
EnsureTlsSetup();
|
||||
client_->SetupClientAuth();
|
||||
server_->RequestClientAuth(true);
|
||||
|
|
@ -199,7 +190,7 @@ FUZZ_P(TlsConnectGeneric, BogusClientAuthSignature) {
|
|||
}
|
||||
|
||||
// Check that session ticket resumption works.
|
||||
FUZZ_P(TlsConnectGeneric, SessionTicketResumption) {
|
||||
FUZZ_P(TlsFuzzTest, SessionTicketResumption) {
|
||||
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
|
||||
Connect();
|
||||
SendReceive();
|
||||
|
|
@ -212,7 +203,7 @@ FUZZ_P(TlsConnectGeneric, SessionTicketResumption) {
|
|||
}
|
||||
|
||||
// Check that session tickets are not encrypted.
|
||||
FUZZ_P(TlsConnectGeneric, UnencryptedSessionTickets) {
|
||||
FUZZ_P(TlsFuzzTest, UnencryptedSessionTickets) {
|
||||
ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
|
||||
|
||||
auto filter = MakeTlsFilter<TlsHandshakeRecorder>(
|
||||
|
|
@ -220,23 +211,45 @@ FUZZ_P(TlsConnectGeneric, UnencryptedSessionTickets) {
|
|||
Connect();
|
||||
|
||||
std::cerr << "ticket" << filter->buffer() << std::endl;
|
||||
size_t offset = 4; /* lifetime */
|
||||
size_t offset = 4; // Skip lifetime.
|
||||
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
offset += 4; /* ticket_age_add */
|
||||
offset += 4; // Skip ticket_age_add.
|
||||
uint32_t nonce_len = 0;
|
||||
EXPECT_TRUE(filter->buffer().Read(offset, 1, &nonce_len));
|
||||
offset += 1 + nonce_len;
|
||||
}
|
||||
offset += 2 + /* ticket length */
|
||||
2; /* TLS_EX_SESS_TICKET_VERSION */
|
||||
|
||||
offset += 2; // Skip the ticket length.
|
||||
|
||||
// This bit parses the contents of the ticket, which would ordinarily be
|
||||
// encrypted. Start by checking that we have the right version. This needs
|
||||
// to be updated every time that TLS_EX_SESS_TICKET_VERSION is changed. But
|
||||
// we don't use the #define. That way, any time that code is updated, this
|
||||
// test will fail unless it is manually checked.
|
||||
uint32_t ticket_version;
|
||||
EXPECT_TRUE(filter->buffer().Read(offset, 2, &ticket_version));
|
||||
EXPECT_EQ(0x010aU, ticket_version);
|
||||
offset += 2;
|
||||
|
||||
// Check the protocol version number.
|
||||
uint32_t tls_version = 0;
|
||||
EXPECT_TRUE(filter->buffer().Read(offset, sizeof(version_), &tls_version));
|
||||
EXPECT_EQ(version_, static_cast<decltype(version_)>(tls_version));
|
||||
offset += sizeof(version_);
|
||||
|
||||
// Check the cipher suite.
|
||||
uint32_t suite = 0;
|
||||
EXPECT_TRUE(filter->buffer().Read(offset + sizeof(version_), 2, &suite));
|
||||
EXPECT_TRUE(filter->buffer().Read(offset, 2, &suite));
|
||||
client_->CheckCipherSuite(static_cast<uint16_t>(suite));
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
FuzzStream, TlsFuzzTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsVAll));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
FuzzDatagram, TlsFuzzTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11Plus));
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -18,9 +18,11 @@
|
|||
'ssl_agent_unittest.cc',
|
||||
'ssl_auth_unittest.cc',
|
||||
'ssl_cert_ext_unittest.cc',
|
||||
'ssl_cipherorder_unittest.cc',
|
||||
'ssl_ciphersuite_unittest.cc',
|
||||
'ssl_custext_unittest.cc',
|
||||
'ssl_damage_unittest.cc',
|
||||
'ssl_debug_env_unittest.cc',
|
||||
'ssl_dhe_unittest.cc',
|
||||
'ssl_drop_unittest.cc',
|
||||
'ssl_ecdh_unittest.cc',
|
||||
|
|
@ -32,11 +34,12 @@
|
|||
'ssl_gather_unittest.cc',
|
||||
'ssl_gtest.cc',
|
||||
'ssl_hrr_unittest.cc',
|
||||
'ssl_keylog_unittest.cc',
|
||||
'ssl_keyupdate_unittest.cc',
|
||||
'ssl_loopback_unittest.cc',
|
||||
'ssl_misc_unittest.cc',
|
||||
'ssl_primitive_unittest.cc',
|
||||
'ssl_record_unittest.cc',
|
||||
'ssl_recordsep_unittest.cc',
|
||||
'ssl_recordsize_unittest.cc',
|
||||
'ssl_resumption_unittest.cc',
|
||||
'ssl_renegotiation_unittest.cc',
|
||||
|
|
@ -52,7 +55,8 @@
|
|||
'tls_filter.cc',
|
||||
'tls_hkdf_unittest.cc',
|
||||
'tls_esni_unittest.cc',
|
||||
'tls_protect.cc'
|
||||
'tls_protect.cc',
|
||||
'tls_subcerts_unittest.cc'
|
||||
],
|
||||
'dependencies': [
|
||||
'<(DEPTH)/exports.gyp:nss_exports',
|
||||
|
|
@ -74,7 +78,7 @@
|
|||
'<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix',
|
||||
],
|
||||
'conditions': [
|
||||
[ 'test_build==1', {
|
||||
[ 'static_libs==1', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
|
||||
],
|
||||
|
|
@ -91,6 +95,14 @@
|
|||
'<(DEPTH)/lib/dbm/src/src.gyp:dbm',
|
||||
],
|
||||
}],
|
||||
[ 'enable_sslkeylogfile==1 and sanitizer_flags==0', {
|
||||
'sources': [
|
||||
'ssl_keylog_unittest.cc',
|
||||
],
|
||||
'defines': [
|
||||
'NSS_ALLOW_SSLKEYLOGFILE',
|
||||
],
|
||||
}],
|
||||
],
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
* 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/. */
|
||||
|
||||
#ifdef NSS_ALLOW_SSLKEYLOGFILE
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
|
@ -15,20 +13,59 @@
|
|||
|
||||
namespace nss_test {
|
||||
|
||||
static const std::string keylog_file_path = "keylog.txt";
|
||||
static const std::string keylog_env = "SSLKEYLOGFILE=" + keylog_file_path;
|
||||
static const std::string kKeylogFilePath = "keylog.txt";
|
||||
static const std::string kKeylogBlankEnv = "SSLKEYLOGFILE=";
|
||||
static const std::string kKeylogSetEnv = kKeylogBlankEnv + kKeylogFilePath;
|
||||
|
||||
extern "C" {
|
||||
extern FILE* ssl_keylog_iob;
|
||||
}
|
||||
|
||||
class KeyLogFileTestBase : public TlsConnectGeneric {
|
||||
private:
|
||||
std::string env_to_set_;
|
||||
|
||||
class KeyLogFileTest : public TlsConnectGeneric {
|
||||
public:
|
||||
virtual void CheckKeyLog() = 0;
|
||||
|
||||
KeyLogFileTestBase(std::string env) : env_to_set_(env) {}
|
||||
|
||||
void SetUp() override {
|
||||
TlsConnectGeneric::SetUp();
|
||||
// Remove previous results (if any).
|
||||
(void)remove(keylog_file_path.c_str());
|
||||
PR_SetEnv(keylog_env.c_str());
|
||||
(void)remove(kKeylogFilePath.c_str());
|
||||
PR_SetEnv(env_to_set_.c_str());
|
||||
}
|
||||
|
||||
void CheckKeyLog() {
|
||||
std::ifstream f(keylog_file_path);
|
||||
void ConnectAndCheck() {
|
||||
// This is a child process, ensure that error messages immediately
|
||||
// propagate or else it will not be visible.
|
||||
::testing::GTEST_FLAG(throw_on_failure) = true;
|
||||
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, true);
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
} else {
|
||||
Connect();
|
||||
}
|
||||
CheckKeyLog();
|
||||
_exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
class KeyLogFileTest : public KeyLogFileTestBase {
|
||||
public:
|
||||
KeyLogFileTest() : KeyLogFileTestBase(kKeylogSetEnv) {}
|
||||
|
||||
void CheckKeyLog() override {
|
||||
std::ifstream f(kKeylogFilePath);
|
||||
std::map<std::string, size_t> labels;
|
||||
std::set<std::string> client_randoms;
|
||||
for (std::string line; std::getline(f, line);) {
|
||||
|
|
@ -65,28 +102,6 @@ class KeyLogFileTest : public TlsConnectGeneric {
|
|||
ASSERT_EQ(4U, labels["EXPORTER_SECRET"]);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectAndCheck() {
|
||||
// This is a child process, ensure that error messages immediately
|
||||
// propagate or else it will not be visible.
|
||||
::testing::GTEST_FLAG(throw_on_failure) = true;
|
||||
|
||||
if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
SetupForZeroRtt();
|
||||
client_->Set0RttEnabled(true);
|
||||
server_->Set0RttEnabled(true);
|
||||
ExpectResumption(RESUME_TICKET);
|
||||
ZeroRttSendReceive(true, true);
|
||||
Handshake();
|
||||
ExpectEarlyDataAccepted(true);
|
||||
CheckConnected();
|
||||
SendReceive();
|
||||
} else {
|
||||
Connect();
|
||||
}
|
||||
CheckKeyLog();
|
||||
_exit(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Tests are run in a separate process to ensure that NSS is not initialized yet
|
||||
|
|
@ -113,6 +128,37 @@ INSTANTIATE_TEST_CASE_P(
|
|||
TlsConnectTestBase::kTlsV13));
|
||||
#endif
|
||||
|
||||
} // namespace nss_test
|
||||
class KeyLogFileUnsetTest : public KeyLogFileTestBase {
|
||||
public:
|
||||
KeyLogFileUnsetTest() : KeyLogFileTestBase(kKeylogBlankEnv) {}
|
||||
|
||||
#endif // NSS_ALLOW_SSLKEYLOGFILE
|
||||
void CheckKeyLog() override {
|
||||
std::ifstream f(kKeylogFilePath);
|
||||
EXPECT_FALSE(f.good());
|
||||
|
||||
EXPECT_EQ(nullptr, ssl_keylog_iob);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(KeyLogFileUnsetTest, KeyLogFile) {
|
||||
testing::GTEST_FLAG(death_test_style) = "threadsafe";
|
||||
|
||||
ASSERT_EXIT(ConnectAndCheck(), ::testing::ExitedWithCode(0), "");
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
KeyLogFileDTLS12, KeyLogFileUnsetTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
|
||||
TlsConnectTestBase::kTlsV11V12));
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
KeyLogFileTLS12, KeyLogFileUnsetTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV10ToV12));
|
||||
#ifndef NSS_DISABLE_TLS_1_3
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
KeyLogFileTLS13, KeyLogFileUnsetTest,
|
||||
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
|
||||
TlsConnectTestBase::kTlsV13));
|
||||
#endif
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
|
|||
|
|
@ -33,6 +33,37 @@ TEST_F(TlsConnectTest, KeyUpdateClient) {
|
|||
CheckEpochs(4, 3);
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, KeyUpdateTooEarly_Client) {
|
||||
StartConnect();
|
||||
auto filter = MakeTlsFilter<TlsEncryptedHandshakeMessageReplacer>(
|
||||
server_, kTlsHandshakeFinished, kTlsHandshakeKeyUpdate);
|
||||
filter->EnableDecryption();
|
||||
|
||||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
ExpectAlert(client_, kTlsAlertUnexpectedMessage);
|
||||
client_->Handshake();
|
||||
client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE);
|
||||
server_->Handshake();
|
||||
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, KeyUpdateTooEarly_Server) {
|
||||
StartConnect();
|
||||
auto filter = MakeTlsFilter<TlsEncryptedHandshakeMessageReplacer>(
|
||||
client_, kTlsHandshakeFinished, kTlsHandshakeKeyUpdate);
|
||||
filter->EnableDecryption();
|
||||
|
||||
client_->Handshake();
|
||||
server_->Handshake();
|
||||
client_->Handshake();
|
||||
ExpectAlert(server_, kTlsAlertUnexpectedMessage);
|
||||
server_->Handshake();
|
||||
server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE);
|
||||
client_->Handshake();
|
||||
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectTest, KeyUpdateClientRequestUpdate) {
|
||||
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
|
||||
Connect();
|
||||
|
|
|
|||
218
security/nss/gtests/ssl_gtest/ssl_primitive_unittest.cc
Normal file
218
security/nss/gtests/ssl_gtest/ssl_primitive_unittest.cc
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/* -*- 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 <memory>
|
||||
|
||||
#include "keyhi.h"
|
||||
#include "pk11pub.h"
|
||||
#include "secerr.h"
|
||||
#include "ssl.h"
|
||||
#include "sslerr.h"
|
||||
#include "sslexp.h"
|
||||
#include "sslproto.h"
|
||||
|
||||
#include "gtest_utils.h"
|
||||
#include "nss_scoped_ptrs.h"
|
||||
#include "scoped_ptrs_ssl.h"
|
||||
#include "tls_connect.h"
|
||||
|
||||
namespace nss_test {
|
||||
|
||||
// From tls_hkdf_unittest.cc:
|
||||
extern size_t GetHashLength(SSLHashType ht);
|
||||
|
||||
class AeadTest : public ::testing::Test {
|
||||
public:
|
||||
AeadTest() : slot_(PK11_GetInternalSlot()) {}
|
||||
|
||||
void InitSecret(SSLHashType hash_type) {
|
||||
static const uint8_t kData[64] = {'s', 'e', 'c', 'r', 'e', 't'};
|
||||
SECItem key_item = {siBuffer, const_cast<uint8_t *>(kData),
|
||||
static_cast<unsigned int>(GetHashLength(hash_type))};
|
||||
PK11SymKey *s =
|
||||
PK11_ImportSymKey(slot_.get(), CKM_SSL3_MASTER_KEY_DERIVE,
|
||||
PK11_OriginUnwrap, CKA_DERIVE, &key_item, NULL);
|
||||
ASSERT_NE(nullptr, s);
|
||||
secret_.reset(s);
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
InitSecret(ssl_hash_sha256);
|
||||
PORT_SetError(0);
|
||||
}
|
||||
|
||||
protected:
|
||||
static void EncryptDecrypt(const ScopedSSLAeadContext &ctx,
|
||||
const uint8_t *ciphertext, size_t ciphertext_len) {
|
||||
static const uint8_t kAad[] = {'a', 'a', 'd'};
|
||||
static const uint8_t kPlaintext[] = {'t', 'e', 'x', 't'};
|
||||
static const size_t kMaxSize = 32;
|
||||
|
||||
ASSERT_GE(kMaxSize, ciphertext_len);
|
||||
ASSERT_LT(0U, ciphertext_len);
|
||||
|
||||
uint8_t output[kMaxSize];
|
||||
unsigned int output_len = 0;
|
||||
EXPECT_EQ(SECSuccess, SSL_AeadEncrypt(ctx.get(), 0, kAad, sizeof(kAad),
|
||||
kPlaintext, sizeof(kPlaintext),
|
||||
output, &output_len, sizeof(output)));
|
||||
ASSERT_EQ(ciphertext_len, static_cast<size_t>(output_len));
|
||||
EXPECT_EQ(0, memcmp(ciphertext, output, ciphertext_len));
|
||||
|
||||
memset(output, 0, sizeof(output));
|
||||
EXPECT_EQ(SECSuccess, SSL_AeadDecrypt(ctx.get(), 0, kAad, sizeof(kAad),
|
||||
ciphertext, ciphertext_len, output,
|
||||
&output_len, sizeof(output)));
|
||||
ASSERT_EQ(sizeof(kPlaintext), static_cast<size_t>(output_len));
|
||||
EXPECT_EQ(0, memcmp(kPlaintext, output, sizeof(kPlaintext)));
|
||||
|
||||
// Now for some tests of decryption failure.
|
||||
// Truncate the input.
|
||||
EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(), 0, kAad, sizeof(kAad),
|
||||
ciphertext, ciphertext_len - 1,
|
||||
output, &output_len, sizeof(output)));
|
||||
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
|
||||
|
||||
// Skip the first byte of the AAD.
|
||||
EXPECT_EQ(
|
||||
SECFailure,
|
||||
SSL_AeadDecrypt(ctx.get(), 0, kAad + 1, sizeof(kAad) - 1, ciphertext,
|
||||
ciphertext_len, output, &output_len, sizeof(output)));
|
||||
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
|
||||
|
||||
uint8_t input[kMaxSize] = {0};
|
||||
// Toggle a byte of the input.
|
||||
memcpy(input, ciphertext, ciphertext_len);
|
||||
input[0] ^= 9;
|
||||
EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(), 0, kAad, sizeof(kAad),
|
||||
input, ciphertext_len, output,
|
||||
&output_len, sizeof(output)));
|
||||
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
|
||||
|
||||
// Toggle the last byte (the auth tag).
|
||||
memcpy(input, ciphertext, ciphertext_len);
|
||||
input[ciphertext_len - 1] ^= 77;
|
||||
EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(), 0, kAad, sizeof(kAad),
|
||||
input, ciphertext_len, output,
|
||||
&output_len, sizeof(output)));
|
||||
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
|
||||
|
||||
// Toggle some of the AAD.
|
||||
memcpy(input, kAad, sizeof(kAad));
|
||||
input[1] ^= 23;
|
||||
EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(), 0, input, sizeof(kAad),
|
||||
ciphertext, ciphertext_len, output,
|
||||
&output_len, sizeof(output)));
|
||||
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
|
||||
}
|
||||
|
||||
protected:
|
||||
ScopedPK11SymKey secret_;
|
||||
|
||||
private:
|
||||
ScopedPK11SlotInfo slot_;
|
||||
};
|
||||
|
||||
// These tests all use fixed inputs: a fixed secret, a fixed label, and fixed
|
||||
// inputs. So they have fixed outputs.
|
||||
static const char *kLabel = "test ";
|
||||
static const uint8_t kCiphertextAes128Gcm[] = {
|
||||
0x11, 0x14, 0xfc, 0x58, 0x4f, 0x44, 0xff, 0x8c, 0xb6, 0xd8,
|
||||
0x20, 0xb3, 0xfb, 0x50, 0xd9, 0x3b, 0xd4, 0xc6, 0xe1, 0x14};
|
||||
static const uint8_t kCiphertextAes256Gcm[] = {
|
||||
0xf7, 0x27, 0x35, 0x80, 0x88, 0xaf, 0x99, 0x85, 0xf2, 0x83,
|
||||
0xca, 0xbb, 0x95, 0x42, 0x09, 0x3f, 0x9c, 0xf3, 0x29, 0xf0};
|
||||
static const uint8_t kCiphertextChaCha20Poly1305[] = {
|
||||
0x4e, 0x89, 0x2c, 0xfa, 0xfc, 0x8c, 0x40, 0x55, 0x6d, 0x7e,
|
||||
0x99, 0xac, 0x8e, 0x54, 0x58, 0xb1, 0x18, 0xd2, 0x66, 0x22};
|
||||
|
||||
TEST_F(AeadTest, AeadBadVersion) {
|
||||
SSLAeadContext *ctx = nullptr;
|
||||
ASSERT_EQ(SECFailure,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_2, TLS_AES_128_GCM_SHA256,
|
||||
secret_.get(), kLabel, strlen(kLabel), &ctx));
|
||||
EXPECT_EQ(nullptr, ctx);
|
||||
}
|
||||
|
||||
TEST_F(AeadTest, AeadUnsupportedCipher) {
|
||||
SSLAeadContext *ctx = nullptr;
|
||||
ASSERT_EQ(SECFailure,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_RSA_WITH_NULL_MD5,
|
||||
secret_.get(), kLabel, strlen(kLabel), &ctx));
|
||||
EXPECT_EQ(nullptr, ctx);
|
||||
}
|
||||
|
||||
TEST_F(AeadTest, AeadOlderCipher) {
|
||||
SSLAeadContext *ctx = nullptr;
|
||||
ASSERT_EQ(
|
||||
SECFailure,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
secret_.get(), kLabel, strlen(kLabel), &ctx));
|
||||
EXPECT_EQ(nullptr, ctx);
|
||||
}
|
||||
|
||||
TEST_F(AeadTest, AeadNoLabel) {
|
||||
SSLAeadContext *ctx = nullptr;
|
||||
ASSERT_EQ(SECFailure,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
|
||||
secret_.get(), nullptr, 12, &ctx));
|
||||
EXPECT_EQ(nullptr, ctx);
|
||||
}
|
||||
|
||||
TEST_F(AeadTest, AeadLongLabel) {
|
||||
SSLAeadContext *ctx = nullptr;
|
||||
ASSERT_EQ(SECFailure,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
|
||||
secret_.get(), "", 254, &ctx));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
EXPECT_EQ(nullptr, ctx);
|
||||
}
|
||||
|
||||
TEST_F(AeadTest, AeadNoPointer) {
|
||||
SSLAeadContext *ctx = nullptr;
|
||||
ASSERT_EQ(SECFailure,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
|
||||
secret_.get(), kLabel, strlen(kLabel), nullptr));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
|
||||
EXPECT_EQ(nullptr, ctx);
|
||||
}
|
||||
|
||||
TEST_F(AeadTest, AeadAes128Gcm) {
|
||||
SSLAeadContext *ctxInit;
|
||||
ASSERT_EQ(SECSuccess,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
|
||||
secret_.get(), kLabel, strlen(kLabel), &ctxInit));
|
||||
ScopedSSLAeadContext ctx(ctxInit);
|
||||
EXPECT_NE(nullptr, ctx);
|
||||
|
||||
EncryptDecrypt(ctx, kCiphertextAes128Gcm, sizeof(kCiphertextAes128Gcm));
|
||||
}
|
||||
|
||||
TEST_F(AeadTest, AeadAes256Gcm) {
|
||||
SSLAeadContext *ctxInit = nullptr;
|
||||
ASSERT_EQ(SECSuccess,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_256_GCM_SHA384,
|
||||
secret_.get(), kLabel, strlen(kLabel), &ctxInit));
|
||||
ScopedSSLAeadContext ctx(ctxInit);
|
||||
EXPECT_NE(nullptr, ctx);
|
||||
|
||||
EncryptDecrypt(ctx, kCiphertextAes256Gcm, sizeof(kCiphertextAes256Gcm));
|
||||
}
|
||||
|
||||
TEST_F(AeadTest, AeadChaCha20Poly1305) {
|
||||
SSLAeadContext *ctxInit;
|
||||
ASSERT_EQ(
|
||||
SECSuccess,
|
||||
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_CHACHA20_POLY1305_SHA256,
|
||||
secret_.get(), kLabel, strlen(kLabel), &ctxInit));
|
||||
ScopedSSLAeadContext ctx(ctxInit);
|
||||
EXPECT_NE(nullptr, ctx);
|
||||
|
||||
EncryptDecrypt(ctx, kCiphertextChaCha20Poly1305,
|
||||
sizeof(kCiphertextChaCha20Poly1305));
|
||||
}
|
||||
|
||||
} // namespace nss_test
|
||||
|
|
@ -205,6 +205,42 @@ TEST_F(TlsConnectDatagram13, ShortHeadersServer) {
|
|||
SendReceive();
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, UnencryptedFinishedMessage) {
|
||||
StartConnect();
|
||||
client_->Handshake(); // Send ClientHello
|
||||
server_->Handshake(); // Send first server flight
|
||||
|
||||
// Record and drop the first record, which is the Finished.
|
||||
auto recorder = std::make_shared<TlsRecordRecorder>(client_);
|
||||
recorder->EnableDecryption();
|
||||
auto dropper = std::make_shared<SelectiveDropFilter>(1);
|
||||
client_->SetFilter(std::make_shared<ChainedPacketFilter>(
|
||||
ChainedPacketFilterInit({recorder, dropper})));
|
||||
client_->Handshake(); // Save and drop CFIN.
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
|
||||
|
||||
ASSERT_EQ(1U, recorder->count());
|
||||
auto& finished = recorder->record(0);
|
||||
|
||||
DataBuffer d;
|
||||
size_t offset = d.Write(0, ssl_ct_handshake, 1);
|
||||
offset = d.Write(offset, SSL_LIBRARY_VERSION_TLS_1_2, 2);
|
||||
offset = d.Write(offset, finished.buffer.len(), 2);
|
||||
d.Append(finished.buffer);
|
||||
client_->SendDirect(d);
|
||||
|
||||
// Now process the message.
|
||||
ExpectAlert(server_, kTlsAlertUnexpectedMessage);
|
||||
// The server should generate an alert.
|
||||
server_->Handshake();
|
||||
EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state());
|
||||
server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_RECORD_TYPE);
|
||||
// Have the client consume the alert.
|
||||
client_->Handshake();
|
||||
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
|
||||
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
|
||||
}
|
||||
|
||||
const static size_t kContentSizesArr[] = {
|
||||
1, kMacSize - 1, kMacSize, 30, 31, 32, 36, 256, 257, 287, 288};
|
||||
|
||||
|
|
|
|||
577
security/nss/gtests/ssl_gtest/ssl_recordsep_unittest.cc
Normal file
577
security/nss/gtests/ssl_gtest/ssl_recordsep_unittest.cc
Normal file
|
|
@ -0,0 +1,577 @@
|
|||
/* -*- 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());
|
||||
EXPECT_TRUE(dummy_layer_);
|
||||
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);
|
||||
switch (expected_state) {
|
||||
case TlsAgent::STATE_CONNECTED:
|
||||
// The handshake callback should have been called, so check that before
|
||||
// checking that SSL_ForceHandshake succeeds.
|
||||
EXPECT_EQ(expected_state, peer->state());
|
||||
EXPECT_EQ(SECSuccess, SSL_ForceHandshake(peer->ssl_fd()));
|
||||
break;
|
||||
|
||||
case TlsAgent::STATE_CONNECTING:
|
||||
// Check that SSL_ForceHandshake() blocks.
|
||||
EXPECT_EQ(SECFailure, SSL_ForceHandshake(peer->ssl_fd()));
|
||||
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
|
||||
// Update and check the state.
|
||||
peer->Handshake();
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTING, peer->state());
|
||||
break;
|
||||
|
||||
default:
|
||||
ADD_FAILURE() << "No idea how to handle this 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;
|
||||
}
|
||||
EXPECT_EQ(SECSuccess,
|
||||
SSL_RecordLayerData(peer->ssl_fd(), epoch_, content_type_,
|
||||
data_.data(),
|
||||
static_cast<unsigned int>(data_.len())));
|
||||
}
|
||||
|
||||
// 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_);
|
||||
}
|
||||
|
||||
TEST_F(TlsConnectStreamTls13, ReplaceRecordLayerAsyncPostHandshake) {
|
||||
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);
|
||||
|
||||
ASSERT_TRUE(client_stage.empty());
|
||||
client_->Handshake();
|
||||
ASSERT_TRUE(client_stage.empty());
|
||||
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
|
||||
|
||||
// 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_);
|
||||
|
||||
// Post-handshake messages should work here.
|
||||
EXPECT_EQ(SECSuccess, SSL_SendSessionTicket(server_->ssl_fd(), nullptr, 0));
|
||||
SendForwardReceive(server_, server_stage, client_);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
|
@ -222,14 +230,15 @@ TEST_P(TlsConnectTls13, RecordSizePlaintextExceed) {
|
|||
|
||||
// Tweak the ciphertext of server records so that they greatly exceed the limit.
|
||||
// This requires a much larger expansion than for plaintext to trigger the
|
||||
// guard, which runs before decryption (current allowance is 304 octets).
|
||||
// guard, which runs before decryption (current allowance is 320 octets,
|
||||
// see MAX_EXPANSION in ssl3con.c).
|
||||
TEST_P(TlsConnectTls13, RecordSizeCiphertextExceed) {
|
||||
EnsureTlsSetup();
|
||||
|
||||
client_->SetOption(SSL_RECORD_SIZE_LIMIT, 64);
|
||||
Connect();
|
||||
|
||||
auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 320);
|
||||
auto server_expand = MakeTlsFilter<TlsRecordExpander>(server_, 336);
|
||||
server_->SendData(100);
|
||||
|
||||
client_->ExpectReadWriteError();
|
||||
|
|
@ -256,9 +265,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 +278,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 +345,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 +365,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,10 +408,24 @@ 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);
|
||||
}
|
||||
|
||||
TEST_P(TlsConnectGeneric, RecordSizeServerExtensionExtra) {
|
||||
EnsureTlsSetup();
|
||||
server_->SetOption(SSL_RECORD_SIZE_LIMIT, 1000);
|
||||
static const uint8_t v[] = {0x01, 0x00, 0x00};
|
||||
auto replace = MakeTlsFilter<TlsExtensionReplacer>(
|
||||
server_, ssl_record_size_limit_xtn, DataBuffer(v, sizeof(v)));
|
||||
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
||||
replace->EnableDecryption();
|
||||
}
|
||||
ConnectExpectAlert(client_, kTlsAlertDecodeError);
|
||||
}
|
||||
|
||||
class RecordSizeDefaultsTest : public ::testing::Test {
|
||||
public:
|
||||
void SetUp() {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue