]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ocspd/common/ocspResponse.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_ocspd / common / ocspResponse.cpp
1 /*
2 * Copyright (c) 2004,2011-2012,2014 Apple 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
113 /* SHA1(issuer public key bytes) */
114 ocspdSha1(mIssuerPubKey.Data, (CC_LONG)mIssuerPubKey.Length, pubKeyHash);
115
116 /* build the CertID from those components */
117 certID.issuerNameHash.Data = issuerNameHash;
118 certID.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
119 certID.issuerPubKeyHash.Data = pubKeyHash;
120 certID.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;
121 certID.serialNumber = mSubjectSerial;
122
123 /* encode */
124 SecAsn1CoderRef coder;
125 SecAsn1CoderCreate(&coder);
126
127 CSSM_DATA tmp = {0, NULL};
128 SecAsn1EncodeItem(coder, &certID, kSecAsn1OCSPCertIDTemplate, &tmp);
129 allocCopyData(tmp, mEncoded);
130 SecAsn1CoderRelease(coder);
131 return &mEncoded;
132 }
133
134 /*
135 * Does this object refer to the same cert as specified SecAsn1OCSPCertID?
136 * This is the main purpose of this class's existence; this function works
137 * even if specified SecAsn1OCSPCertID uses a different hash algorithm
138 * than we do, since we keep copies of our basic components.
139 *
140 * Returns true if compare successful.
141 */
142 typedef void (*hashFcn)(const void *data, CC_LONG len, unsigned char *md);
143
144 bool OCSPClientCertID::compareToExist(
145 const SecAsn1OCSPCertID &exist)
146 {
147 /* easy part */
148 if(!ocspdCompareCssmData(&mSubjectSerial, &exist.serialNumber)) {
149 return false;
150 }
151
152 hashFcn hf = NULL;
153 const CSSM_OID *alg = &exist.algId.algorithm;
154 uint8 digest[OCSPD_MAX_DIGEST_LEN];
155 CSSM_DATA digestData = {0, digest};
156
157 if(ocspdCompareCssmData(alg, &CSSMOID_SHA1)) {
158 hf = ocspdSha1;
159 digestData.Length = CC_SHA1_DIGEST_LENGTH;
160 }
161 else if(ocspdCompareCssmData(alg, &CSSMOID_MD5)) {
162 hf = ocspdMD5;
163 digestData.Length = CC_MD5_DIGEST_LENGTH;
164 }
165 else if(ocspdCompareCssmData(alg, &CSSMOID_MD4)) {
166 hf = ocspdMD4;
167 digestData.Length = CC_MD4_DIGEST_LENGTH;
168 }
169 /* an OID for SHA256? */
170 else {
171 return false;
172 }
173
174 /* generate digests using exist's hash algorithm */
175 hf(mIssuerName.Data, (CC_LONG)mIssuerName.Length, digest);
176 if(!ocspdCompareCssmData(&digestData, &exist.issuerNameHash)) {
177 return false;
178 }
179 hf(mIssuerPubKey.Data, (CC_LONG)mIssuerPubKey.Length, digest);
180 if(!ocspdCompareCssmData(&digestData, &exist.issuerPubKeyHash)) {
181 return false;
182 }
183
184 return true;
185 }
186
187 bool OCSPClientCertID::compareToExist(
188 const CSSM_DATA &exist)
189 {
190 SecAsn1CoderRef coder;
191 SecAsn1OCSPCertID certID;
192 bool brtn = false;
193
194 SecAsn1CoderCreate(&coder);
195 memset(&certID, 0, sizeof(certID));
196 if(SecAsn1DecodeData(coder, &exist, kSecAsn1OCSPCertIDTemplate, &certID)) {
197 goto errOut;
198 }
199 brtn = compareToExist(certID);
200 errOut:
201 SecAsn1CoderRelease(coder);
202 return brtn;
203 }
204
205 #pragma mark ---- OCSPSingleResponse ----
206
207 /*
208 * Constructor, called by OCSPResponse.
209 */
210 OCSPSingleResponse::OCSPSingleResponse(
211 SecAsn1OCSPSingleResponse *resp)
212 : mCertStatus(CS_NotParsed),
213 mThisUpdate(NULL_TIME),
214 mNextUpdate(NULL_TIME),
215 mRevokedTime(NULL_TIME),
216 mCrlReason(CrlReason_NONE),
217 mExtensions(NULL)
218 {
219 assert(resp != NULL);
220
221 SecAsn1CoderCreate(&mCoder);
222 if((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) {
223 ocspdErrorLog("OCSPSingleResponse: bad certStatus\n");
224 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
225 }
226 mCertStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK);
227 if(mCertStatus == CS_Revoked) {
228 /* decode further to get SecAsn1OCSPRevokedInfo */
229 SecAsn1OCSPCertStatus certStatus;
230 memset(&certStatus, 0, sizeof(certStatus));
231 if(SecAsn1DecodeData(mCoder, &resp->certStatus,
232 kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) {
233 ocspdErrorLog("OCSPSingleResponse: err decoding certStatus\n");
234 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
235 }
236 SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo;
237 if(revokedInfo != NULL) {
238 /* Treat this as optional even for CS_Revoked */
239 mRevokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime);
240 const CSSM_DATA *revReason = revokedInfo->revocationReason;
241 if((revReason != NULL) &&
242 (revReason->Data != NULL) &&
243 (revReason->Length != 0)) {
244 mCrlReason = revReason->Data[0];
245 }
246 }
247 }
248 mThisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
249 if(resp->nextUpdate != NULL) {
250 mNextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
251 }
252 mExtensions = new OCSPExtensions(resp->singleExtensions);
253 ocspdDebug("OCSPSingleResponse: status %d reason %d", (int)mCertStatus,
254 (int)mCrlReason);
255 }
256
257 OCSPSingleResponse::~OCSPSingleResponse()
258 {
259 delete mExtensions;
260 SecAsn1CoderRelease(mCoder);
261 }
262
263 /*** Extensions-specific accessors ***/
264 #if 0 /* unused ? */
265 const CSSM_DATA *OCSPSingleResponse::*crlUrl()
266 {
267 /* TBD */
268 return NULL;
269 }
270 #endif
271
272 const CSSM_DATA *OCSPSingleResponse::crlNum()
273 {
274 /* TBD */
275 return NULL;
276
277 }
278
279 CFAbsoluteTime OCSPSingleResponse::crlTime() /* may be NULL_TIME */
280 {
281 /* TBD */
282 return NULL_TIME;
283 }
284
285 /* archive cutoff */
286 CFAbsoluteTime OCSPSingleResponse::archiveCutoff()
287 {
288 /* TBD */
289 return NULL_TIME;
290 }
291
292 #pragma mark ---- OCSPResponse ----
293
294 OCSPResponse::OCSPResponse(
295 const CSSM_DATA &resp,
296 CFTimeInterval defaultTTL) // default time-to-live in seconds
297 : mLatestNextUpdate(NULL_TIME),
298 mExpireTime(NULL_TIME),
299 mExtensions(NULL)
300 {
301 SecAsn1CoderCreate(&mCoder);
302 memset(&mTopResp, 0, sizeof(mTopResp));
303 memset(&mBasicResponse, 0, sizeof(mBasicResponse));
304 memset(&mResponseData, 0, sizeof(mResponseData));
305 memset(&mResponderId, 0, sizeof(mResponderId));
306 mResponderIdTag = (SecAsn1OCSPResponderIDTag)0; // invalid
307 mEncResponderName.Data = NULL;
308 mEncResponderName.Length = 0;
309
310 if(SecAsn1DecodeData(mCoder, &resp, kSecAsn1OCSPResponseTemplate, &mTopResp)) {
311 ocspdErrorLog("OCSPResponse: decode failure at top level\n");
312 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
313 }
314
315 /* remainder is valid only on RS_Success */
316 if((mTopResp.responseStatus.Data == NULL) ||
317 (mTopResp.responseStatus.Length == 0)) {
318 ocspdErrorLog("OCSPResponse: no responseStatus\n");
319 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
320 }
321 if(mTopResp.responseStatus.Data[0] != RS_Success) {
322 /* not a failure of our constructor; this object is now useful, but
323 * only for this one byte of status info */
324 return;
325 }
326 if(mTopResp.responseBytes == NULL) {
327 /* I don't see how this can be legal on RS_Success */
328 ocspdErrorLog("OCSPResponse: empty responseBytes\n");
329 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
330 }
331 if(!ocspdCompareCssmData(&mTopResp.responseBytes->responseType,
332 &CSSMOID_PKIX_OCSP_BASIC)) {
333 ocspdErrorLog("OCSPResponse: unknown responseType\n");
334 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
335 }
336
337 /* decode the SecAsn1OCSPBasicResponse */
338 if(SecAsn1DecodeData(mCoder, &mTopResp.responseBytes->response,
339 kSecAsn1OCSPBasicResponseTemplate, &mBasicResponse)) {
340 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse\n");
341 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
342 }
343
344 /* signature and cert evaluation done externally */
345
346 /* decode the SecAsn1OCSPResponseData */
347 if(SecAsn1DecodeData(mCoder, &mBasicResponse.tbsResponseData,
348 kSecAsn1OCSPResponseDataTemplate, &mResponseData)) {
349 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData\n");
350 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
351 }
352 if(mResponseData.responderID.Data == NULL) {
353 ocspdErrorLog("OCSPResponse: bad responderID\n");
354 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
355 }
356
357 /* choice processing for ResponderID */
358 mResponderIdTag = (SecAsn1OCSPResponderIDTag)
359 (mResponseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK);
360 const SecAsn1Template *templ;
361 switch(mResponderIdTag) {
362 case RIT_Name:
363 templ = kSecAsn1OCSPResponderIDAsNameTemplate;
364 break;
365 case RIT_Key:
366 templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
367 break;
368 default:
369 ocspdErrorLog("OCSPResponse: bad responderID tag\n");
370 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
371 }
372 if(SecAsn1DecodeData(mCoder, &mResponseData.responderID, templ, &mResponderId)) {
373 ocspdErrorLog("OCSPResponse: decode failure at responderID\n");
374 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
375 }
376
377 /* check temporal validity */
378 if(!calculateValidity(defaultTTL)) {
379 /* Whoops, abort */
380 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
381 }
382
383 /*
384 * Individual responses looked into when we're asked for a specific one
385 * via singleResponse()
386 */
387 mExtensions = new OCSPExtensions(mResponseData.responseExtensions);
388 }
389
390 OCSPResponse::~OCSPResponse()
391 {
392 delete mExtensions;
393 SecAsn1CoderRelease(mCoder);
394 }
395
396 SecAsn1OCSPResponseStatus OCSPResponse::responseStatus()
397 {
398 assert(mTopResp.responseStatus.Data != NULL); /* else constructor should have failed */
399 return (SecAsn1OCSPResponseStatus)(mTopResp.responseStatus.Data[0]);
400 }
401
402 const CSSM_DATA *OCSPResponse::nonce() /* NULL means not present */
403 {
404 OCSPExtension *ext = mExtensions->findExtension(CSSMOID_PKIX_OCSP_NONCE);
405 if(ext == NULL) {
406 return NULL;
407 }
408 OCSPNonce *nonceExt = dynamic_cast<OCSPNonce *>(ext);
409 return &(nonceExt->nonce());
410 }
411
412 CFAbsoluteTime OCSPResponse::producedAt()
413 {
414 return genTimeToCFAbsTime(&mResponseData.producedAt);
415 }
416
417 uint32 OCSPResponse::numSignerCerts()
418 {
419 return ocspdArraySize((const void **)mBasicResponse.certs);
420 }
421
422 const CSSM_DATA *OCSPResponse::signerCert(uint32 dex)
423 {
424 uint32 numCerts = numSignerCerts();
425 if(dex >= numCerts) {
426 ocspdErrorLog("OCSPResponse::signerCert: numCerts overflow\n");
427 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
428 }
429 return mBasicResponse.certs[dex];
430 }
431
432 /*
433 * Obtain a OCSPSingleResponse for a given "smart" CertID.
434 */
435 OCSPSingleResponse *OCSPResponse::singleResponseFor(OCSPClientCertID &matchCertID)
436 {
437 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
438 for(unsigned dex=0; dex<numResponses; dex++) {
439 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
440 SecAsn1OCSPCertID &certID = resp->certID;
441 if(matchCertID.compareToExist(certID)) {
442 try {
443 OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp);
444 return singleResp;
445 }
446 catch(...) {
447 /* try to find another... */
448 continue;
449 }
450 }
451 }
452 ocspdDebug("OCSPResponse::singleResponse: certID not found");
453 return NULL;
454 }
455
456 /*
457 * If responderID is of form RIT_Name, return the encoded version of the
458 * NSS_Name (for comparison with issuer's subjectName). Evaluated lazily,
459 * once, in mCoder space.
460 */
461 const CSSM_DATA *OCSPResponse::encResponderName()
462 {
463 if(mResponderIdTag != RIT_Name) {
464 assert(0);
465 return NULL;
466 }
467 if(mEncResponderName.Data != NULL) {
468 return &mEncResponderName;
469 }
470 if(SecAsn1EncodeItem(mCoder, &mResponderId.byName, kSecAsn1AnyTemplate,
471 &mEncResponderName)) {
472 ocspdDebug("OCSPResponse::encResponderName: error encoding ResponderId!");
473 return NULL;
474 }
475 return &mEncResponderName;
476 }
477
478 /*
479 * Obtain a OCSPSingleResponse for a given raw encoded CertID.
480 */
481 OCSPSingleResponse *OCSPResponse::singleResponseFor(const CSSM_DATA &matchCertID)
482 {
483 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
484 for(unsigned dex=0; dex<numResponses; dex++) {
485 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
486 CSSM_DATA certID = {0, NULL};
487 if(SecAsn1EncodeItem(mCoder, &resp->certID, kSecAsn1OCSPCertIDTemplate,
488 &certID)) {
489 ocspdDebug("OCSPResponse::singleResponse: error encoding certID!");
490 return NULL;
491 }
492 if(!ocspdCompareCssmData(&matchCertID, &certID)) {
493 /* try to find another */
494 continue;
495 }
496 try {
497 OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp);
498 return singleResp;
499 }
500 catch(...) {
501 /* try to find another... */
502 continue;
503 }
504 }
505 ocspdDebug("OCSPResponse::singleResponse: certID not found");
506 return NULL;
507
508 }
509
510 /*
511 * Calculate temporal validity; set mLatestNextUpdate and mExpireTime. Only
512 * called from constructor. Returns true if valid, else returns false.
513 */
514 bool OCSPResponse::calculateValidity(CFTimeInterval defaultTTL)
515 {
516 mLatestNextUpdate = NULL_TIME;
517 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
518
519 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
520 for(unsigned dex=0; dex<numResponses; dex++) {
521 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
522
523 /*
524 * First off, a thisUpdate later than 'now' invalidates the whole response.
525 */
526 CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
527 if(thisUpdate > now) {
528 ocspdErrorLog("OCSPResponse::calculateValidity: thisUpdate not passed\n");
529 return false;
530 }
531
532 /*
533 * Accumulate latest nextUpdate
534 */
535 if(resp->nextUpdate != NULL) {
536 CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
537 if(nextUpdate > mLatestNextUpdate) {
538 mLatestNextUpdate = nextUpdate;
539 }
540 }
541 }
542
543 CFAbsoluteTime defaultExpire = now + defaultTTL;
544 if(mLatestNextUpdate == NULL_TIME) {
545 /* absolute expire time = current time plus default TTL */
546 mExpireTime = defaultExpire;
547 }
548 else if(defaultExpire < mLatestNextUpdate) {
549 /* caller more stringent than response */
550 mExpireTime = defaultExpire;
551 }
552 else {
553 /* response more stringent than caller */
554 if(mLatestNextUpdate < now) {
555 ocspdErrorLog("OCSPResponse::calculateValidity: now > mLatestNextUpdate\n");
556 return false;
557 }
558 mExpireTime = mLatestNextUpdate;
559 }
560 return true;
561 }
562