]> git.saurik.com Git - apple/security.git/blob - libsecurity_ocspd/common/ocspResponse.cpp
Security-55471.14.18.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, (CC_LONG)mIssuerName.Length, issuerNameHash);
112 /* SHA1(issuer public key) */
113 ocspdSha1(mIssuerPubKey.Data, (CC_LONG)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, (CC_LONG)mIssuerName.Length, digest);
175 if(!ocspdCompareCssmData(&digestData, &exist.issuerNameHash)) {
176 return false;
177 }
178 hf(mIssuerPubKey.Data, (CC_LONG)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 #if 0 /* unused ? */
264 const CSSM_DATA *OCSPSingleResponse::*crlUrl()
265 {
266 /* TBD */
267 return NULL;
268 }
269 #endif
270
271 const CSSM_DATA *OCSPSingleResponse::crlNum()
272 {
273 /* TBD */
274 return NULL;
275
276 }
277
278 CFAbsoluteTime OCSPSingleResponse::crlTime() /* may be NULL_TIME */
279 {
280 /* TBD */
281 return NULL_TIME;
282 }
283
284 /* archive cutoff */
285 CFAbsoluteTime OCSPSingleResponse::archiveCutoff()
286 {
287 /* TBD */
288 return NULL_TIME;
289 }
290
291 #pragma mark ---- OCSPResponse ----
292
293 OCSPResponse::OCSPResponse(
294 const CSSM_DATA &resp,
295 CFTimeInterval defaultTTL) // default time-to-live in seconds
296 : mLatestNextUpdate(NULL_TIME),
297 mExpireTime(NULL_TIME),
298 mExtensions(NULL)
299 {
300 SecAsn1CoderCreate(&mCoder);
301 memset(&mTopResp, 0, sizeof(mTopResp));
302 memset(&mBasicResponse, 0, sizeof(mBasicResponse));
303 memset(&mResponseData, 0, sizeof(mResponseData));
304 memset(&mResponderId, 0, sizeof(mResponderId));
305 mResponderIdTag = (SecAsn1OCSPResponderIDTag)0; // invalid
306 mEncResponderName.Data = NULL;
307 mEncResponderName.Length = 0;
308
309 if(SecAsn1DecodeData(mCoder, &resp, kSecAsn1OCSPResponseTemplate, &mTopResp)) {
310 ocspdErrorLog("OCSPResponse: decode failure at top level\n");
311 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
312 }
313
314 /* remainder is valid only on RS_Success */
315 if((mTopResp.responseStatus.Data == NULL) ||
316 (mTopResp.responseStatus.Length == 0)) {
317 ocspdErrorLog("OCSPResponse: no responseStatus\n");
318 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
319 }
320 if(mTopResp.responseStatus.Data[0] != RS_Success) {
321 /* not a failure of our constructor; this object is now useful, but
322 * only for this one byte of status info */
323 return;
324 }
325 if(mTopResp.responseBytes == NULL) {
326 /* I don't see how this can be legal on RS_Success */
327 ocspdErrorLog("OCSPResponse: empty responseBytes\n");
328 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
329 }
330 if(!ocspdCompareCssmData(&mTopResp.responseBytes->responseType,
331 &CSSMOID_PKIX_OCSP_BASIC)) {
332 ocspdErrorLog("OCSPResponse: unknown responseType\n");
333 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
334 }
335
336 /* decode the SecAsn1OCSPBasicResponse */
337 if(SecAsn1DecodeData(mCoder, &mTopResp.responseBytes->response,
338 kSecAsn1OCSPBasicResponseTemplate, &mBasicResponse)) {
339 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse\n");
340 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
341 }
342
343 /* signature and cert evaluation done externally */
344
345 /* decode the SecAsn1OCSPResponseData */
346 if(SecAsn1DecodeData(mCoder, &mBasicResponse.tbsResponseData,
347 kSecAsn1OCSPResponseDataTemplate, &mResponseData)) {
348 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData\n");
349 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
350 }
351 if(mResponseData.responderID.Data == NULL) {
352 ocspdErrorLog("OCSPResponse: bad responderID\n");
353 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
354 }
355
356 /* choice processing for ResponderID */
357 mResponderIdTag = (SecAsn1OCSPResponderIDTag)
358 (mResponseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK);
359 const SecAsn1Template *templ;
360 switch(mResponderIdTag) {
361 case RIT_Name:
362 templ = kSecAsn1OCSPResponderIDAsNameTemplate;
363 break;
364 case RIT_Key:
365 templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
366 break;
367 default:
368 ocspdErrorLog("OCSPResponse: bad responderID tag\n");
369 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
370 }
371 if(SecAsn1DecodeData(mCoder, &mResponseData.responderID, templ, &mResponderId)) {
372 ocspdErrorLog("OCSPResponse: decode failure at responderID\n");
373 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
374 }
375
376 /* check temporal validity */
377 if(!calculateValidity(defaultTTL)) {
378 /* Whoops, abort */
379 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
380 }
381
382 /*
383 * Individual responses looked into when we're asked for a specific one
384 * via singleResponse()
385 */
386 mExtensions = new OCSPExtensions(mResponseData.responseExtensions);
387 }
388
389 OCSPResponse::~OCSPResponse()
390 {
391 delete mExtensions;
392 SecAsn1CoderRelease(mCoder);
393 }
394
395 SecAsn1OCSPResponseStatus OCSPResponse::responseStatus()
396 {
397 assert(mTopResp.responseStatus.Data != NULL); /* else constructor should have failed */
398 return (SecAsn1OCSPResponseStatus)(mTopResp.responseStatus.Data[0]);
399 }
400
401 const CSSM_DATA *OCSPResponse::nonce() /* NULL means not present */
402 {
403 OCSPExtension *ext = mExtensions->findExtension(CSSMOID_PKIX_OCSP_NONCE);
404 if(ext == NULL) {
405 return NULL;
406 }
407 OCSPNonce *nonceExt = dynamic_cast<OCSPNonce *>(ext);
408 return &(nonceExt->nonce());
409 }
410
411 CFAbsoluteTime OCSPResponse::producedAt()
412 {
413 return genTimeToCFAbsTime(&mResponseData.producedAt);
414 }
415
416 uint32 OCSPResponse::numSignerCerts()
417 {
418 return ocspdArraySize((const void **)mBasicResponse.certs);
419 }
420
421 const CSSM_DATA *OCSPResponse::signerCert(uint32 dex)
422 {
423 uint32 numCerts = numSignerCerts();
424 if(dex >= numCerts) {
425 ocspdErrorLog("OCSPResponse::signerCert: numCerts overflow\n");
426 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
427 }
428 return mBasicResponse.certs[dex];
429 }
430
431 /*
432 * Obtain a OCSPSingleResponse for a given "smart" CertID.
433 */
434 OCSPSingleResponse *OCSPResponse::singleResponseFor(OCSPClientCertID &matchCertID)
435 {
436 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
437 for(unsigned dex=0; dex<numResponses; dex++) {
438 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
439 SecAsn1OCSPCertID &certID = resp->certID;
440 if(matchCertID.compareToExist(certID)) {
441 try {
442 OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp);
443 return singleResp;
444 }
445 catch(...) {
446 /* try to find another... */
447 continue;
448 }
449 }
450 }
451 ocspdDebug("OCSPResponse::singleResponse: certID not found");
452 return NULL;
453 }
454
455 /*
456 * If responderID is of form RIT_Name, return the encoded version of the
457 * NSS_Name (for comparison with issuer's subjectName). Evaluated lazily,
458 * once, in mCoder space.
459 */
460 const CSSM_DATA *OCSPResponse::encResponderName()
461 {
462 if(mResponderIdTag != RIT_Name) {
463 assert(0);
464 return NULL;
465 }
466 if(mEncResponderName.Data != NULL) {
467 return &mEncResponderName;
468 }
469 if(SecAsn1EncodeItem(mCoder, &mResponderId.byName, kSecAsn1AnyTemplate,
470 &mEncResponderName)) {
471 ocspdDebug("OCSPResponse::encResponderName: error encoding ResponderId!");
472 return NULL;
473 }
474 return &mEncResponderName;
475 }
476
477 /*
478 * Obtain a OCSPSingleResponse for a given raw encoded CertID.
479 */
480 OCSPSingleResponse *OCSPResponse::singleResponseFor(const CSSM_DATA &matchCertID)
481 {
482 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
483 for(unsigned dex=0; dex<numResponses; dex++) {
484 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
485 CSSM_DATA certID = {0, NULL};
486 if(SecAsn1EncodeItem(mCoder, &resp->certID, kSecAsn1OCSPCertIDTemplate,
487 &certID)) {
488 ocspdDebug("OCSPResponse::singleResponse: error encoding certID!");
489 return NULL;
490 }
491 if(!ocspdCompareCssmData(&matchCertID, &certID)) {
492 /* try to find another */
493 continue;
494 }
495 try {
496 OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp);
497 return singleResp;
498 }
499 catch(...) {
500 /* try to find another... */
501 continue;
502 }
503 }
504 ocspdDebug("OCSPResponse::singleResponse: certID not found");
505 return NULL;
506
507 }
508
509 /*
510 * Calculate temporal validity; set mLatestNextUpdate and mExpireTime. Only
511 * called from constructor. Returns true if valid, else returns false.
512 */
513 bool OCSPResponse::calculateValidity(CFTimeInterval defaultTTL)
514 {
515 mLatestNextUpdate = NULL_TIME;
516 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
517
518 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
519 for(unsigned dex=0; dex<numResponses; dex++) {
520 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
521
522 /*
523 * First off, a thisUpdate later than 'now' invalidates the whole response.
524 */
525 CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
526 if(thisUpdate > now) {
527 ocspdErrorLog("OCSPResponse::calculateValidity: thisUpdate not passed\n");
528 return false;
529 }
530
531 /*
532 * Accumulate latest nextUpdate
533 */
534 if(resp->nextUpdate != NULL) {
535 CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
536 if(nextUpdate > mLatestNextUpdate) {
537 mLatestNextUpdate = nextUpdate;
538 }
539 }
540 }
541
542 CFAbsoluteTime defaultExpire = now + defaultTTL;
543 if(mLatestNextUpdate == NULL_TIME) {
544 /* absolute expire time = current time plus default TTL */
545 mExpireTime = defaultExpire;
546 }
547 else if(defaultExpire < mLatestNextUpdate) {
548 /* caller more stringent than response */
549 mExpireTime = defaultExpire;
550 }
551 else {
552 /* response more stringent than caller */
553 if(mLatestNextUpdate < now) {
554 ocspdErrorLog("OCSPResponse::calculateValidity: now > mLatestNextUpdate\n");
555 return false;
556 }
557 mExpireTime = mLatestNextUpdate;
558 }
559 return true;
560 }
561