GenerateOCSPResponse.cpp (5924B)
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/. */ 6 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 */ 11 12 #include "cert.h" 13 #include "nspr.h" 14 #include "nss.h" 15 #include "plarenas.h" 16 #include "prerror.h" 17 #include "ssl.h" 18 #include "secerr.h" 19 20 #include "OCSPCommon.h" 21 #include "ScopedNSSTypes.h" 22 #include "TLSServer.h" 23 24 using namespace mozilla; 25 using namespace mozilla::test; 26 27 struct OCSPResponseName { 28 const char* mTypeString; 29 const OCSPResponseType mORT; 30 }; 31 32 const static OCSPResponseName kOCSPResponseNameList[] = { 33 {"good", ORTGood}, // the certificate is good 34 {"good-delegated", ORTDelegatedIncluded}, // the certificate is good, using 35 // a delegated signer 36 {"revoked", ORTRevoked}, // the certificate has been revoked 37 {"unknown", ORTUnknown}, // the responder doesn't know if the 38 // cert is good 39 {"goodotherca", ORTGoodOtherCA}, // the wrong CA has signed the 40 // response 41 {"expiredresponse", ORTExpired}, // the signature on the response has 42 // expired 43 {"oldvalidperiod", ORTExpiredFreshCA}, // fresh signature, but old validity 44 // period 45 {"empty", ORTEmpty}, // an empty stapled response 46 47 {"malformed", ORTMalformed}, // the response from the responder 48 // was malformed 49 {"serverr", ORTSrverr}, // the response indicates there was a 50 // server error 51 {"trylater", ORTTryLater}, // the responder replied with 52 // "try again later" 53 {"resp-unsigned", ORTNeedsSig}, // the response needs a signature 54 {"unauthorized", ORTUnauthorized}, // the responder does not know about 55 // the cert 56 {"bad-signature", ORTBadSignature}, // the response has a bad signature 57 {"longvalidityalmostold", 58 ORTLongValidityAlmostExpired}, // the response is 59 // still valid, but the generation 60 // is almost a year old 61 {"ancientstillvalid", ORTAncientAlmostExpired}, // The response is still 62 // valid but the generation 63 // is almost two years old 64 }; 65 66 bool StringToOCSPResponseType(const char* respText, 67 /*out*/ OCSPResponseType* OCSPType) { 68 if (!OCSPType) { 69 return false; 70 } 71 for (auto ocspResponseName : kOCSPResponseNameList) { 72 if (strcmp(respText, ocspResponseName.mTypeString) == 0) { 73 *OCSPType = ocspResponseName.mORT; 74 return true; 75 } 76 } 77 return false; 78 } 79 80 bool WriteResponse(const char* filename, const SECItem* item) { 81 if (!filename || !item || !item->data) { 82 PR_fprintf(PR_STDERR, "invalid parameters to WriteResponse"); 83 return false; 84 } 85 86 UniquePRFileDesc outFile( 87 PR_Open(filename, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0644)); 88 if (!outFile) { 89 PrintPRError("cannot open file for writing"); 90 return false; 91 } 92 int32_t rv = PR_Write(outFile.get(), item->data, item->len); 93 if (rv < 0 || (uint32_t)rv != item->len) { 94 PrintPRError("File write failure"); 95 return false; 96 } 97 98 return true; 99 } 100 101 int main(int argc, char* argv[]) { 102 if (argc < 7 || (argc - 7) % 5 != 0) { 103 PR_fprintf( 104 PR_STDERR, 105 "usage: %s <NSS DB directory> <responsetype> " 106 "<cert_nick> <extranick> <this_update_skew> <outfilename> [<resptype> " 107 "<cert_nick> <extranick> <this_update_skew> <outfilename>]* \n", 108 argv[0]); 109 exit(EXIT_FAILURE); 110 } 111 SECStatus rv = InitializeNSS(argv[1]); 112 if (rv != SECSuccess) { 113 PR_fprintf(PR_STDERR, "Failed to initialize NSS\n"); 114 exit(EXIT_FAILURE); 115 } 116 UniquePLArenaPool arena(PORT_NewArena(256 * argc)); 117 if (!arena) { 118 PrintPRError("PORT_NewArena failed"); 119 exit(EXIT_FAILURE); 120 } 121 122 for (int i = 2; i + 3 < argc; i += 5) { 123 const char* ocspTypeText = argv[i]; 124 const char* certNick = argv[i + 1]; 125 const char* extraCertname = argv[i + 2]; 126 const char* skewChars = argv[i + 3]; 127 const char* filename = argv[i + 4]; 128 129 OCSPResponseType ORT; 130 if (!StringToOCSPResponseType(ocspTypeText, &ORT)) { 131 PR_fprintf(PR_STDERR, "Cannot generate OCSP response of type %s\n", 132 ocspTypeText); 133 exit(EXIT_FAILURE); 134 } 135 136 UniqueCERTCertificate cert(PK11_FindCertFromNickname(certNick, nullptr)); 137 if (!cert) { 138 PrintPRError("PK11_FindCertFromNickname failed"); 139 PR_fprintf(PR_STDERR, "Failed to find certificate with nick '%s'\n", 140 certNick); 141 exit(EXIT_FAILURE); 142 } 143 144 time_t skew = static_cast<time_t>(atoll(skewChars)); 145 146 SECItemArray* response = 147 GetOCSPResponseForType(ORT, cert, arena, extraCertname, skew); 148 if (!response) { 149 PR_fprintf(PR_STDERR, 150 "Failed to generate OCSP response of type %s " 151 "for %s\n", 152 ocspTypeText, certNick); 153 exit(EXIT_FAILURE); 154 } 155 156 if (!WriteResponse(filename, &response->items[0])) { 157 PR_fprintf(PR_STDERR, "Failed to write file %s\n", filename); 158 exit(EXIT_FAILURE); 159 } 160 } 161 return 0; 162 }