Bug 1939208 - Localize messages according to application context. r=android-reviewers...
[gecko.git] / security / manager / ssl / tests / unit / tlsserver / cmd / OCSPStaplingServer.cpp
blob1defc524374b1df77561eb9aa62de4600c2327cc
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 // This is a standalone server that delivers various stapled OCSP responses.
6 // The client is expected to connect, initiate an SSL handshake (with SNI
7 // to indicate which "server" to connect to), and verify the OCSP response.
8 // If all is good, the client then sends one encrypted byte and receives that
9 // same byte back.
10 // This server also has the ability to "call back" another process waiting on
11 // it. That is, when the server is all set up and ready to receive connections,
12 // it will connect to a specified port and issue a simple HTTP request.
14 #include <fstream>
15 #include <stdio.h>
17 #include "OCSPCommon.h"
18 #include "TLSServer.h"
20 using namespace mozilla;
21 using namespace mozilla::pkix::test;
22 using namespace mozilla::test;
24 const OCSPHost sOCSPHosts[] = {
25 {"ocsp-stapling-good.example.com", ORTGood, nullptr, nullptr},
26 {"ocsp-stapling-revoked.example.com", ORTRevoked, nullptr, nullptr},
27 {"ocsp-stapling-revoked-old.example.com", ORTRevokedOld, nullptr, nullptr},
28 {"ocsp-stapling-unknown.example.com", ORTUnknown, nullptr, nullptr},
29 {"ocsp-stapling-unknown-old.example.com", ORTUnknownOld, nullptr, nullptr},
30 {"ocsp-stapling-good-other.example.com", ORTGoodOtherCert,
31 "ocspOtherEndEntity", nullptr},
32 {"ocsp-stapling-good-other-ca.example.com", ORTGoodOtherCA, "other-test-ca",
33 nullptr},
34 {"ocsp-stapling-expired.example.com", ORTExpired, nullptr, nullptr},
35 {"ocsp-stapling-expired-fresh-ca.example.com", ORTExpiredFreshCA, nullptr,
36 nullptr},
37 {"ocsp-stapling-none.example.com", ORTNone, nullptr, nullptr},
38 {"ocsp-stapling-empty.example.com", ORTEmpty, nullptr, nullptr},
39 {"ocsp-stapling-malformed.example.com", ORTMalformed, nullptr, nullptr},
40 {"ocsp-stapling-srverr.example.com", ORTSrverr, nullptr, nullptr},
41 {"ocsp-stapling-trylater.example.com", ORTTryLater, nullptr, nullptr},
42 {"ocsp-stapling-needssig.example.com", ORTNeedsSig, nullptr, nullptr},
43 {"ocsp-stapling-unauthorized.example.com", ORTUnauthorized, nullptr,
44 nullptr},
45 {"ocsp-stapling-with-intermediate.example.com", ORTGood, nullptr,
46 "ocspEEWithIntermediate"},
47 {"ocsp-stapling-bad-signature.example.com", ORTBadSignature, nullptr,
48 nullptr},
49 {"ocsp-stapling-skip-responseBytes.example.com", ORTSkipResponseBytes,
50 nullptr, nullptr},
51 {"ocsp-stapling-critical-extension.example.com", ORTCriticalExtension,
52 nullptr, nullptr},
53 {"ocsp-stapling-noncritical-extension.example.com", ORTNoncriticalExtension,
54 nullptr, nullptr},
55 {"ocsp-stapling-empty-extensions.example.com", ORTEmptyExtensions, nullptr,
56 nullptr},
57 {"ocsp-stapling-delegated-included.example.com", ORTDelegatedIncluded,
58 "delegatedSigner", nullptr},
59 {"ocsp-stapling-delegated-included-last.example.com",
60 ORTDelegatedIncludedLast, "delegatedSigner", nullptr},
61 {"ocsp-stapling-delegated-missing.example.com", ORTDelegatedMissing,
62 "delegatedSigner", nullptr},
63 {"ocsp-stapling-delegated-missing-multiple.example.com",
64 ORTDelegatedMissingMultiple, "delegatedSigner", nullptr},
65 {"ocsp-stapling-delegated-no-extKeyUsage.example.com", ORTDelegatedIncluded,
66 "invalidDelegatedSignerNoExtKeyUsage", nullptr},
67 {"ocsp-stapling-delegated-from-intermediate.example.com",
68 ORTDelegatedIncluded, "invalidDelegatedSignerFromIntermediate", nullptr},
69 {"ocsp-stapling-delegated-keyUsage-crlSigning.example.com",
70 ORTDelegatedIncluded, "invalidDelegatedSignerKeyUsageCrlSigning", nullptr},
71 {"ocsp-stapling-delegated-wrong-extKeyUsage.example.com",
72 ORTDelegatedIncluded, "invalidDelegatedSignerWrongExtKeyUsage", nullptr},
73 {"ocsp-stapling-ancient-valid.example.com", ORTAncientAlmostExpired,
74 nullptr, nullptr},
75 {"keysize-ocsp-delegated.example.com", ORTDelegatedIncluded,
76 "rsa-1016-keysizeDelegatedSigner", nullptr},
77 {"revoked-ca-cert-used-as-end-entity.example.com", ORTRevoked,
78 "ca-used-as-end-entity", nullptr},
79 {"ocsp-stapling-must-staple.example.com", ORTGood, nullptr,
80 "must-staple-ee"},
81 {"ocsp-stapling-must-staple-revoked.example.com", ORTRevoked, nullptr,
82 "must-staple-ee"},
83 {"ocsp-stapling-must-staple-missing.example.com", ORTNone, nullptr,
84 "must-staple-ee"},
85 {"ocsp-stapling-must-staple-empty.example.com", ORTEmpty, nullptr,
86 "must-staple-ee"},
87 {"ocsp-stapling-must-staple-ee-with-must-staple-int.example.com", ORTGood,
88 nullptr, "must-staple-ee-with-must-staple-int"},
89 {"ocsp-stapling-plain-ee-with-must-staple-int.example.com", ORTGood,
90 nullptr, "must-staple-missing-ee"},
91 {"ocsp-stapling-must-staple-expired.example.com", ORTExpired, nullptr,
92 "must-staple-ee"},
93 {"ocsp-stapling-must-staple-try-later.example.com", ORTTryLater, nullptr,
94 "must-staple-ee"},
95 {"ocsp-stapling-must-staple-invalid-signer.example.com", ORTGoodOtherCA,
96 "other-test-ca", "must-staple-ee"},
97 {"multi-tls-feature-good.example.com", ORTNone, nullptr,
98 "multi-tls-feature-good-ee"},
99 {"multi-tls-feature-bad.example.com", ORTNone, nullptr,
100 "multi-tls-feature-bad-ee"},
101 {nullptr, ORTNull, nullptr, nullptr}};
103 enum class SCTsVia {
104 None,
105 OCSP,
106 TLS,
109 struct CTHost {
110 const char* mHostName;
111 std::vector<const char*> mSCTFilenames;
112 SCTsVia mSCTsVia;
115 MOZ_RUNINIT const CTHost sCTHosts[] = {
116 {"ct-via-ocsp.example.com",
117 {"test_ct/ct-via-ocsp-1.sct", "test_ct/ct-via-ocsp-2.sct"},
118 SCTsVia::OCSP},
119 {"ct-via-tls.example.com",
120 {"test_ct/ct-via-tls-1.sct", "test_ct/ct-via-tls-2.sct"},
121 SCTsVia::TLS},
122 {"ct-tampered.example.com",
123 {"test_ct/ct-tampered-1.sct", "test_ct/ct-tampered-2.sct"},
124 SCTsVia::TLS},
125 {nullptr, {}, SCTsVia::None}};
127 ByteString ReadSCTList(const std::vector<const char*>& sctFilenames) {
128 std::vector<std::string> scts;
129 for (const auto& sctFilename : sctFilenames) {
130 std::ifstream in(sctFilename, std::ios::binary);
131 if (in.bad() || !in.is_open()) {
132 if (gDebugLevel >= DEBUG_ERRORS) {
133 fprintf(stderr, "couldn't open '%s'\n", sctFilename);
134 return ByteString();
137 std::ostringstream contentsStream;
138 contentsStream << in.rdbuf();
139 std::string contents = contentsStream.str();
140 scts.push_back(std::move(contents));
143 ByteString contents;
144 for (const auto& sct : scts) {
145 // Each SCT has a 2-byte length prefix.
146 contents.push_back(sct.length() / 256);
147 contents.push_back(sct.length() % 256);
148 contents.append(reinterpret_cast<const uint8_t*>(sct.data()), sct.length());
150 // The entire SCT list also has a 2-byte length prefix.
151 ByteString sctList;
152 sctList.push_back(contents.length() / 256);
153 sctList.push_back(contents.length() % 256);
154 sctList.append(reinterpret_cast<const uint8_t*>(contents.data()),
155 contents.length());
156 return sctList;
159 int32_t DoSNISocketConfig(PRFileDesc* aFd, const SECItem* aSrvNameArr,
160 uint32_t aSrvNameArrSize, void* aArg) {
161 const char* hostName = nullptr;
162 OCSPResponseType ocspResponseType = ORTNone;
163 const char* additionalCertName = nullptr;
164 const char* serverCertName = nullptr;
165 ByteString sctList;
166 SCTsVia sctsVia = SCTsVia::None;
168 const OCSPHost* host =
169 GetHostForSNI(aSrvNameArr, aSrvNameArrSize, sOCSPHosts);
170 if (host) {
171 hostName = host->mHostName;
172 ocspResponseType = host->mORT;
173 additionalCertName = host->mAdditionalCertName;
174 serverCertName = host->mServerCertName;
175 } else {
176 const CTHost* ctHost =
177 GetHostForSNI(aSrvNameArr, aSrvNameArrSize, sCTHosts);
178 if (!ctHost) {
179 return SSL_SNI_SEND_ALERT;
181 hostName = ctHost->mHostName;
182 ocspResponseType = ORTGood;
183 serverCertName = ctHost->mHostName;
184 sctList = ReadSCTList(ctHost->mSCTFilenames);
185 if (sctList.empty()) {
186 return SSL_SNI_SEND_ALERT;
188 sctsVia = ctHost->mSCTsVia;
191 if (gDebugLevel >= DEBUG_VERBOSE) {
192 fprintf(stderr, "found pre-defined host '%s'\n", hostName);
195 const char* certNickname =
196 serverCertName ? serverCertName : DEFAULT_CERT_NICKNAME;
198 UniqueCERTCertificate cert;
199 SSLKEAType certKEA;
200 if (SECSuccess != ConfigSecureServerWithNamedCert(aFd, certNickname, &cert,
201 &certKEA, nullptr)) {
202 return SSL_SNI_SEND_ALERT;
205 // If the OCSP response type is "none", don't staple a response.
206 if (ocspResponseType == ORTNone) {
207 return 0;
210 UniquePLArenaPool arena(PORT_NewArena(1024));
211 if (!arena) {
212 PrintPRError("PORT_NewArena failed");
213 return SSL_SNI_SEND_ALERT;
216 // response is contained by the arena - freeing the arena will free it
217 SECItemArray* response =
218 GetOCSPResponseForType(ocspResponseType, cert, arena, additionalCertName,
219 0, sctsVia == SCTsVia::OCSP ? &sctList : nullptr);
220 if (!response) {
221 return SSL_SNI_SEND_ALERT;
224 // SSL_SetStapledOCSPResponses makes a deep copy of response
225 SECStatus st = SSL_SetStapledOCSPResponses(aFd, response, certKEA);
226 if (st != SECSuccess) {
227 PrintPRError("SSL_SetStapledOCSPResponses failed");
228 return SSL_SNI_SEND_ALERT;
231 if (sctsVia == SCTsVia::TLS) {
232 SECItem scts = {siBuffer, const_cast<unsigned char*>(sctList.data()),
233 (unsigned int)sctList.size()};
234 st = SSL_SetSignedCertTimestamps(aFd, &scts, certKEA);
235 if (st != SECSuccess) {
236 PrintPRError("SSL_SetSignedCertTimestamps failed");
237 return SSL_SNI_SEND_ALERT;
241 return 0;
244 int main(int argc, char* argv[]) {
245 return StartServer(argc, argv, DoSNISocketConfig, nullptr);