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