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 * tpOcspCertVfy.cpp - OCSP cert verification routines
26 */
27
28#include "tpOcspCertVfy.h"
29#include "tpdebugging.h"
30#include "certGroupUtils.h"
31#include <Security/oidscert.h>
32#include <CommonCrypto/CommonDigest.h>
33#include <security_ocspd/ocspdUtils.h>
34
35/*
36 * Is signerCert authorized to sign OCSP responses by issuerCert? IssuerCert is
37 * assumed to be (i.e., must, but we don't check that here) the signer of the
38 * cert being verified, which is not in the loop for this op. Just a bool returned;
39 * it's autoritized or it's not.
40 */
41static bool tpIsAuthorizedOcspSigner(
42	TPCertInfo &issuerCert,		// issuer of cert being verified
43	TPCertInfo &signerCert)		// potential signer of OCSP response
44{
45	CSSM_DATA_PTR		fieldValue = NULL;			// mallocd by CL
46	CSSM_RETURN			crtn;
47	bool				ourRtn = false;
48	CE_ExtendedKeyUsage *eku = NULL;
49	bool				foundEku = false;
50
51	/*
52	 * First see if issuerCert issued signerCert (No signature vfy yet, just
53	 * subject/issuer check).
54	 */
55	if(!issuerCert.isIssuerOf(signerCert)) {
56		return false;
57	}
58
59	/* Fetch ExtendedKeyUse field from signerCert */
60	crtn = signerCert.fetchField(&CSSMOID_ExtendedKeyUsage, &fieldValue);
61	if(crtn) {
62		tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no EKU");
63		return false;
64	}
65	CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data;
66	if(cssmExt->format != CSSM_X509_DATAFORMAT_PARSED) {
67		tpOcspDebug("tpIsAuthorizedOcspSigner: bad extension format");
68		goto errOut;
69	}
70	eku = (CE_ExtendedKeyUsage *)cssmExt->value.parsedValue;
71
72	/* Look for OID_KP_OCSPSigning */
73	for(unsigned dex=0; dex<eku->numPurposes; dex++) {
74		if(tpCompareCssmData(&eku->purposes[dex], &CSSMOID_OCSPSigning)) {
75			foundEku = true;
76			break;
77		}
78	}
79	if(!foundEku) {
80		tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no OCSP "
81			"signing EKU");
82		goto errOut;
83	}
84
85	/*
86	 * OK, signerCert is authorized by *someone* to sign OCSP requests, and
87	 * it claims to be issued by issuer. Sig verify to be sure.
88	 * FIXME this is not handling partial public keys, which would be a colossal
89	 * mess to handle in this module...so we don't.
90	 */
91	crtn = signerCert.verifyWithIssuer(&issuerCert, NULL);
92	if(crtn == CSSM_OK) {
93		tpOcspDebug("tpIsAuthorizedOcspSigner: FOUND authorized signer");
94		ourRtn = true;
95	}
96	else {
97		/* This is a highly irregular situation... */
98		tpOcspDebug("tpIsAuthorizedOcspSigner: signer sig verify FAIL");
99	}
100errOut:
101	if(fieldValue != NULL) {
102		signerCert.freeField(&CSSMOID_ExtendedKeyUsage, fieldValue);
103	}
104	return ourRtn;
105}
106
107/*
108 * Check ResponderID linkage between an OCSPResponse and a cert we believe to
109 * be the issuer of both that response and the cert being verified. Returns
110 * true if OK.
111 */
112static
113bool tpOcspResponderIDCheck(
114	OCSPResponse	&ocspResp,
115	TPCertInfo		&signer)
116{
117	bool shouldBeSigner = false;
118	if(ocspResp.responderIDTag() == RIT_Name) {
119		/*
120		 * Name inside response must == signer's SubjectName.
121		 * Note we can't use signer.subjectName(); that's normalized.
122		 */
123
124		const CSSM_DATA *respIdName = ocspResp.encResponderName();
125		CSSM_DATA *subjectName = NULL;
126		CSSM_RETURN crtn = signer.fetchField(&CSSMOID_X509V1SubjectNameStd,
127			&subjectName);
128		if(crtn) {
129			/* bad cert */
130			tpOcspDebug("tpOcspResponderIDCheck: error on fetchField(subjectName");
131			return false;
132		}
133		if(tpCompareCssmData(respIdName, subjectName)) {
134			tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byName");
135			shouldBeSigner = true;
136		}
137		else {
138			tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byName");
139		}
140		signer.freeField(&CSSMOID_X509V1SubjectNameStd, subjectName);
141	}
142	else {
143		/* ResponderID.byKey must == SHA1(signer's public key) */
144		const CSSM_KEY *pubKey = signer.pubKey();
145		assert(pubKey != NULL);
146		uint8 digest[CC_SHA1_DIGEST_LENGTH];
147		CSSM_DATA keyHash = {CC_SHA1_DIGEST_LENGTH, digest};
148		ocspdSha1(pubKey->KeyData.Data, (CC_LONG)pubKey->KeyData.Length, digest);
149		const CSSM_DATA *respKeyHash = &ocspResp.responderID().byKey;
150		if(tpCompareCssmData(&keyHash, respKeyHash)) {
151			tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byKey");
152			shouldBeSigner = true;
153		}
154		else {
155			tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byKey");
156		}
157	}
158	return shouldBeSigner;
159}
160
161/*
162 * Verify the signature of an OCSP response. Caller is responsible for all other
163 * verification of the response, this is just the crypto.
164 * Returns true on success.
165 */
166static bool tpOcspResponseSigVerify(
167	TPVerifyContext		&vfyCtx,
168	OCSPResponse		&ocspResp,		// parsed response
169	TPCertInfo			&signer)
170{
171	/* get signature algorithm in CSSM form from the response */
172	const SecAsn1OCSPBasicResponse &basicResp = ocspResp.basicResponse();
173	const CSSM_OID *algOid = &basicResp.algId.algorithm;
174	CSSM_ALGORITHMS sigAlg;
175
176	if(!cssmOidToAlg(algOid, &sigAlg)) {
177		tpOcspDebug("tpOcspResponseSigVerify: unknown signature algorithm");
178	}
179
180	/* signer's public key from the cert */
181	const CSSM_KEY *pubKey = signer.pubKey();
182
183	/* signature: on decode, length is in BITS */
184	CSSM_DATA sig = basicResp.sig;
185	sig.Length /= 8;
186
187	CSSM_RETURN crtn;
188	CSSM_CC_HANDLE sigHand;
189	bool ourRtn = false;
190	crtn = CSSM_CSP_CreateSignatureContext(vfyCtx.cspHand, sigAlg, NULL,
191		pubKey, &sigHand);
192	if(crtn) {
193		#ifndef	NDEBUG
194		cssmPerror("tpOcspResponseSigVerify, CSSM_CSP_CreateSignatureContext", crtn);
195		#endif
196		return false;
197	}
198	crtn = CSSM_VerifyData(sigHand, &basicResp.tbsResponseData, 1,
199		CSSM_ALGID_NONE, &sig);
200	if(crtn) {
201		#ifndef	NDEBUG
202		cssmPerror("tpOcspResponseSigVerify, CSSM_VerifyData", crtn);
203		#endif
204	}
205	else {
206		ourRtn = true;
207	}
208	CSSM_DeleteContext(sigHand);
209	return ourRtn;
210}
211
212/* possible return from tpIsOcspIssuer() */
213typedef enum {
214	OIS_No,			// not the issuer
215	OIS_Good,		// is the issuer and signature matches
216	OIS_BadSig,		// appears to be issuer, but signature doesn't match
217} OcspIssuerStatus;
218
219/* type of rawCert passed to tpIsOcspIssuer */
220typedef enum {
221	OCT_Local,		// LocalResponder - no checking other than signature
222	OCT_Issuer,		// it's the issuer of the cert being verified
223	OCT_Provided,	// came with response, provenance unknown
224} OcspCertType;
225
226/*
227 * Did specified cert issue the OCSP response?
228 *
229 * This implements the algorithm described in RFC2560, section 4.2.2.2,
230 * "Authorized Responders". It sees if the cert could be the issuer of the
231 * OCSP response per that algorithm; then if it could, it performs signature
232 * verification.
233 */
234static OcspIssuerStatus tpIsOcspIssuer(
235	TPVerifyContext		&vfyCtx,
236	OCSPResponse		&ocspResp,		// parsed response
237	/* on input specify at least one of the following two */
238	const CSSM_DATA		*signerData,
239	TPCertInfo			*signer,
240	OcspCertType		certType,		// where rawCert came from
241	TPCertInfo			*issuer,		// OPTIONAL, if known
242	TPCertInfo			**signerRtn)	// optionally RETURNED if at all possible
243{
244	assert((signerData != NULL) || (signer != NULL));
245
246	/* get signer as TPCertInfo if caller hasn't provided */
247	TPCertInfo *tmpSigner = NULL;
248	if(signer == NULL) {
249		try {
250			tmpSigner = new TPCertInfo(vfyCtx.clHand, vfyCtx.cspHand, signerData,
251				TIC_CopyData, vfyCtx.verifyTime);
252		}
253		catch(...) {
254			tpOcspDebug("tpIsOcspIssuer: bad cert");
255			return OIS_No;
256		}
257		signer = tmpSigner;
258	}
259	if(signer == NULL) {
260		return OIS_No;
261	}
262	if(signerRtn != NULL) {
263		*signerRtn = signer;
264	}
265
266	/*
267	 * Qualification of "this can be the signer" depends on where the
268	 * signer came from.
269	 */
270	bool shouldBeSigner = false;
271	OcspIssuerStatus ourRtn = OIS_No;
272
273	switch(certType) {
274		case OCT_Local:			// caller trusts this and thinks it's the signer
275			shouldBeSigner = true;
276			break;
277		case OCT_Issuer:		// last resort, the actual issuer
278			/* check ResponderID linkage */
279			shouldBeSigner = tpOcspResponderIDCheck(ocspResp, *signer);
280			break;
281		case OCT_Provided:
282		{
283			/*
284			 * This cert came with the response.
285			 */
286			if(issuer == NULL) {
287				/*
288				 * careful, might not know the issuer...how would this path ever
289				 * work then? I don't think it needs to because you can NOT
290				 * do OCSP on a cert without its issuer in hand.
291				 */
292				break;
293			}
294
295			/* check EKU linkage */
296			shouldBeSigner = tpIsAuthorizedOcspSigner(*issuer, *signer);
297			break;
298		}
299	}
300	if(!shouldBeSigner) {
301		goto errOut;
302	}
303
304	/* verify the signature */
305	if(tpOcspResponseSigVerify(vfyCtx, ocspResp, *signer)) {
306		ourRtn = OIS_Good;
307	}
308
309errOut:
310	if((signerRtn == NULL) && (tmpSigner != NULL)) {
311		delete tmpSigner;
312	}
313	return ourRtn;
314
315}
316
317OcspRespStatus tpVerifyOcspResp(
318	TPVerifyContext		&vfyCtx,
319	SecNssCoder			&coder,
320	TPCertInfo			*issuer,		// issuer of the related cert, may be issuer of
321										//   reply, may not be known
322	OCSPResponse		&ocspResp,
323	CSSM_RETURN			&cssmErr)		// possible per-cert error
324{
325	OcspRespStatus	ourRtn = ORS_Unknown;
326	CSSM_RETURN		crtn;
327
328	tpOcspDebug("tpVerifyOcspResp top");
329
330	switch(ocspResp.responseStatus()) {
331		case RS_Success:
332			crtn = CSSM_OK;
333			break;
334		case RS_MalformedRequest:
335			crtn = CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ;
336			break;
337		case RS_InternalError:
338			crtn = CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR;
339			break;
340		case RS_TryLater:
341			crtn = CSSMERR_APPLETP_OCSP_RESP_TRY_LATER;
342			break;
343		case RS_SigRequired:
344			crtn = CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED;
345			break;
346		case RS_Unauthorized:
347			crtn = CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED;
348			break;
349		default:
350			crtn = CSSMERR_APPLETP_OCSP_BAD_RESPONSE;
351			break;
352	}
353	if(crtn) {
354		tpOcspDebug("tpVerifyOcspResp aborting due to response status %d",
355			(int)(ocspResp.responseStatus()));
356		cssmErr = crtn;
357		return ORS_Unknown;
358	}
359	cssmErr = CSSM_OK;
360
361	/* one of our main jobs is to locate the signer of the response, here */
362	TPCertInfo *signerInfo = NULL;
363	TPCertInfo *signerInfoTBD = NULL;		// if non NULL at end, we delete
364	/* we'll be verifying into this cert group */
365	TPCertGroup	ocspCerts(vfyCtx.alloc, TGO_Caller);
366	CSSM_BOOL verifiedToRoot;
367	CSSM_BOOL verifiedToAnchor;
368	CSSM_BOOL verifiedViaTrustSetting;
369
370	const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts = vfyCtx.ocspOpts;
371	OcspIssuerStatus issuerStat;
372
373	/*
374	 * Set true if we ever find an apparent issuer which does not correctly
375	 * pass signature verify. If true and we never success, that's a XXX error.
376	 */
377	bool foundBadIssuer = false;
378	bool foundLocalResponder = false;
379	uint32 numSignerCerts = ocspResp.numSignerCerts();
380
381	/*
382	 * This cert group, allocated by AppleTPSession::CertGroupVerify(),
383	 * serves two functions here:
384	 *
385	 * -- it accumulates certs we get from the net (as parts of OCSP responses)
386	 *    for user in verifying OCSPResponse-related certs.
387	 *    TPCertGroup::buildCertGroup() uses this group as one of the many
388	 *    sources of certs when building a cert chain.
389	 *
390	 * -- it provides a container into which to stash TPCertInfos which
391	 *    persist at least as long as the TPVerifyContext; it's of type TGO_Group,
392	 *    so all of the certs added to it get freed when the group does.
393	 */
394	assert(vfyCtx.signerCerts != NULL);
395
396	TPCertGroup &gatheredCerts = vfyCtx.gatheredCerts;
397
398	/* set up for disposal of TPCertInfos created by TPCertGroup::buildCertGroup() */
399	TPCertGroup	certsToBeFreed(vfyCtx.alloc, TGO_Group);
400
401	/*
402	 * First job is to find the cert which signed this response.
403	 * Give priority to caller's LocalResponderCert.
404	 */
405	if((ocspOpts != NULL) && (ocspOpts->LocalResponderCert != NULL)) {
406		TPCertInfo *responderInfo = NULL;
407		issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp,
408			ocspOpts->LocalResponderCert, NULL,
409			OCT_Local, issuer, &responderInfo);
410		switch(issuerStat) {
411			case OIS_BadSig:
412				foundBadIssuer = true;
413				/* drop thru */
414			case OIS_No:
415				if(responderInfo != NULL) {
416					/* can't use it - should this be an immediate error? */
417					delete responderInfo;
418				}
419				break;
420			case OIS_Good:
421				assert(responderInfo != NULL);
422				signerInfo = signerInfoTBD = responderInfo;
423				foundLocalResponder = true;
424				tpOcspDebug("tpVerifyOcspResp: signer := LocalResponderCert");
425				break;
426		}
427	}
428
429	if((signerInfo == NULL) && (numSignerCerts != 0)) {
430		/*
431		 * App did not specify a local responder (or provided a bad one)
432		 * and the response came with some certs. Try those.
433		 */
434		TPCertInfo *respCert = NULL;
435		for(unsigned dex=0; dex<numSignerCerts; dex++) {
436			const CSSM_DATA *certData = ocspResp.signerCert(dex);
437			if(signerInfo == NULL) {
438				/* stop trying this after we succeed... */
439				issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp,
440					certData, NULL,
441					OCT_Provided, issuer, &respCert);
442				switch(issuerStat) {
443					case OIS_No:
444						break;
445					case OIS_Good:
446						assert(respCert != NULL);
447						signerInfo = signerInfoTBD = respCert;
448						tpOcspDebug("tpVerifyOcspResp: signer := signerCert[%u]", dex);
449						break;
450					case OIS_BadSig:
451						foundBadIssuer = true;
452						break;
453				}
454			}
455			else {
456				/*
457				 * At least add this cert to certGroup for verification.
458				 * OcspCert will own the TPCertInfo.
459				 */
460				try {
461					respCert = new TPCertInfo(vfyCtx.clHand, vfyCtx.cspHand, certData,
462						TIC_CopyData, vfyCtx.verifyTime);
463				}
464				catch(...) {
465					tpOcspDebug("tpVerifyOcspResp: BAD signerCert[%u]", dex);
466				}
467			}
468			/* if we got a TPCertInfo, and it's not the signer, add it to certGroup */
469			if((respCert != NULL) && (respCert != signerInfo)) {
470				gatheredCerts.appendCert(respCert);
471			}
472		}
473	}
474
475	if((signerInfo == NULL) && (issuer != NULL)) {
476		/*
477		 * Haven't found it yet, try the actual issuer
478		 */
479		issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp,
480			NULL, issuer,
481			OCT_Issuer, issuer, NULL);
482		switch(issuerStat) {
483			case OIS_BadSig:
484				ourRtn = ORS_Unknown;
485				cssmErr = CSSMERR_APPLETP_OCSP_SIG_ERROR;
486				goto errOut;
487			case OIS_No:
488				break;
489			case OIS_Good:
490				signerInfo = issuer;
491				tpOcspDebug("tpVerifyOcspResp: signer := issuer");
492				break;
493		}
494	}
495
496	if(signerInfo == NULL) {
497		if((issuer != NULL) && !issuer->isStatusFatal(CSSMERR_APPLETP_OCSP_NO_SIGNER)) {
498			/* user wants to proceed without verifying! */
499			tpOcspDebug("tpVerifyOcspResp: no signer found, user allows!");
500			ourRtn = ORS_Good;
501		}
502		else {
503			tpOcspDebug("tpVerifyOcspResp: no signer found");
504			ourRtn = ORS_Unknown;
505			/* caller adds to per-cert status */
506			cssmErr = CSSMERR_APPLETP_OCSP_NO_SIGNER;
507		}
508		goto errOut;
509	}
510
511	if(signerInfo != NULL && !foundLocalResponder) {
512		/*
513		 * tpIsOcspIssuer has verified that signerInfo is the signer of the
514		 * OCSP response, and that it is either the issuer of the cert being
515		 * checked or is a valid authorized responder for that issuer based on
516		 * key id linkage and EKU. There is no stipulation in RFC2560 to also
517		 * build the chain back to a trusted anchor; however, we'll continue to
518		 * enforce this for the local responder case. (10742723)
519		 */
520		tpOcspDebug("tpVerifyOcspResp SUCCESS");
521		ourRtn = ORS_Good;
522		goto errOut;
523	}
524
525	/*
526	 * Last remaining task is to verify the signer, and all the certs back to
527	 * an anchor
528	 */
529
530	/* start from scratch with both of these groups */
531	gatheredCerts.setAllUnused();
532	vfyCtx.signerCerts->setAllUnused();
533	crtn = ocspCerts.buildCertGroup(
534			*signerInfo,			// subject item
535			vfyCtx.signerCerts,		// inCertGroup the original group-to-be-verified
536			vfyCtx.dbList,			// optional
537			vfyCtx.clHand,
538			vfyCtx.cspHand,
539			vfyCtx.verifyTime,
540			vfyCtx.numAnchorCerts,
541			vfyCtx.anchorCerts,
542			certsToBeFreed,			// local to-be-freed right now
543			&gatheredCerts,			// accumulate gathered certs here
544			CSSM_FALSE,				// subjectIsInGroup
545			vfyCtx.actionFlags,
546			vfyCtx.policyOid,
547			vfyCtx.policyStr,
548			vfyCtx.policyStrLen,
549			kSecTrustSettingsKeyUseSignRevocation,
550			verifiedToRoot,
551			verifiedToAnchor,
552			verifiedViaTrustSetting);
553	if(crtn) {
554		tpOcspDebug("tpVerifyOcspResp buildCertGroup failure");
555		cssmErr = crtn;
556		ourRtn = ORS_Unknown;
557		goto errOut;
558	}
559
560	if(!verifiedToAnchor && !verifiedViaTrustSetting) {
561		/* required */
562		ourRtn = ORS_Unknown;
563		if(verifiedToRoot) {
564			/* verified to root which is not an anchor */
565			tpOcspDebug("tpVerifyOcspResp root, no anchor");
566			cssmErr = CSSMERR_APPLETP_OCSP_INVALID_ANCHOR_CERT;
567		}
568		else {
569			/* partial chain, no root, not verifiable by anchor */
570			tpOcspDebug("tpVerifyOcspResp no root, no anchor");
571			cssmErr = CSSMERR_APPLETP_OCSP_NOT_TRUSTED;
572		}
573		if((issuer != NULL) && !issuer->isStatusFatal(cssmErr)) {
574			tpOcspDebug("...ignoring last error per trust setting");
575			ourRtn = ORS_Good;
576		}
577		else {
578			ourRtn = ORS_Unknown;
579		}
580	}
581	else {
582		tpOcspDebug("tpVerifyOcspResp SUCCESS; chain verified");
583		ourRtn = ORS_Good;
584	}
585
586	/* FIXME policy verify? */
587
588errOut:
589	delete signerInfoTBD;
590	/* any other cleanup? */
591	return ourRtn;
592}
593