michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ts=2 sw=2 tw=80 et: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* This simple program takes a database directory, and one or more tuples like michael@0: * michael@0: * to generate (one or more) ocsp responses. michael@0: */ michael@0: michael@0: #include michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "nspr.h" michael@0: #include "nss.h" michael@0: #include "plarenas.h" michael@0: #include "prerror.h" michael@0: #include "ssl.h" michael@0: #include "secerr.h" michael@0: michael@0: #include "OCSPCommon.h" michael@0: #include "ScopedNSSTypes.h" michael@0: #include "TLSServer.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::test; michael@0: michael@0: struct OCSPResponseName michael@0: { michael@0: const char *mTypeString; michael@0: const OCSPResponseType mORT; michael@0: }; michael@0: michael@0: const static OCSPResponseName kOCSPResponseNameList[] = { michael@0: { "good", ORTGood }, // the certificate is good michael@0: { "revoked", ORTRevoked}, // the certificate has been revoked michael@0: { "unknown", ORTUnknown}, // the responder doesn't know if the michael@0: // cert is good michael@0: { "goodotherca", ORTGoodOtherCA}, // the wrong CA has signed the michael@0: // response michael@0: { "expiredresponse", ORTExpired}, // the signature on the response has michael@0: // expired michael@0: { "oldvalidperiod", ORTExpiredFreshCA}, // fresh signature, but old validity michael@0: // period michael@0: { "empty", ORTEmpty}, // an empty stapled response michael@0: michael@0: { "malformed", ORTMalformed}, // the response from the responder michael@0: // was malformed michael@0: { "serverr", ORTSrverr}, // the response indicates there was a michael@0: // server error michael@0: { "trylater", ORTTryLater}, // the responder replied with michael@0: // "try again later" michael@0: { "resp-unsigned", ORTNeedsSig}, // the response needs a signature michael@0: { "unauthorized", ORTUnauthorized}, // the responder does not know about michael@0: // the cert michael@0: { "bad-signature", ORTBadSignature}, // the response has a bad signature michael@0: { "longvalidityalmostold", ORTLongValidityAlmostExpired}, // the response is michael@0: // still valid, but the generation michael@0: // is almost a year old michael@0: { "ancientstillvalid", ORTAncientAlmostExpired}, // The response is still michael@0: // valid but the generation is almost michael@0: // two years old michael@0: }; michael@0: michael@0: michael@0: bool michael@0: stringToOCSPResponseType(const char* respText, michael@0: /*out*/ OCSPResponseType* OCSPType) michael@0: { michael@0: if (!OCSPType) { michael@0: return false; michael@0: } michael@0: for (uint32_t i = 0; i < mozilla::ArrayLength(kOCSPResponseNameList); i++) { michael@0: if (strcmp(respText, kOCSPResponseNameList[i].mTypeString) == 0) { michael@0: *OCSPType = kOCSPResponseNameList[i].mORT; michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: WriteResponse(const char* filename, const SECItem* item) michael@0: { michael@0: if (!filename || !item || !item->data) { michael@0: PR_fprintf(PR_STDERR, "invalid parameters to WriteResponse"); michael@0: return false; michael@0: } michael@0: michael@0: ScopedPRFileDesc outFile(PR_Open(filename, michael@0: PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, michael@0: 0644)); michael@0: if (!outFile) { michael@0: PrintPRError("cannot open file for writing"); michael@0: return false; michael@0: } michael@0: int32_t rv = PR_Write(outFile, item->data, item->len); michael@0: if (rv < 0 || (uint32_t) rv != item->len) { michael@0: PrintPRError("File write failure"); michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: michael@0: michael@0: int michael@0: main(int argc, char* argv[]) michael@0: { michael@0: michael@0: if (argc < 6 || (argc - 6) % 4 != 0) { michael@0: PR_fprintf(PR_STDERR, "usage: %s " michael@0: " [ " michael@0: " ]* \n", michael@0: argv[0]); michael@0: exit(EXIT_FAILURE); michael@0: } michael@0: const char* dbdir = argv[1]; michael@0: michael@0: SECStatus rv; michael@0: rv = NSS_Init(dbdir); michael@0: if (rv != SECSuccess) { michael@0: PrintPRError("Failed to initialize NSS"); michael@0: exit(EXIT_FAILURE); michael@0: } michael@0: PLArenaPool* arena = PORT_NewArena(256 * argc); michael@0: if (!arena) { michael@0: PrintPRError("PORT_NewArena failed"); michael@0: exit(EXIT_FAILURE); michael@0: } michael@0: michael@0: for (int i = 2; i + 3 < argc; i += 4) { michael@0: const char* ocspTypeText = argv[i]; michael@0: const char* certNick = argv[i + 1]; michael@0: const char* extraCertname = argv[i + 2]; michael@0: const char* filename = argv[i + 3]; michael@0: michael@0: OCSPResponseType ORT; michael@0: if (!stringToOCSPResponseType(ocspTypeText, &ORT)) { michael@0: PR_fprintf(PR_STDERR, "Cannot generate OCSP response of type %s\n", michael@0: ocspTypeText); michael@0: exit(EXIT_FAILURE); michael@0: } michael@0: michael@0: ScopedCERTCertificate cert; michael@0: cert = PK11_FindCertFromNickname(certNick, nullptr); michael@0: if (!cert) { michael@0: PR_fprintf(PR_STDERR, "Failed to find certificate with nick '%s'\n", michael@0: certNick); michael@0: exit(EXIT_FAILURE); michael@0: } michael@0: michael@0: SECItemArray* response = GetOCSPResponseForType(ORT, cert, arena, michael@0: extraCertname); michael@0: if (!response) { michael@0: PR_fprintf(PR_STDERR, "Failed to generate OCSP response of type %s " michael@0: "for %s\n", ocspTypeText, certNick); michael@0: exit(EXIT_FAILURE); michael@0: } michael@0: michael@0: if (!WriteResponse(filename, &response->items[0])) { michael@0: PR_fprintf(PR_STDERR, "Failed to write file %s\n", filename); michael@0: exit(EXIT_FAILURE); michael@0: } michael@0: } michael@0: return 0; michael@0: }