|
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/. */ |
|
4 |
|
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. |
|
13 |
|
14 #include <stdio.h> |
|
15 |
|
16 #include "OCSPCommon.h" |
|
17 #include "TLSServer.h" |
|
18 |
|
19 using namespace mozilla; |
|
20 using namespace mozilla::test; |
|
21 |
|
22 const OCSPHost sOCSPHosts[] = |
|
23 { |
|
24 { "ocsp-stapling-good.example.com", ORTGood, nullptr }, |
|
25 { "ocsp-stapling-revoked.example.com", ORTRevoked, nullptr }, |
|
26 { "ocsp-stapling-revoked-old.example.com", ORTRevokedOld, nullptr }, |
|
27 { "ocsp-stapling-unknown.example.com", ORTUnknown, nullptr }, |
|
28 { "ocsp-stapling-unknown-old.example.com", ORTUnknownOld, nullptr }, |
|
29 { "ocsp-stapling-good-other.example.com", ORTGoodOtherCert, "ocspOtherEndEntity" }, |
|
30 { "ocsp-stapling-good-other-ca.example.com", ORTGoodOtherCA, "otherCA" }, |
|
31 { "ocsp-stapling-expired.example.com", ORTExpired, nullptr }, |
|
32 { "ocsp-stapling-expired-fresh-ca.example.com", ORTExpiredFreshCA, nullptr }, |
|
33 { "ocsp-stapling-none.example.com", ORTNone, nullptr }, |
|
34 { "ocsp-stapling-empty.example.com", ORTEmpty, nullptr }, |
|
35 { "ocsp-stapling-malformed.example.com", ORTMalformed, nullptr }, |
|
36 { "ocsp-stapling-srverr.example.com", ORTSrverr, nullptr }, |
|
37 { "ocsp-stapling-trylater.example.com", ORTTryLater, nullptr }, |
|
38 { "ocsp-stapling-needssig.example.com", ORTNeedsSig, nullptr }, |
|
39 { "ocsp-stapling-unauthorized.example.com", ORTUnauthorized, nullptr }, |
|
40 { "ocsp-stapling-with-intermediate.example.com", ORTGood, "ocspEEWithIntermediate" }, |
|
41 { "ocsp-stapling-bad-signature.example.com", ORTBadSignature, nullptr }, |
|
42 { "ocsp-stapling-skip-responseBytes.example.com", ORTSkipResponseBytes, nullptr }, |
|
43 { "ocsp-stapling-critical-extension.example.com", ORTCriticalExtension, nullptr }, |
|
44 { "ocsp-stapling-noncritical-extension.example.com", ORTNoncriticalExtension, nullptr }, |
|
45 { "ocsp-stapling-empty-extensions.example.com", ORTEmptyExtensions, nullptr }, |
|
46 { "ocsp-stapling-delegated-included.example.com", ORTDelegatedIncluded, "delegatedSigner" }, |
|
47 { "ocsp-stapling-delegated-included-last.example.com", ORTDelegatedIncludedLast, "delegatedSigner" }, |
|
48 { "ocsp-stapling-delegated-missing.example.com", ORTDelegatedMissing, "delegatedSigner" }, |
|
49 { "ocsp-stapling-delegated-missing-multiple.example.com", ORTDelegatedMissingMultiple, "delegatedSigner" }, |
|
50 { "ocsp-stapling-delegated-no-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerNoExtKeyUsage" }, |
|
51 { "ocsp-stapling-delegated-from-intermediate.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerFromIntermediate" }, |
|
52 { "ocsp-stapling-delegated-keyUsage-crlSigning.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerKeyUsageCrlSigning" }, |
|
53 { "ocsp-stapling-delegated-wrong-extKeyUsage.example.com", ORTDelegatedIncluded, "invalidDelegatedSignerWrongExtKeyUsage" }, |
|
54 { "ocsp-stapling-ancient-valid.example.com", ORTAncientAlmostExpired, nullptr}, |
|
55 { nullptr, ORTNull, nullptr } |
|
56 }; |
|
57 |
|
58 int32_t |
|
59 DoSNISocketConfig(PRFileDesc *aFd, const SECItem *aSrvNameArr, |
|
60 uint32_t aSrvNameArrSize, void *aArg) |
|
61 { |
|
62 const OCSPHost *host = GetHostForSNI(aSrvNameArr, aSrvNameArrSize, |
|
63 sOCSPHosts); |
|
64 if (!host) { |
|
65 return SSL_SNI_SEND_ALERT; |
|
66 } |
|
67 |
|
68 if (gDebugLevel >= DEBUG_VERBOSE) { |
|
69 fprintf(stderr, "found pre-defined host '%s'\n", host->mHostName); |
|
70 } |
|
71 |
|
72 const char *certNickname; |
|
73 if (strcmp(host->mHostName, |
|
74 "ocsp-stapling-with-intermediate.example.com") == 0) { |
|
75 certNickname = host->mAdditionalCertName; |
|
76 } else { |
|
77 certNickname = DEFAULT_CERT_NICKNAME; |
|
78 } |
|
79 |
|
80 ScopedCERTCertificate cert; |
|
81 SSLKEAType certKEA; |
|
82 if (SECSuccess != ConfigSecureServerWithNamedCert(aFd, certNickname, |
|
83 &cert, &certKEA)) { |
|
84 return SSL_SNI_SEND_ALERT; |
|
85 } |
|
86 |
|
87 // If the OCSP response type is "none", don't staple a response. |
|
88 if (host->mORT == ORTNone) { |
|
89 return 0; |
|
90 } |
|
91 |
|
92 PLArenaPool *arena = PORT_NewArena(1024); |
|
93 if (!arena) { |
|
94 PrintPRError("PORT_NewArena failed"); |
|
95 return SSL_SNI_SEND_ALERT; |
|
96 } |
|
97 |
|
98 // response is contained by the arena - freeing the arena will free it |
|
99 SECItemArray *response = GetOCSPResponseForType(host->mORT, cert, arena, |
|
100 host->mAdditionalCertName); |
|
101 if (!response) { |
|
102 PORT_FreeArena(arena, PR_FALSE); |
|
103 return SSL_SNI_SEND_ALERT; |
|
104 } |
|
105 |
|
106 // SSL_SetStapledOCSPResponses makes a deep copy of response |
|
107 SECStatus st = SSL_SetStapledOCSPResponses(aFd, response, certKEA); |
|
108 PORT_FreeArena(arena, PR_FALSE); |
|
109 if (st != SECSuccess) { |
|
110 PrintPRError("SSL_SetStapledOCSPResponses failed"); |
|
111 return SSL_SNI_SEND_ALERT; |
|
112 } |
|
113 |
|
114 return 0; |
|
115 } |
|
116 |
|
117 int |
|
118 main(int argc, char *argv[]) |
|
119 { |
|
120 if (argc != 2) { |
|
121 fprintf(stderr, "usage: %s <NSS DB directory>\n", argv[0]); |
|
122 return 1; |
|
123 } |
|
124 |
|
125 return StartServer(argv[1], DoSNISocketConfig, nullptr); |
|
126 } |