]> git.saurik.com Git - apple/security.git/blob - libsecurity_ocspd/common/ocspResponse.cpp
Security-55178.0.1.tar.gz
[apple/security.git] / libsecurity_ocspd / common / ocspResponse.cpp
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * ocspResponse.cpp - OCSP Response class
26 */
27 #include "ocspResponse.h"
28 #include "ocspdUtils.h"
29 #include <Security/cssmapple.h>
30 #include <Security/oidscrl.h>
31 #include <Security/oidsalg.h>
32 #include "ocspdDebug.h"
33 #include <CommonCrypto/CommonDigest.h>
34 #include <security_cdsa_utilities/cssmerrors.h>
35 #include <Security/SecAsn1Templates.h>
36
37 /* malloc & copy CSSM_DATA using std malloc */
38 static void allocCopyData(
39 const CSSM_DATA &src,
40 CSSM_DATA &dst)
41 {
42 if(src.Length == 0) {
43 dst.Data = NULL;
44 dst.Length = 0;
45 return;
46 }
47 dst.Data = (uint8 *)malloc(src.Length);
48 memmove(dst.Data, src.Data, src.Length);
49 dst.Length = src.Length;
50 }
51
52 /* std free() of a CSSM_DATA */
53 static void freeData(
54 CSSM_DATA &d)
55 {
56 if(d.Data) {
57 free(d.Data);
58 d.Data = NULL;
59 }
60 d.Length = 0;
61 }
62
63 #pragma mark ---- OCSPClientCertID ----
64
65 /*
66 * Basic constructor given issuer's public key and name, and subject's
67 * serial number.
68 */
69 OCSPClientCertID::OCSPClientCertID(
70 const CSSM_DATA &issuerName,
71 const CSSM_DATA &issuerPubKey,
72 const CSSM_DATA &subjectSerial)
73 {
74 mEncoded.Data = NULL;
75 mEncoded.Length = 0;
76 allocCopyData(issuerName, mIssuerName);
77 allocCopyData(issuerPubKey, mIssuerPubKey);
78 allocCopyData(subjectSerial, mSubjectSerial);
79 }
80
81 OCSPClientCertID::~OCSPClientCertID()
82 {
83 freeData(mIssuerName);
84 freeData(mIssuerPubKey);
85 freeData(mSubjectSerial);
86 freeData(mEncoded);
87 }
88
89 /* preencoded DER NULL */
90 static uint8 nullParam[2] = {5, 0};
91
92 /*
93 * DER encode in specified coder's memory.
94 */
95 const CSSM_DATA *OCSPClientCertID::encode()
96 {
97 if(mEncoded.Data != NULL) {
98 return &mEncoded;
99 }
100
101 SecAsn1OCSPCertID certID;
102 uint8 issuerNameHash[CC_SHA1_DIGEST_LENGTH];
103 uint8 pubKeyHash[CC_SHA1_DIGEST_LENGTH];
104
105 /* algId refers to the hash we'll perform in issuer name and key */
106 certID.algId.algorithm = CSSMOID_SHA1;
107 certID.algId.parameters.Data = nullParam;
108 certID.algId.parameters.Length = sizeof(nullParam);
109
110 /* SHA1(issuerName) */
111 ocspdSha1(mIssuerName.Data, mIssuerName.Length, issuerNameHash);
112 /* SHA1(issuer public key) */
113 ocspdSha1(mIssuerPubKey.Data, mIssuerPubKey.Length, pubKeyHash);
114
115 /* build the CertID from those components */
116 certID.issuerNameHash.Data = issuerNameHash;
117 certID.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
118 certID.issuerPubKeyHash.Data = pubKeyHash;
119 certID.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;
120 certID.serialNumber = mSubjectSerial;
121
122 /* encode */
123 SecAsn1CoderRef coder;
124 SecAsn1CoderCreate(&coder);
125
126 CSSM_DATA tmp = {0, NULL};
127 SecAsn1EncodeItem(coder, &certID, kSecAsn1OCSPCertIDTemplate, &tmp);
128 allocCopyData(tmp, mEncoded);
129 SecAsn1CoderRelease(coder);
130 return &mEncoded;
131 }
132
133 /*
134 * Does this object refer to the same cert as specified SecAsn1OCSPCertID?
135 * This is the main purpose of this class's existence; this function works
136 * even if specified SecAsn1OCSPCertID uses a different hash algorithm
137 * than we do, since we keep copies of our basic components.
138 *
139 * Returns true if compare successful.
140 */
141 typedef void (*hashFcn)(const void *data, CC_LONG len, unsigned char *md);
142
143 bool OCSPClientCertID::compareToExist(
144 const SecAsn1OCSPCertID &exist)
145 {
146 /* easy part */
147 if(!ocspdCompareCssmData(&mSubjectSerial, &exist.serialNumber)) {
148 return false;
149 }
150
151 hashFcn hf = NULL;
152 const CSSM_OID *alg = &exist.algId.algorithm;
153 uint8 digest[OCSPD_MAX_DIGEST_LEN];
154 CSSM_DATA digestData = {0, digest};
155
156 if(ocspdCompareCssmData(alg, &CSSMOID_SHA1)) {
157 hf = ocspdSha1;
158 digestData.Length = CC_SHA1_DIGEST_LENGTH;
159 }
160 else if(ocspdCompareCssmData(alg, &CSSMOID_MD5)) {
161 hf = ocspdMD5;
162 digestData.Length = CC_MD5_DIGEST_LENGTH;
163 }
164 else if(ocspdCompareCssmData(alg, &CSSMOID_MD4)) {
165 hf = ocspdMD4;
166 digestData.Length = CC_MD4_DIGEST_LENGTH;
167 }
168 /* an OID for SHA256? */
169 else {
170 return false;
171 }
172
173 /* generate digests using exist's hash algorithm */
174 hf(mIssuerName.Data, mIssuerName.Length, digest);
175 if(!ocspdCompareCssmData(&digestData, &exist.issuerNameHash)) {
176 return false;
177 }
178 hf(mIssuerPubKey.Data, mIssuerPubKey.Length, digest);
179 if(!ocspdCompareCssmData(&digestData, &exist.issuerPubKeyHash)) {
180 return false;
181 }
182
183 return true;
184 }
185
186 bool OCSPClientCertID::compareToExist(
187 const CSSM_DATA &exist)
188 {
189 SecAsn1CoderRef coder;
190 SecAsn1OCSPCertID certID;
191 bool brtn = false;
192
193 SecAsn1CoderCreate(&coder);
194 memset(&certID, 0, sizeof(certID));
195 if(SecAsn1DecodeData(coder, &exist, kSecAsn1OCSPCertIDTemplate, &certID)) {
196 goto errOut;
197 }
198 brtn = compareToExist(certID);
199 errOut:
200 SecAsn1CoderRelease(coder);
201 return brtn;
202 }
203
204 #pragma mark ---- OCSPSingleResponse ----
205
206 /*
207 * Constructor, called by OCSPResponse.
208 */
209 OCSPSingleResponse::OCSPSingleResponse(
210 SecAsn1OCSPSingleResponse *resp)
211 : mCertStatus(CS_NotParsed),
212 mThisUpdate(NULL_TIME),
213 mNextUpdate(NULL_TIME),
214 mRevokedTime(NULL_TIME),
215 mCrlReason(CrlReason_NONE),
216 mExtensions(NULL)
217 {
218 assert(resp != NULL);
219
220 SecAsn1CoderCreate(&mCoder);
221 if((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) {
222 ocspdErrorLog("OCSPSingleResponse: bad certStatus\n");
223 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
224 }
225 mCertStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK);
226 if(mCertStatus == CS_Revoked) {
227 /* decode further to get SecAsn1OCSPRevokedInfo */
228 SecAsn1OCSPCertStatus certStatus;
229 memset(&certStatus, 0, sizeof(certStatus));
230 if(SecAsn1DecodeData(mCoder, &resp->certStatus,
231 kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) {
232 ocspdErrorLog("OCSPSingleResponse: err decoding certStatus\n");
233 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
234 }
235 SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo;
236 if(revokedInfo != NULL) {
237 /* Treat this as optional even for CS_Revoked */
238 mRevokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime);
239 const CSSM_DATA *revReason = revokedInfo->revocationReason;
240 if((revReason != NULL) &&
241 (revReason->Data != NULL) &&
242 (revReason->Length != 0)) {
243 mCrlReason = revReason->Data[0];
244 }
245 }
246 }
247 mThisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
248 if(resp->nextUpdate != NULL) {
249 mNextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
250 }
251 mExtensions = new OCSPExtensions(resp->singleExtensions);
252 ocspdDebug("OCSPSingleResponse: status %d reason %d", (int)mCertStatus,
253 (int)mCrlReason);
254 }
255
256 OCSPSingleResponse::~OCSPSingleResponse()
257 {
258 delete mExtensions;
259 SecAsn1CoderRelease(mCoder);
260 }
261
262 /*** Extensions-specific accessors ***/
263 const CSSM_DATA *OCSPSingleResponse::*crlUrl()
264 {
265 /* TBD */
266 return NULL;
267 }
268
269 const CSSM_DATA *OCSPSingleResponse::crlNum()
270 {
271 /* TBD */
272 return NULL;
273
274 }
275
276 CFAbsoluteTime OCSPSingleResponse::crlTime() /* may be NULL_TIME */
277 {
278 /* TBD */
279 return NULL_TIME;
280 }
281
282 /* archive cutoff */
283 CFAbsoluteTime OCSPSingleResponse::archiveCutoff()
284 {
285 /* TBD */
286 return NULL_TIME;
287 }
288
289 #pragma mark ---- OCSPResponse ----
290
291 OCSPResponse::OCSPResponse(
292 const CSSM_DATA &resp,
293 CFTimeInterval defaultTTL) // default time-to-live in seconds
294 : mLatestNextUpdate(NULL_TIME),
295 mExpireTime(NULL_TIME),
296 mExtensions(NULL)
297 {
298 SecAsn1CoderCreate(&mCoder);
299 memset(&mTopResp, 0, sizeof(mTopResp));
300 memset(&mBasicResponse, 0, sizeof(mBasicResponse));
301 memset(&mResponseData, 0, sizeof(mResponseData));
302 memset(&mResponderId, 0, sizeof(mResponderId));
303 mResponderIdTag = (SecAsn1OCSPResponderIDTag)0; // invalid
304 mEncResponderName.Data = NULL;
305 mEncResponderName.Length = 0;
306
307 if(SecAsn1DecodeData(mCoder, &resp, kSecAsn1OCSPResponseTemplate, &mTopResp)) {
308 ocspdErrorLog("OCSPResponse: decode failure at top level\n");
309 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
310 }
311
312 /* remainder is valid only on RS_Success */
313 if((mTopResp.responseStatus.Data == NULL) ||
314 (mTopResp.responseStatus.Length == 0)) {
315 ocspdErrorLog("OCSPResponse: no responseStatus\n");
316 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
317 }
318 if(mTopResp.responseStatus.Data[0] != RS_Success) {
319 /* not a failure of our constructor; this object is now useful, but
320 * only for this one byte of status info */
321 return;
322 }
323 if(mTopResp.responseBytes == NULL) {
324 /* I don't see how this can be legal on RS_Success */
325 ocspdErrorLog("OCSPResponse: empty responseBytes\n");
326 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
327 }
328 if(!ocspdCompareCssmData(&mTopResp.responseBytes->responseType,
329 &CSSMOID_PKIX_OCSP_BASIC)) {
330 ocspdErrorLog("OCSPResponse: unknown responseType\n");
331 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
332 }
333
334 /* decode the SecAsn1OCSPBasicResponse */
335 if(SecAsn1DecodeData(mCoder, &mTopResp.responseBytes->response,
336 kSecAsn1OCSPBasicResponseTemplate, &mBasicResponse)) {
337 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse\n");
338 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
339 }
340
341 /* signature and cert evaluation done externally */
342
343 /* decode the SecAsn1OCSPResponseData */
344 if(SecAsn1DecodeData(mCoder, &mBasicResponse.tbsResponseData,
345 kSecAsn1OCSPResponseDataTemplate, &mResponseData)) {
346 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData\n");
347 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
348 }
349 if(mResponseData.responderID.Data == NULL) {
350 ocspdErrorLog("OCSPResponse: bad responderID\n");
351 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
352 }
353
354 /* choice processing for ResponderID */
355 mResponderIdTag = (SecAsn1OCSPResponderIDTag)
356 (mResponseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK);
357 const SecAsn1Template *templ;
358 switch(mResponderIdTag) {
359 case RIT_Name:
360 templ = kSecAsn1OCSPResponderIDAsNameTemplate;
361 break;
362 case RIT_Key:
363 templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
364 break;
365 default:
366 ocspdErrorLog("OCSPResponse: bad responderID tag\n");
367 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
368 }
369 if(SecAsn1DecodeData(mCoder, &mResponseData.responderID, templ, &mResponderId)) {
370 ocspdErrorLog("OCSPResponse: decode failure at responderID\n");
371 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
372 }
373
374 /* check temporal validity */
375 if(!calculateValidity(defaultTTL)) {
376 /* Whoops, abort */
377 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
378 }
379
380 /*
381 * Individual responses looked into when we're asked for a specific one
382 * via singleResponse()
383 */
384 mExtensions = new OCSPExtensions(mResponseData.responseExtensions);
385 }
386
387 OCSPResponse::~OCSPResponse()
388 {
389 delete mExtensions;
390 SecAsn1CoderRelease(mCoder);
391 }
392
393 SecAsn1OCSPResponseStatus OCSPResponse::responseStatus()
394 {
395 assert(mTopResp.responseStatus.Data != NULL); /* else constructor should have failed */
396 return (SecAsn1OCSPResponseStatus)(mTopResp.responseStatus.Data[0]);
397 }
398
399 const CSSM_DATA *OCSPResponse::nonce() /* NULL means not present */
400 {
401 OCSPExtension *ext = mExtensions->findExtension(CSSMOID_PKIX_OCSP_NONCE);
402 if(ext == NULL) {
403 return NULL;
404 }
405 OCSPNonce *nonceExt = dynamic_cast<OCSPNonce *>(ext);
406 return &(nonceExt->nonce());
407 }
408
409 CFAbsoluteTime OCSPResponse::producedAt()
410 {
411 return genTimeToCFAbsTime(&mResponseData.producedAt);
412 }
413
414 uint32 OCSPResponse::numSignerCerts()
415 {
416 return ocspdArraySize((const void **)mBasicResponse.certs);
417 }
418
419 const CSSM_DATA *OCSPResponse::signerCert(uint32 dex)
420 {
421 uint32 numCerts = numSignerCerts();
422 if(dex >= numCerts) {
423 ocspdErrorLog("OCSPResponse::signerCert: numCerts overflow\n");
424 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
425 }
426 return mBasicResponse.certs[dex];
427 }
428
429 /*
430 * Obtain a OCSPSingleResponse for a given "smart" CertID.
431 */
432 OCSPSingleResponse *OCSPResponse::singleResponseFor(OCSPClientCertID &matchCertID)
433 {
434 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
435 for(unsigned dex=0; dex<numResponses; dex++) {
436 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
437 SecAsn1OCSPCertID &certID = resp->certID;
438 if(matchCertID.compareToExist(certID)) {
439 try {
440 OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp);
441 return singleResp;
442 }
443 catch(...) {
444 /* try to find another... */
445 continue;
446 }
447 }
448 }
449 ocspdDebug("OCSPResponse::singleResponse: certID not found");
450 return NULL;
451 }
452
453 /*
454 * If responderID is of form RIT_Name, return the encoded version of the
455 * NSS_Name (for comparison with issuer's subjectName). Evaluated lazily,
456 * once, in mCoder space.
457 */
458 const CSSM_DATA *OCSPResponse::encResponderName()
459 {
460 if(mResponderIdTag != RIT_Name) {
461 assert(0);
462 return NULL;
463 }
464 if(mEncResponderName.Data != NULL) {
465 return &mEncResponderName;
466 }
467 if(SecAsn1EncodeItem(mCoder, &mResponderId.byName, kSecAsn1AnyTemplate,
468 &mEncResponderName)) {
469 ocspdDebug("OCSPResponse::encResponderName: error encoding ResponderId!");
470 return NULL;
471 }
472 return &mEncResponderName;
473 }
474
475 /*
476 * Obtain a OCSPSingleResponse for a given raw encoded CertID.
477 */
478 OCSPSingleResponse *OCSPResponse::singleResponseFor(const CSSM_DATA &matchCertID)
479 {
480 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
481 for(unsigned dex=0; dex<numResponses; dex++) {
482 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
483 CSSM_DATA certID = {0, NULL};
484 if(SecAsn1EncodeItem(mCoder, &resp->certID, kSecAsn1OCSPCertIDTemplate,
485 &certID)) {
486 ocspdDebug("OCSPResponse::singleResponse: error encoding certID!");
487 return NULL;
488 }
489 if(!ocspdCompareCssmData(&matchCertID, &certID)) {
490 /* try to find another */
491 continue;
492 }
493 try {
494 OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp);
495 return singleResp;
496 }
497 catch(...) {
498 /* try to find another... */
499 continue;
500 }
501 }
502 ocspdDebug("OCSPResponse::singleResponse: certID not found");
503 return NULL;
504
505 }
506
507 /*
508 * Calculate temporal validity; set mLatestNextUpdate and mExpireTime. Only
509 * called from constructor. Returns true if valid, else returns false.
510 */
511 bool OCSPResponse::calculateValidity(CFTimeInterval defaultTTL)
512 {
513 mLatestNextUpdate = NULL_TIME;
514 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
515
516 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
517 for(unsigned dex=0; dex<numResponses; dex++) {
518 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
519
520 /*
521 * First off, a thisUpdate later than 'now' invalidates the whole response.
522 */
523 CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
524 if(thisUpdate > now) {
525 ocspdErrorLog("OCSPResponse::calculateValidity: thisUpdate not passed\n");
526 return false;
527 }
528
529 /*
530 * Accumulate latest nextUpdate
531 */
532 if(resp->nextUpdate != NULL) {
533 CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
534 if(nextUpdate > mLatestNextUpdate) {
535 mLatestNextUpdate = nextUpdate;
536 }
537 }
538 }
539
540 CFAbsoluteTime defaultExpire = now + defaultTTL;
541 if(mLatestNextUpdate == NULL_TIME) {
542 /* absolute expire time = current time plus default TTL */
543 mExpireTime = defaultExpire;
544 }
545 else if(defaultExpire < mLatestNextUpdate) {
546 /* caller more stringent than response */
547 mExpireTime = defaultExpire;
548 }
549 else {
550 /* response more stringent than caller */
551 if(mLatestNextUpdate < now) {
552 ocspdErrorLog("OCSPResponse::calculateValidity: now > mLatestNextUpdate\n");
553 return false;
554 }
555 mExpireTime = mLatestNextUpdate;
556 }
557 return true;
558 }
559