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 */
38static 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 */
53static 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 */
69OCSPClientCertID::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
81OCSPClientCertID::~OCSPClientCertID()
82{
83	freeData(mIssuerName);
84	freeData(mIssuerPubKey);
85	freeData(mSubjectSerial);
86	freeData(mEncoded);
87}
88
89/* preencoded DER NULL */
90static uint8 nullParam[2] = {5, 0};
91
92/*
93 * DER encode in specified coder's memory.
94 */
95const 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 */
141typedef void (*hashFcn)(const void *data, CC_LONG len, unsigned char *md);
142
143bool 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
186bool 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);
199errOut:
200	SecAsn1CoderRelease(coder);
201	return brtn;
202}
203
204#pragma mark ---- OCSPSingleResponse ----
205
206/*
207 * Constructor, called by OCSPResponse.
208 */
209OCSPSingleResponse::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
256OCSPSingleResponse::~OCSPSingleResponse()
257{
258	delete mExtensions;
259	SecAsn1CoderRelease(mCoder);
260}
261
262/*** Extensions-specific accessors ***/
263#if 0 /* unused ? */
264const CSSM_DATA *OCSPSingleResponse::*crlUrl()
265{
266	/* TBD */
267	return NULL;
268}
269#endif
270
271const CSSM_DATA *OCSPSingleResponse::crlNum()
272{
273	/* TBD */
274	return NULL;
275
276}
277
278CFAbsoluteTime OCSPSingleResponse::crlTime()			/* may be NULL_TIME */
279{
280	/* TBD */
281	return NULL_TIME;
282}
283
284/* archive cutoff */
285CFAbsoluteTime OCSPSingleResponse::archiveCutoff()
286{
287	/* TBD */
288	return NULL_TIME;
289}
290
291#pragma mark ---- OCSPResponse ----
292
293OCSPResponse::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
389OCSPResponse::~OCSPResponse()
390{
391	delete mExtensions;
392	SecAsn1CoderRelease(mCoder);
393}
394
395SecAsn1OCSPResponseStatus OCSPResponse::responseStatus()
396{
397	assert(mTopResp.responseStatus.Data != NULL);	/* else constructor should have failed */
398	return (SecAsn1OCSPResponseStatus)(mTopResp.responseStatus.Data[0]);
399}
400
401const 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
411CFAbsoluteTime OCSPResponse::producedAt()
412{
413	return genTimeToCFAbsTime(&mResponseData.producedAt);
414}
415
416uint32 OCSPResponse::numSignerCerts()
417{
418	return ocspdArraySize((const void **)mBasicResponse.certs);
419}
420
421const 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 */
434OCSPSingleResponse *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 */
460const 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 */
480OCSPSingleResponse *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 */
513bool 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
562