Update NSS to 3.48 while keeping vc2013 hackfix and no-sslkeylogfile intact.

This commit is contained in:
Roy Tam 2020-01-03 13:36:26 +08:00
commit 171849c8e5
351 changed files with 115185 additions and 57946 deletions

View file

@ -21,6 +21,13 @@
'libraries': [
'-lws2_32',
],
'conditions': [
['static_libs==1', {
'libraries': [
'-ladvapi32',
],
}],
],
}],
['OS=="android"', {
'libraries': [

View file

@ -1,6 +1,5 @@
#include "nspr.h"
#include "nss.h"
#include "ssl.h"
#include <cstdlib>
@ -29,9 +28,6 @@ int main(int argc, char **argv) {
if (NSS_Initialize(workdir, "", "", SECMOD_DB, flags) != SECSuccess) {
return 1;
}
if (NSS_SetDomesticPolicy() != SECSuccess) {
return 1;
}
int rv = RUN_ALL_TESTS();
if (NSS_Shutdown() != SECSuccess) {

View file

@ -13,22 +13,22 @@
#include <string>
#include <vector>
typedef struct chacha_testvector_str {
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 invalid_tag;
bool invalid_iv;
} chacha_testvector;
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 chacha_testvector kChaCha20Vectors[] = {
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,
@ -116,7 +116,7 @@ const chacha_testvector kChaCha20Vectors[] = {
// Testvectors from project wycheproof
// <https://github.com/google/wycheproof>
const chacha_testvector kChaCha20WycheproofVectors[] = {
const chaChaTestVector kChaCha20WycheproofVectors[] = {
// Comment: rfc7539
{0,
@ -149,6 +149,32 @@ const chacha_testvector kChaCha20WycheproofVectors[] = {
false,
false},
// Comment:
{1,
{},
{},
{0x80, 0xba, 0x31, 0x92, 0xc8, 0x03, 0xce, 0x96, 0x5e, 0xa3, 0x71,
0xd5, 0xff, 0x07, 0x3c, 0xf0, 0xf4, 0x3b, 0x6a, 0x2a, 0xb5, 0x76,
0xb2, 0x08, 0x42, 0x6e, 0x11, 0x40, 0x9c, 0x09, 0xb9, 0xb0},
{0x4d, 0xa5, 0xbf, 0x8d, 0xfd, 0x58, 0x52, 0xc1, 0xea, 0x12, 0x37, 0x9d},
{0x76, 0xac, 0xb3, 0x42, 0xcf, 0x31, 0x66, 0xa5, 0xb6, 0x3c, 0x0c, 0x0e,
0xa1, 0x38, 0x3c, 0x8d},
false,
false},
// Comment:
{2,
{},
{0xbd, 0x50, 0x67, 0x64, 0xf2, 0xd2, 0xc4, 0x10},
{0x7a, 0x4c, 0xd7, 0x59, 0x17, 0x2e, 0x02, 0xeb, 0x20, 0x4d, 0xb2,
0xc3, 0xf5, 0xc7, 0x46, 0x22, 0x7d, 0xf5, 0x84, 0xfc, 0x13, 0x45,
0x19, 0x63, 0x91, 0xdb, 0xb9, 0x57, 0x7a, 0x25, 0x07, 0x42},
{0xa9, 0x2e, 0xf0, 0xac, 0x99, 0x1d, 0xd5, 0x16, 0xa3, 0xc6, 0xf6, 0x89},
{0x90, 0x6f, 0xa6, 0x28, 0x4b, 0x52, 0xf8, 0x7b, 0x73, 0x59, 0xcb, 0xaa,
0x75, 0x63, 0xc7, 0x09},
false,
false},
// Comment:
{3,
{0x2a},
@ -1294,6 +1320,286 @@ const chacha_testvector kChaCha20WycheproofVectors[] = {
false,
false},
// Comment: Flipped bit 0 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{61,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa2, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 1 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{62,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa1, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 7 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{63,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0x23, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 8 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{64,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe2, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 31 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{65,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0x79, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 32 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{66,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfa, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 33 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{67,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xf9, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 63 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{68,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x9b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 64 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{69,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5b, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 77 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{70,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xf2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 80 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{71,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x61, 0x7f,
0x40, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 96 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{72,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x41, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 97 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{73,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x42, 0xb7, 0xf4, 0x47},
true,
false},
// Comment: Flipped bit 120 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{74,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x46},
true,
false},
// Comment: Flipped bit 121 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{75,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x45},
true,
false},
// Comment: Flipped bit 126 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{76,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0x07},
true,
false},
// Comment: Flipped bit 127 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{77,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x1b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0xc7},
true,
false},
// Comment: Flipped bit 63 and 127 in tag expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{78,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xa3, 0xe3, 0xfd, 0xf9, 0xfb, 0xa6, 0x86, 0x9b, 0x5a, 0xd2, 0x60, 0x7f,
0x40, 0xb7, 0xf4, 0xc7},
true,
false},
// Comment: Tag changed to all zero expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{79,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00},
true,
false},
// Comment: tag change to all 1 expected
// tag:a3e3fdf9fba6861b5ad2607f40b7f447
{80,
{},
{0x61, 0x61, 0x64},
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
0xbb, 0xcc, 0xdd, 0xee, 0xff, 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},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff},
true,
false},
// Comment: Flipped bit 0 in tag expected
// tag:27da374f17b7f1b23844a5490bfc4001
{81,

View file

@ -48,9 +48,9 @@ const curve25519_testvector kCurve25519Vectors[] = {
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},
0x03, 0x20, 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},
{},
false},
@ -70,6 +70,66 @@ const curve25519_testvector kCurve25519Vectors[] = {
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},
// A private key with leading zeros (they should not be stripped)
{{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,
0x00, 0x99, 0xD1, 0x90, 0x60, 0xCF, 0x79, 0xF0, 0x6F, 0x4F, 0x2E, 0x47,
0x97, 0x5B, 0x2A, 0x90, 0x01, 0x6C, 0x94, 0xF4, 0x3D, 0x94, 0x02, 0x57,
0x13, 0xDB, 0xB2, 0xA3, 0xD9, 0x54, 0x0B, 0xE5, 0xa1, 0x23, 0x03, 0x21,
0x05, 0x66, 0xA7, 0x26, 0xE0, 0xFC, 0x83, 0xEF, 0xA2, 0x56, 0xF4, 0xCC,
0xEA, 0x71, 0x07, 0x4D, 0xBB, 0x5C, 0x76, 0x0A, 0x9F, 0xF4, 0x7E, 0x5C,
0x5D, 0x4C, 0xB8, 0xDA, 0x9E, 0x44, 0x60, 0x52, 0x00},
{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},
{0xB9, 0x4B, 0x92, 0xEA, 0xDA, 0x64, 0x40, 0xD3, 0x08, 0x63, 0x06,
0x45, 0xF4, 0x4C, 0xCD, 0x19, 0x7B, 0xE6, 0x0A, 0xBC, 0x6C, 0x9D,
0x96, 0x8F, 0x5D, 0x70, 0x44, 0x55, 0xD0, 0x1B, 0xEE, 0x4A},
true},
// A private key that's too short
{{0x30, 0x66, 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, 0x4B, 0x30, 0x49, 0x02, 0x01, 0x01, 0x04, 0x1F,
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},
false},
// A private key that's too long
{{0x30, 0x68, 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, 0x4D, 0x30, 0x4B, 0x02, 0x01, 0x01, 0x04, 0x21,
0x43, 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},
false}};
// Testvectors from project wycheproof

File diff suppressed because it is too large Load diff

View file

@ -13,22 +13,22 @@
#include <string>
#include <vector>
typedef struct chacha_testvector_str {
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 invalid_tag;
bool invalid_iv;
} chacha_testvector;
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 chacha_testvector kChaCha20Vectors[] = {
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,

View file

@ -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__

View file

@ -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);
}

View 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));
}
}
}
}

View file

@ -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,6 +35,7 @@
'ecl_unittest.cc',
'ghash_unittest.cc',
'rsa_unittest.cc',
'cmac_unittests.cc',
'<(DEPTH)/gtests/common/gtests.cc'
],
'dependencies': [
@ -85,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': [

View file

@ -148,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);
@ -255,4 +290,4 @@ TEST_F(DISABLED_MPITest, MpiCmpConstTest) {
mp_clear(&c);
}
} // nss_test
} // namespace nss_test

View file

@ -1,138 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{bca37a72-5b07-46cf-b44e-89f8e06451a2}</ProjectGuid>
<Config Condition="'$(Config)'==''">Release</Config>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Base>true</Base>
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Base>true</Base>
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
<OutputExt>lib</OutputExt>
<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
<Defines>NO_STRICT</Defines>
<DynamicRTL>true</DynamicRTL>
<UsePackages>true</UsePackages>
<ProjectType>CppStaticLibrary</ProjectType>
<BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
<PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi</PackageImports>
<BCC_wpar>false</BCC_wpar>
<IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</IncludePath>
<AllPackageLibs>rtl.lib;vcl.lib</AllPackageLibs>
<TLIB_PageSize>32</TLIB_PageSize>
<ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</ILINK_LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
<DCC_Optimize>false</DCC_Optimize>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<Defines>_DEBUG;$(Defines)</Defines>
<ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
<BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
<ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
<BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
<DCC_Define>DEBUG</DCC_Define>
<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
<IntermediateOutputDir>Debug</IntermediateOutputDir>
<TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
<BCC_StackFrames>true</BCC_StackFrames>
<BCC_DisableOptimizations>true</BCC_DisableOptimizations>
<ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>Full</TASM_Debugging>
<BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<Defines>NDEBUG;$(Defines)</Defines>
<IntermediateOutputDir>Release</IntermediateOutputDir>
<ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>None</TASM_Debugging>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
<Borland.ProjectType>CppStaticLibrary</Borland.ProjectType>
<BorlandProject>
<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
</Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">1</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines><HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Count">1</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item0">32</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item1">16</HistoryLists_hlTLIB_PageSize></HistoryLists_hlTLIB_PageSize></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
</ProjectExtensions>
<Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
<ItemGroup>
<None Include="..\include\gtest\gtest-death-test.h">
<BuildOrder>3</BuildOrder>
</None>
<None Include="..\include\gtest\gtest-message.h">
<BuildOrder>4</BuildOrder>
</None>
<None Include="..\include\gtest\gtest-param-test.h">
<BuildOrder>5</BuildOrder>
</None>
<None Include="..\include\gtest\gtest-spi.h">
<BuildOrder>6</BuildOrder>
</None>
<None Include="..\include\gtest\gtest-test-part.h">
<BuildOrder>7</BuildOrder>
</None>
<None Include="..\include\gtest\gtest-typed-test.h">
<BuildOrder>8</BuildOrder>
</None>
<None Include="..\include\gtest\gtest.h">
<BuildOrder>0</BuildOrder>
</None>
<None Include="..\include\gtest\gtest_pred_impl.h">
<BuildOrder>1</BuildOrder>
</None>
<None Include="..\include\gtest\gtest_prod.h">
<BuildOrder>2</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-death-test-internal.h">
<BuildOrder>9</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-filepath.h">
<BuildOrder>10</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-internal.h">
<BuildOrder>11</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-linked_ptr.h">
<BuildOrder>12</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-param-util-generated.h">
<BuildOrder>14</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-param-util.h">
<BuildOrder>13</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-port.h">
<BuildOrder>15</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-string.h">
<BuildOrder>16</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-type-util.h">
<BuildOrder>17</BuildOrder>
</None>
<CppCompile Include="gtest_all.cc">
<BuildOrder>18</BuildOrder>
</CppCompile>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
</BuildConfiguration>
</ItemGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{bca37a72-5b07-46cf-b44e-89f8e06451a2}</ProjectGuid>
<Config Condition="'$(Config)'==''">Release</Config>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Base>true</Base>
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Base>true</Base>
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
<OutputExt>lib</OutputExt>
<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
<Defines>NO_STRICT</Defines>
<DynamicRTL>true</DynamicRTL>
<UsePackages>true</UsePackages>
<ProjectType>CppStaticLibrary</ProjectType>
<BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
<PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi</PackageImports>
<BCC_wpar>false</BCC_wpar>
<IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</IncludePath>
<AllPackageLibs>rtl.lib;vcl.lib</AllPackageLibs>
<TLIB_PageSize>32</TLIB_PageSize>
<ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</ILINK_LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
<DCC_Optimize>false</DCC_Optimize>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<Defines>_DEBUG;$(Defines)</Defines>
<ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
<BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
<ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
<BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
<DCC_Define>DEBUG</DCC_Define>
<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
<IntermediateOutputDir>Debug</IntermediateOutputDir>
<TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
<BCC_StackFrames>true</BCC_StackFrames>
<BCC_DisableOptimizations>true</BCC_DisableOptimizations>
<ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>Full</TASM_Debugging>
<BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<Defines>NDEBUG;$(Defines)</Defines>
<IntermediateOutputDir>Release</IntermediateOutputDir>
<ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>None</TASM_Debugging>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
<Borland.ProjectType>CppStaticLibrary</Borland.ProjectType>
<BorlandProject>
<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
</Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">1</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines><HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Count">1</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item0">32</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item1">16</HistoryLists_hlTLIB_PageSize></HistoryLists_hlTLIB_PageSize></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
</ProjectExtensions>
<Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
<ItemGroup>
<None Include="..\include\gtest\gtest-death-test.h">
<BuildOrder>3</BuildOrder>
</None>
<None Include="..\include\gtest\gtest-message.h">
<BuildOrder>4</BuildOrder>
</None>
<None Include="..\include\gtest\gtest-param-test.h">
<BuildOrder>5</BuildOrder>
</None>
<None Include="..\include\gtest\gtest-spi.h">
<BuildOrder>6</BuildOrder>
</None>
<None Include="..\include\gtest\gtest-test-part.h">
<BuildOrder>7</BuildOrder>
</None>
<None Include="..\include\gtest\gtest-typed-test.h">
<BuildOrder>8</BuildOrder>
</None>
<None Include="..\include\gtest\gtest.h">
<BuildOrder>0</BuildOrder>
</None>
<None Include="..\include\gtest\gtest_pred_impl.h">
<BuildOrder>1</BuildOrder>
</None>
<None Include="..\include\gtest\gtest_prod.h">
<BuildOrder>2</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-death-test-internal.h">
<BuildOrder>9</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-filepath.h">
<BuildOrder>10</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-internal.h">
<BuildOrder>11</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-linked_ptr.h">
<BuildOrder>12</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-param-util-generated.h">
<BuildOrder>14</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-param-util.h">
<BuildOrder>13</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-port.h">
<BuildOrder>15</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-string.h">
<BuildOrder>16</BuildOrder>
</None>
<None Include="..\include\gtest\internal\gtest-type-util.h">
<BuildOrder>17</BuildOrder>
</None>
<CppCompile Include="gtest_all.cc">
<BuildOrder>18</BuildOrder>
</CppCompile>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
</BuildConfiguration>
</ItemGroup>
</Project>

View file

@ -1,54 +1,54 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{c1d923e0-6cba-4332-9b6f-3420acbf5091}</ProjectGuid>
</PropertyGroup>
<ItemGroup />
<ItemGroup>
<Projects Include="gtest.cbproj" />
<Projects Include="gtest_main.cbproj" />
<Projects Include="gtest_unittest.cbproj" />
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Default.Personality</Borland.Personality>
<Borland.ProjectType />
<BorlandProject>
<BorlandProject xmlns=""><Default.Personality></Default.Personality></BorlandProject></BorlandProject>
</ProjectExtensions>
<Target Name="gtest">
<MSBuild Projects="gtest.cbproj" Targets="" />
</Target>
<Target Name="gtest:Clean">
<MSBuild Projects="gtest.cbproj" Targets="Clean" />
</Target>
<Target Name="gtest:Make">
<MSBuild Projects="gtest.cbproj" Targets="Make" />
</Target>
<Target Name="gtest_main">
<MSBuild Projects="gtest_main.cbproj" Targets="" />
</Target>
<Target Name="gtest_main:Clean">
<MSBuild Projects="gtest_main.cbproj" Targets="Clean" />
</Target>
<Target Name="gtest_main:Make">
<MSBuild Projects="gtest_main.cbproj" Targets="Make" />
</Target>
<Target Name="gtest_unittest">
<MSBuild Projects="gtest_unittest.cbproj" Targets="" />
</Target>
<Target Name="gtest_unittest:Clean">
<MSBuild Projects="gtest_unittest.cbproj" Targets="Clean" />
</Target>
<Target Name="gtest_unittest:Make">
<MSBuild Projects="gtest_unittest.cbproj" Targets="Make" />
</Target>
<Target Name="Build">
<CallTarget Targets="gtest;gtest_main;gtest_unittest" />
</Target>
<Target Name="Clean">
<CallTarget Targets="gtest:Clean;gtest_main:Clean;gtest_unittest:Clean" />
</Target>
<Target Name="Make">
<CallTarget Targets="gtest:Make;gtest_main:Make;gtest_unittest:Make" />
</Target>
<Import Condition="Exists('$(MSBuildBinPath)\Borland.Group.Targets')" Project="$(MSBuildBinPath)\Borland.Group.Targets" />
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{c1d923e0-6cba-4332-9b6f-3420acbf5091}</ProjectGuid>
</PropertyGroup>
<ItemGroup />
<ItemGroup>
<Projects Include="gtest.cbproj" />
<Projects Include="gtest_main.cbproj" />
<Projects Include="gtest_unittest.cbproj" />
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Default.Personality</Borland.Personality>
<Borland.ProjectType />
<BorlandProject>
<BorlandProject xmlns=""><Default.Personality></Default.Personality></BorlandProject></BorlandProject>
</ProjectExtensions>
<Target Name="gtest">
<MSBuild Projects="gtest.cbproj" Targets="" />
</Target>
<Target Name="gtest:Clean">
<MSBuild Projects="gtest.cbproj" Targets="Clean" />
</Target>
<Target Name="gtest:Make">
<MSBuild Projects="gtest.cbproj" Targets="Make" />
</Target>
<Target Name="gtest_main">
<MSBuild Projects="gtest_main.cbproj" Targets="" />
</Target>
<Target Name="gtest_main:Clean">
<MSBuild Projects="gtest_main.cbproj" Targets="Clean" />
</Target>
<Target Name="gtest_main:Make">
<MSBuild Projects="gtest_main.cbproj" Targets="Make" />
</Target>
<Target Name="gtest_unittest">
<MSBuild Projects="gtest_unittest.cbproj" Targets="" />
</Target>
<Target Name="gtest_unittest:Clean">
<MSBuild Projects="gtest_unittest.cbproj" Targets="Clean" />
</Target>
<Target Name="gtest_unittest:Make">
<MSBuild Projects="gtest_unittest.cbproj" Targets="Make" />
</Target>
<Target Name="Build">
<CallTarget Targets="gtest;gtest_main;gtest_unittest" />
</Target>
<Target Name="Clean">
<CallTarget Targets="gtest:Clean;gtest_main:Clean;gtest_unittest:Clean" />
</Target>
<Target Name="Make">
<CallTarget Targets="gtest:Make;gtest_main:Make;gtest_unittest:Make" />
</Target>
<Import Condition="Exists('$(MSBuildBinPath)\Borland.Group.Targets')" Project="$(MSBuildBinPath)\Borland.Group.Targets" />
</Project>

View file

@ -1,38 +1,38 @@
// Copyright 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Josh Kelley (joshkel@gmail.com)
//
// Google C++ Testing Framework (Google Test)
//
// C++Builder's IDE cannot build a static library from files with hyphens
// in their name. See http://qc.codegear.com/wc/qcmain.aspx?d=70977 .
// This file serves as a workaround.
#include "src/gtest-all.cc"
// Copyright 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Josh Kelley (joshkel@gmail.com)
//
// Google C++ Testing Framework (Google Test)
//
// C++Builder's IDE cannot build a static library from files with hyphens
// in their name. See http://qc.codegear.com/wc/qcmain.aspx?d=70977 .
// This file serves as a workaround.
#include "src/gtest-all.cc"

View file

@ -1,40 +1,40 @@
// Copyright 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Josh Kelley (joshkel@gmail.com)
//
// Google C++ Testing Framework (Google Test)
//
// Links gtest.lib and gtest_main.lib into the current project in C++Builder.
// This means that these libraries can't be renamed, but it's the only way to
// ensure that Debug versus Release test builds are linked against the
// appropriate Debug or Release build of the libraries.
#pragma link "gtest.lib"
#pragma link "gtest_main.lib"
// Copyright 2009, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Josh Kelley (joshkel@gmail.com)
//
// Google C++ Testing Framework (Google Test)
//
// Links gtest.lib and gtest_main.lib into the current project in C++Builder.
// This means that these libraries can't be renamed, but it's the only way to
// ensure that Debug versus Release test builds are linked against the
// appropriate Debug or Release build of the libraries.
#pragma link "gtest.lib"
#pragma link "gtest_main.lib"

View file

@ -1,82 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{bca37a72-5b07-46cf-b44e-89f8e06451a2}</ProjectGuid>
<Config Condition="'$(Config)'==''">Release</Config>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Base>true</Base>
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Base>true</Base>
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
<OutputExt>lib</OutputExt>
<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
<Defines>NO_STRICT</Defines>
<DynamicRTL>true</DynamicRTL>
<UsePackages>true</UsePackages>
<ProjectType>CppStaticLibrary</ProjectType>
<BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
<PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi</PackageImports>
<BCC_wpar>false</BCC_wpar>
<IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</IncludePath>
<AllPackageLibs>rtl.lib;vcl.lib</AllPackageLibs>
<TLIB_PageSize>32</TLIB_PageSize>
<ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</ILINK_LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
<DCC_Optimize>false</DCC_Optimize>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<Defines>_DEBUG;$(Defines)</Defines>
<ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
<BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
<ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
<BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
<DCC_Define>DEBUG</DCC_Define>
<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
<IntermediateOutputDir>Debug</IntermediateOutputDir>
<TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
<BCC_StackFrames>true</BCC_StackFrames>
<BCC_DisableOptimizations>true</BCC_DisableOptimizations>
<ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>Full</TASM_Debugging>
<BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<Defines>NDEBUG;$(Defines)</Defines>
<IntermediateOutputDir>Release</IntermediateOutputDir>
<ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>None</TASM_Debugging>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
<Borland.ProjectType>CppStaticLibrary</Borland.ProjectType>
<BorlandProject>
<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
</Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">1</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines><HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Count">1</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item0">32</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item1">16</HistoryLists_hlTLIB_PageSize></HistoryLists_hlTLIB_PageSize></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
</ProjectExtensions>
<Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
<ItemGroup>
<CppCompile Include="..\src\gtest_main.cc">
<BuildOrder>0</BuildOrder>
</CppCompile>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
</BuildConfiguration>
</ItemGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{bca37a72-5b07-46cf-b44e-89f8e06451a2}</ProjectGuid>
<Config Condition="'$(Config)'==''">Release</Config>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Base>true</Base>
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Base>true</Base>
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
<OutputExt>lib</OutputExt>
<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
<Defines>NO_STRICT</Defines>
<DynamicRTL>true</DynamicRTL>
<UsePackages>true</UsePackages>
<ProjectType>CppStaticLibrary</ProjectType>
<BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
<PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi</PackageImports>
<BCC_wpar>false</BCC_wpar>
<IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</IncludePath>
<AllPackageLibs>rtl.lib;vcl.lib</AllPackageLibs>
<TLIB_PageSize>32</TLIB_PageSize>
<ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</ILINK_LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
<DCC_Optimize>false</DCC_Optimize>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<Defines>_DEBUG;$(Defines)</Defines>
<ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
<BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
<ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
<BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
<DCC_Define>DEBUG</DCC_Define>
<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
<IntermediateOutputDir>Debug</IntermediateOutputDir>
<TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
<BCC_StackFrames>true</BCC_StackFrames>
<BCC_DisableOptimizations>true</BCC_DisableOptimizations>
<ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>Full</TASM_Debugging>
<BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<Defines>NDEBUG;$(Defines)</Defines>
<IntermediateOutputDir>Release</IntermediateOutputDir>
<ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>None</TASM_Debugging>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
<Borland.ProjectType>CppStaticLibrary</Borland.ProjectType>
<BorlandProject>
<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
</Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">1</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines><HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Count">1</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item0">32</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item1">16</HistoryLists_hlTLIB_PageSize></HistoryLists_hlTLIB_PageSize></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
</ProjectExtensions>
<Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
<ItemGroup>
<CppCompile Include="..\src\gtest_main.cc">
<BuildOrder>0</BuildOrder>
</CppCompile>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
</BuildConfiguration>
</ItemGroup>
</Project>

View file

@ -1,88 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{eea63393-5ac5-4b9c-8909-d75fef2daa41}</ProjectGuid>
<Config Condition="'$(Config)'==''">Release</Config>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Base>true</Base>
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Base>true</Base>
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<OutputExt>exe</OutputExt>
<BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
<Defines>NO_STRICT</Defines>
<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
<DynamicRTL>true</DynamicRTL>
<ILINK_ObjectSearchPath>..\test</ILINK_ObjectSearchPath>
<UsePackages>true</UsePackages>
<ProjectType>CppConsoleApplication</ProjectType>
<NoVCL>true</NoVCL>
<BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
<PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi</PackageImports>
<BCC_wpar>false</BCC_wpar>
<IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..</IncludePath>
<ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</ILINK_LibraryPath>
<Multithreaded>true</Multithreaded>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
<DCC_Optimize>false</DCC_Optimize>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<Defines>_DEBUG;$(Defines)</Defines>
<ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
<BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
<ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
<BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
<DCC_Define>DEBUG</DCC_Define>
<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
<IntermediateOutputDir>Debug</IntermediateOutputDir>
<TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
<BCC_StackFrames>true</BCC_StackFrames>
<BCC_DisableOptimizations>true</BCC_DisableOptimizations>
<ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>Full</TASM_Debugging>
<BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<Defines>NDEBUG;$(Defines)</Defines>
<IntermediateOutputDir>Release</IntermediateOutputDir>
<ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>None</TASM_Debugging>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
<Borland.ProjectType>CppConsoleApplication</Borland.ProjectType>
<BorlandProject>
<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
</Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item1">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item2">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;$(OUTPUTDIR);..\test</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">2</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item1">STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
</ProjectExtensions>
<Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
<ItemGroup>
<CppCompile Include="..\test\gtest_unittest.cc">
<BuildOrder>0</BuildOrder>
</CppCompile>
<CppCompile Include="gtest_link.cc">
<BuildOrder>1</BuildOrder>
</CppCompile>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
</BuildConfiguration>
</ItemGroup>
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{eea63393-5ac5-4b9c-8909-d75fef2daa41}</ProjectGuid>
<Config Condition="'$(Config)'==''">Release</Config>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Base>true</Base>
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Base>true</Base>
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<OutputExt>exe</OutputExt>
<BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
<Defines>NO_STRICT</Defines>
<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
<DynamicRTL>true</DynamicRTL>
<ILINK_ObjectSearchPath>..\test</ILINK_ObjectSearchPath>
<UsePackages>true</UsePackages>
<ProjectType>CppConsoleApplication</ProjectType>
<NoVCL>true</NoVCL>
<BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
<PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi</PackageImports>
<BCC_wpar>false</BCC_wpar>
<IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..</IncludePath>
<ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</ILINK_LibraryPath>
<Multithreaded>true</Multithreaded>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
<DCC_Optimize>false</DCC_Optimize>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<Defines>_DEBUG;$(Defines)</Defines>
<ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
<BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
<ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
<BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
<DCC_Define>DEBUG</DCC_Define>
<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
<IntermediateOutputDir>Debug</IntermediateOutputDir>
<TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
<BCC_StackFrames>true</BCC_StackFrames>
<BCC_DisableOptimizations>true</BCC_DisableOptimizations>
<ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>Full</TASM_Debugging>
<BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<Defines>NDEBUG;$(Defines)</Defines>
<IntermediateOutputDir>Release</IntermediateOutputDir>
<ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
<TASM_Debugging>None</TASM_Debugging>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
<Borland.ProjectType>CppConsoleApplication</Borland.ProjectType>
<BorlandProject>
<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
<Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
</Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item1">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item2">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;$(OUTPUTDIR);..\test</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">2</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item1">STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
</ProjectExtensions>
<Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
<ItemGroup>
<CppCompile Include="..\test\gtest_unittest.cc">
<BuildOrder>0</BuildOrder>
</CppCompile>
<CppCompile Include="gtest_link.cc">
<BuildOrder>1</BuildOrder>
</CppCompile>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
</BuildConfiguration>
</ItemGroup>
</Project>

View file

@ -29,6 +29,7 @@ NSS_SRCDIRS = \
ssl_gtest \
$(SYSINIT_GTEST) \
nss_bogo_shim \
pkcs11testmodule \
$(NULL)
endif
endif

View file

@ -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',
],

View file

@ -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;
}

View file

@ -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
{

View file

@ -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;

View file

@ -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;

View file

@ -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, &notGood, usage));
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &notGood, usage));

View file

@ -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
{

View file

@ -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);

View file

@ -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();

View file

@ -7,22 +7,32 @@ DEPTH = ../..
MODULE = nss
CPPSRCS = \
pk11_aeskeywrap_unittest.cc \
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

View 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());
}
}

View file

@ -37,39 +37,57 @@ class Pkcs11AesGcmTest : public ::testing::TestWithParam<gcm_kat_value> {
}
// 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));
ASSERT_TRUE(!!symKey) << msg;
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, &params, 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, &params, 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, &params, output.data(), &outputLen,
output.size(), plaintext.data(), plaintext.size());
gcm_params.ulTagBits = 128;
rv = PK11_Encrypt(sym_key.get(), mech, &params, output.data(), &output_len,
output.size(), plaintext.data(), plaintext.size());
if (invalid_iv) {
EXPECT_EQ(rv, SECFailure) << msg;
EXPECT_EQ(SECFailure, rv) << msg;
EXPECT_EQ(0U, output_len);
return;
} else {
EXPECT_EQ(rv, SECSuccess) << msg;
}
EXPECT_EQ(SECSuccess, rv) << msg;
ASSERT_EQ(outputLen, output.size()) << msg;
ASSERT_EQ(output_len, output.size()) << msg;
// Check ciphertext and tag.
if (invalid_ct) {
@ -79,48 +97,49 @@ class Pkcs11AesGcmTest : public ::testing::TestWithParam<gcm_kat_value> {
}
// 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, &params, decrypted.data(),
&decryptedLen, decrypted.size(), output.data(), outputLen);
EXPECT_EQ(rv, SECSuccess) << msg;
ASSERT_EQ(decryptedLen, plaintext.size()) << msg;
rv = PK11_Decrypt(sym_key.get(), mech, &params, 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))
EXPECT_EQ(plaintext,
std::vector<uint8_t>(decrypted.begin(),
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, &params, output.data(), &outputLen,
output.size(), data.data(), data.size());
unsigned int output_len = 0;
return PK11_Encrypt(sym_key.get(), mech, &params, output.data(),
&output_len, output.size(), data.data(), data.size());
}
const CK_MECHANISM_TYPE mech = CKM_AES_GCM;
@ -136,17 +155,17 @@ INSTANTIATE_TEST_CASE_P(WycheproofTestVector, Pkcs11AesGcmTest,
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

View file

@ -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 */

View 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 */

View 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, encrypted, &encrypted_len,
sizeof(encrypted), kInput, input_len);
EXPECT_EQ(SECFailure, rv);
param.len++;
rv = PK11_Encrypt(key.get(), CKM_AES_CBC, &param, 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, &param, encrypted, &encrypted_len,
sizeof(encrypted), kInput, input_len);
EXPECT_EQ(SECFailure, rv);
param.len++;
rv = PK11_Encrypt(key.get(), CKM_AES_CTS, &param, 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

View file

@ -26,7 +26,7 @@ static const uint8_t kCtrNonce[16] = {'c', 0, 0, 0, 'n'};
static const uint8_t kData[16] = {'d'};
class Pkcs11ChaCha20Poly1305Test
: public ::testing::TestWithParam<chacha_testvector> {
: public ::testing::TestWithParam<chaChaTestVector> {
public:
void EncryptDecrypt(const ScopedPK11SymKey& key, const bool invalid_iv,
const bool invalid_tag, const uint8_t* data,
@ -44,108 +44,141 @@ class Pkcs11ChaCha20Poly1305Test
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, &params, 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(key.get(), kMech, &params, output.data(),
&outputLen, output.size(), data, data_len);
rv = PK11_Encrypt(key.get(), kMech, &params, 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;
} else {
EXPECT_EQ(rv, SECSuccess);
}
EXPECT_EQ(rv, SECSuccess);
EXPECT_EQ(encrypted.size(), static_cast<size_t>(encrypted_len));
// Check ciphertext and tag.
if (ct) {
ASSERT_EQ(ct_len, outputLen);
EXPECT_TRUE(!memcmp(ct, output.data(), outputLen) != invalid_tag);
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(key.get(), kMech, &params, decrypted.data(), &decryptedLen,
decrypted.size(), output.data(), 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, &params, 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, &params, decrypted.data(),
&decrypted_len, decrypted.size(), encrypted.data(),
encrypted.size());
EXPECT_EQ(rv, SECSuccess);
// Check the plaintext.
ASSERT_EQ(data_len, decryptedLen);
EXPECT_TRUE(!memcmp(data, decrypted.data(), decryptedLen));
ASSERT_EQ(data_len, decrypted_len);
EXPECT_TRUE(!memcmp(data, decrypted.data(), decrypted_len));
// Decrypt with bogus data.
// Skip if there's no data to modify.
if (outputLen != 0) {
std::vector<uint8_t> bogusCiphertext(output);
bogusCiphertext[0] ^= 0xff;
if (encrypted_len > 0) {
decrypted_len = 0;
std::vector<uint8_t> bogus_ciphertext(encrypted);
bogus_ciphertext[0] ^= 0xff;
rv = PK11_Decrypt(key.get(), kMech, &params, decrypted.data(),
&decryptedLen, decrypted.size(), bogusCiphertext.data(),
outputLen);
EXPECT_NE(rv, SECSuccess);
&decrypted_len, decrypted.size(),
bogus_ciphertext.data(), encrypted_len);
EXPECT_EQ(rv, SECFailure);
EXPECT_EQ(0U, decrypted_len);
}
// Decrypt with bogus tag.
// Skip if there's no tag to modify.
if (outputLen != 0) {
std::vector<uint8_t> bogusTag(output);
bogusTag[outputLen - 1] ^= 0xff;
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, &params, decrypted.data(),
&decryptedLen, decrypted.size(), bogusTag.data(),
outputLen);
EXPECT_NE(rv, SECSuccess);
&decrypted_len, decrypted.size(), bogus_tag.data(),
encrypted_len);
EXPECT_EQ(rv, SECFailure);
EXPECT_EQ(0U, decrypted_len);
}
// Decrypt with bogus IV.
// iv_len == 0 is invalid and should be caught earlier.
// Still skip, if there's no IV to modify.
if (iv_len != 0) {
SECItem bogusParams(params);
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.data());
bogusIV[0] ^= 0xff;
rv = PK11_Decrypt(key.get(), kMech, &bogusParams, decrypted.data(),
&decryptedLen, data_len, output.data(), 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.
// Skip when AAD was empty and can't be modified.
// Alternatively we could generate random aad.
if (aad_len != 0) {
SECItem bogusParams(params);
CK_NSS_AEAD_PARAMS bogusAeadParams(aead_params);
bogusParams.data = reinterpret_cast<unsigned char*>(&bogusAeadParams);
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.data());
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(key.get(), kMech, &bogusParams, decrypted.data(),
&decryptedLen, data_len, output.data(), 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 chacha_testvector testvector) {
void EncryptDecrypt(const chaChaTestVector testvector) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
SECItem key_item = {siBuffer, toUcharPtr(testvector.Key.data()),
static_cast<unsigned int>(testvector.Key.size())};
SECItem keyItem = {siBuffer, toUcharPtr(testvector.Key.data()),
static_cast<unsigned int>(testvector.Key.size())};
// Import key.
ScopedPK11SymKey key(PK11_ImportSymKey(slot.get(), kMech, PK11_OriginUnwrap,
CKA_ENCRYPT, &key_item, nullptr));
CKA_ENCRYPT, &keyItem, nullptr));
EXPECT_TRUE(!!key);
// Check.
EncryptDecrypt(key, testvector.invalid_iv, testvector.invalid_tag,
EncryptDecrypt(key, testvector.invalidIV, testvector.invalidTag,
testvector.Data.data(), testvector.Data.size(),
testvector.AAD.data(), testvector.AAD.size(),
testvector.IV.data(), testvector.IV.size(),
@ -162,9 +195,9 @@ TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateEncryptDecrypt) {
EXPECT_TRUE(!!key);
// Generate random data.
std::vector<uint8_t> data(512);
std::vector<uint8_t> input(512);
SECStatus rv =
PK11_GenerateRandomOnSlot(slot.get(), data.data(), data.size());
PK11_GenerateRandomOnSlot(slot.get(), input.data(), input.size());
EXPECT_EQ(rv, SECSuccess);
// Generate random AAD.
@ -178,7 +211,7 @@ TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateEncryptDecrypt) {
EXPECT_EQ(rv, SECSuccess);
// Check.
EncryptDecrypt(key, false, false, data.data(), data.size(), aad.data(),
EncryptDecrypt(key, false, false, input.data(), input.size(), aad.data(),
aad.size(), iv.data(), iv.size());
}
@ -194,30 +227,31 @@ TEST_F(Pkcs11ChaCha20Poly1305Test, Xor) {
slot.get(), kMechXor, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr));
EXPECT_TRUE(!!key);
SECItem ctr_nonce_item = {siBuffer, toUcharPtr(kCtrNonce),
static_cast<unsigned int>(sizeof(kCtrNonce))};
uint8_t output[sizeof(kData)];
unsigned int output_len = 88; // This should be overwritten.
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, &ctr_nonce_item, output, &output_len,
sizeof(output), kData, sizeof(kData));
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>(output_len));
EXPECT_EQ(0, memcmp(kExpected, output, sizeof(kExpected)));
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, &ctr_nonce_item, output, &output_len,
sizeof(output), kData, sizeof(kData));
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>(output_len));
EXPECT_EQ(0, memcmp(kExpected, output, sizeof(kExpected)));
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, &ctr_nonce_item, output, &output_len,
sizeof(output), kExpected, sizeof(kExpected));
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>(output_len));
EXPECT_EQ(0, memcmp(kData, output, sizeof(kData)));
ASSERT_EQ(sizeof(kExpected), static_cast<size_t>(encrypted_len));
EXPECT_EQ(0, memcmp(kData, encrypted, sizeof(kData)));
}
// This test just ensures that a key can be generated for use with the XOR
@ -227,15 +261,15 @@ TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateXor) {
ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
EXPECT_TRUE(!!key);
SECItem ctr_nonce_item = {siBuffer, toUcharPtr(kCtrNonce),
static_cast<unsigned int>(sizeof(kCtrNonce))};
uint8_t output[sizeof(kData)];
unsigned int output_len = 88; // This should be overwritten.
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, &ctr_nonce_item, output, &output_len,
sizeof(output), kData, sizeof(kData));
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>(output_len));
ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len));
}
TEST_F(Pkcs11ChaCha20Poly1305Test, XorInvalidParams) {
@ -243,18 +277,18 @@ TEST_F(Pkcs11ChaCha20Poly1305Test, XorInvalidParams) {
ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr));
EXPECT_TRUE(!!key);
SECItem ctr_nonce_item = {siBuffer, toUcharPtr(kCtrNonce),
static_cast<unsigned int>(sizeof(kCtrNonce)) - 1};
uint8_t output[sizeof(kData)];
unsigned int output_len = 88;
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, &ctr_nonce_item, output, &output_len,
sizeof(output), kData, sizeof(kData));
PK11_Encrypt(key.get(), kMechXor, &ctrNonceItem, encrypted,
&encrypted_len, sizeof(encrypted), kData, sizeof(kData));
EXPECT_EQ(SECFailure, rv);
ctr_nonce_item.data = nullptr;
rv = PK11_Encrypt(key.get(), kMechXor, &ctr_nonce_item, output, &output_len,
sizeof(output), kData, sizeof(kData));
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());
}

View file

@ -5,7 +5,7 @@
#include <memory>
#include "nss.h"
#include "pk11pub.h"
#include "prerror.h"
#include "cpputil.h"
#include "nss_scoped_ptrs.h"
@ -20,46 +20,90 @@ class Pkcs11Curve25519Test
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));
if (!expect_success && !certSpki) {
ScopedCERTSubjectPublicKeyInfo cert_spki(
SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_item));
if (!expect_success && !cert_spki) {
return;
}
ASSERT_TRUE(certSpki);
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));
ASSERT_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);
}
};

View file

@ -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

View 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, &params, 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

View file

@ -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)),

View file

@ -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,

View 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

View file

@ -11,20 +11,29 @@
'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': [
@ -45,6 +54,7 @@
'<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
'<(DEPTH)/lib/ssl/ssl.gyp:ssl',
'<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix',
],
}, {
'dependencies': [
@ -55,6 +65,12 @@
],
}
],
'target_defaults': {
'defines': [
'DLL_PREFIX=\"<(dll_prefix)\"',
'DLL_SUFFIX=\"<(dll_suffix)\"'
]
},
'variables': {
'module': 'nss'
}

View file

@ -15,6 +15,7 @@
#include "nss_scoped_ptrs.h"
#include "gtest/gtest.h"
#include "databuffer.h"
#include "pk11_keygen.h"
namespace nss_test {
@ -30,7 +31,7 @@ struct PK11GenericObjectsDeleter {
class Pk11KeyImportTestBase : public ::testing::Test {
public:
Pk11KeyImportTestBase(CK_MECHANISM_TYPE mech) : mech_(mech) {}
Pk11KeyImportTestBase() = default;
virtual ~Pk11KeyImportTestBase() = default;
void SetUp() override {
@ -42,20 +43,19 @@ class Pk11KeyImportTestBase : public ::testing::Test {
password_.reset(SECITEM_DupItem(&pwItem));
}
void Test() {
void Test(const Pkcs11KeyPairGenerator& generator) {
// Generate a key and export it.
KeyType key_type;
KeyType key_type = nullKey;
ScopedSECKEYEncryptedPrivateKeyInfo key_info;
ScopedSECItem public_value;
GenerateAndExport(&key_type, &key_info, &public_value);
GenerateAndExport(generator, &key_type, &key_info, &public_value);
ASSERT_NE(nullptr, public_value);
// Note: NSS is currently unable export wrapped DH keys, so this doesn't
// test
// CKM_DH_PKCS_KEY_PAIR_GEN beyond generate and verify
// 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.
@ -73,17 +73,6 @@ class Pk11KeyImportTestBase : public ::testing::Test {
CheckForPublicKey(priv_key, public_value.get());
}
protected:
class ParamHolder {
public:
virtual ~ParamHolder() = default;
virtual void* get() = 0;
};
virtual std::unique_ptr<ParamHolder> MakeParams() = 0;
CK_MECHANISM_TYPE mech_;
private:
SECItem GetPublicComponent(ScopedSECKEYPublicKey& pub_key) {
SECItem null = {siBuffer, NULL, 0};
@ -202,20 +191,14 @@ class Pk11KeyImportTestBase : public ::testing::Test {
}
}
void GenerateAndExport(KeyType* key_type,
void GenerateAndExport(const Pkcs11KeyPairGenerator& generator,
KeyType* key_type,
ScopedSECKEYEncryptedPrivateKeyInfo* key_info,
ScopedSECItem* public_value) {
auto params = MakeParams();
ASSERT_NE(nullptr, params);
SECKEYPublicKey* pub_tmp;
ScopedSECKEYPrivateKey priv_key(
PK11_GenerateKeyPair(slot_.get(), mech_, params->get(), &pub_tmp,
PR_FALSE, PR_TRUE, nullptr));
ASSERT_NE(nullptr, priv_key) << "PK11_GenerateKeyPair failed: "
<< PORT_ErrorToName(PORT_GetError());
ScopedSECKEYPublicKey pub_key(pub_tmp);
ASSERT_NE(nullptr, pub_key);
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;
@ -240,14 +223,13 @@ class Pk11KeyImportTestBase : public ::testing::Test {
CheckForPublicKey(priv_key, pub_val);
*key_type = t;
public_value->reset(SECITEM_DupItem(pub_val));
// Note: NSS is currently unable export wrapped DH keys, so this doesn't
// test
// CKM_DH_PKCS_KEY_PAIR_GEN beyond generate and verify
if (mech_ == CKM_DH_PKCS_KEY_PAIR_GEN) {
// 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,
@ -266,82 +248,13 @@ class Pk11KeyImportTest
: public Pk11KeyImportTestBase,
public ::testing::WithParamInterface<CK_MECHANISM_TYPE> {
public:
Pk11KeyImportTest() : Pk11KeyImportTestBase(GetParam()) {}
Pk11KeyImportTest() = default;
virtual ~Pk11KeyImportTest() = default;
protected:
std::unique_ptr<ParamHolder> MakeParams() override {
switch (mech_) {
case CKM_RSA_PKCS_KEY_PAIR_GEN:
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) {
return std::unique_ptr<ParamHolder>(new PqgParamHolder(pqg_params));
}
return std::unique_ptr<ParamHolder>(new DhParamHolder(pqg_params));
}
default:
ADD_FAILURE() << "unknown OID " << mech_;
}
return nullptr;
}
private:
class RsaParamHolder : public ParamHolder {
public:
RsaParamHolder()
: params_({/*.keySizeInBits = */ 1024, /*.pe = */ 0x010001}) {}
~RsaParamHolder() = default;
void* get() override { return &params_; }
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_({/*.arena = */ nullptr,
/*.prime = */ params->prime,
/*.base = */ params->base}) {}
~DhParamHolder() = default;
void* get() override { return &params_; }
private:
SECKEYDHParams params_;
};
};
TEST_P(Pk11KeyImportTest, GenerateExportImport) { Test(); }
TEST_P(Pk11KeyImportTest, GenerateExportImport) {
Test(Pkcs11KeyPairGenerator(GetParam()));
}
INSTANTIATE_TEST_CASE_P(Pk11KeyImportTest, Pk11KeyImportTest,
::testing::Values(CKM_RSA_PKCS_KEY_PAIR_GEN,
@ -351,42 +264,13 @@ INSTANTIATE_TEST_CASE_P(Pk11KeyImportTest, Pk11KeyImportTest,
class Pk11KeyImportTestEC : public Pk11KeyImportTestBase,
public ::testing::WithParamInterface<SECOidTag> {
public:
Pk11KeyImportTestEC() : Pk11KeyImportTestBase(CKM_EC_KEY_PAIR_GEN) {}
Pk11KeyImportTestEC() = default;
virtual ~Pk11KeyImportTestEC() = default;
protected:
std::unique_ptr<ParamHolder> MakeParams() override {
return std::unique_ptr<ParamHolder>(new EcParamHolder(GetParam()));
}
private:
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_ = {/*.type = */ siBuffer,
/*.data = */ extra_.get(),
/*.len = */ static_cast<unsigned int>(plen)};
}
~EcParamHolder() = default;
void* get() override { return &ec_params_; }
private:
SECKEYECParams ec_params_;
std::unique_ptr<uint8_t[]> extra_;
};
};
TEST_P(Pk11KeyImportTestEC, GenerateExportImport) { Test(); }
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,

View 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

View 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 &params_; }
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 &params_; }
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

View 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

View 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

View file

@ -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

View 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, &params, output.data(),
&output_len, output_size, data.data(), data.size());
} else {
return PK11_Decrypt(sym_key.get(), kMech, &params, 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

View file

@ -59,6 +59,9 @@ class Pk11SignatureTest : public ::testing::Test {
ScopedCERTSubjectPublicKeyInfo certSpki(
SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem));
if (!certSpki) {
return nullptr;
}
return ScopedSECKEYPublicKey(SECKEY_ExtractPublicKey(certSpki.get()));
}

View 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

View 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

View 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)

View 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;
}

View file

@ -0,0 +1,8 @@
;+NSS_3.48 { # NSS 3.48 release
;+ global:
LIBRARY pkcs11testmodule ;-
EXPORTS ;-
C_GetFunctionList;
;+ local:
;+ *;
;+};

View 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'
}
}

View 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

View file

@ -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)

View file

@ -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) {

View file

@ -12,6 +12,7 @@
'type': 'executable',
'sources': [
'softoken_gtest.cc',
'softoken_nssckbi_testlib_gtest.cc',
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
@ -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': {

View file

@ -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

View file

@ -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,10 +340,6 @@ SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group) {
return groupDef->keaType;
}
void SSLInt_SetTicketLifetime(uint32_t lifetime) {
ssl_ticket_lifetime = lifetime;
}
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size) {
sslSocket *ss;
@ -324,10 +363,6 @@ SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size) {
return SECSuccess;
}
void SSLInt_RolloverAntiReplay(void) {
tls13_AntiReplayRollover(ssl_TimeUsec());
}
SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending) {
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {

View file

@ -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);
@ -40,8 +41,8 @@ SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to);
SECStatus SSLInt_AdvanceWriteSeqByAWindow(PRFileDesc *fd, PRInt32 extra);
SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group);
SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending);
void SSLInt_SetTicketLifetime(uint32_t lifetime);
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size);
void SSLInt_RolloverAntiReplay(void);
SECStatus SSLInt_TweakChannelInfoForDC(PRFileDesc *fd, PRBool changeAuthKeyBits,
PRBool changeScheme);
#endif // ndef libssl_internals_h_

View file

@ -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 \
@ -53,6 +55,7 @@ CPPSRCS = \
tls_hkdf_unittest.cc \
tls_filter.cc \
tls_protect.cc \
tls_subcerts_unittest.cc \
tls_esni_unittest.cc \
$(SSLKEYLOGFILE_FILES) \
$(NULL)

View file

@ -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();
@ -870,6 +899,130 @@ TEST_F(TlsConnectDatagram13, ZeroRttShortReadDtls) {
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);

View file

@ -247,7 +247,9 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuth) {
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));
}
@ -289,7 +291,9 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuthMultiple) {
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(
@ -302,7 +306,9 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuthMultiple) {
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));
}
@ -383,7 +389,9 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuthAfterClientAuth) {
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(
@ -396,7 +404,9 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuthAfterClientAuth) {
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));
}
@ -537,14 +547,63 @@ TEST_F(TlsConnectStreamTls13, PostHandshakeAuthDecline) {
capture_cert_req->buffer().len()));
}
// In TLS 1.3, the client sends its cert rejection on the
// second flight, and since it has already received the
// server's Finished, it transitions to complete and
// then gets an alert from the server. The test harness
// doesn't handle this right yet.
TEST_P(TlsConnectStream, DISABLED_ClientAuthRequiredRejected) {
// 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);
ConnectExpectFail();
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) {
@ -580,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()));
}
@ -722,6 +783,7 @@ TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureScheme) {
1024);
}
// Client should refuse to connect without a usable signature scheme.
TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureSchemeOnly) {
static const SSLSignatureScheme kSignatureScheme[] = {
ssl_sig_rsa_pkcs1_sha256};
@ -729,7 +791,21 @@ TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureSchemeOnly) {
Reset(TlsAgent::kServerRsa, "rsa");
client_->SetSignatureSchemes(kSignatureScheme,
PR_ARRAY_SIZE(kSignatureScheme));
server_->SetSignatureSchemes(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);
@ -1288,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) {
@ -1372,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>

View file

@ -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,

View 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(),
&current_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(),
&current_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(),
&current_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(),
&current_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(),
&current_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(),
&current_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

View file

@ -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_);
@ -69,34 +72,47 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
switch (sig_scheme_) {
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_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_;
@ -112,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);
@ -192,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_;
};

View 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

View file

@ -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

View file

@ -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));

View file

@ -652,7 +652,7 @@ TEST_P(TlsExtensionTest12, SignatureAlgorithmDisableDSA) {
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
client_->SetSignatureSchemes(schemes.data(), schemes.size());
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
// Check if no DSA algorithms are advertised.

View file

@ -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

View file

@ -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',
@ -53,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',

View file

@ -13,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);) {
@ -63,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
@ -111,4 +128,37 @@ INSTANTIATE_TEST_CASE_P(
TlsConnectTestBase::kTlsV13));
#endif
class KeyLogFileUnsetTest : public KeyLogFileTestBase {
public:
KeyLogFileUnsetTest() : KeyLogFileTestBase(kKeylogBlankEnv) {}
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

View file

@ -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();

View file

@ -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};

View file

@ -230,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();

View file

@ -11,6 +11,11 @@
#include "sslerr.h"
#include "sslproto.h"
extern "C" {
// This is not something that should make you happy.
#include "libssl_internals.h"
}
#include "gtest_utils.h"
#include "tls_connect.h"
@ -34,6 +39,24 @@ TEST_P(TlsConnectStreamPre13, RenegotiateServer) {
CheckConnected();
}
TEST_P(TlsConnectStreamPre13, RenegotiateRandoms) {
SSL3Random crand1, crand2, srand1, srand2;
Connect();
EXPECT_EQ(SECSuccess,
SSLInt_GetHandshakeRandoms(client_->ssl_fd(), crand1, srand1));
// Renegotiate and check that both randoms have changed.
client_->PrepareForRenegotiate();
server_->StartRenegotiate();
Handshake();
CheckConnected();
EXPECT_EQ(SECSuccess,
SSLInt_GetHandshakeRandoms(client_->ssl_fd(), crand2, srand2));
EXPECT_NE(0, memcmp(crand1, crand2, sizeof(SSL3Random)));
EXPECT_NE(0, memcmp(srand1, srand2, sizeof(SSL3Random)));
}
// The renegotiation options shouldn't cause an error if TLS 1.3 is chosen.
TEST_F(TlsConnectTest, RenegotiationConfigTls13) {
EnsureTlsSetup();

View file

@ -325,14 +325,17 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicketForget) {
SendReceive();
}
// Tickets last two days maximum; this is a time longer than that.
static const PRTime kLongerThanTicketLifetime =
3LL * 24 * 60 * 60 * PR_USEC_PER_SEC;
TEST_P(TlsConnectGenericResumption, ConnectWithExpiredTicketAtClient) {
SSLInt_SetTicketLifetime(1); // one second
// This causes a ticket resumption.
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Connect();
SendReceive();
WAIT_(false, 1000);
AdvanceTime(kLongerThanTicketLifetime);
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@ -354,7 +357,6 @@ TEST_P(TlsConnectGenericResumption, ConnectWithExpiredTicketAtClient) {
}
TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtServer) {
SSLInt_SetTicketLifetime(1); // one second
// This causes a ticket resumption.
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Connect();
@ -373,7 +375,7 @@ TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtServer) {
EXPECT_TRUE(capture->captured());
EXPECT_LT(0U, capture->extension().len());
WAIT_(false, 1000); // Let the ticket expire on the server.
AdvanceTime(kLongerThanTicketLifetime);
Handshake();
CheckConnected();
@ -421,6 +423,7 @@ static int32_t SwitchCertificates(TlsAgent* agent, const SECItem* srvNameArr,
TEST_P(TlsConnectGeneric, ServerSNICertSwitch) {
Connect();
ScopedCERTCertificate cert1(SSL_PeerCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
Reset();
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
@ -429,6 +432,7 @@ TEST_P(TlsConnectGeneric, ServerSNICertSwitch) {
Connect();
ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
CheckKeys();
EXPECT_FALSE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
@ -437,6 +441,7 @@ TEST_P(TlsConnectGeneric, ServerSNICertTypeSwitch) {
Reset(TlsAgent::kServerEcdsa256);
Connect();
ScopedCERTCertificate cert1(SSL_PeerCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
Reset();
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
@ -447,6 +452,7 @@ TEST_P(TlsConnectGeneric, ServerSNICertTypeSwitch) {
Connect();
ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
@ -531,6 +537,7 @@ TEST_P(TlsConnectTls13, TestTls13ResumeNoCertificateRequest) {
Connect();
SendReceive(); // Need to read so that we absorb the session ticket.
ScopedCERTCertificate cert1(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@ -546,6 +553,7 @@ TEST_P(TlsConnectTls13, TestTls13ResumeNoCertificateRequest) {
// Sanity check whether the client certificate matches the one
// decrypted from ticket.
ScopedCERTCertificate cert2(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
@ -561,6 +569,7 @@ TEST_P(TlsConnectTls13, WriteBeforeHandshakeCompleteOnResumption) {
Connect();
SendReceive(); // Absorb the session ticket.
ScopedCERTCertificate cert1(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@ -577,6 +586,7 @@ TEST_P(TlsConnectTls13, WriteBeforeHandshakeCompleteOnResumption) {
// Check whether the client certificate matches the one from the ticket.
ScopedCERTCertificate cert2(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
@ -589,15 +599,17 @@ static uint16_t ChooseOneCipher(uint16_t version) {
return TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
}
static uint16_t ChooseAnotherCipher(uint16_t version) {
static uint16_t ChooseIncompatibleCipher(uint16_t version) {
if (version >= SSL_LIBRARY_VERSION_TLS_1_3) {
return TLS_AES_256_GCM_SHA384;
}
return TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
}
// Test that we don't resume when we can't negotiate the same cipher.
TEST_P(TlsConnectGenericResumption, TestResumeClientDifferentCipher) {
// Test that we don't resume when we can't negotiate the same cipher. Note that
// for TLS 1.3, resumption is allowed between compatible ciphers, that is those
// with the same KDF hash, but we choose an incompatible one here.
TEST_P(TlsConnectGenericResumption, ResumeClientIncompatibleCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
client_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
@ -607,7 +619,7 @@ TEST_P(TlsConnectGenericResumption, TestResumeClientDifferentCipher) {
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ExpectResumption(RESUME_NONE);
client_->EnableSingleCipher(ChooseAnotherCipher(version_));
client_->EnableSingleCipher(ChooseIncompatibleCipher(version_));
uint16_t ticket_extension;
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
ticket_extension = ssl_tls13_pre_shared_key_xtn;
@ -622,24 +634,24 @@ TEST_P(TlsConnectGenericResumption, TestResumeClientDifferentCipher) {
}
// Test that we don't resume when we can't negotiate the same cipher.
TEST_P(TlsConnectGenericResumption, TestResumeServerDifferentCipher) {
TEST_P(TlsConnectGenericResumption, ResumeServerIncompatibleCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
SendReceive(); // Need to read so that we absorb the session ticket.
SendReceive(); // Absorb the session ticket.
CheckKeys();
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ExpectResumption(RESUME_NONE);
server_->EnableSingleCipher(ChooseAnotherCipher(version_));
server_->EnableSingleCipher(ChooseIncompatibleCipher(version_));
Connect();
CheckKeys();
}
// Test that the client doesn't tolerate the server picking a different cipher
// suite for resumption.
TEST_P(TlsConnectStream, TestResumptionOverrideCipher) {
TEST_P(TlsConnectStream, ResumptionOverrideCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
@ -648,8 +660,8 @@ TEST_P(TlsConnectStream, TestResumptionOverrideCipher) {
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
MakeTlsFilter<SelectedCipherSuiteReplacer>(server_,
ChooseAnotherCipher(version_));
MakeTlsFilter<SelectedCipherSuiteReplacer>(
server_, ChooseIncompatibleCipher(version_));
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
@ -668,6 +680,38 @@ TEST_P(TlsConnectStream, TestResumptionOverrideCipher) {
}
}
// In TLS 1.3, it is possible to resume with a different cipher if it has the
// same hash.
TEST_P(TlsConnectTls13, ResumeClientCompatibleCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
client_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
Connect();
SendReceive(); // Absorb the session ticket.
CheckKeys();
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ExpectResumption(RESUME_TICKET);
client_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256);
Connect();
CheckKeys();
}
TEST_P(TlsConnectTls13, ResumeServerCompatibleCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
server_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
Connect();
SendReceive(); // Absorb the session ticket.
CheckKeys();
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ExpectResumption(RESUME_TICKET);
server_->EnableSingleCipher(TLS_CHACHA20_POLY1305_SHA256);
Connect();
CheckKeys();
}
class SelectedVersionReplacer : public TlsHandshakeFilter {
public:
SelectedVersionReplacer(const std::shared_ptr<TlsAgent>& a, uint16_t version)
@ -757,7 +801,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
ASSERT_LT(0U, initialTicket.len());
ScopedCERTCertificate cert1(SSL_PeerCertificate(client_->ssl_fd()));
ASSERT_TRUE(!!cert1.get());
ASSERT_NE(nullptr, cert1.get());
Reset();
ClearStats();
@ -773,7 +817,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
ASSERT_LT(0U, c2->extension().len());
ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
ASSERT_TRUE(!!cert2.get());
ASSERT_NE(nullptr, cert2.get());
// Check that the cipher suite is reported the same on both sides, though in
// TLS 1.3 resumption actually negotiates a different cipher suite.
@ -1109,7 +1153,7 @@ TEST_P(TlsConnectGenericResumption, ReConnectAgainTicket) {
ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
}
void CheckGetInfoResult(uint32_t alpnSize, uint32_t earlyDataSize,
void CheckGetInfoResult(PRTime now, uint32_t alpnSize, uint32_t earlyDataSize,
ScopedCERTCertificate& cert,
ScopedSSLResumptionTokenInfo& token) {
ASSERT_TRUE(cert);
@ -1125,7 +1169,7 @@ void CheckGetInfoResult(uint32_t alpnSize, uint32_t earlyDataSize,
ASSERT_EQ(earlyDataSize, token->maxEarlyDataSize);
ASSERT_LT(ssl_TimeUsec(), token->expirationTime);
ASSERT_LT(now, token->expirationTime);
}
// The client should generate a new, randomized session_id
@ -1174,8 +1218,9 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfo) {
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
ASSERT_NE(nullptr, cert.get());
CheckGetInfoResult(0, 0, cert, token);
CheckGetInfoResult(now(), 0, 0, cert, token);
Handshake();
CheckConnected();
@ -1183,6 +1228,56 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfo) {
SendReceive();
}
TEST_P(TlsConnectGenericResumptionToken, RefuseExpiredTicketClient) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
Connect();
SendReceive();
// Move the clock to the expiration time of the ticket.
SSLResumptionTokenInfo tokenInfo = {0};
ScopedSSLResumptionTokenInfo token(&tokenInfo);
client_->GetTokenInfo(token);
AdvanceTime(token->expirationTime - now());
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_TICKET);
StartConnect();
ASSERT_EQ(SECFailure,
SSL_SetResumptionToken(client_->ssl_fd(),
client_->GetResumptionToken().data(),
client_->GetResumptionToken().size()));
EXPECT_EQ(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR, PORT_GetError());
}
TEST_P(TlsConnectGenericResumptionToken, RefuseExpiredTicketServer) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
Connect();
SendReceive();
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_NONE);
// Start the handshake and send the ClientHello.
StartConnect();
ASSERT_EQ(SECSuccess,
SSL_SetResumptionToken(client_->ssl_fd(),
client_->GetResumptionToken().data(),
client_->GetResumptionToken().size()));
client_->Handshake();
// Move the clock to the expiration time of the ticket.
SSLResumptionTokenInfo tokenInfo = {0};
ScopedSSLResumptionTokenInfo token(&tokenInfo);
client_->GetTokenInfo(token);
AdvanceTime(token->expirationTime - now());
Handshake();
CheckConnected();
}
TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
EnableAlpn();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
@ -1204,8 +1299,9 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
ASSERT_NE(nullptr, cert.get());
CheckGetInfoResult(1, 0, cert, token);
CheckGetInfoResult(now(), 1, 0, cert, token);
Handshake();
CheckConnected();
@ -1216,7 +1312,7 @@ TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
TEST_P(TlsConnectTls13ResumptionToken, ConnectResumeGetInfoZeroRtt) {
EnableAlpn();
SSLInt_RolloverAntiReplay();
RolloverAntiReplay();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->Set0RttEnabled(true);
Connect();
@ -1239,8 +1335,8 @@ TEST_P(TlsConnectTls13ResumptionToken, ConnectResumeGetInfoZeroRtt) {
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
CheckGetInfoResult(1, 1024, cert, token);
ASSERT_NE(nullptr, cert.get());
CheckGetInfoResult(now(), 1, 1024, cert, token);
ZeroRttSendReceive(true, true);
Handshake();
@ -1272,6 +1368,54 @@ TEST_P(TlsConnectGenericResumption, ConnectResumeClientAuth) {
SendReceive();
}
// Check that resumption is blocked if the server requires client auth.
TEST_P(TlsConnectGenericResumption, ClientAuthRequiredOnResumption) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->RequestClientAuth(false);
Connect();
SendReceive();
Reset();
client_->SetupClientAuth();
server_->RequestClientAuth(true);
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_NONE);
Connect();
SendReceive();
}
// Check that resumption is blocked if the server requires client auth and
// the client fails to provide a certificate.
TEST_P(TlsConnectGenericResumption, ClientAuthRequiredOnResumptionNoCert) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->RequestClientAuth(false);
Connect();
SendReceive();
Reset();
server_->RequestClientAuth(true);
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
// Drive handshake manually because TLS 1.3 needs it.
StartConnect();
client_->Handshake(); // CH
server_->Handshake(); // SH.. (no resumption)
client_->Handshake(); // ...
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
// In TLS 1.3, the client thinks that everything is OK here.
ASSERT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
ExpectAlert(server_, kTlsAlertCertificateRequired);
server_->Handshake(); // Alert
client_->Handshake(); // Receive Alert
client_->CheckErrorCode(SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT);
} else {
ExpectAlert(server_, kTlsAlertBadCertificate);
server_->Handshake(); // Alert
client_->Handshake(); // Receive Alert
client_->CheckErrorCode(SSL_ERROR_BAD_CERT_ALERT);
}
server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
}
TEST_F(TlsConnectStreamTls13, ExternalTokenAfterHrr) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
Connect();

View file

@ -55,6 +55,10 @@ TEST_P(TlsConnectGeneric, ServerNegotiateTls12) {
// two validate that we can also detect fallback using the
// SSL_SetDowngradeCheckVersion() API.
TEST_F(TlsConnectTest, TestDowngradeDetectionToTls11) {
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
SSL_LIBRARY_VERSION_TLS_1_2);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
SSL_LIBRARY_VERSION_TLS_1_2);
client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
MakeTlsFilter<TlsClientHelloVersionSetter>(client_,
SSL_LIBRARY_VERSION_TLS_1_1);
@ -116,11 +120,11 @@ TEST_F(TlsConnectTest, TestDowngradeDetectionToTls10) {
TEST_F(TlsConnectTest, TestFallbackFromTls12) {
client_->SetOption(SSL_ENABLE_HELLO_DOWNGRADE_CHECK, PR_TRUE);
client_->SetDowngradeCheckVersion(SSL_LIBRARY_VERSION_TLS_1_2);
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
SSL_LIBRARY_VERSION_TLS_1_1);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
SSL_LIBRARY_VERSION_TLS_1_2);
client_->SetDowngradeCheckVersion(SSL_LIBRARY_VERSION_TLS_1_2);
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);

View file

@ -47,6 +47,8 @@ const std::string TlsAgent::kServerEcdsa521 = "ecdsa521";
const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa";
const std::string TlsAgent::kServerEcdhEcdsa = "ecdh_ecdsa";
const std::string TlsAgent::kServerDsa = "dsa";
const std::string TlsAgent::kDelegatorEcdsa256 = "delegator_ecdsa256";
const std::string TlsAgent::kDelegatorRsae2048 = "delegator_rsae2048";
static const uint8_t kCannedTls13ServerHello[] = {
0x03, 0x03, 0x9c, 0xbc, 0x14, 0x9b, 0x0e, 0x2e, 0xfa, 0x0d, 0xf3,
@ -127,16 +129,76 @@ void TlsAgent::SetState(State s) {
ScopedCERTCertificate* cert,
ScopedSECKEYPrivateKey* priv) {
cert->reset(PK11_FindCertFromNickname(name.c_str(), nullptr));
EXPECT_NE(nullptr, cert);
if (!cert) return false;
EXPECT_NE(nullptr, cert->get());
if (!cert->get()) return false;
priv->reset(PK11_FindKeyByAnyCert(cert->get(), nullptr));
EXPECT_NE(nullptr, priv);
if (!priv) return false;
EXPECT_NE(nullptr, priv->get());
if (!priv->get()) return false;
return true;
}
// Loads a key pair from the certificate identified by |id|.
/*static*/ bool TlsAgent::LoadKeyPairFromCert(const std::string& name,
ScopedSECKEYPublicKey* pub,
ScopedSECKEYPrivateKey* priv) {
ScopedCERTCertificate cert;
if (!TlsAgent::LoadCertificate(name, &cert, priv)) {
return false;
}
pub->reset(SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo));
if (!pub->get()) {
return false;
}
return true;
}
void TlsAgent::DelegateCredential(const std::string& name,
const ScopedSECKEYPublicKey& dc_pub,
SSLSignatureScheme dc_cert_verify_alg,
PRUint32 dc_valid_for, PRTime now,
SECItem* dc) {
ScopedCERTCertificate cert;
ScopedSECKEYPrivateKey cert_priv;
EXPECT_TRUE(TlsAgent::LoadCertificate(name, &cert, &cert_priv))
<< "Could not load delegate certificate: " << name
<< "; test db corrupt?";
EXPECT_EQ(SECSuccess,
SSL_DelegateCredential(cert.get(), cert_priv.get(), dc_pub.get(),
dc_cert_verify_alg, dc_valid_for, now, dc));
}
void TlsAgent::EnableDelegatedCredentials() {
ASSERT_TRUE(EnsureTlsSetup());
SetOption(SSL_ENABLE_DELEGATED_CREDENTIALS, PR_TRUE);
}
void TlsAgent::AddDelegatedCredential(const std::string& dc_name,
SSLSignatureScheme dc_cert_verify_alg,
PRUint32 dc_valid_for, PRTime now) {
ASSERT_TRUE(EnsureTlsSetup());
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(dc_name, &pub, &priv));
StackSECItem dc;
TlsAgent::DelegateCredential(name_, pub, dc_cert_verify_alg, dc_valid_for,
now, &dc);
SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
nullptr, &dc, priv.get()};
EXPECT_TRUE(ConfigServerCert(name_, true, &extra_data));
}
bool TlsAgent::ConfigServerCert(const std::string& id, bool updateKeyBits,
const SSLExtraServerCertData* serverCertData) {
ScopedCERTCertificate cert;
@ -224,6 +286,9 @@ bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) {
EXPECT_EQ(SECSuccess, rv);
if (rv != SECSuccess) return false;
// All these tests depend on having this disabled to start with.
SetOption(SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_FALSE);
return true;
}
@ -251,6 +316,10 @@ bool TlsAgent::MaybeSetResumptionToken() {
return true;
}
void TlsAgent::SetAntiReplayContext(ScopedSSLAntiReplayContext& ctx) {
EXPECT_EQ(SECSuccess, SSL_SetAntiReplayContext(ssl_fd_.get(), ctx.get()));
}
void TlsAgent::SetupClientAuth() {
EXPECT_TRUE(EnsureTlsSetup());
ASSERT_EQ(CLIENT, role_);
@ -279,7 +348,7 @@ SECStatus TlsAgent::GetClientAuthDataHook(void* self, PRFileDesc* fd,
ScopedCERTCertificate peerCert(SSL_PeerCertificate(agent->ssl_fd()));
EXPECT_TRUE(peerCert) << "Client should be able to see the server cert";
// See bug 1457716
// See bug 1573945
// CheckCertReqAgainstDefaultCAs(caNames);
ScopedCERTCertificate cert;
@ -725,26 +794,26 @@ void TlsAgent::WaitForErrorCode(int32_t expected, uint32_t delay) const {
}
void TlsAgent::CheckPreliminaryInfo() {
SSLPreliminaryChannelInfo info;
SSLPreliminaryChannelInfo preinfo;
EXPECT_EQ(SECSuccess,
SSL_GetPreliminaryChannelInfo(ssl_fd(), &info, sizeof(info)));
EXPECT_EQ(sizeof(info), info.length);
EXPECT_TRUE(info.valuesSet & ssl_preinfo_version);
EXPECT_TRUE(info.valuesSet & ssl_preinfo_cipher_suite);
SSL_GetPreliminaryChannelInfo(ssl_fd(), &preinfo, sizeof(preinfo)));
EXPECT_EQ(sizeof(preinfo), preinfo.length);
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_version);
EXPECT_TRUE(preinfo.valuesSet & ssl_preinfo_cipher_suite);
// A version of 0 is invalid and indicates no expectation. This value is
// initialized to 0 so that tests that don't explicitly set an expected
// version can negotiate a version.
if (!expected_version_) {
expected_version_ = info.protocolVersion;
expected_version_ = preinfo.protocolVersion;
}
EXPECT_EQ(expected_version_, info.protocolVersion);
EXPECT_EQ(expected_version_, preinfo.protocolVersion);
// As with the version; 0 is the null cipher suite (and also invalid).
if (!expected_cipher_suite_) {
expected_cipher_suite_ = info.cipherSuite;
expected_cipher_suite_ = preinfo.cipherSuite;
}
EXPECT_EQ(expected_cipher_suite_, info.cipherSuite);
EXPECT_EQ(expected_cipher_suite_, preinfo.cipherSuite);
}
// Check that all the expected callbacks have been called.
@ -776,6 +845,13 @@ void TlsAgent::ResetPreliminaryInfo() {
expected_cipher_suite_ = 0;
}
void TlsAgent::UpdatePreliminaryChannelInfo() {
SECStatus rv = SSL_GetPreliminaryChannelInfo(ssl_fd_.get(), &pre_info_,
sizeof(pre_info_));
EXPECT_EQ(SECSuccess, rv);
EXPECT_EQ(sizeof(pre_info_), pre_info_.length);
}
void TlsAgent::ValidateCipherSpecs() {
PRInt32 cipherSpecs = SSLInt_CountCipherSpecs(ssl_fd());
// We use one ciphersuite in each direction.
@ -838,6 +914,7 @@ void TlsAgent::Connected() {
// Preliminary values are exposed through callbacks during the handshake.
// If either expected values were set or the callbacks were called, check
// that the final values are correct.
UpdatePreliminaryChannelInfo();
EXPECT_EQ(expected_version_, info_.protocolVersion);
EXPECT_EQ(expected_cipher_suite_, info_.cipherSuite);

View file

@ -76,6 +76,8 @@ class TlsAgent : public PollTarget {
static const std::string kServerEcdhEcdsa;
static const std::string kServerEcdhRsa;
static const std::string kServerDsa;
static const std::string kDelegatorEcdsa256; // draft-ietf-tls-subcerts
static const std::string kDelegatorRsae2048; // draft-ietf-tls-subcerts
TlsAgent(const std::string& name, Role role, SSLProtocolVariant variant);
virtual ~TlsAgent();
@ -108,9 +110,32 @@ class TlsAgent : public PollTarget {
void PrepareForRenegotiate();
// Prepares for renegotiation, then actually triggers it.
void StartRenegotiate();
void SetAntiReplayContext(ScopedSSLAntiReplayContext& ctx);
static bool LoadCertificate(const std::string& name,
ScopedCERTCertificate* cert,
ScopedSECKEYPrivateKey* priv);
static bool LoadKeyPairFromCert(const std::string& name,
ScopedSECKEYPublicKey* pub,
ScopedSECKEYPrivateKey* priv);
// Delegated credentials.
//
// Generate a delegated credential and sign it using the certificate
// associated with |name|.
static void DelegateCredential(const std::string& name,
const ScopedSECKEYPublicKey& dcPub,
SSLSignatureScheme dcCertVerifyAlg,
PRUint32 dcValidFor, PRTime now, SECItem* dc);
// Indicate support for the delegated credentials extension.
void EnableDelegatedCredentials();
// Generate and configure a delegated credential to use in the handshake with
// clients that support this extension..
void AddDelegatedCredential(const std::string& dc_name,
SSLSignatureScheme dcCertVerifyAlg,
PRUint32 dcValidFor, PRTime now);
void UpdatePreliminaryChannelInfo();
bool ConfigServerCert(const std::string& name, bool updateKeyBits = false,
const SSLExtraServerCertData* serverCertData = nullptr);
bool ConfigServerCertWithChain(const std::string& name);
@ -200,16 +225,20 @@ class TlsAgent : public PollTarget {
PRFileDesc* ssl_fd() const { return ssl_fd_.get(); }
std::shared_ptr<DummyPrSocket>& adapter() { return adapter_; }
const SSLChannelInfo& info() const {
EXPECT_EQ(STATE_CONNECTED, state_);
return info_;
}
const SSLPreliminaryChannelInfo& pre_info() const { return pre_info_; }
bool is_compressed() const {
return info_.compressionMethod != ssl_compression_null;
return info().compressionMethod != ssl_compression_null;
}
uint16_t server_key_bits() const { return server_key_bits_; }
uint16_t min_version() const { return vrange_.min; }
uint16_t max_version() const { return vrange_.max; }
uint16_t version() const {
EXPECT_EQ(STATE_CONNECTED, state_);
return info_.protocolVersion;
}
uint16_t version() const { return info().protocolVersion; }
bool cipher_suite(uint16_t* suite) const {
if (state_ != STATE_CONNECTED) return false;
@ -400,6 +429,7 @@ class TlsAgent : public PollTarget {
bool handshake_callback_called_;
bool resumption_callback_called_;
SSLChannelInfo info_;
SSLPreliminaryChannelInfo pre_info_;
SSLCipherSuiteInfo csinfo_;
SSLVersionRange vrange_;
PRErrorCode error_code_;

View file

@ -106,6 +106,10 @@ std::string VersionString(uint16_t version) {
}
}
// The default anti-replay window for tests. Tests that rely on a different
// value call SSL_InitAntiReplay directly.
static PRTime kAntiReplayWindow = 100 * PR_USEC_PER_SEC;
TlsConnectTestBase::TlsConnectTestBase(SSLProtocolVariant variant,
uint16_t version)
: variant_(variant),
@ -203,11 +207,15 @@ void TlsConnectTestBase::RestoreAlgorithmPolicy() {
}
}
PRTime TlsConnectTestBase::TimeFunc(void* arg) {
return *reinterpret_cast<PRTime*>(arg);
}
void TlsConnectTestBase::SetUp() {
SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
SSLInt_ClearSelfEncryptKey();
SSLInt_SetTicketLifetime(30);
SSL_SetupAntiReplay(1 * PR_USEC_PER_SEC, 1, 3);
now_ = PR_Now();
ResetAntiReplay(kAntiReplayWindow);
ClearStats();
SaveAlgorithmPolicy();
Init();
@ -232,6 +240,14 @@ void TlsConnectTestBase::Init() {
}
}
void TlsConnectTestBase::ResetAntiReplay(PRTime window) {
SSLAntiReplayContext* p_anti_replay = nullptr;
EXPECT_EQ(SECSuccess,
SSL_CreateAntiReplayContext(now_, window, 1, 3, &p_anti_replay));
EXPECT_NE(nullptr, p_anti_replay);
anti_replay_.reset(p_anti_replay);
}
void TlsConnectTestBase::Reset() {
// Take a copy of the names because they are about to disappear.
std::string server_name = server_->name();
@ -250,7 +266,8 @@ void TlsConnectTestBase::Reset(const std::string& server_name,
server_->SkipVersionChecks();
}
std::cerr << "Reset" << std::endl;
std::cerr << "Reset server:" << server_name << ", client:" << client_name
<< std::endl;
Init();
}
@ -282,10 +299,14 @@ void TlsConnectTestBase::EnsureTlsSetup() {
: nullptr));
EXPECT_TRUE(client_->EnsureTlsSetup(client_model_ ? client_model_->ssl_fd()
: nullptr));
server_->SetAntiReplayContext(anti_replay_);
EXPECT_EQ(SECSuccess, SSL_SetTimeFunc(client_->ssl_fd(),
TlsConnectTestBase::TimeFunc, &now_));
EXPECT_EQ(SECSuccess, SSL_SetTimeFunc(server_->ssl_fd(),
TlsConnectTestBase::TimeFunc, &now_));
}
void TlsConnectTestBase::Handshake() {
EnsureTlsSetup();
client_->SetServerKeyBits(server_->server_key_bits());
client_->Handshake();
server_->Handshake();
@ -302,16 +323,16 @@ void TlsConnectTestBase::EnableExtendedMasterSecret() {
}
void TlsConnectTestBase::Connect() {
server_->StartConnect(server_model_ ? server_model_->ssl_fd() : nullptr);
client_->StartConnect(client_model_ ? client_model_->ssl_fd() : nullptr);
StartConnect();
client_->MaybeSetResumptionToken();
Handshake();
CheckConnected();
}
void TlsConnectTestBase::StartConnect() {
server_->StartConnect(server_model_ ? server_model_->ssl_fd() : nullptr);
client_->StartConnect(client_model_ ? client_model_->ssl_fd() : nullptr);
EnsureTlsSetup();
server_->StartConnect();
client_->StartConnect();
}
void TlsConnectTestBase::ConnectWithCipherSuite(uint16_t cipher_suite) {
@ -679,8 +700,9 @@ void TlsConnectTestBase::SendReceive(size_t total) {
// Do a first connection so we can do 0-RTT on the second one.
void TlsConnectTestBase::SetupForZeroRtt() {
// Force rollover of the anti-replay window.
// If we don't do this, then all 0-RTT attempts will be rejected.
SSLInt_RolloverAntiReplay();
RolloverAntiReplay();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
@ -792,12 +814,20 @@ void TlsConnectTestBase::ShiftDtlsTimers() {
time_shift = time;
}
if (time_shift == PR_INTERVAL_NO_TIMEOUT) {
return;
if (time_shift != PR_INTERVAL_NO_TIMEOUT) {
AdvanceTime(PR_IntervalToMicroseconds(time_shift));
EXPECT_EQ(SECSuccess,
SSLInt_ShiftDtlsTimers(client_->ssl_fd(), time_shift));
EXPECT_EQ(SECSuccess,
SSLInt_ShiftDtlsTimers(server_->ssl_fd(), time_shift));
}
}
EXPECT_EQ(SECSuccess, SSLInt_ShiftDtlsTimers(client_->ssl_fd(), time_shift));
EXPECT_EQ(SECSuccess, SSLInt_ShiftDtlsTimers(server_->ssl_fd(), time_shift));
void TlsConnectTestBase::AdvanceTime(PRTime time_shift) { now_ += time_shift; }
// Advance time by a full anti-replay window.
void TlsConnectTestBase::RolloverAntiReplay() {
AdvanceTime(kAntiReplayWindow);
}
TlsConnectGeneric::TlsConnectGeneric()

View file

@ -48,6 +48,8 @@ class TlsConnectTestBase : public ::testing::Test {
virtual void SetUp();
virtual void TearDown();
PRTime now() const { return now_; }
// Initialize client and server.
void Init();
// Clear the statistics.
@ -131,6 +133,10 @@ class TlsConnectTestBase : public ::testing::Test {
// Move the DTLS timers for both endpoints to pop the next timer.
void ShiftDtlsTimers();
void AdvanceTime(PRTime time_shift);
void ResetAntiReplay(PRTime window);
void RolloverAntiReplay();
void SaveAlgorithmPolicy();
void RestoreAlgorithmPolicy();
@ -145,6 +151,7 @@ class TlsConnectTestBase : public ::testing::Test {
SessionResumptionMode expected_resumption_mode_;
uint8_t expected_resumptions_;
std::vector<std::vector<uint8_t>> session_ids_;
ScopedSSLAntiReplayContext anti_replay_;
// A simple value of "a", "b". Note that the preferred value of "a" is placed
// at the end, because the NSS API follows the now defunct NPN specification,
@ -157,17 +164,19 @@ class TlsConnectTestBase : public ::testing::Test {
// ssl_extension_unittest.cc.
const std::vector<SECOidTag> algorithms_ = {SEC_OID_APPLY_SSL_POLICY,
SEC_OID_ANSIX9_DSA_SIGNATURE,
SEC_OID_CURVE25519};
SEC_OID_CURVE25519, SEC_OID_SHA1};
std::vector<std::tuple<SECOidTag, uint32_t>> saved_policies_;
private:
void CheckResumption(SessionResumptionMode expected);
void CheckExtendedMasterSecret();
void CheckEarlyDataAccepted();
static PRTime TimeFunc(void* arg);
bool expect_extended_master_secret_;
bool expect_early_data_accepted_;
bool skip_version_checks_;
PRTime now_;
// Track groups and make sure that there are no duplicates.
class DuplicateGroupChecker {

View file

@ -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/. */
#include <ctime>
#include "secerr.h"
#include "ssl.h"
@ -57,7 +55,7 @@ static void UpdateEsniKeysChecksum(DataBuffer* buf) {
buf->Write(2, sha256, 4);
}
static void GenerateEsniKey(time_t windowStart, SSLNamedGroup group,
static void GenerateEsniKey(PRTime now, SSLNamedGroup group,
std::vector<uint16_t>& cipher_suites,
DataBuffer* record,
ScopedSECKEYPublicKey* pubKey = nullptr,
@ -73,8 +71,9 @@ static void GenerateEsniKey(time_t windowStart, SSLNamedGroup group,
unsigned int encoded_len = 0;
SECStatus rv = SSL_EncodeESNIKeys(
&cipher_suites[0], cipher_suites.size(), group, pub, 100, windowStart,
windowStart + 10, encoded, &encoded_len, sizeof(encoded));
&cipher_suites[0], cipher_suites.size(), group, pub, 100,
(now / PR_USEC_PER_SEC) - 1, (now / PR_USEC_PER_SEC) + 10, encoded,
&encoded_len, sizeof(encoded));
ASSERT_EQ(SECSuccess, rv);
ASSERT_GT(encoded_len, 0U);
@ -92,15 +91,15 @@ static void GenerateEsniKey(time_t windowStart, SSLNamedGroup group,
record->Write(0, encoded, encoded_len);
}
static void SetupEsni(const std::shared_ptr<TlsAgent>& client,
static void SetupEsni(PRTime now, const std::shared_ptr<TlsAgent>& client,
const std::shared_ptr<TlsAgent>& server,
SSLNamedGroup group = ssl_grp_ec_curve25519) {
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
DataBuffer record;
GenerateEsniKey(time(nullptr), ssl_grp_ec_curve25519, kDefaultSuites, &record,
&pub, &priv);
GenerateEsniKey(now, ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
&priv);
SECStatus rv = SSL_SetESNIKeyPair(server->ssl_fd(), priv.get(), record.data(),
record.len());
ASSERT_EQ(SECSuccess, rv);
@ -124,77 +123,87 @@ static void CheckSniExtension(const DataBuffer& data) {
ASSERT_EQ(expected, name);
}
static void ClientInstallEsni(std::shared_ptr<TlsAgent>& agent,
const DataBuffer& record, PRErrorCode err = 0) {
SECStatus rv =
SSL_EnableESNI(agent->ssl_fd(), record.data(), record.len(), kDummySni);
if (err == 0) {
ASSERT_EQ(SECSuccess, rv);
} else {
ASSERT_EQ(SECFailure, rv);
ASSERT_EQ(err, PORT_GetError());
}
}
class TlsAgentEsniTest : public TlsAgentTestClient13 {
public:
void SetUp() override { now_ = PR_Now(); }
TEST_P(TlsAgentTestClient13, EsniInstall) {
protected:
PRTime now() const { return now_; }
void InstallEsni(const DataBuffer& record, PRErrorCode err = 0) {
SECStatus rv = SSL_EnableESNI(agent_->ssl_fd(), record.data(), record.len(),
kDummySni);
if (err == 0) {
ASSERT_EQ(SECSuccess, rv);
} else {
ASSERT_EQ(SECFailure, rv);
ASSERT_EQ(err, PORT_GetError());
}
}
private:
PRTime now_ = 0;
};
TEST_P(TlsAgentEsniTest, EsniInstall) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
ClientInstallEsni(agent_, record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
InstallEsni(record);
}
// The next set of tests fail at setup time.
TEST_P(TlsAgentTestClient13, EsniInvalidHash) {
TEST_P(TlsAgentEsniTest, EsniInvalidHash) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.data()[2]++;
ClientInstallEsni(agent_, record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
}
TEST_P(TlsAgentTestClient13, EsniInvalidVersion) {
TEST_P(TlsAgentEsniTest, EsniInvalidVersion) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.Write(0, 0xffff, 2);
ClientInstallEsni(agent_, record, SSL_ERROR_UNSUPPORTED_VERSION);
InstallEsni(record, SSL_ERROR_UNSUPPORTED_VERSION);
}
TEST_P(TlsAgentTestClient13, EsniShort) {
TEST_P(TlsAgentEsniTest, EsniShort) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.Truncate(record.len() - 1);
UpdateEsniKeysChecksum(&record);
ClientInstallEsni(agent_, record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
}
TEST_P(TlsAgentTestClient13, EsniLong) {
TEST_P(TlsAgentEsniTest, EsniLong) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.Write(record.len(), 1, 1);
UpdateEsniKeysChecksum(&record);
ClientInstallEsni(agent_, record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
}
TEST_P(TlsAgentTestClient13, EsniExtensionMismatch) {
TEST_P(TlsAgentEsniTest, EsniExtensionMismatch) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.Write(record.len() - 1, 1, 1);
UpdateEsniKeysChecksum(&record);
ClientInstallEsni(agent_, record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
InstallEsni(record, SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
}
// The following tests fail by ignoring the Esni block.
TEST_P(TlsAgentTestClient13, EsniUnknownGroup) {
TEST_P(TlsAgentEsniTest, EsniUnknownGroup) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
record.Write(8, 0xffff, 2); // Fake group
UpdateEsniKeysChecksum(&record);
ClientInstallEsni(agent_, record, 0);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
@ -202,11 +211,11 @@ TEST_P(TlsAgentTestClient13, EsniUnknownGroup) {
ASSERT_TRUE(!filter->captured());
}
TEST_P(TlsAgentTestClient13, EsniUnknownCS) {
TEST_P(TlsAgentEsniTest, EsniUnknownCS) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kBogusSuites, &record);
ClientInstallEsni(agent_, record, 0);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kBogusSuites, &record);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
@ -214,12 +223,12 @@ TEST_P(TlsAgentTestClient13, EsniUnknownCS) {
ASSERT_TRUE(!filter->captured());
}
TEST_P(TlsAgentTestClient13, EsniInvalidCS) {
TEST_P(TlsAgentEsniTest, EsniInvalidCS) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kTls12Suites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kTls12Suites, &record);
UpdateEsniKeysChecksum(&record);
ClientInstallEsni(agent_, record, 0);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
@ -227,36 +236,34 @@ TEST_P(TlsAgentTestClient13, EsniInvalidCS) {
ASSERT_TRUE(!filter->captured());
}
TEST_P(TlsAgentTestClient13, EsniNotReady) {
TEST_P(TlsAgentEsniTest, EsniNotReady) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0) + 1000, ssl_grp_ec_curve25519, kDefaultSuites,
&record);
ClientInstallEsni(agent_, record, 0);
GenerateEsniKey(now() + 1000, ssl_grp_ec_curve25519, kDefaultSuites, &record);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
ASSERT_TRUE(!filter->captured());
}
TEST_P(TlsAgentTestClient13, EsniExpired) {
TEST_P(TlsAgentEsniTest, EsniExpired) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0) - 1000, ssl_grp_ec_curve25519, kDefaultSuites,
&record);
ClientInstallEsni(agent_, record, 0);
GenerateEsniKey(now() - 1000, ssl_grp_ec_curve25519, kDefaultSuites, &record);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
ASSERT_TRUE(!filter->captured());
}
TEST_P(TlsAgentTestClient13, NoSniSoNoEsni) {
TEST_P(TlsAgentEsniTest, NoSniSoNoEsni) {
EnsureInit();
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
SSL_SetURL(agent_->ssl_fd(), "");
ClientInstallEsni(agent_, record, 0);
InstallEsni(record, 0);
auto filter =
MakeTlsFilter<TlsExtensionCapture>(agent_, ssl_tls13_encrypted_sni_xtn);
agent_->Handshake();
@ -275,7 +282,7 @@ static int32_t SniCallback(TlsAgent* agent, const SECItem* srvNameAddr,
TEST_P(TlsConnectTls13, ConnectEsni) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
auto cFilterSni =
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn);
auto cFilterEsni =
@ -300,7 +307,7 @@ TEST_P(TlsConnectTls13, ConnectEsniHrr) {
EnsureTlsSetup();
const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
server_->ConfigNamedGroups(groups);
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
auto hrr_capture = MakeTlsFilter<TlsHandshakeRecorder>(
server_, kTlsHandshakeHelloRetryRequest);
auto filter =
@ -322,8 +329,8 @@ TEST_P(TlsConnectTls13, ConnectEsniNoDummy) {
ScopedSECKEYPrivateKey priv;
DataBuffer record;
GenerateEsniKey(time(nullptr), ssl_grp_ec_curve25519, kDefaultSuites, &record,
&pub, &priv);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
&priv);
SECStatus rv = SSL_SetESNIKeyPair(server_->ssl_fd(), priv.get(),
record.data(), record.len());
ASSERT_EQ(SECSuccess, rv);
@ -346,8 +353,8 @@ TEST_P(TlsConnectTls13, ConnectEsniNullDummy) {
ScopedSECKEYPrivateKey priv;
DataBuffer record;
GenerateEsniKey(time(nullptr), ssl_grp_ec_curve25519, kDefaultSuites, &record,
&pub, &priv);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
&priv);
SECStatus rv = SSL_SetESNIKeyPair(server_->ssl_fd(), priv.get(),
record.data(), record.len());
ASSERT_EQ(SECSuccess, rv);
@ -372,14 +379,15 @@ TEST_P(TlsConnectTls13, ConnectEsniCSMismatch) {
ScopedSECKEYPrivateKey priv;
DataBuffer record;
GenerateEsniKey(time(nullptr), ssl_grp_ec_curve25519, kDefaultSuites, &record,
&pub, &priv);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record, &pub,
&priv);
PRUint8 encoded[1024];
unsigned int encoded_len = 0;
SECStatus rv = SSL_EncodeESNIKeys(
&kChaChaSuite[0], kChaChaSuite.size(), ssl_grp_ec_curve25519, pub.get(),
100, time(0), time(0) + 10, encoded, &encoded_len, sizeof(encoded));
100, (now() / PR_USEC_PER_SEC) - 1, (now() / PR_USEC_PER_SEC) + 10,
encoded, &encoded_len, sizeof(encoded));
ASSERT_EQ(SECSuccess, rv);
ASSERT_LT(0U, encoded_len);
rv = SSL_SetESNIKeyPair(server_->ssl_fd(), priv.get(), encoded, encoded_len);
@ -392,7 +400,7 @@ TEST_P(TlsConnectTls13, ConnectEsniCSMismatch) {
TEST_P(TlsConnectTls13, ConnectEsniP256) {
EnsureTlsSetup();
SetupEsni(client_, server_, ssl_grp_ec_secp256r1);
SetupEsni(now(), client_, server_, ssl_grp_ec_secp256r1);
auto cfilter =
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_server_name_xtn);
auto sfilter =
@ -405,18 +413,21 @@ TEST_P(TlsConnectTls13, ConnectEsniP256) {
TEST_P(TlsConnectTls13, ConnectMismatchedEsniKeys) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
// Now install a new set of keys on the client, so we have a mismatch.
DataBuffer record;
GenerateEsniKey(time(0), ssl_grp_ec_curve25519, kDefaultSuites, &record);
ClientInstallEsni(client_, record, 0);
GenerateEsniKey(now(), ssl_grp_ec_curve25519, kDefaultSuites, &record);
SECStatus rv =
SSL_EnableESNI(client_->ssl_fd(), record.data(), record.len(), kDummySni);
ASSERT_EQ(SECSuccess, rv);
ConnectExpectAlert(server_, illegal_parameter);
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
}
TEST_P(TlsConnectTls13, ConnectDamagedEsniExtensionCH) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
auto filter = MakeTlsFilter<TlsExtensionDamager>(
client_, ssl_tls13_encrypted_sni_xtn, 50); // in the ciphertext
ConnectExpectAlert(server_, illegal_parameter);
@ -425,7 +436,7 @@ TEST_P(TlsConnectTls13, ConnectDamagedEsniExtensionCH) {
TEST_P(TlsConnectTls13, ConnectRemoveEsniExtensionEE) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
auto filter =
MakeTlsFilter<TlsExtensionDropper>(server_, ssl_tls13_encrypted_sni_xtn);
filter->EnableDecryption();
@ -435,7 +446,7 @@ TEST_P(TlsConnectTls13, ConnectRemoveEsniExtensionEE) {
TEST_P(TlsConnectTls13, ConnectShortEsniExtensionEE) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
DataBuffer shortNonce;
auto filter = MakeTlsFilter<TlsExtensionReplacer>(
server_, ssl_tls13_encrypted_sni_xtn, shortNonce);
@ -446,7 +457,7 @@ TEST_P(TlsConnectTls13, ConnectShortEsniExtensionEE) {
TEST_P(TlsConnectTls13, ConnectBogusEsniExtensionEE) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
const uint8_t bogusNonceBuf[16] = {0};
DataBuffer bogusNonce(bogusNonceBuf, sizeof(bogusNonceBuf));
auto filter = MakeTlsFilter<TlsExtensionReplacer>(
@ -461,7 +472,7 @@ TEST_P(TlsConnectTls13, ConnectBogusEsniExtensionEE) {
// The client then aborts when it sees the server did TLS 1.2.
TEST_P(TlsConnectTls13, EsniButTLS12Server) {
EnsureTlsSetup();
SetupEsni(client_, server_);
SetupEsni(now(), client_, server_);
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
@ -472,4 +483,4 @@ TEST_P(TlsConnectTls13, EsniButTLS12Server) {
ASSERT_FALSE(SSLInt_ExtensionNegotiated(server_->ssl_fd(),
ssl_tls13_encrypted_sni_xtn));
}
}
} // namespace nss_test

View file

@ -441,6 +441,80 @@ class TlsExtensionDropper : public TlsExtensionFilter {
uint16_t extension_;
};
class TlsHandshakeDropper : public TlsHandshakeFilter {
public:
TlsHandshakeDropper(const std::shared_ptr<TlsAgent>& a)
: TlsHandshakeFilter(a) {}
protected:
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) override {
return DROP;
}
};
class TlsEncryptedHandshakeMessageReplacer : public TlsRecordFilter {
public:
TlsEncryptedHandshakeMessageReplacer(const std::shared_ptr<TlsAgent>& a,
uint8_t old_ct, uint8_t new_ct)
: TlsRecordFilter(a), old_ct_(old_ct), new_ct_(new_ct) {}
protected:
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& record, size_t* offset,
DataBuffer* output) override {
if (header.content_type() != ssl_ct_application_data) {
return KEEP;
}
uint16_t protection_epoch = 0;
uint8_t inner_content_type;
DataBuffer plaintext;
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
&plaintext) ||
!plaintext.len()) {
return KEEP;
}
if (inner_content_type != ssl_ct_handshake) {
return KEEP;
}
size_t off = 0;
uint32_t msg_len = 0;
uint32_t msg_type = 255; // Not a real message
do {
if (!plaintext.Read(off, 1, &msg_type) || msg_type == old_ct_) {
break;
}
// Increment and check next messages
if (!plaintext.Read(++off, 3, &msg_len)) {
break;
}
off += 3 + msg_len;
} while (msg_type != old_ct_);
if (msg_type == old_ct_) {
plaintext.Write(off, new_ct_, 1);
}
DataBuffer ciphertext;
bool ok = Protect(spec(protection_epoch), header, inner_content_type,
plaintext, &ciphertext, 0);
if (!ok) {
return KEEP;
}
*offset = header.Write(output, *offset, ciphertext);
return CHANGE;
}
private:
uint8_t old_ct_;
uint8_t new_ct_;
};
class TlsExtensionInjector : public TlsHandshakeFilter {
public:
TlsExtensionInjector(const std::shared_ptr<TlsAgent>& a, uint16_t ext,

View file

@ -0,0 +1,568 @@
/* -*- 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 <ctime>
#include "prtime.h"
#include "secerr.h"
#include "ssl.h"
#include "gtest_utils.h"
#include "tls_agent.h"
#include "tls_connect.h"
namespace nss_test {
const std::string kEcdsaDelegatorId = TlsAgent::kDelegatorEcdsa256;
const std::string kRsaeDelegatorId = TlsAgent::kDelegatorRsae2048;
const std::string kDCId = TlsAgent::kServerEcdsa256;
const SSLSignatureScheme kDCScheme = ssl_sig_ecdsa_secp256r1_sha256;
const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds */;
static void CheckPreliminaryPeerDelegCred(
const std::shared_ptr<TlsAgent>& client, bool expected,
PRUint32 key_bits = 0, SSLSignatureScheme sig_scheme = ssl_sig_none) {
EXPECT_NE(0U, (client->pre_info().valuesSet & ssl_preinfo_peer_auth));
EXPECT_EQ(expected, client->pre_info().peerDelegCred);
if (expected) {
EXPECT_EQ(key_bits, client->pre_info().authKeyBits);
EXPECT_EQ(sig_scheme, client->pre_info().signatureScheme);
}
}
static void CheckPeerDelegCred(const std::shared_ptr<TlsAgent>& client,
bool expected, PRUint32 key_bits = 0) {
EXPECT_EQ(expected, client->info().peerDelegCred);
EXPECT_EQ(expected, client->pre_info().peerDelegCred);
if (expected) {
EXPECT_EQ(key_bits, client->info().authKeyBits);
EXPECT_EQ(key_bits, client->pre_info().authKeyBits);
EXPECT_EQ(client->info().signatureScheme,
client->pre_info().signatureScheme);
}
}
// AuthCertificate callbacks to simulate DC validation
static SECStatus CheckPreliminaryDC(TlsAgent* agent, bool checksig,
bool isServer) {
agent->UpdatePreliminaryChannelInfo();
EXPECT_EQ(PR_TRUE, agent->pre_info().peerDelegCred);
EXPECT_EQ(256U, agent->pre_info().authKeyBits);
EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, agent->pre_info().signatureScheme);
return SECSuccess;
}
static SECStatus CheckPreliminaryNoDC(TlsAgent* agent, bool checksig,
bool isServer) {
agent->UpdatePreliminaryChannelInfo();
EXPECT_EQ(PR_FALSE, agent->pre_info().peerDelegCred);
return SECSuccess;
}
// AuthCertificate callbacks for modifying DC attributes.
// This allows testing tls13_CertificateVerify for rejection
// of DC attributes that have changed since AuthCertificateHook
// may have handled them.
static SECStatus ModifyDCAuthKeyBits(TlsAgent* agent, bool checksig,
bool isServer) {
return SSLInt_TweakChannelInfoForDC(agent->ssl_fd(),
PR_TRUE, // Change authKeyBits
PR_FALSE); // Change scheme
}
static SECStatus ModifyDCScheme(TlsAgent* agent, bool checksig, bool isServer) {
return SSLInt_TweakChannelInfoForDC(agent->ssl_fd(),
PR_FALSE, // Change authKeyBits
PR_TRUE); // Change scheme
}
// Attempt to configure a DC when either the DC or DC private key is missing.
TEST_P(TlsConnectTls13, DCNotConfigured) {
// Load and delegate the credential.
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(kDCId, &pub, &priv));
StackSECItem dc;
TlsAgent::DelegateCredential(kEcdsaDelegatorId, pub, kDCScheme, kDCValidFor,
now(), &dc);
// Attempt to install the certificate and DC with a missing DC private key.
EnsureTlsSetup();
SSLExtraServerCertData extra_data_missing_dc_priv_key = {
ssl_auth_null, nullptr, nullptr, nullptr, &dc, nullptr};
EXPECT_FALSE(server_->ConfigServerCert(kEcdsaDelegatorId, true,
&extra_data_missing_dc_priv_key));
// Attempt to install the certificate and with only the DC private key.
EnsureTlsSetup();
SSLExtraServerCertData extra_data_missing_dc = {
ssl_auth_null, nullptr, nullptr, nullptr, nullptr, priv.get()};
EXPECT_FALSE(server_->ConfigServerCert(kEcdsaDelegatorId, true,
&extra_data_missing_dc));
}
// Connected with ECDSA-P256.
TEST_P(TlsConnectTls13, DCConnectEcdsaP256) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 256);
EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, client_->info().signatureScheme);
}
// Connected with ECDSA-P521.
TEST_P(TlsConnectTls13, DCConnectEcdsaP521) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
now());
client_->EnableDelegatedCredentials();
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 521);
EXPECT_EQ(ssl_sig_ecdsa_secp521r1_sha512, client_->info().signatureScheme);
}
// Connected with RSA-PSS, using an RSAE DC SPKI.
TEST_P(TlsConnectTls13, DCConnectRsaPssRsae) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(
TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_rsae_sha256, kDCValidFor, now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 1024);
EXPECT_EQ(ssl_sig_rsa_pss_rsae_sha256, client_->info().signatureScheme);
}
// Connected with RSA-PSS, using a RSAE Delegator SPKI.
TEST_P(TlsConnectTls13, DCConnectRsaeDelegator) {
Reset(kRsaeDelegatorId);
static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256,
ssl_sig_rsa_pss_pss_sha256};
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(
TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 1024);
EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
}
// Connected with RSA-PSS, using a PSS SPKI.
TEST_P(TlsConnectTls13, DCConnectRsaPssPss) {
Reset(kEcdsaDelegatorId);
// Need to enable PSS-PSS, which is not on by default.
static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256,
ssl_sig_rsa_pss_pss_sha256};
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(
TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, true, 1024);
EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
}
// Generate a weak key. We can't do this in the fixture because certutil
// won't sign with such a tiny key. That's OK, because this is fast(ish).
static void GenerateWeakRsaKey(ScopedSECKEYPrivateKey& priv,
ScopedSECKEYPublicKey& pub) {
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ASSERT_TRUE(slot);
PK11RSAGenParams rsaparams;
// The absolute minimum size of RSA key that we can use with SHA-256 is
// 256bit (hash) + 256bit (salt) + 8 (start byte) + 8 (end byte) = 528.
rsaparams.keySizeInBits = 528;
rsaparams.pe = 65537;
// Bug 1012786: PK11_GenerateKeyPair can fail if there is insufficient
// entropy to generate a random key. We can fake some.
for (int retry = 0; retry < 10; ++retry) {
SECKEYPublicKey* p_pub = nullptr;
priv.reset(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
&rsaparams, &p_pub, false, false, nullptr));
pub.reset(p_pub);
if (priv) {
return;
}
ASSERT_FALSE(pub);
if (PORT_GetError() != SEC_ERROR_PKCS11_FUNCTION_FAILED) {
break;
}
// https://xkcd.com/221/
static const uint8_t FRESH_ENTROPY[16] = {4};
ASSERT_EQ(
SECSuccess,
PK11_RandomUpdate(
const_cast<void*>(reinterpret_cast<const void*>(FRESH_ENTROPY)),
sizeof(FRESH_ENTROPY)));
break;
}
ADD_FAILURE() << "Unable to generate an RSA key: "
<< PORT_ErrorToName(PORT_GetError());
}
// Fail to connect with a weak RSA key.
TEST_P(TlsConnectTls13, DCWeakKey) {
Reset(kEcdsaDelegatorId);
EnsureTlsSetup();
ScopedSECKEYPrivateKey dc_priv;
ScopedSECKEYPublicKey dc_pub;
GenerateWeakRsaKey(dc_priv, dc_pub);
ASSERT_TRUE(dc_priv);
// Construct a DC.
StackSECItem dc;
TlsAgent::DelegateCredential(kEcdsaDelegatorId, dc_pub,
ssl_sig_rsa_pss_rsae_sha256, kDCValidFor, now(),
&dc);
// Configure the DC on the server.
SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
nullptr, &dc, dc_priv.get()};
EXPECT_TRUE(server_->ConfigServerCert(kEcdsaDelegatorId, true, &extra_data));
client_->EnableDelegatedCredentials();
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
ConnectExpectAlert(client_, kTlsAlertInsufficientSecurity);
}
class ReplaceDCSigScheme : public TlsHandshakeFilter {
public:
ReplaceDCSigScheme(const std::shared_ptr<TlsAgent>& a)
: TlsHandshakeFilter(a, {ssl_hs_certificate_verify}) {}
protected:
PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) override {
*output = input;
output->Write(0, ssl_sig_ecdsa_secp384r1_sha384, 2);
return CHANGE;
}
};
// Aborted because of incorrect DC signature algorithm indication.
TEST_P(TlsConnectTls13, DCAbortBadExpectedCertVerifyAlg) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
now());
auto filter = MakeTlsFilter<ReplaceDCSigScheme>(server_);
filter->EnableDecryption();
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}
// Aborted because of invalid DC signature.
TEST_P(TlsConnectTls13, DCAbortBadSignature) {
Reset(kEcdsaDelegatorId);
EnsureTlsSetup();
client_->EnableDelegatedCredentials();
ScopedSECKEYPublicKey pub;
ScopedSECKEYPrivateKey priv;
EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(kDCId, &pub, &priv));
StackSECItem dc;
TlsAgent::DelegateCredential(kEcdsaDelegatorId, pub, kDCScheme, kDCValidFor,
now(), &dc);
ASSERT_TRUE(dc.data != nullptr);
// Flip the first bit of the DC so that the signature is invalid.
dc.data[0] ^= 0x01;
SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
nullptr, &dc, priv.get()};
EXPECT_TRUE(server_->ConfigServerCert(kEcdsaDelegatorId, true, &extra_data));
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_DC_BAD_SIGNATURE);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}
// Aborted because of expired DC.
TEST_P(TlsConnectTls13, DCAbortExpired) {
Reset(kEcdsaDelegatorId);
server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
client_->EnableDelegatedCredentials();
// When the client checks the time, it will be at least one second after the
// DC expired.
AdvanceTime((static_cast<PRTime>(kDCValidFor) + 1) * PR_USEC_PER_SEC);
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
client_->CheckErrorCode(SSL_ERROR_DC_EXPIRED);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
}
// Aborted because of invalid key usage.
TEST_P(TlsConnectTls13, DCAbortBadKeyUsage) {
// The sever does not have the delegationUsage extension.
Reset(TlsAgent::kServerEcdsa256);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
}
// Connected without DC because of no client indication.
TEST_P(TlsConnectTls13, DCConnectNoClientSupport) {
Reset(kEcdsaDelegatorId);
server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_FALSE(cfilter->captured());
CheckPeerDelegCred(client_, false);
}
// Connected without DC because of no server DC.
TEST_P(TlsConnectTls13, DCConnectNoServerSupport) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, false);
}
// Connected without DC because client doesn't support TLS 1.3.
TEST_P(TlsConnectTls13, DCConnectClientNoTls13) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_2);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
// Should fallback to TLS 1.2 and not negotiate a DC.
EXPECT_FALSE(cfilter->captured());
CheckPeerDelegCred(client_, false);
}
// Connected without DC because server doesn't support TLS 1.3.
TEST_P(TlsConnectTls13, DCConnectServerNoTls13) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_3);
server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
SSL_LIBRARY_VERSION_TLS_1_2);
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
// Should fallback to TLS 1.2 and not negotiate a DC. The client will still
// send the indication because it supports 1.3.
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, false);
}
// Connected without DC because client doesn't support the signature scheme.
TEST_P(TlsConnectTls13, DCConnectExpectedCertVerifyAlgNotSupported) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
static const SSLSignatureScheme kClientSchemes[] = {
ssl_sig_ecdsa_secp256r1_sha256,
};
client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes));
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
now());
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
client_, ssl_delegated_credentials_xtn);
Connect();
// Client sends indication, but the server doesn't send a DC.
EXPECT_TRUE(cfilter->captured());
CheckPeerDelegCred(client_, false);
}
// Check that preliminary channel info properly reflects the DC.
TEST_P(TlsConnectTls13, DCCheckPreliminaryInfo) {
Reset(kEcdsaDelegatorId);
EnsureTlsSetup();
client_->EnableDelegatedCredentials();
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
now());
auto filter = MakeTlsFilter<TlsHandshakeDropper>(server_);
filter->SetHandshakeTypes(
{kTlsHandshakeCertificateVerify, kTlsHandshakeFinished});
filter->EnableDecryption();
StartConnect();
client_->Handshake(); // Send ClientHello
server_->Handshake(); // Send ServerHello
client_->SetAuthCertificateCallback(CheckPreliminaryDC);
client_->Handshake(); // Process response
client_->UpdatePreliminaryChannelInfo();
CheckPreliminaryPeerDelegCred(client_, true, 256,
ssl_sig_ecdsa_secp256r1_sha256);
}
// Check that preliminary channel info properly reflects a lack of DC.
TEST_P(TlsConnectTls13, DCCheckPreliminaryInfoNoDC) {
Reset(kEcdsaDelegatorId);
EnsureTlsSetup();
client_->EnableDelegatedCredentials();
auto filter = MakeTlsFilter<TlsHandshakeDropper>(server_);
filter->SetHandshakeTypes(
{kTlsHandshakeCertificateVerify, kTlsHandshakeFinished});
filter->EnableDecryption();
StartConnect();
client_->Handshake(); // Send ClientHello
server_->Handshake(); // Send ServerHello
client_->SetAuthCertificateCallback(CheckPreliminaryNoDC);
client_->Handshake(); // Process response
client_->UpdatePreliminaryChannelInfo();
CheckPreliminaryPeerDelegCred(client_, false);
}
// Tweak the scheme in between |Cert| and |CertVerify|.
TEST_P(TlsConnectTls13, DCRejectModifiedDCScheme) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
client_->SetAuthCertificateCallback(ModifyDCScheme);
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
now());
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH);
}
// Tweak the authKeyBits in between |Cert| and |CertVerify|.
TEST_P(TlsConnectTls13, DCRejectModifiedDCAuthKeyBits) {
Reset(kEcdsaDelegatorId);
client_->EnableDelegatedCredentials();
client_->SetAuthCertificateCallback(ModifyDCAuthKeyBits);
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
now());
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH);
}
class DCDelegation : public ::testing::Test {};
TEST_F(DCDelegation, DCDelegations) {
PRTime now = PR_Now();
ScopedCERTCertificate cert;
ScopedSECKEYPrivateKey priv;
ASSERT_TRUE(TlsAgent::LoadCertificate(kEcdsaDelegatorId, &cert, &priv));
ScopedSECKEYPublicKey pub_rsa;
ScopedSECKEYPrivateKey priv_rsa;
ASSERT_TRUE(
TlsAgent::LoadKeyPairFromCert(TlsAgent::kServerRsa, &pub_rsa, &priv_rsa));
StackSECItem dc;
EXPECT_EQ(SECFailure,
SSL_DelegateCredential(cert.get(), priv.get(), pub_rsa.get(),
ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
now, &dc));
EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
// Using different PSS hashes should be OK.
EXPECT_EQ(SECSuccess,
SSL_DelegateCredential(cert.get(), priv.get(), pub_rsa.get(),
ssl_sig_rsa_pss_rsae_sha256, kDCValidFor,
now, &dc));
// Make sure to reset |dc| after each success.
dc.Reset();
EXPECT_EQ(SECSuccess, SSL_DelegateCredential(
cert.get(), priv.get(), pub_rsa.get(),
ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now, &dc));
dc.Reset();
EXPECT_EQ(SECSuccess, SSL_DelegateCredential(
cert.get(), priv.get(), pub_rsa.get(),
ssl_sig_rsa_pss_pss_sha384, kDCValidFor, now, &dc));
dc.Reset();
ScopedSECKEYPublicKey pub_ecdsa;
ScopedSECKEYPrivateKey priv_ecdsa;
ASSERT_TRUE(TlsAgent::LoadKeyPairFromCert(TlsAgent::kServerEcdsa256,
&pub_ecdsa, &priv_ecdsa));
EXPECT_EQ(SECFailure,
SSL_DelegateCredential(cert.get(), priv.get(), pub_ecdsa.get(),
ssl_sig_rsa_pss_rsae_sha256, kDCValidFor,
now, &dc));
EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
EXPECT_EQ(SECFailure, SSL_DelegateCredential(
cert.get(), priv.get(), pub_ecdsa.get(),
ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now, &dc));
EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
EXPECT_EQ(SECFailure,
SSL_DelegateCredential(cert.get(), priv.get(), pub_ecdsa.get(),
ssl_sig_ecdsa_secp384r1_sha384, kDCValidFor,
now, &dc));
EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
}
} // namespace nss_test