security/manager/ssl/tests/unit/tlsserver/cmd/GenerateOCSPResponse.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

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 }

mercurial