1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,170 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 tw=80 et: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* This simple program takes a database directory, and one or more tuples like 1.11 + * <typeOfResponse> <CertNick> <ExtraCertNick> <outPutFilename> 1.12 + * to generate (one or more) ocsp responses. 1.13 + */ 1.14 + 1.15 +#include <stdio.h> 1.16 + 1.17 +#include "mozilla/ArrayUtils.h" 1.18 + 1.19 +#include "nspr.h" 1.20 +#include "nss.h" 1.21 +#include "plarenas.h" 1.22 +#include "prerror.h" 1.23 +#include "ssl.h" 1.24 +#include "secerr.h" 1.25 + 1.26 +#include "OCSPCommon.h" 1.27 +#include "ScopedNSSTypes.h" 1.28 +#include "TLSServer.h" 1.29 + 1.30 +using namespace mozilla; 1.31 +using namespace mozilla::test; 1.32 + 1.33 +struct OCSPResponseName 1.34 +{ 1.35 + const char *mTypeString; 1.36 + const OCSPResponseType mORT; 1.37 +}; 1.38 + 1.39 +const static OCSPResponseName kOCSPResponseNameList[] = { 1.40 + { "good", ORTGood }, // the certificate is good 1.41 + { "revoked", ORTRevoked}, // the certificate has been revoked 1.42 + { "unknown", ORTUnknown}, // the responder doesn't know if the 1.43 + // cert is good 1.44 + { "goodotherca", ORTGoodOtherCA}, // the wrong CA has signed the 1.45 + // response 1.46 + { "expiredresponse", ORTExpired}, // the signature on the response has 1.47 + // expired 1.48 + { "oldvalidperiod", ORTExpiredFreshCA}, // fresh signature, but old validity 1.49 + // period 1.50 + { "empty", ORTEmpty}, // an empty stapled response 1.51 + 1.52 + { "malformed", ORTMalformed}, // the response from the responder 1.53 + // was malformed 1.54 + { "serverr", ORTSrverr}, // the response indicates there was a 1.55 + // server error 1.56 + { "trylater", ORTTryLater}, // the responder replied with 1.57 + // "try again later" 1.58 + { "resp-unsigned", ORTNeedsSig}, // the response needs a signature 1.59 + { "unauthorized", ORTUnauthorized}, // the responder does not know about 1.60 + // the cert 1.61 + { "bad-signature", ORTBadSignature}, // the response has a bad signature 1.62 + { "longvalidityalmostold", ORTLongValidityAlmostExpired}, // the response is 1.63 + // still valid, but the generation 1.64 + // is almost a year old 1.65 + { "ancientstillvalid", ORTAncientAlmostExpired}, // The response is still 1.66 + // valid but the generation is almost 1.67 + // two years old 1.68 +}; 1.69 + 1.70 + 1.71 +bool 1.72 +stringToOCSPResponseType(const char* respText, 1.73 + /*out*/ OCSPResponseType* OCSPType) 1.74 +{ 1.75 + if (!OCSPType) { 1.76 + return false; 1.77 + } 1.78 + for (uint32_t i = 0; i < mozilla::ArrayLength(kOCSPResponseNameList); i++) { 1.79 + if (strcmp(respText, kOCSPResponseNameList[i].mTypeString) == 0) { 1.80 + *OCSPType = kOCSPResponseNameList[i].mORT; 1.81 + return true; 1.82 + } 1.83 + } 1.84 + return false; 1.85 +} 1.86 + 1.87 +bool 1.88 +WriteResponse(const char* filename, const SECItem* item) 1.89 +{ 1.90 + if (!filename || !item || !item->data) { 1.91 + PR_fprintf(PR_STDERR, "invalid parameters to WriteResponse"); 1.92 + return false; 1.93 + } 1.94 + 1.95 + ScopedPRFileDesc outFile(PR_Open(filename, 1.96 + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 1.97 + 0644)); 1.98 + if (!outFile) { 1.99 + PrintPRError("cannot open file for writing"); 1.100 + return false; 1.101 + } 1.102 + int32_t rv = PR_Write(outFile, item->data, item->len); 1.103 + if (rv < 0 || (uint32_t) rv != item->len) { 1.104 + PrintPRError("File write failure"); 1.105 + return false; 1.106 + } 1.107 + 1.108 + return true; 1.109 +} 1.110 + 1.111 + 1.112 + 1.113 +int 1.114 +main(int argc, char* argv[]) 1.115 +{ 1.116 + 1.117 + if (argc < 6 || (argc - 6) % 4 != 0) { 1.118 + PR_fprintf(PR_STDERR, "usage: %s <NSS DB directory> <responsetype> " 1.119 + "<cert_nick> <extranick> <outfilename> [<resptype> " 1.120 + "<cert_nick> <extranick> <outfilename>]* \n", 1.121 + argv[0]); 1.122 + exit(EXIT_FAILURE); 1.123 + } 1.124 + const char* dbdir = argv[1]; 1.125 + 1.126 + SECStatus rv; 1.127 + rv = NSS_Init(dbdir); 1.128 + if (rv != SECSuccess) { 1.129 + PrintPRError("Failed to initialize NSS"); 1.130 + exit(EXIT_FAILURE); 1.131 + } 1.132 + PLArenaPool* arena = PORT_NewArena(256 * argc); 1.133 + if (!arena) { 1.134 + PrintPRError("PORT_NewArena failed"); 1.135 + exit(EXIT_FAILURE); 1.136 + } 1.137 + 1.138 + for (int i = 2; i + 3 < argc; i += 4) { 1.139 + const char* ocspTypeText = argv[i]; 1.140 + const char* certNick = argv[i + 1]; 1.141 + const char* extraCertname = argv[i + 2]; 1.142 + const char* filename = argv[i + 3]; 1.143 + 1.144 + OCSPResponseType ORT; 1.145 + if (!stringToOCSPResponseType(ocspTypeText, &ORT)) { 1.146 + PR_fprintf(PR_STDERR, "Cannot generate OCSP response of type %s\n", 1.147 + ocspTypeText); 1.148 + exit(EXIT_FAILURE); 1.149 + } 1.150 + 1.151 + ScopedCERTCertificate cert; 1.152 + cert = PK11_FindCertFromNickname(certNick, nullptr); 1.153 + if (!cert) { 1.154 + PR_fprintf(PR_STDERR, "Failed to find certificate with nick '%s'\n", 1.155 + certNick); 1.156 + exit(EXIT_FAILURE); 1.157 + } 1.158 + 1.159 + SECItemArray* response = GetOCSPResponseForType(ORT, cert, arena, 1.160 + extraCertname); 1.161 + if (!response) { 1.162 + PR_fprintf(PR_STDERR, "Failed to generate OCSP response of type %s " 1.163 + "for %s\n", ocspTypeText, certNick); 1.164 + exit(EXIT_FAILURE); 1.165 + } 1.166 + 1.167 + if (!WriteResponse(filename, &response->items[0])) { 1.168 + PR_fprintf(PR_STDERR, "Failed to write file %s\n", filename); 1.169 + exit(EXIT_FAILURE); 1.170 + } 1.171 + } 1.172 + return 0; 1.173 +}