1/*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19/*
20 * DecodedCert.cpp - object representing a decoded cert, in NSS
21 * format, with extensions parsed and decoded (still in NSS format).
22 *
23 * Created 9/1/2000 by Doug Mitchell.
24 * Copyright (c) 2000 by Apple Computer.
25 */
26
27#include "DecodedCert.h"
28#include "clNssUtils.h"
29#include "cldebugging.h"
30#include "AppleX509CLSession.h"
31#include "CSPAttacher.h"
32#include <Security/cssmapple.h>
33#include <Security/oidscert.h>
34
35DecodedCert::DecodedCert(
36	AppleX509CLSession	&session)
37	: DecodedItem(session)
38{
39	memset(&mCert, 0, sizeof(mCert));
40}
41
42/* one-shot constructor, decoding from DER-encoded data */
43DecodedCert::DecodedCert(
44	AppleX509CLSession	&session,
45	const CssmData 	&encodedCert)
46	: DecodedItem(session)
47{
48	memset(&mCert, 0, sizeof(mCert));
49	PRErrorCode prtn = mCoder.decode(encodedCert.data(), encodedCert.length(),
50		kSecAsn1SignedCertTemplate, &mCert);
51	if(prtn) {
52		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
53	}
54	mDecodedExtensions.decodeFromNss(mCert.tbs.extensions);
55	mState = IS_DecodedAll;
56}
57
58DecodedCert::~DecodedCert()
59{
60}
61
62/* decode TBSCert and its extensions */
63void DecodedCert::decodeTbs(
64	const CssmData	&encodedTbs)
65{
66	assert(mState == IS_Empty);
67
68	memset(&mCert, 0, sizeof(mCert));
69	PRErrorCode prtn = mCoder.decode(encodedTbs.data(), encodedTbs.length(),
70		kSecAsn1TBSCertificateTemplate, &mCert.tbs);
71	if(prtn) {
72		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
73	}
74	mDecodedExtensions.decodeFromNss(mCert.tbs.extensions);
75	mState = IS_DecodedTBS;
76}
77
78void DecodedCert::encodeExtensions()
79{
80	NSS_TBSCertificate &tbs = mCert.tbs;
81	assert(mState == IS_Building);
82	assert(tbs.extensions == NULL);
83
84	if(mDecodedExtensions.numExtensions() == 0) {
85		/* no extensions, no error */
86		return;
87	}
88	mDecodedExtensions.encodeToNss(tbs.extensions);
89}
90
91/*
92 * FIXME : how to determine max encoding size at run time!?
93 */
94#define MAX_TEMPLATE_SIZE	(8 * 1024)
95
96/* encode TBS component; only called from CertCreateTemplate */
97void DecodedCert::encodeTbs(
98	CssmOwnedData	&encodedTbs)
99{
100	encodeExtensions();
101	assert(mState == IS_Building);
102
103	/* enforce required fields - could go deeper, maybe we should */
104	NSS_TBSCertificate &tbs = mCert.tbs;
105	if((tbs.signature.algorithm.Data == NULL) ||
106	   (tbs.issuer.rdns == NULL) ||
107	   (tbs.subject.rdns == NULL) ||
108	   (tbs.subjectPublicKeyInfo.subjectPublicKey.Data == NULL)) {
109		clErrorLog("DecodedCert::encodeTbs: incomplete TBS");
110		/* an odd, undocumented error return */
111		CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES);
112	}
113
114	PRErrorCode prtn;
115	prtn = SecNssEncodeItemOdata(&tbs, kSecAsn1TBSCertificateTemplate,
116		encodedTbs);
117	if(prtn) {
118		CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
119	}
120}
121
122/*
123 * Cook up CSSM_KEYUSE, gleaning as much as possible from
124 * (optional) extensions. If no applicable extensions available,
125 * we'll just return CSSM_KEYUSE_ANY.
126 *
127 * Note that the standard KeyUsage flags involving 'signing' translate
128 * to verify since we're only dealing with public keys.
129 */
130CSSM_KEYUSE DecodedCert::inferKeyUsage() const
131{
132	CSSM_KEYUSE keyUse = 0;
133	const DecodedExten *decodedExten;
134	uint32 numFields;
135
136	/* Basic KeyUsage */
137	decodedExten = DecodedItem::findDecodedExt(CSSMOID_KeyUsage, false,
138		0, numFields);
139	if(decodedExten) {
140		CSSM_DATA *ku = (CSSM_DATA *)decodedExten->nssObj();
141		assert(ku != NULL);
142		CE_KeyUsage kuse = clBitStringToKeyUsage(*ku);
143		if(kuse & CE_KU_DigitalSignature) {
144			keyUse |= CSSM_KEYUSE_VERIFY;
145		}
146		if(kuse & CE_KU_NonRepudiation) {
147			keyUse |= CSSM_KEYUSE_VERIFY;
148		}
149		if(kuse & CE_KU_KeyEncipherment) {
150			keyUse |= CSSM_KEYUSE_WRAP;
151		}
152		if(kuse & CE_KU_KeyAgreement) {
153			keyUse |= CSSM_KEYUSE_DERIVE;
154		}
155		if(kuse & CE_KU_KeyCertSign) {
156			keyUse |= CSSM_KEYUSE_VERIFY;
157		}
158		if(kuse & CE_KU_CRLSign) {
159			keyUse |= CSSM_KEYUSE_VERIFY;
160		}
161		if(kuse & CE_KU_DataEncipherment) {
162			keyUse |= CSSM_KEYUSE_ENCRYPT;
163		}
164	}
165
166	/* Extended key usage */
167	decodedExten = DecodedItem::findDecodedExt(CSSMOID_ExtendedKeyUsage,
168			false, 0, numFields);
169	if(decodedExten) {
170		NSS_ExtKeyUsage *euse = (NSS_ExtKeyUsage *)decodedExten->nssObj();
171		assert(euse != NULL);
172		unsigned numUses = clNssArraySize((const void **)euse->purposes);
173		for(unsigned dex=0; dex<numUses; dex++) {
174		const CSSM_OID *thisUse = euse->purposes[dex];
175			if(clCompareCssmData(thisUse, &CSSMOID_ExtendedKeyUsageAny)) {
176				/* we're done */
177				keyUse = CSSM_KEYUSE_ANY;
178				break;
179			}
180			else if(clCompareCssmData(thisUse, &CSSMOID_ServerAuth)) {
181				keyUse |= (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DERIVE);
182			}
183			else if(clCompareCssmData(thisUse, &CSSMOID_ClientAuth)) {
184				keyUse |= (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DERIVE);
185			}
186			else if(clCompareCssmData(thisUse, &CSSMOID_ExtendedUseCodeSigning)) {
187				keyUse |= CSSM_KEYUSE_VERIFY;
188			}
189			else if(clCompareCssmData(thisUse, &CSSMOID_EmailProtection)) {
190				keyUse |=
191					(CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_DERIVE);
192			}
193			else if(clCompareCssmData(thisUse, &CSSMOID_TimeStamping)) {
194				keyUse |= CSSM_KEYUSE_VERIFY;
195			}
196			else if(clCompareCssmData(thisUse, &CSSMOID_OCSPSigning)) {
197				keyUse |= CSSM_KEYUSE_VERIFY;
198			}
199			else if(clCompareCssmData(thisUse, &CSSMOID_APPLE_EKU_SYSTEM_IDENTITY)) {
200				/* system identity - fairly liberal: CMS as well as SSL */
201				keyUse |=
202					(CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_ENCRYPT);
203			}
204			else if(clCompareCssmData(thisUse, &CSSMOID_KERBv5_PKINIT_KP_CLIENT_AUTH)) {
205				/*
206				 * Kerberos PKINIT client:
207				 * -- KDC verifies client signature in a CMS msg in AS-REQ
208				 * -- KDC encrypts for client in a CMS msg in AS-REP
209				 */
210				keyUse |= (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_WRAP);
211			}
212			else if(clCompareCssmData(thisUse, &CSSMOID_KERBv5_PKINIT_KP_KDC)) {
213				/*
214				 * Kerberos PKINIT server:
215				 * -- client verifies KDC signature in a CMS msg in AS-REP
216				 */
217				keyUse |= CSSM_KEYUSE_VERIFY;
218			}
219		}
220	}
221
222	/* NetscapeCertType */
223	decodedExten = DecodedItem::findDecodedExt(CSSMOID_NetscapeCertType,
224			false, 0, numFields);
225	if(decodedExten) {
226		/* nssObj() is a CSSM_DATA ptr, whose Data points to the bits we want */
227		CSSM_DATA *nctData = (CSSM_DATA *)decodedExten->nssObj();
228		if((nctData != NULL) && (nctData->Length > 0)) {
229			CE_NetscapeCertType nct = ((uint16)nctData->Data[0]) << 8;
230			if(nctData->Length > 1) {
231				nct |= nctData->Data[1];
232			}
233
234			/* All this usage bits imply signature verify capability */
235			if(nct & (CE_NCT_SSL_Client | CE_NCT_SSL_Server | CE_NCT_SMIME | CE_NCT_ObjSign |
236					  CE_NCT_SSL_CA | CE_NCT_SMIME_CA | CE_NCT_ObjSignCA)) {
237				keyUse |= CSSM_KEYUSE_VERIFY;
238			}
239		}
240	}
241	if(keyUse == 0) {
242		/* Nothing found; take the default. */
243		keyUse = CSSM_KEYUSE_ANY;
244	}
245	return keyUse;
246}
247
248/*
249 * Obtain a CSSM_KEY from a decoded cert, inferring as much as we can
250 * from required fields (subjectPublicKeyInfo) and extensions (for
251 * KeyUse).
252 */
253CSSM_KEY_PTR DecodedCert::extractCSSMKey(
254	Allocator		&alloc)	const
255{
256	const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &keyInfo =
257		mCert.tbs.subjectPublicKeyInfo;
258	return CL_extractCSSMKeyNSS(keyInfo, alloc, this);
259}
260
261