]>
Commit | Line | Data |
---|---|---|
bac41a7b A |
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) | |
29654253 | 37 | : alloc(session), |
bac41a7b A |
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) | |
29654253 | 48 | : alloc(session), |
bac41a7b A |
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 | } | |
29654253 | 203 | return CL_extractCSSMKey(*snaccKeyInfo, alloc, this); |
bac41a7b A |
204 | } |
205 |