1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
/* 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 standalone server that uses various bad certificates.
// The client is expected to connect, initiate an SSL handshake (with SNI
// to indicate which "server" to connect to), and verify the certificate.
// If all is good, the client then sends one encrypted byte and receives that
// same byte back.
// This server also has the ability to "call back" another process waiting on
// it. That is, when the server is all set up and ready to receive connections,
// it will connect to a specified port and issue a simple HTTP request.
#include <stdio.h>
#include "TLSServer.h"
using namespace mozilla;
using namespace mozilla::test;
struct BadCertHost
{
const char *mHostName;
const char *mCertName;
};
// Hostname, cert nickname pairs.
const BadCertHost sBadCertHosts[] =
{
{ "expired.example.com", "expired-ee" },
{ "notyetvalid.example.com", "notYetValid" },
{ "before-epoch.example.com", "beforeEpoch" },
{ "selfsigned.example.com", "selfsigned" },
{ "unknownissuer.example.com", "unknownissuer" },
{ "mismatch.example.com", "mismatch" },
{ "mismatch-CN.example.com", "mismatchCN" },
{ "expiredissuer.example.com", "expiredissuer" },
{ "notyetvalidissuer.example.com", "notYetValidIssuer" },
{ "before-epoch-issuer.example.com", "beforeEpochIssuer" },
{ "md5signature.example.com", "md5signature" },
{ "untrusted.example.com", "default-ee" },
{ "untrustedissuer.example.com", "untrustedissuer" },
{ "mismatch-expired.example.com", "mismatch-expired" },
{ "mismatch-notYetValid.example.com", "mismatch-notYetValid" },
{ "mismatch-untrusted.example.com", "mismatch-untrusted" },
{ "untrusted-expired.example.com", "untrusted-expired" },
{ "md5signature-expired.example.com", "md5signature-expired" },
{ "mismatch-untrusted-expired.example.com", "mismatch-untrusted-expired" },
{ "inadequatekeyusage.example.com", "inadequatekeyusage-ee" },
{ "selfsigned-inadequateEKU.example.com", "selfsigned-inadequateEKU" },
{ "self-signed-end-entity-with-cA-true.example.com", "self-signed-EE-with-cA-true" },
{ "ca-used-as-end-entity.example.com", "ca-used-as-end-entity" },
{ "ca-used-as-end-entity-name-mismatch.example.com", "ca-used-as-end-entity" },
// All of include-subdomains.pinning.example.com is pinned to End Entity
// Test Cert with nick default-ee. Any other nick will only
// pass pinning when security.cert_pinning.enforcement.level != strict and
// otherCA is added as a user-specified trust anchor. See StaticHPKPins.h.
{ "include-subdomains.pinning.example.com", "default-ee" },
{ "good.include-subdomains.pinning.example.com", "default-ee" },
{ "bad.include-subdomains.pinning.example.com", "other-issuer-ee" },
{ "bad.include-subdomains.pinning.example.com.", "other-issuer-ee" },
{ "bad.include-subdomains.pinning.example.com..", "other-issuer-ee" },
{ "exclude-subdomains.pinning.example.com", "default-ee" },
{ "sub.exclude-subdomains.pinning.example.com", "other-issuer-ee" },
{ "test-mode.pinning.example.com", "other-issuer-ee" },
{ "unknownissuer.include-subdomains.pinning.example.com", "unknownissuer" },
{ "unknownissuer.test-mode.pinning.example.com", "unknownissuer" },
{ "nsCertTypeNotCritical.example.com", "nsCertTypeNotCritical" },
{ "nsCertTypeCriticalWithExtKeyUsage.example.com", "nsCertTypeCriticalWithExtKeyUsage" },
{ "nsCertTypeCritical.example.com", "nsCertTypeCritical" },
{ "end-entity-issued-by-v1-cert.example.com", "eeIssuedByV1Cert" },
{ "end-entity-issued-by-non-CA.example.com", "eeIssuedByNonCA" },
{ "inadequate-key-size-ee.example.com", "inadequateKeySizeEE" },
{ "badSubjectAltNames.example.com", "badSubjectAltNames" },
{ "ipAddressAsDNSNameInSAN.example.com", "ipAddressAsDNSNameInSAN" },
{ "noValidNames.example.com", "noValidNames" },
{ "bug413909.xn--hxajbheg2az3al.xn--jxalpdlp", "idn-certificate" },
{ "emptyissuername.example.com", "emptyIssuerName" },
{ "ev-test.example.com", "ev-test" },
{ nullptr, nullptr }
};
int32_t
DoSNISocketConfigBySubjectCN(PRFileDesc* aFd, const SECItem* aSrvNameArr,
uint32_t aSrvNameArrSize)
{
for (uint32_t i = 0; i < aSrvNameArrSize; i++) {
UniquePORTString name(
static_cast<char*>(PORT_ZAlloc(aSrvNameArr[i].len + 1)));
if (name) {
PORT_Memcpy(name.get(), aSrvNameArr[i].data, aSrvNameArr[i].len);
if (ConfigSecureServerWithNamedCert(aFd, name.get(), nullptr, nullptr)
== SECSuccess) {
return 0;
}
}
}
return SSL_SNI_SEND_ALERT;
}
int32_t
DoSNISocketConfig(PRFileDesc* aFd, const SECItem* aSrvNameArr,
uint32_t aSrvNameArrSize, void* aArg)
{
const BadCertHost* host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize,
sBadCertHosts);
if (!host) {
// No static cert <-> hostname mapping found. This happens when we use a
// collection of certificates in a given directory and build a cert DB at
// runtime, rather than using an NSS cert DB populated at build time.
// (This will be the default in the future.)
// For all given server names, check if the runtime-built cert DB contains
// a certificate with a matching subject CN.
return DoSNISocketConfigBySubjectCN(aFd, aSrvNameArr, aSrvNameArrSize);
}
if (gDebugLevel >= DEBUG_VERBOSE) {
fprintf(stderr, "found pre-defined host '%s'\n", host->mHostName);
}
UniqueCERTCertificate cert;
SSLKEAType certKEA;
if (SECSuccess != ConfigSecureServerWithNamedCert(aFd, host->mCertName,
&cert, &certKEA)) {
return SSL_SNI_SEND_ALERT;
}
return 0;
}
int
main(int argc, char *argv[])
{
if (argc != 2) {
fprintf(stderr, "usage: %s <NSS DB directory>\n", argv[0]);
return 1;
}
return StartServer(argv[1], DoSNISocketConfig, nullptr);
}
|