Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 tw=80 et: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* This simple program takes a database directory, and one or more tuples like
8 * <typeOfResponse> <CertNick> <ExtraCertNick> <outPutFilename>
9 * to generate (one or more) ocsp responses.
10 */
12 #include <stdio.h>
14 #include "mozilla/ArrayUtils.h"
16 #include "nspr.h"
17 #include "nss.h"
18 #include "plarenas.h"
19 #include "prerror.h"
20 #include "ssl.h"
21 #include "secerr.h"
23 #include "OCSPCommon.h"
24 #include "ScopedNSSTypes.h"
25 #include "TLSServer.h"
27 using namespace mozilla;
28 using namespace mozilla::test;
30 struct OCSPResponseName
31 {
32 const char *mTypeString;
33 const OCSPResponseType mORT;
34 };
36 const static OCSPResponseName kOCSPResponseNameList[] = {
37 { "good", ORTGood }, // the certificate is good
38 { "revoked", ORTRevoked}, // the certificate has been revoked
39 { "unknown", ORTUnknown}, // the responder doesn't know if the
40 // cert is good
41 { "goodotherca", ORTGoodOtherCA}, // the wrong CA has signed the
42 // response
43 { "expiredresponse", ORTExpired}, // the signature on the response has
44 // expired
45 { "oldvalidperiod", ORTExpiredFreshCA}, // fresh signature, but old validity
46 // period
47 { "empty", ORTEmpty}, // an empty stapled response
49 { "malformed", ORTMalformed}, // the response from the responder
50 // was malformed
51 { "serverr", ORTSrverr}, // the response indicates there was a
52 // server error
53 { "trylater", ORTTryLater}, // the responder replied with
54 // "try again later"
55 { "resp-unsigned", ORTNeedsSig}, // the response needs a signature
56 { "unauthorized", ORTUnauthorized}, // the responder does not know about
57 // the cert
58 { "bad-signature", ORTBadSignature}, // the response has a bad signature
59 { "longvalidityalmostold", ORTLongValidityAlmostExpired}, // the response is
60 // still valid, but the generation
61 // is almost a year old
62 { "ancientstillvalid", ORTAncientAlmostExpired}, // The response is still
63 // valid but the generation is almost
64 // two years old
65 };
68 bool
69 stringToOCSPResponseType(const char* respText,
70 /*out*/ OCSPResponseType* OCSPType)
71 {
72 if (!OCSPType) {
73 return false;
74 }
75 for (uint32_t i = 0; i < mozilla::ArrayLength(kOCSPResponseNameList); i++) {
76 if (strcmp(respText, kOCSPResponseNameList[i].mTypeString) == 0) {
77 *OCSPType = kOCSPResponseNameList[i].mORT;
78 return true;
79 }
80 }
81 return false;
82 }
84 bool
85 WriteResponse(const char* filename, const SECItem* item)
86 {
87 if (!filename || !item || !item->data) {
88 PR_fprintf(PR_STDERR, "invalid parameters to WriteResponse");
89 return false;
90 }
92 ScopedPRFileDesc outFile(PR_Open(filename,
93 PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
94 0644));
95 if (!outFile) {
96 PrintPRError("cannot open file for writing");
97 return false;
98 }
99 int32_t rv = PR_Write(outFile, item->data, item->len);
100 if (rv < 0 || (uint32_t) rv != item->len) {
101 PrintPRError("File write failure");
102 return false;
103 }
105 return true;
106 }
110 int
111 main(int argc, char* argv[])
112 {
114 if (argc < 6 || (argc - 6) % 4 != 0) {
115 PR_fprintf(PR_STDERR, "usage: %s <NSS DB directory> <responsetype> "
116 "<cert_nick> <extranick> <outfilename> [<resptype> "
117 "<cert_nick> <extranick> <outfilename>]* \n",
118 argv[0]);
119 exit(EXIT_FAILURE);
120 }
121 const char* dbdir = argv[1];
123 SECStatus rv;
124 rv = NSS_Init(dbdir);
125 if (rv != SECSuccess) {
126 PrintPRError("Failed to initialize NSS");
127 exit(EXIT_FAILURE);
128 }
129 PLArenaPool* arena = PORT_NewArena(256 * argc);
130 if (!arena) {
131 PrintPRError("PORT_NewArena failed");
132 exit(EXIT_FAILURE);
133 }
135 for (int i = 2; i + 3 < argc; i += 4) {
136 const char* ocspTypeText = argv[i];
137 const char* certNick = argv[i + 1];
138 const char* extraCertname = argv[i + 2];
139 const char* filename = argv[i + 3];
141 OCSPResponseType ORT;
142 if (!stringToOCSPResponseType(ocspTypeText, &ORT)) {
143 PR_fprintf(PR_STDERR, "Cannot generate OCSP response of type %s\n",
144 ocspTypeText);
145 exit(EXIT_FAILURE);
146 }
148 ScopedCERTCertificate cert;
149 cert = PK11_FindCertFromNickname(certNick, nullptr);
150 if (!cert) {
151 PR_fprintf(PR_STDERR, "Failed to find certificate with nick '%s'\n",
152 certNick);
153 exit(EXIT_FAILURE);
154 }
156 SECItemArray* response = GetOCSPResponseForType(ORT, cert, arena,
157 extraCertname);
158 if (!response) {
159 PR_fprintf(PR_STDERR, "Failed to generate OCSP response of type %s "
160 "for %s\n", ocspTypeText, certNick);
161 exit(EXIT_FAILURE);
162 }
164 if (!WriteResponse(filename, &response->items[0])) {
165 PR_fprintf(PR_STDERR, "Failed to write file %s\n", filename);
166 exit(EXIT_FAILURE);
167 }
168 }
169 return 0;
170 }