1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "OCSPCommon.h"
10 #include "mozpkix/pkixder.h"
11 #include "mozpkix/test/pkixtestnss.h"
12 #include "mozpkix/test/pkixtestutil.h"
17 using namespace mozilla
;
18 using namespace mozilla::pkix
;
19 using namespace mozilla::pkix::test
;
20 using namespace mozilla::test
;
22 static TestKeyPair
* CreateTestKeyPairFromCert(
23 const UniqueCERTCertificate
& cert
) {
24 ScopedSECKEYPrivateKey
privateKey(PK11_FindKeyByAnyCert(cert
.get(), nullptr));
28 ScopedSECKEYPublicKey
publicKey(CERT_ExtractPublicKey(cert
.get()));
32 return CreateTestKeyPair(RSA_PKCS1(), publicKey
, privateKey
);
35 SECItemArray
* GetOCSPResponseForType(OCSPResponseType aORT
,
36 const UniqueCERTCertificate
& aCert
,
37 const UniquePLArenaPool
& aArena
,
38 const char* aAdditionalCertName
,
39 time_t aThisUpdateSkew
,
40 ByteString
* aSCTList
) {
43 // Note: |aAdditionalCertName| may or may not need to be non-null depending
44 // on the |aORT| value given.
46 // Ensure NSS can sign responses using small RSA keys.
47 NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE
, 512);
49 if (aORT
== ORTNone
) {
50 if (gDebugLevel
>= DEBUG_WARNINGS
) {
52 "GetOCSPResponseForType called with type ORTNone, "
53 "which makes no sense.\n");
58 if (aORT
== ORTEmpty
) {
59 SECItemArray
* arr
= SECITEM_AllocArray(aArena
.get(), nullptr, 1);
60 arr
->items
[0].data
= nullptr;
61 arr
->items
[0].len
= 0;
65 time_t now
= time(nullptr) + aThisUpdateSkew
;
66 time_t oldNow
= now
- (8 * Time::ONE_DAY_IN_SECONDS
);
68 mozilla::UniqueCERTCertificate
cert(CERT_DupCertificate(aCert
.get()));
70 if (aORT
== ORTGoodOtherCert
) {
71 cert
.reset(PK11_FindCertFromNickname(aAdditionalCertName
, nullptr));
73 PrintPRError("PK11_FindCertFromNickname failed");
77 // XXX CERT_FindCertIssuer uses the old, deprecated path-building logic
78 mozilla::UniqueCERTCertificate
issuerCert(
79 CERT_FindCertIssuer(aCert
.get(), PR_Now(), certUsageSSLCA
));
81 PrintPRError("CERT_FindCertIssuer failed");
85 if (issuer
.Init(cert
->derIssuer
.data
, cert
->derIssuer
.len
) != Success
) {
88 Input issuerPublicKey
;
89 if (issuerPublicKey
.Init(issuerCert
->derPublicKey
.data
,
90 issuerCert
->derPublicKey
.len
) != Success
) {
94 if (serialNumber
.Init(cert
->serialNumber
.data
, cert
->serialNumber
.len
) !=
98 CertID
certID(issuer
, issuerPublicKey
, serialNumber
);
99 OCSPResponseContext
context(certID
, now
);
101 mozilla::UniqueCERTCertificate signerCert
;
102 if (aORT
== ORTGoodOtherCA
|| aORT
== ORTDelegatedIncluded
||
103 aORT
== ORTDelegatedIncludedLast
|| aORT
== ORTDelegatedMissing
||
104 aORT
== ORTDelegatedMissingMultiple
) {
105 signerCert
.reset(PK11_FindCertFromNickname(aAdditionalCertName
, nullptr));
107 PrintPRError("PK11_FindCertFromNickname failed");
114 if (aORT
== ORTDelegatedIncluded
) {
115 certs
[0].assign(signerCert
->derCert
.data
, signerCert
->derCert
.len
);
116 context
.certs
= certs
;
118 if (aORT
== ORTDelegatedIncludedLast
|| aORT
== ORTDelegatedMissingMultiple
) {
119 certs
[0].assign(issuerCert
->derCert
.data
, issuerCert
->derCert
.len
);
120 certs
[1].assign(cert
->derCert
.data
, cert
->derCert
.len
);
121 certs
[2].assign(issuerCert
->derCert
.data
, issuerCert
->derCert
.len
);
122 if (aORT
!= ORTDelegatedMissingMultiple
) {
123 certs
[3].assign(signerCert
->derCert
.data
, signerCert
->derCert
.len
);
125 context
.certs
= certs
;
130 context
.responseStatus
= 1;
133 context
.responseStatus
= 2;
136 context
.responseStatus
= 3;
139 context
.responseStatus
= 5;
141 case ORTUnauthorized
:
142 context
.responseStatus
= 6;
145 // context.responseStatus is 0 in all other cases, and it has
146 // already been initialized in the constructor.
149 if (aORT
== ORTSkipResponseBytes
) {
150 context
.skipResponseBytes
= true;
152 if (aORT
== ORTExpired
|| aORT
== ORTExpiredFreshCA
||
153 aORT
== ORTRevokedOld
|| aORT
== ORTUnknownOld
) {
154 context
.thisUpdate
= oldNow
;
155 context
.nextUpdate
= oldNow
+ Time::ONE_DAY_IN_SECONDS
;
157 if (aORT
== ORTLongValidityAlmostExpired
) {
158 context
.thisUpdate
= now
- (320 * Time::ONE_DAY_IN_SECONDS
);
160 if (aORT
== ORTAncientAlmostExpired
) {
161 context
.thisUpdate
= now
- (640 * Time::ONE_DAY_IN_SECONDS
);
163 if (aORT
== ORTRevoked
|| aORT
== ORTRevokedOld
) {
164 context
.certStatus
= 1;
166 if (aORT
== ORTUnknown
|| aORT
== ORTUnknownOld
) {
167 context
.certStatus
= 2;
169 if (aORT
== ORTBadSignature
) {
170 context
.badSignature
= true;
172 OCSPResponseExtension extension
;
173 if (aORT
== ORTCriticalExtension
|| aORT
== ORTNoncriticalExtension
) {
174 // python DottedOIDToCode.py --tlv
175 // some-Mozilla-OID 1.3.6.1.4.1.13769.666.666.666.1.500.9.2
176 static const uint8_t tlv_some_Mozilla_OID
[] = {
177 0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85,
178 0x1a, 0x85, 0x1a, 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x02};
180 extension
.id
.assign(tlv_some_Mozilla_OID
, sizeof(tlv_some_Mozilla_OID
));
181 extension
.critical
= (aORT
== ORTCriticalExtension
);
182 extension
.value
.push_back(0x05); // tag: NULL
183 extension
.value
.push_back(0x00); // length: 0
184 extension
.next
= nullptr;
185 context
.responseExtensions
= &extension
;
187 if (aORT
== ORTEmptyExtensions
) {
188 context
.includeEmptyExtensions
= true;
192 signerCert
.reset(CERT_DupCertificate(issuerCert
.get()));
194 context
.signerKeyPair
.reset(CreateTestKeyPairFromCert(signerCert
));
195 if (!context
.signerKeyPair
) {
196 PrintPRError("PK11_FindKeyByAnyCert failed");
200 OCSPResponseExtension singleExtension
;
202 // SingleExtension for Signed Certificate Timestamp List.
203 // See Section 3.3 of RFC 6962.
204 // python DottedOIDToCode.py --tlv
205 // id_ocsp_singleExtensionSctList 1.3.6.1.4.1.11129.2.4.5
206 static const uint8_t tlv_id_ocsp_singleExtensionSctList
[] = {
207 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x05};
208 singleExtension
.id
.assign(tlv_id_ocsp_singleExtensionSctList
,
209 sizeof(tlv_id_ocsp_singleExtensionSctList
));
210 singleExtension
.critical
= true;
211 singleExtension
.value
= TLV(der::OCTET_STRING
, *aSCTList
);
212 singleExtension
.next
= nullptr;
213 context
.singleExtensions
= &singleExtension
;
216 ByteString
response(CreateEncodedOCSPResponse(context
));
217 if (ENCODING_FAILED(response
)) {
218 PrintPRError("CreateEncodedOCSPResponse failed");
222 SECItem item
= {siBuffer
, const_cast<uint8_t*>(response
.data()),
223 static_cast<unsigned int>(response
.length())};
224 SECItemArray arr
= {&item
, 1};
225 return SECITEM_DupArray(aArena
.get(), &arr
);