Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "OCSPCommon.h"
#include <stdio.h>
#include "TLSServer.h"
#include "mozpkix/pkixder.h"
#include "mozpkix/test/pkixtestnss.h"
#include "mozpkix/test/pkixtestutil.h"
#include "nss.h"
#include "secder.h"
#include "secerr.h"
using namespace mozilla;
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
using namespace mozilla::test;
static TestKeyPair* CreateTestKeyPairFromCert(
const UniqueCERTCertificate& cert) {
ScopedSECKEYPrivateKey privateKey(PK11_FindKeyByAnyCert(cert.get(), nullptr));
if (!privateKey) {
return nullptr;
}
ScopedSECKEYPublicKey publicKey(CERT_ExtractPublicKey(cert.get()));
if (!publicKey) {
return nullptr;
}
return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey);
}
SECItemArray* GetOCSPResponseForType(OCSPResponseType aORT,
const UniqueCERTCertificate& aCert,
const UniquePLArenaPool& aArena,
const char* aAdditionalCertName,
time_t aThisUpdateSkew,
ByteString* aSCTList) {
MOZ_ASSERT(aArena);
MOZ_ASSERT(aCert);
// Note: |aAdditionalCertName| may or may not need to be non-null depending
// on the |aORT| value given.
// Ensure NSS can sign responses using small RSA keys.
NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 512);
if (aORT == ORTNone) {
if (gDebugLevel >= DEBUG_WARNINGS) {
fprintf(stderr,
"GetOCSPResponseForType called with type ORTNone, "
"which makes no sense.\n");
}
return nullptr;
}
if (aORT == ORTEmpty) {
SECItemArray* arr = SECITEM_AllocArray(aArena.get(), nullptr, 1);
arr->items[0].data = nullptr;
arr->items[0].len = 0;
return arr;
}
time_t now = time(nullptr) + aThisUpdateSkew;
time_t oldNow = now - (8 * Time::ONE_DAY_IN_SECONDS);
mozilla::UniqueCERTCertificate cert(CERT_DupCertificate(aCert.get()));
if (aORT == ORTGoodOtherCert) {
cert.reset(PK11_FindCertFromNickname(aAdditionalCertName, nullptr));
if (!cert) {
PrintPRError("PK11_FindCertFromNickname failed");
return nullptr;
}
}
// XXX CERT_FindCertIssuer uses the old, deprecated path-building logic
mozilla::UniqueCERTCertificate issuerCert(
CERT_FindCertIssuer(aCert.get(), PR_Now(), certUsageSSLCA));
if (!issuerCert) {
PrintPRError("CERT_FindCertIssuer failed");
return nullptr;
}
Input issuer;
if (issuer.Init(cert->derIssuer.data, cert->derIssuer.len) != Success) {
return nullptr;
}
Input issuerPublicKey;
if (issuerPublicKey.Init(issuerCert->derPublicKey.data,
issuerCert->derPublicKey.len) != Success) {
return nullptr;
}
Input serialNumber;
if (serialNumber.Init(cert->serialNumber.data, cert->serialNumber.len) !=
Success) {
return nullptr;
}
CertID certID(issuer, issuerPublicKey, serialNumber);
OCSPResponseContext context(certID, now);
mozilla::UniqueCERTCertificate signerCert;
if (aORT == ORTGoodOtherCA || aORT == ORTDelegatedIncluded ||
aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissing ||
aORT == ORTDelegatedMissingMultiple) {
signerCert.reset(PK11_FindCertFromNickname(aAdditionalCertName, nullptr));
if (!signerCert) {
PrintPRError("PK11_FindCertFromNickname failed");
return nullptr;
}
}
ByteString certs[5];
if (aORT == ORTDelegatedIncluded) {
certs[0].assign(signerCert->derCert.data, signerCert->derCert.len);
context.certs = certs;
}
if (aORT == ORTDelegatedIncludedLast || aORT == ORTDelegatedMissingMultiple) {
certs[0].assign(issuerCert->derCert.data, issuerCert->derCert.len);
certs[1].assign(cert->derCert.data, cert->derCert.len);
certs[2].assign(issuerCert->derCert.data, issuerCert->derCert.len);
if (aORT != ORTDelegatedMissingMultiple) {
certs[3].assign(signerCert->derCert.data, signerCert->derCert.len);
}
context.certs = certs;
}
switch (aORT) {
case ORTMalformed:
context.responseStatus = 1;
break;
case ORTSrverr:
context.responseStatus = 2;
break;
case ORTTryLater:
context.responseStatus = 3;
break;
case ORTNeedsSig:
context.responseStatus = 5;
break;
case ORTUnauthorized:
context.responseStatus = 6;
break;
default:
// context.responseStatus is 0 in all other cases, and it has
// already been initialized in the constructor.
break;
}
if (aORT == ORTSkipResponseBytes) {
context.skipResponseBytes = true;
}
if (aORT == ORTExpired || aORT == ORTExpiredFreshCA ||
aORT == ORTRevokedOld || aORT == ORTUnknownOld) {
context.thisUpdate = oldNow;
context.nextUpdate = oldNow + Time::ONE_DAY_IN_SECONDS;
}
if (aORT == ORTLongValidityAlmostExpired) {
context.thisUpdate = now - (320 * Time::ONE_DAY_IN_SECONDS);
}
if (aORT == ORTAncientAlmostExpired) {
context.thisUpdate = now - (640 * Time::ONE_DAY_IN_SECONDS);
}
if (aORT == ORTRevoked || aORT == ORTRevokedOld) {
context.certStatus = 1;
}
if (aORT == ORTUnknown || aORT == ORTUnknownOld) {
context.certStatus = 2;
}
if (aORT == ORTBadSignature) {
context.badSignature = true;
}
OCSPResponseExtension extension;
if (aORT == ORTCriticalExtension || aORT == ORTNoncriticalExtension) {
// python DottedOIDToCode.py --tlv
// some-Mozilla-OID 1.3.6.1.4.1.13769.666.666.666.1.500.9.2
static const uint8_t tlv_some_Mozilla_OID[] = {
0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85,
0x1a, 0x85, 0x1a, 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x02};
extension.id.assign(tlv_some_Mozilla_OID, sizeof(tlv_some_Mozilla_OID));
extension.critical = (aORT == ORTCriticalExtension);
extension.value.push_back(0x05); // tag: NULL
extension.value.push_back(0x00); // length: 0
extension.next = nullptr;
context.responseExtensions = &extension;
}
if (aORT == ORTEmptyExtensions) {
context.includeEmptyExtensions = true;
}
if (!signerCert) {
signerCert.reset(CERT_DupCertificate(issuerCert.get()));
}
context.signerKeyPair.reset(CreateTestKeyPairFromCert(signerCert));
if (!context.signerKeyPair) {
PrintPRError("PK11_FindKeyByAnyCert failed");
return nullptr;
}
OCSPResponseExtension singleExtension;
if (aSCTList) {
// SingleExtension for Signed Certificate Timestamp List.
// See Section 3.3 of RFC 6962.
// python DottedOIDToCode.py --tlv
// id_ocsp_singleExtensionSctList 1.3.6.1.4.1.11129.2.4.5
static const uint8_t tlv_id_ocsp_singleExtensionSctList[] = {
0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x05};
singleExtension.id.assign(tlv_id_ocsp_singleExtensionSctList,
sizeof(tlv_id_ocsp_singleExtensionSctList));
singleExtension.critical = true;
singleExtension.value = TLV(der::OCTET_STRING, *aSCTList);
singleExtension.next = nullptr;
context.singleExtensions = &singleExtension;
}
ByteString response(CreateEncodedOCSPResponse(context));
if (ENCODING_FAILED(response)) {
PrintPRError("CreateEncodedOCSPResponse failed");
return nullptr;
}
SECItem item = {siBuffer, const_cast<uint8_t*>(response.data()),
static_cast<unsigned int>(response.length())};
SECItemArray arr = {&item, 1};
return SECITEM_DupArray(aArena.get(), &arr);
}