security/pkix/test/lib/pkixtestutil.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
     3 /* Copyright 2013 Mozilla Foundation
     4  *
     5  * Licensed under the Apache License, Version 2.0 (the "License");
     6  * you may not use this file except in compliance with the License.
     7  * You may obtain a copy of the License at
     8  *
     9  *     http://www.apache.org/licenses/LICENSE-2.0
    10  *
    11  * Unless required by applicable law or agreed to in writing, software
    12  * distributed under the License is distributed on an "AS IS" BASIS,
    13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  * See the License for the specific language governing permissions and
    15  * limitations under the License.
    16  */
    18 #include "pkixcheck.h"
    19 #include "pkixder.h"
    20 #include "pkixtestutil.h"
    22 #include "cryptohi.h"
    23 #include "hasht.h"
    24 #include "pk11pub.h"
    25 #include "prinit.h"
    26 #include "secder.h"
    28 namespace mozilla { namespace pkix { namespace test {
    30 class Output
    31 {
    32 public:
    33   Output()
    34     : numItems(0)
    35     , length(0)
    36   {
    37   }
    39   // Makes a shallow copy of the input item. All input items must have a
    40   // lifetime that extends at least to where Squash is called.
    41   der::Result Add(const SECItem* item)
    42   {
    43     PR_ASSERT(item);
    44     PR_ASSERT(item->data);
    46     if (numItems >= MaxSequenceItems) {
    47       return der::Fail(SEC_ERROR_INVALID_ARGS);
    48     }
    49     if (length + item->len > 65535) {
    50       return der::Fail(SEC_ERROR_INVALID_ARGS);
    51     }
    53     contents[numItems] = item;
    54     numItems++;
    55     length += item->len;
    56     return der::Success;
    57   }
    59   SECItem* Squash(PLArenaPool* arena, uint8_t tag)
    60   {
    61     PR_ASSERT(arena);
    63     size_t lengthLength = length < 128 ? 1
    64                         : length < 256 ? 2
    65                                        : 3;
    66     size_t totalLength = 1 + lengthLength + length;
    67     SECItem* output = SECITEM_AllocItem(arena, nullptr, totalLength);
    68     if (!output) {
    69       return nullptr;
    70     }
    71     uint8_t* d = output->data;
    72     *d++ = tag;
    73     EncodeLength(d, length, lengthLength);
    74     d += lengthLength;
    75     for (size_t i = 0; i < numItems; i++) {
    76       memcpy(d, contents[i]->data, contents[i]->len);
    77       d += contents[i]->len;
    78     }
    79     return output;
    80   }
    82 private:
    83   void
    84   EncodeLength(uint8_t* data, size_t length, size_t lengthLength)
    85   {
    86     switch (lengthLength) {
    87       case 1:
    88         data[0] = length;
    89         break;
    90       case 2:
    91         data[0] = 0x81;
    92         data[1] = length;
    93         break;
    94       case 3:
    95         data[0] = 0x82;
    96         data[1] = length / 256;
    97         data[2] = length % 256;
    98         break;
    99       default:
   100         PR_NOT_REACHED("EncodeLength: bad lengthLength");
   101         PR_Abort();
   102     }
   103   }
   105   static const size_t MaxSequenceItems = 5;
   106   const SECItem* contents[MaxSequenceItems];
   107   size_t numItems;
   108   size_t length;
   110   Output(const Output&) /* = delete */;
   111   void operator=(const Output&) /* = delete */;
   112 };
   114 OCSPResponseContext::OCSPResponseContext(PLArenaPool* arena,
   115                                          CERTCertificate* cert,
   116                                          PRTime time)
   117   : arena(arena)
   118   , cert(CERT_DupCertificate(cert))
   119   , issuerCert(nullptr)
   120   , signerCert(nullptr)
   121   , responseStatus(0)
   122   , skipResponseBytes(false)
   123   , producedAt(time)
   124   , thisUpdate(time)
   125   , nextUpdate(time + 10 * PR_USEC_PER_SEC)
   126   , includeNextUpdate(true)
   127   , certIDHashAlg(SEC_OID_SHA1)
   128   , certStatus(0)
   129   , revocationTime(0)
   130   , badSignature(false)
   131   , responderIDType(ByKeyHash)
   132   , extensions(nullptr)
   133   , includeEmptyExtensions(false)
   134 {
   135   for (size_t i = 0; i < MaxIncludedCertificates; i++) {
   136     includedCertificates[i] = nullptr;
   137   }
   138 }
   140 static SECItem* ResponseBytes(OCSPResponseContext& context);
   141 static SECItem* BasicOCSPResponse(OCSPResponseContext& context);
   142 static SECItem* ResponseData(OCSPResponseContext& context);
   143 static SECItem* ResponderID(OCSPResponseContext& context);
   144 static SECItem* KeyHash(OCSPResponseContext& context);
   145 static SECItem* SingleResponse(OCSPResponseContext& context);
   146 static SECItem* CertID(OCSPResponseContext& context);
   147 static SECItem* CertStatus(OCSPResponseContext& context);
   148 static SECItem* Certificates(OCSPResponseContext& context);
   150 static SECItem*
   151 EncodeNested(PLArenaPool* arena, uint8_t tag, SECItem* inner)
   152 {
   153   Output output;
   154   if (output.Add(inner) != der::Success) {
   155     return nullptr;
   156   }
   157   return output.Squash(arena, tag);
   158 }
   160 // A return value of 0 is an error, but this should never happen in practice
   161 // because this function aborts in that case.
   162 static size_t
   163 HashAlgorithmToLength(SECOidTag hashAlg)
   164 {
   165   switch (hashAlg) {
   166     case SEC_OID_SHA1:
   167       return SHA1_LENGTH;
   168     case SEC_OID_SHA256:
   169       return SHA256_LENGTH;
   170     case SEC_OID_SHA384:
   171       return SHA384_LENGTH;
   172     case SEC_OID_SHA512:
   173       return SHA512_LENGTH;
   174     default:
   175       PR_NOT_REACHED("HashAlgorithmToLength: bad hashAlg");
   176       PR_Abort();
   177   }
   178   return 0;
   179 }
   181 static SECItem*
   182 HashedOctetString(PLArenaPool* arena, const SECItem* bytes, SECOidTag hashAlg)
   183 {
   184   size_t hashLen = HashAlgorithmToLength(hashAlg);
   185   if (hashLen == 0) {
   186     return nullptr;
   187   }
   188   SECItem* hashBuf = SECITEM_AllocItem(arena, nullptr, hashLen);
   189   if (!hashBuf) {
   190     return nullptr;
   191   }
   192   if (PK11_HashBuf(hashAlg, hashBuf->data, bytes->data, bytes->len)
   193         != SECSuccess) {
   194     return nullptr;
   195   }
   197   return EncodeNested(arena, der::OCTET_STRING, hashBuf);
   198 }
   200 static SECItem*
   201 KeyHashHelper(PLArenaPool* arena, const CERTCertificate* cert)
   202 {
   203   // We only need a shallow copy here.
   204   SECItem spk = cert->subjectPublicKeyInfo.subjectPublicKey;
   205   DER_ConvertBitString(&spk); // bits to bytes
   206   return HashedOctetString(arena, &spk, SEC_OID_SHA1);
   207 }
   209 static SECItem*
   210 AlgorithmIdentifier(PLArenaPool* arena, SECOidTag algTag)
   211 {
   212   SECAlgorithmIDStr aid;
   213   aid.algorithm.data = nullptr;
   214   aid.algorithm.len = 0;
   215   aid.parameters.data = nullptr;
   216   aid.parameters.len = 0;
   217   if (SECOID_SetAlgorithmID(arena, &aid, algTag, nullptr) != SECSuccess) {
   218     return nullptr;
   219   }
   220   static const SEC_ASN1Template algorithmIDTemplate[] = {
   221     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECAlgorithmID) },
   222     { SEC_ASN1_OBJECT_ID, offsetof(SECAlgorithmID, algorithm) },
   223     { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, offsetof(SECAlgorithmID, parameters) },
   224     { 0 }
   225   };
   226   SECItem* algorithmID = SEC_ASN1EncodeItem(arena, nullptr, &aid,
   227                                             algorithmIDTemplate);
   228   return algorithmID;
   229 }
   231 static SECItem*
   232 PRTimeToEncodedTime(PLArenaPool* arena, PRTime time)
   233 {
   234   SECItem derTime;
   235   if (DER_TimeToGeneralizedTimeArena(arena, &derTime, time) != SECSuccess) {
   236     return nullptr;
   237   }
   238   return EncodeNested(arena, der::GENERALIZED_TIME, &derTime);
   239 }
   241 SECItem*
   242 CreateEncodedOCSPResponse(OCSPResponseContext& context)
   243 {
   244   if (!context.arena || !context.cert || !context.issuerCert ||
   245       !context.signerCert) {
   246     PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
   247     return nullptr;
   248   }
   250   // OCSPResponse ::= SEQUENCE {
   251   //    responseStatus          OCSPResponseStatus,
   252   //    responseBytes       [0] EXPLICIT ResponseBytes OPTIONAL }
   254   // OCSPResponseStatus ::= ENUMERATED {
   255   //    successful          (0),  -- Response has valid confirmations
   256   //    malformedRequest    (1),  -- Illegal confirmation request
   257   //    internalError       (2),  -- Internal error in issuer
   258   //    tryLater            (3),  -- Try again later
   259   //                              -- (4) is not used
   260   //    sigRequired         (5),  -- Must sign the request
   261   //    unauthorized        (6)   -- Request unauthorized
   262   // }
   263   SECItem* responseStatus = SECITEM_AllocItem(context.arena, nullptr, 3);
   264   if (!responseStatus) {
   265     return nullptr;
   266   }
   267   responseStatus->data[0] = der::ENUMERATED;
   268   responseStatus->data[1] = 1;
   269   responseStatus->data[2] = context.responseStatus;
   271   SECItem* responseBytesNested = nullptr;
   272   if (!context.skipResponseBytes) {
   273     SECItem* responseBytes = ResponseBytes(context);
   274     if (!responseBytes) {
   275       return nullptr;
   276     }
   278     responseBytesNested = EncodeNested(context.arena,
   279                                        der::CONSTRUCTED |
   280                                        der::CONTEXT_SPECIFIC,
   281                                        responseBytes);
   282     if (!responseBytesNested) {
   283       return nullptr;
   284     }
   285   }
   287   Output output;
   288   if (output.Add(responseStatus) != der::Success) {
   289     return nullptr;
   290   }
   291   if (responseBytesNested) {
   292     if (output.Add(responseBytesNested) != der::Success) {
   293       return nullptr;
   294     }
   295   }
   296   return output.Squash(context.arena, der::SEQUENCE);
   297 }
   299 // ResponseBytes ::= SEQUENCE {
   300 //    responseType            OBJECT IDENTIFIER,
   301 //    response                OCTET STRING }
   302 SECItem*
   303 ResponseBytes(OCSPResponseContext& context)
   304 {
   305   // Includes tag and length
   306   static const uint8_t id_pkix_ocsp_basic_encoded[] = {
   307     0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
   308   };
   309   SECItem id_pkix_ocsp_basic = {
   310     siBuffer,
   311     const_cast<uint8_t*>(id_pkix_ocsp_basic_encoded),
   312     PR_ARRAY_SIZE(id_pkix_ocsp_basic_encoded)
   313   };
   314   SECItem* response = BasicOCSPResponse(context);
   315   if (!response) {
   316     return nullptr;
   317   }
   318   SECItem* responseNested = EncodeNested(context.arena, der::OCTET_STRING,
   319                                          response);
   320   if (!responseNested) {
   321     return nullptr;
   322   }
   324   Output output;
   325   if (output.Add(&id_pkix_ocsp_basic) != der::Success) {
   326     return nullptr;
   327   }
   328   if (output.Add(responseNested) != der::Success) {
   329     return nullptr;
   330   }
   331   return output.Squash(context.arena, der::SEQUENCE);
   332 }
   334 // BasicOCSPResponse ::= SEQUENCE {
   335 //   tbsResponseData          ResponseData,
   336 //   signatureAlgorithm       AlgorithmIdentifier,
   337 //   signature                BIT STRING,
   338 //   certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
   339 SECItem*
   340 BasicOCSPResponse(OCSPResponseContext& context)
   341 {
   342   SECItem* tbsResponseData = ResponseData(context);
   343   if (!tbsResponseData) {
   344     return nullptr;
   345   }
   348   pkix::ScopedPtr<SECKEYPrivateKey, SECKEY_DestroyPrivateKey> privKey(
   349     PK11_FindKeyByAnyCert(context.signerCert.get(), nullptr));
   350   if (!privKey) {
   351     return nullptr;
   352   }
   353   SECOidTag signatureAlgTag = SEC_GetSignatureAlgorithmOidTag(privKey->keyType,
   354                                                               SEC_OID_SHA1);
   355   if (signatureAlgTag == SEC_OID_UNKNOWN) {
   356     return nullptr;
   357   }
   358   SECItem* signatureAlgorithm = AlgorithmIdentifier(context.arena,
   359                                                     signatureAlgTag);
   360   if (!signatureAlgorithm) {
   361     return nullptr;
   362   }
   364   // SEC_SignData doesn't take an arena parameter, so we have to manage
   365   // the memory allocated in signature.
   366   SECItem signature;
   367   if (SEC_SignData(&signature, tbsResponseData->data, tbsResponseData->len,
   368                    privKey.get(), signatureAlgTag) != SECSuccess)
   369   {
   370     return nullptr;
   371   }
   372   // We have to add a byte at the beginning indicating no unused bits.
   373   // TODO: add ability to have signatures of bit length not divisible by 8,
   374   // resulting in unused bits in the bitstring encoding
   375   SECItem* prefixedSignature = SECITEM_AllocItem(context.arena, nullptr,
   376                                                  signature.len + 1);
   377   if (!prefixedSignature) {
   378     SECITEM_FreeItem(&signature, false);
   379     return nullptr;
   380   }
   381   prefixedSignature->data[0] = 0;
   382   memcpy(prefixedSignature->data + 1, signature.data, signature.len);
   383   SECITEM_FreeItem(&signature, false);
   384   if (context.badSignature) {
   385     PR_ASSERT(prefixedSignature->len > 8);
   386     prefixedSignature->data[8]++;
   387   }
   388   SECItem* signatureNested = EncodeNested(context.arena, der::BIT_STRING,
   389                                           prefixedSignature);
   390   if (!signatureNested) {
   391     return nullptr;
   392   }
   393   SECItem* certificatesNested = nullptr;
   394   if (context.includedCertificates[0]) {
   395     SECItem* certificates = Certificates(context);
   396     if (!certificates) {
   397       return nullptr;
   398     }
   399     certificatesNested = EncodeNested(context.arena,
   400                                       der::CONSTRUCTED |
   401                                       der::CONTEXT_SPECIFIC |
   402                                       0,
   403                                       certificates);
   404     if (!certificatesNested) {
   405       return nullptr;
   406     }
   407   }
   409   Output output;
   410   if (output.Add(tbsResponseData) != der::Success) {
   411     return nullptr;
   412   }
   413   if (output.Add(signatureAlgorithm) != der::Success) {
   414     return nullptr;
   415   }
   416   if (output.Add(signatureNested) != der::Success) {
   417     return nullptr;
   418   }
   419   if (certificatesNested) {
   420     if (output.Add(certificatesNested) != der::Success) {
   421       return nullptr;
   422     }
   423   }
   424   return output.Squash(context.arena, der::SEQUENCE);
   425 }
   427 // Extension ::= SEQUENCE {
   428 //   id               OBJECT IDENTIFIER,
   429 //   critical         BOOLEAN DEFAULT FALSE
   430 //   value            OCTET STRING
   431 // }
   432 static SECItem*
   433 OCSPExtension(OCSPResponseContext& context, OCSPResponseExtension* extension)
   434 {
   435   Output output;
   436   if (output.Add(&extension->id) != der::Success) {
   437     return nullptr;
   438   }
   439   if (extension->critical) {
   440     static const uint8_t trueEncoded[3] = { 0x01, 0x01, 0xFF };
   441     SECItem critical = {
   442       siBuffer,
   443       const_cast<uint8_t*>(trueEncoded),
   444       PR_ARRAY_SIZE(trueEncoded)
   445     };
   446     if (output.Add(&critical) != der::Success) {
   447       return nullptr;
   448     }
   449   }
   450   SECItem* value = EncodeNested(context.arena, der::OCTET_STRING,
   451                                 &extension->value);
   452   if (!value) {
   453     return nullptr;
   454   }
   455   if (output.Add(value) != der::Success) {
   456     return nullptr;
   457   }
   458   return output.Squash(context.arena, der::SEQUENCE);
   459 }
   461 // Extensions ::= [1] {
   462 //   SEQUENCE OF Extension
   463 // }
   464 static SECItem*
   465 Extensions(OCSPResponseContext& context)
   466 {
   467   Output output;
   468   for (OCSPResponseExtension* extension = context.extensions;
   469        extension; extension = extension->next) {
   470     SECItem* extensionEncoded = OCSPExtension(context, extension);
   471     if (!extensionEncoded) {
   472       return nullptr;
   473     }
   474     if (output.Add(extensionEncoded) != der::Success) {
   475       return nullptr;
   476     }
   477   }
   478   SECItem* extensionsEncoded = output.Squash(context.arena, der::SEQUENCE);
   479   if (!extensionsEncoded) {
   480     return nullptr;
   481   }
   482   return EncodeNested(context.arena,
   483                       der::CONSTRUCTED |
   484                       der::CONTEXT_SPECIFIC |
   485                       1,
   486                       extensionsEncoded);
   487 }
   489 // ResponseData ::= SEQUENCE {
   490 //    version             [0] EXPLICIT Version DEFAULT v1,
   491 //    responderID             ResponderID,
   492 //    producedAt              GeneralizedTime,
   493 //    responses               SEQUENCE OF SingleResponse,
   494 //    responseExtensions  [1] EXPLICIT Extensions OPTIONAL }
   495 SECItem*
   496 ResponseData(OCSPResponseContext& context)
   497 {
   498   SECItem* responderID = ResponderID(context);
   499   if (!responderID) {
   500     return nullptr;
   501   }
   502   SECItem* producedAtEncoded = PRTimeToEncodedTime(context.arena,
   503                                                    context.producedAt);
   504   if (!producedAtEncoded) {
   505     return nullptr;
   506   }
   507   SECItem* responses = SingleResponse(context);
   508   if (!responses) {
   509     return nullptr;
   510   }
   511   SECItem* responsesNested = EncodeNested(context.arena, der::SEQUENCE,
   512                                           responses);
   513   if (!responsesNested) {
   514     return nullptr;
   515   }
   516   SECItem* responseExtensions = nullptr;
   517   if (context.extensions || context.includeEmptyExtensions) {
   518     responseExtensions = Extensions(context);
   519   }
   521   Output output;
   522   if (output.Add(responderID) != der::Success) {
   523     return nullptr;
   524   }
   525   if (output.Add(producedAtEncoded) != der::Success) {
   526     return nullptr;
   527   }
   528   if (output.Add(responsesNested) != der::Success) {
   529     return nullptr;
   530   }
   531   if (responseExtensions) {
   532     if (output.Add(responseExtensions) != der::Success) {
   533       return nullptr;
   534     }
   535   }
   536   return output.Squash(context.arena, der::SEQUENCE);
   537 }
   539 // ResponderID ::= CHOICE {
   540 //    byName              [1] Name,
   541 //    byKey               [2] KeyHash }
   542 // }
   543 SECItem*
   544 ResponderID(OCSPResponseContext& context)
   545 {
   546   SECItem* contents = nullptr;
   547   if (context.responderIDType == OCSPResponseContext::ByName) {
   548     contents = &context.signerCert->derSubject;
   549   } else if (context.responderIDType == OCSPResponseContext::ByKeyHash) {
   550     contents = KeyHash(context);
   551     if (!contents) {
   552       return nullptr;
   553     }
   554   } else {
   555     return nullptr;
   556   }
   558   return EncodeNested(context.arena,
   559                       der::CONSTRUCTED |
   560                       der::CONTEXT_SPECIFIC |
   561                       context.responderIDType,
   562                       contents);
   563 }
   565 // KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
   566 //                          -- (i.e., the SHA-1 hash of the value of the
   567 //                          -- BIT STRING subjectPublicKey [excluding
   568 //                          -- the tag, length, and number of unused
   569 //                          -- bits] in the responder's certificate)
   570 SECItem*
   571 KeyHash(OCSPResponseContext& context)
   572 {
   573   return KeyHashHelper(context.arena, context.signerCert.get());
   574 }
   576 // SingleResponse ::= SEQUENCE {
   577 //    certID                  CertID,
   578 //    certStatus              CertStatus,
   579 //    thisUpdate              GeneralizedTime,
   580 //    nextUpdate          [0] EXPLICIT GeneralizedTime OPTIONAL,
   581 //    singleExtensions    [1] EXPLICIT Extensions OPTIONAL }
   582 SECItem*
   583 SingleResponse(OCSPResponseContext& context)
   584 {
   585   SECItem* certID = CertID(context);
   586   if (!certID) {
   587     return nullptr;
   588   }
   589   SECItem* certStatus = CertStatus(context);
   590   if (!certStatus) {
   591     return nullptr;
   592   }
   593   SECItem* thisUpdateEncoded = PRTimeToEncodedTime(context.arena,
   594                                                    context.thisUpdate);
   595   if (!thisUpdateEncoded) {
   596     return nullptr;
   597   }
   598   SECItem* nextUpdateEncodedNested = nullptr;
   599   if (context.includeNextUpdate) {
   600     SECItem* nextUpdateEncoded = PRTimeToEncodedTime(context.arena,
   601                                                      context.nextUpdate);
   602     if (!nextUpdateEncoded) {
   603       return nullptr;
   604     }
   605     nextUpdateEncodedNested = EncodeNested(context.arena,
   606                                            der::CONSTRUCTED |
   607                                            der::CONTEXT_SPECIFIC |
   608                                            0,
   609                                            nextUpdateEncoded);
   610     if (!nextUpdateEncodedNested) {
   611       return nullptr;
   612     }
   613   }
   615   Output output;
   616   if (output.Add(certID) != der::Success) {
   617     return nullptr;
   618   }
   619   if (output.Add(certStatus) != der::Success) {
   620     return nullptr;
   621   }
   622   if (output.Add(thisUpdateEncoded) != der::Success) {
   623     return nullptr;
   624   }
   625   if (nextUpdateEncodedNested) {
   626     if (output.Add(nextUpdateEncodedNested) != der::Success) {
   627       return nullptr;
   628     }
   629   }
   630   return output.Squash(context.arena, der::SEQUENCE);
   631 }
   633 // CertID          ::=     SEQUENCE {
   634 //        hashAlgorithm       AlgorithmIdentifier,
   635 //        issuerNameHash      OCTET STRING, -- Hash of issuer's DN
   636 //        issuerKeyHash       OCTET STRING, -- Hash of issuer's public key
   637 //        serialNumber        CertificateSerialNumber }
   638 SECItem*
   639 CertID(OCSPResponseContext& context)
   640 {
   641   SECItem* hashAlgorithm = AlgorithmIdentifier(context.arena,
   642                                                context.certIDHashAlg);
   643   if (!hashAlgorithm) {
   644     return nullptr;
   645   }
   646   SECItem* issuerNameHash = HashedOctetString(context.arena,
   647                                               &context.issuerCert->derSubject,
   648                                               context.certIDHashAlg);
   649   if (!issuerNameHash) {
   650     return nullptr;
   651   }
   652   SECItem* issuerKeyHash = KeyHashHelper(context.arena,
   653                                          context.issuerCert.get());
   654   if (!issuerKeyHash) {
   655     return nullptr;
   656   }
   657   static const SEC_ASN1Template serialTemplate[] = {
   658     { SEC_ASN1_INTEGER, offsetof(CERTCertificate, serialNumber) },
   659     { 0 }
   660   };
   661   SECItem* serialNumber = SEC_ASN1EncodeItem(context.arena, nullptr,
   662                                              context.cert.get(),
   663                                              serialTemplate);
   664   if (!serialNumber) {
   665     return nullptr;
   666   }
   668   Output output;
   669   if (output.Add(hashAlgorithm) != der::Success) {
   670     return nullptr;
   671   }
   672   if (output.Add(issuerNameHash) != der::Success) {
   673     return nullptr;
   674   }
   675   if (output.Add(issuerKeyHash) != der::Success) {
   676     return nullptr;
   677   }
   678   if (output.Add(serialNumber) != der::Success) {
   679     return nullptr;
   680   }
   681   return output.Squash(context.arena, der::SEQUENCE);
   682 }
   684 // CertStatus ::= CHOICE {
   685 //    good                [0] IMPLICIT NULL,
   686 //    revoked             [1] IMPLICIT RevokedInfo,
   687 //    unknown             [2] IMPLICIT UnknownInfo }
   688 //
   689 // RevokedInfo ::= SEQUENCE {
   690 //    revocationTime              GeneralizedTime,
   691 //    revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
   692 //
   693 // UnknownInfo ::= NULL
   694 //
   695 SECItem*
   696 CertStatus(OCSPResponseContext& context)
   697 {
   698   switch (context.certStatus) {
   699     // Both good and unknown are ultimately represented as NULL - the only
   700     // difference is in the tag that identifies them.
   701     case 0:
   702     case 2:
   703     {
   704       SECItem* status = SECITEM_AllocItem(context.arena, nullptr, 2);
   705       if (!status) {
   706         return nullptr;
   707       }
   708       status->data[0] = der::CONTEXT_SPECIFIC | context.certStatus;
   709       status->data[1] = 0;
   710       return status;
   711     }
   712     case 1:
   713     {
   714       SECItem* revocationTime = PRTimeToEncodedTime(context.arena,
   715                                                     context.revocationTime);
   716       if (!revocationTime) {
   717         return nullptr;
   718       }
   719       // TODO(bug 980536): add support for revocationReason
   720       return EncodeNested(context.arena,
   721                           der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 1,
   722                           revocationTime);
   723     }
   724     default:
   725       PR_NOT_REACHED("CertStatus: bad context.certStatus");
   726       PR_Abort();
   727   }
   728   return nullptr;
   729 }
   731 // SEQUENCE OF Certificate
   732 SECItem*
   733 Certificates(OCSPResponseContext& context)
   734 {
   735   Output output;
   736   for (size_t i = 0; i < context.MaxIncludedCertificates; i++) {
   737     CERTCertificate* cert = context.includedCertificates[i].get();
   738     if (!cert) {
   739       break;
   740     }
   741     output.Add(&cert->derCert);
   742   }
   743   return output.Squash(context.arena, der::SEQUENCE);
   744 }
   746 } } } // namespace mozilla::pkix::test

mercurial