/ OSX / libsecurity_ocspd / common / ocspResponse.cpp
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