]> git.saurik.com Git - apple/security.git/blob - libsecurity_apple_x509_cl/lib/DecodedCert.cpp
Security-55471.tar.gz
[apple/security.git] / libsecurity_apple_x509_cl / lib / DecodedCert.cpp
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
35 DecodedCert::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 */
43 DecodedCert::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
58 DecodedCert::~DecodedCert()
59 {
60 }
61
62 /* decode TBSCert and its extensions */
63 void 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
78 void 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 */
97 void 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 */
130 CSSM_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 */
253 CSSM_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