]> git.saurik.com Git - apple/security.git/blob - AppleX509CL/DecodedCert.cpp
Security-28.tar.gz
[apple/security.git] / AppleX509CL / 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 snacc-decoded cert, with extensions
21 * parsed and decoded (still in snacc 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 "SnaccUtils.h"
29 #include "cldebugging.h"
30 #include "AppleX509CLSession.h"
31 #include "CSPAttacher.h"
32 #include <Security/cdsaUtils.h>
33 #include <Security/cssmapple.h>
34
35 DecodedCert::DecodedCert(
36 AppleX509CLSession &session)
37 : alloc(CssmAllocator::standard()),
38 mSession(session)
39 {
40 certificateToSign = new CertificateToSign;
41 reset();
42 }
43
44 /* one-shot constructor, decoding from DER-encoded data */
45 DecodedCert::DecodedCert(
46 AppleX509CLSession &session,
47 const CssmData &encodedCert)
48 : alloc(CssmAllocator::standard()),
49 mSession(session)
50 {
51 reset();
52 SC_decodeAsnObj(encodedCert, *this);
53 decodeExtensions();
54 mState = CS_DecodedCert;
55 }
56
57 DecodedCert::~DecodedCert()
58 {
59 /* free all extensions */
60 unsigned dex;
61
62 for(dex=0; dex<mNumExtensions; dex++) {
63 DecodedExten *exten = &mExtensions[dex];
64 delete exten->extnId;
65 delete exten->snaccObj;
66 }
67 alloc.free(mExtensions);
68 reset();
69 }
70
71 /* decode TBSCert and its extensions */
72 void DecodedCert::decodeTbs(
73 const CssmData &encodedTbs)
74 {
75 CASSERT(mState == CS_Empty);
76 CASSERT(certificateToSign != NULL);
77 try {
78 SC_decodeAsnObj(encodedTbs, *certificateToSign);
79 }
80 catch (...) {
81 errorLog0("decodeTbs: tbs.BDec failure\n");
82 /* FIXME - leave in bad state? delete and clear? let's be cautious...*/
83 delete certificateToSign;
84 certificateToSign = new CertificateToSign;
85 }
86 decodeExtensions();
87 mState = CS_DecodedTBS;
88 }
89
90 /*
91 * FIXME : how to determine max encoding size at run time!?
92 */
93 #define MAX_TEMPLATE_SIZE (8 * 1024)
94
95 /* encode TBS component; only called from CertCreateTemplate */
96 void DecodedCert::encodeTbs(
97 CssmOwnedData &encodedTbs)
98 {
99 encodeExtensions();
100 CASSERT(mState == CS_Building);
101 if(certificateToSign == NULL) {
102 errorLog0("DecodedCert::encodeTbs: no TBS\n");
103 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
104 }
105
106 /* enforce required fields - could go deeper, maybe we should */
107 if((certificateToSign->signature == NULL) ||
108 (certificateToSign->issuer == NULL) ||
109 (certificateToSign->validity == NULL) ||
110 (certificateToSign->subject == NULL) ||
111 (certificateToSign->subjectPublicKeyInfo == NULL)) {
112 errorLog0("DecodedCert::encodeTbs: incomplete TBS\n");
113 /* an odd, undocumented error return */
114 CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES);
115 }
116 SC_encodeAsnObj(*certificateToSign, encodedTbs, MAX_TEMPLATE_SIZE);
117 }
118
119 /*
120 * Cook up CSSM_KEYUSE, gleaning as much as possible from
121 * (optional) extensions. If no applicable extensions available,
122 * we'll just return CSSM_KEYUSE_ANY.
123 *
124 * Note that the standard KeyUsage flags involving 'signing' translate
125 * to verify since we're only dealing with public keys.
126 */
127 CSSM_KEYUSE DecodedCert::inferKeyUsage() const
128 {
129 CSSM_KEYUSE keyUse = 0;
130 DecodedExten *decodedExten;
131 uint32 numFields;
132
133 decodedExten = findDecodedExt(id_ce_keyUsage, false, 0, numFields);
134 if(decodedExten) {
135 KeyUsage *ku = dynamic_cast<KeyUsage *>(decodedExten->snaccObj);
136 if(ku == NULL) {
137 errorLog0("inferKeyUsage: dynamic_cast failure(1)\n");
138 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
139 }
140 if(ku->GetBit(KeyUsage::digitalSignature)) {
141 keyUse |= CSSM_KEYUSE_VERIFY;
142 }
143 if(ku->GetBit(KeyUsage::nonRepudiation)) {
144 keyUse |= CSSM_KEYUSE_VERIFY;
145 }
146 if(ku->GetBit(KeyUsage::keyEncipherment)) {
147 keyUse |= CSSM_KEYUSE_WRAP;
148 }
149 if(ku->GetBit(KeyUsage::keyAgreement)) {
150 keyUse |= CSSM_KEYUSE_DERIVE;
151 }
152 if(ku->GetBit(KeyUsage::keyCertSign)) {
153 keyUse |= CSSM_KEYUSE_VERIFY;
154 }
155 if(ku->GetBit(KeyUsage::cRLSign)) {
156 keyUse |= CSSM_KEYUSE_VERIFY;
157 }
158 if(ku->GetBit(KeyUsage::dataEncipherment)) {
159 keyUse |= CSSM_KEYUSE_ENCRYPT;
160 }
161 }
162 decodedExten = findDecodedExt(id_ce_extKeyUsage, false, 0, numFields);
163 if(decodedExten) {
164 ExtKeyUsageSyntax *eku =
165 dynamic_cast<ExtKeyUsageSyntax *>(decodedExten->snaccObj);
166 if(eku == NULL) {
167 errorLog0("inferKeyUsage: dynamic_cast failure(2)\n");
168 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
169 }
170 unsigned numOids = eku->Count();
171 eku->SetCurrToFirst();
172 unsigned oidDex;
173 for(oidDex=0; oidDex<numOids; oidDex++) {
174 KeyPurposeId *purp = eku->Curr();
175 if(*purp == id_kp_codeSigning) {
176 keyUse |= CSSM_KEYUSE_VERIFY;
177 }
178 /* I don't think the other purposes are useful... */
179 eku->GoNext();
180 }
181 }
182 if(keyUse == 0) {
183 /* Nothing found; take the default. */
184 keyUse = CSSM_KEYUSE_ANY;
185 }
186 return keyUse;
187 }
188
189 /*
190 * Obtain a CSSM_KEY from a decoded cert, inferring as much as we can
191 * from required fields (subjectPublicKeyInfo) and extensions (for
192 * KeyUse).
193 */
194 CSSM_KEY_PTR DecodedCert::extractCSSMKey(
195 CssmAllocator &alloc) const
196 {
197 CASSERT(certificateToSign != NULL);
198 SubjectPublicKeyInfo *snaccKeyInfo = certificateToSign->subjectPublicKeyInfo;
199 if((snaccKeyInfo == NULL) ||
200 (snaccKeyInfo->algorithm == NULL)) {
201 CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES);
202 }
203 CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR) alloc.malloc(sizeof(CSSM_KEY));
204 memset(cssmKey, 0, sizeof(CSSM_KEY));
205 CSSM_KEYHEADER &hdr = cssmKey->KeyHeader;
206 CssmRemoteData keyData(alloc, cssmKey->KeyData);
207 try {
208 hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
209 /* CspId blank */
210 hdr.BlobType = CSSM_KEYBLOB_RAW;
211 hdr.AlgorithmId = CL_snaccOidToCssmAlg(snaccKeyInfo->algorithm->algorithm);
212
213 /*
214 * Format inferred from AlgorithmId. I have never seen these defined
215 * anywhere, e.g., whart's the format of an RSA public key in a cert?
216 * X509 certainly doesn't say. However. the following two cases are known
217 * to be correct.
218 */
219 switch(hdr.AlgorithmId) {
220 case CSSM_ALGID_RSA:
221 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
222 break;
223 case CSSM_ALGID_DSA:
224 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
225 break;
226 case CSSM_ALGID_FEE:
227 /* CSSM_KEYBLOB_RAW_FORMAT_NONE --> DER encoded */
228 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
229 break;
230 default:
231 /* punt */
232 hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
233 }
234 hdr.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
235
236 /* KeyUsage inferred from extensions */
237 hdr.KeyUsage = inferKeyUsage();
238
239 /* start/end date unknown, leave zero */
240 hdr.WrapAlgorithmId = CSSM_ALGID_NONE;
241 hdr.WrapMode = CSSM_ALGMODE_NONE;
242
243 /*
244 * subjectPublicKeyInfo.subjectPublicKey (AsnBits) ==> KeyData
245 */
246 SC_asnBitsToCssmData(snaccKeyInfo->subjectPublicKey, keyData);
247 keyData.release();
248
249 /*
250 * LogicalKeySizeInBits - ask the CSP
251 */
252 CSSM_CSP_HANDLE cspHand = getGlobalCspHand(true);
253 CSSM_KEY_SIZE keySize;
254 CSSM_RETURN crtn;
255 crtn = CSSM_QueryKeySizeInBits(cspHand, NULL, cssmKey, &keySize);
256 if(crtn) {
257 CssmError::throwMe(crtn);
258 }
259 cssmKey->KeyHeader.LogicalKeySizeInBits =
260 keySize.LogicalKeySizeInBits;
261 }
262 catch (...) {
263 alloc.free(cssmKey);
264 throw;
265 }
266 return cssmKey;
267 }
268
269 void DecodedCert::freeCSSMKey(
270 CSSM_KEY_PTR cssmKey,
271 CssmAllocator &alloc,
272 bool freeTop)
273 {
274 if(cssmKey == NULL) {
275 return;
276 }
277 alloc.free(cssmKey->KeyData.Data);
278 memset(cssmKey, 0, sizeof(CSSM_KEY));
279 if(freeTop) {
280 alloc.free(cssmKey);
281 }
282 }
283