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 /*
6 * ocspresp - self test for OCSP response creation
7 */
8
9 #include "nspr.h"
10 #include "secutil.h"
11 #include "secpkcs7.h"
12 #include "cert.h"
13 #include "certdb.h"
14 #include "nss.h"
15 #include "pk11func.h"
16 #include "cryptohi.h"
17 #include "ocsp.h"
18
19 #if defined(XP_UNIX)
20 #include <unistd.h>
21 #endif
22
23 #include <stdio.h>
24 #include <string.h>
25
26 secuPWData pwdata = { PW_NONE, 0 };
27
28 static PRBool
getCaAndSubjectCert(CERTCertDBHandle * certHandle,const char * caNick,const char * eeNick,CERTCertificate ** outCA,CERTCertificate ** outCert)29 getCaAndSubjectCert(CERTCertDBHandle *certHandle,
30 const char *caNick, const char *eeNick,
31 CERTCertificate **outCA, CERTCertificate **outCert)
32 {
33 *outCA = CERT_FindCertByNickname(certHandle, caNick);
34 *outCert = CERT_FindCertByNickname(certHandle, eeNick);
35 return *outCA && *outCert;
36 }
37
38 static SECItem *
encode(PLArenaPool * arena,CERTOCSPCertID * cid,CERTCertificate * ca)39 encode(PLArenaPool *arena, CERTOCSPCertID *cid, CERTCertificate *ca)
40 {
41 SECItem *response;
42 PRTime now = PR_Now();
43 PRTime nextUpdate;
44 CERTOCSPSingleResponse **responses;
45 CERTOCSPSingleResponse *sr;
46
47 if (!arena)
48 return NULL;
49
50 nextUpdate = now + 10 * PR_USEC_PER_SEC; /* in the future */
51
52 sr = CERT_CreateOCSPSingleResponseGood(arena, cid, now, &nextUpdate);
53
54 /* meaning of value 2: one entry + one end marker */
55 responses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse *, 2);
56 if (responses == NULL)
57 return NULL;
58
59 responses[0] = sr;
60 responses[1] = NULL;
61
62 response = CERT_CreateEncodedOCSPSuccessResponse(
63 arena, ca, ocspResponderID_byName, now, responses, &pwdata);
64
65 return response;
66 }
67
68 static SECItem *
encodeRevoked(PLArenaPool * arena,CERTOCSPCertID * cid,CERTCertificate * ca)69 encodeRevoked(PLArenaPool *arena, CERTOCSPCertID *cid, CERTCertificate *ca)
70 {
71 SECItem *response;
72 PRTime now = PR_Now();
73 PRTime revocationTime;
74 CERTOCSPSingleResponse **responses;
75 CERTOCSPSingleResponse *sr;
76
77 if (!arena)
78 return NULL;
79
80 revocationTime = now - 10 * PR_USEC_PER_SEC; /* in the past */
81
82 sr = CERT_CreateOCSPSingleResponseRevoked(arena, cid, now, NULL,
83 revocationTime, NULL);
84
85 /* meaning of value 2: one entry + one end marker */
86 responses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse *, 2);
87 if (responses == NULL)
88 return NULL;
89
90 responses[0] = sr;
91 responses[1] = NULL;
92
93 response = CERT_CreateEncodedOCSPSuccessResponse(
94 arena, ca, ocspResponderID_byName, now, responses, &pwdata);
95
96 return response;
97 }
98
99 int
Usage(void)100 Usage(void)
101 {
102 PRFileDesc *pr_stderr = PR_STDERR;
103 PR_fprintf(pr_stderr, "ocspresp runs an internal selftest for OCSP response creation");
104 PR_fprintf(pr_stderr, "Usage:");
105 PR_fprintf(pr_stderr,
106 "\tocspresp <dbdir> <CA-nick> <EE-nick> [-p <pass>] [-f <file>]\n");
107 PR_fprintf(pr_stderr,
108 "\tdbdir: Find security databases in \"dbdir\"\n");
109 PR_fprintf(pr_stderr,
110 "\tCA-nick: nickname of a trusted CA certificate with private key\n");
111 PR_fprintf(pr_stderr,
112 "\tEE-nick: nickname of a entity cert issued by CA\n");
113 PR_fprintf(pr_stderr,
114 "\t-p: a password for db\n");
115 PR_fprintf(pr_stderr,
116 "\t-f: a filename containing the password for db\n");
117 return -1;
118 }
119
120 int
main(int argc,char ** argv)121 main(int argc, char **argv)
122 {
123 SECStatus rv;
124 int retval = -1;
125 CERTCertDBHandle *certHandle = NULL;
126 CERTCertificate *caCert = NULL, *cert = NULL;
127 CERTOCSPCertID *cid = NULL;
128 PLArenaPool *arena = NULL;
129 PRTime now = PR_Now();
130
131 SECItem *encoded = NULL;
132 CERTOCSPResponse *decoded = NULL;
133
134 SECItem *encodedRev = NULL;
135 CERTOCSPResponse *decodedRev = NULL;
136
137 SECItem *encodedFail = NULL;
138 CERTOCSPResponse *decodedFail = NULL;
139
140 CERTCertificate *obtainedSignerCert = NULL;
141
142 if (argc != 4 && argc != 6) {
143 return Usage();
144 }
145
146 if (argc == 6) {
147 if (!strcmp(argv[4], "-p")) {
148 pwdata.source = PW_PLAINTEXT;
149 pwdata.data = PORT_Strdup(argv[5]);
150 } else if (!strcmp(argv[4], "-f")) {
151 pwdata.source = PW_FROMFILE;
152 pwdata.data = PORT_Strdup(argv[5]);
153 } else
154 return Usage();
155 }
156
157 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
158 /*rv = NSS_Init(SECU_ConfigDirectory(NULL));*/
159 rv = NSS_Init(argv[1]);
160 if (rv != SECSuccess) {
161 SECU_PrintPRandOSError(argv[0]);
162 goto loser;
163 }
164
165 PK11_SetPasswordFunc(SECU_GetModulePassword);
166
167 certHandle = CERT_GetDefaultCertDB();
168 if (!certHandle)
169 goto loser;
170
171 if (!getCaAndSubjectCert(certHandle, argv[2], argv[3], &caCert, &cert))
172 goto loser;
173
174 cid = CERT_CreateOCSPCertID(cert, now);
175
176 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
177 encoded = encode(arena, cid, caCert);
178 PORT_Assert(encoded);
179 decoded = CERT_DecodeOCSPResponse(encoded);
180 PORT_CheckSuccess(CERT_GetOCSPResponseStatus(decoded));
181
182 PORT_CheckSuccess(CERT_VerifyOCSPResponseSignature(decoded, certHandle, &pwdata,
183 &obtainedSignerCert, caCert));
184 PORT_CheckSuccess(CERT_GetOCSPStatusForCertID(certHandle, decoded, cid,
185 obtainedSignerCert, now));
186 CERT_DestroyCertificate(obtainedSignerCert);
187
188 encodedRev = encodeRevoked(arena, cid, caCert);
189 PORT_Assert(encodedRev);
190 decodedRev = CERT_DecodeOCSPResponse(encodedRev);
191 PORT_CheckSuccess(CERT_GetOCSPResponseStatus(decodedRev));
192
193 PORT_CheckSuccess(CERT_VerifyOCSPResponseSignature(decodedRev, certHandle, &pwdata,
194 &obtainedSignerCert, caCert));
195 #ifdef DEBUG
196 {
197 rv = CERT_GetOCSPStatusForCertID(certHandle, decodedRev, cid,
198 obtainedSignerCert, now);
199 PORT_Assert(rv == SECFailure);
200 PORT_Assert(PORT_GetError() == SEC_ERROR_REVOKED_CERTIFICATE);
201 }
202 #else
203 (void)CERT_GetOCSPStatusForCertID(certHandle, decodedRev, cid,
204 obtainedSignerCert, now);
205 #endif
206 CERT_DestroyCertificate(obtainedSignerCert);
207
208 encodedFail = CERT_CreateEncodedOCSPErrorResponse(
209 arena, SEC_ERROR_OCSP_TRY_SERVER_LATER);
210 PORT_Assert(encodedFail);
211 decodedFail = CERT_DecodeOCSPResponse(encodedFail);
212 #ifdef DEBUG
213 {
214 rv = CERT_GetOCSPResponseStatus(decodedFail);
215 PORT_Assert(rv == SECFailure);
216 PORT_Assert(PORT_GetError() == SEC_ERROR_OCSP_TRY_SERVER_LATER);
217 }
218 #else
219 (void)CERT_GetOCSPResponseStatus(decodedFail);
220 #endif
221 retval = 0;
222 loser:
223 if (retval != 0)
224 SECU_PrintError(argv[0], "tests failed");
225
226 if (cid)
227 CERT_DestroyOCSPCertID(cid);
228 if (cert)
229 CERT_DestroyCertificate(cert);
230 if (caCert)
231 CERT_DestroyCertificate(caCert);
232 if (arena)
233 PORT_FreeArena(arena, PR_FALSE);
234 if (decoded)
235 CERT_DestroyOCSPResponse(decoded);
236 if (decodedRev)
237 CERT_DestroyOCSPResponse(decodedRev);
238 if (decodedFail)
239 CERT_DestroyOCSPResponse(decodedFail);
240 if (pwdata.data) {
241 PORT_Free(pwdata.data);
242 }
243
244 if (NSS_Shutdown() != SECSuccess) {
245 SECU_PrintError(argv[0], "NSS shutdown:");
246 if (retval == 0)
247 retval = -2;
248 }
249
250 return retval;
251 }
252