]>
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 | * Session_Crypto.cpp: CL session functions: sign, verify, CSSM_KEY extraction. | |
21 | * | |
22 | * Created 9/1/2000 by Doug Mitchell. | |
23 | * Copyright (c) 2000 by Apple Computer. | |
24 | */ | |
25 | ||
26 | #include "AppleX509CLSession.h" | |
27 | #include "DecodedCert.h" | |
28 | #include "SnaccUtils.h" | |
29 | #include "cldebugging.h" | |
30 | #include "CSPAttacher.h" | |
29654253 | 31 | #include "CertBuilder.h" |
bac41a7b A |
32 | #include <Security/oidscert.h> |
33 | #include <Security/cssmapple.h> | |
34 | #include <Security/cssmerrno.h> | |
35 | #include <Security/cdsaUtils.h> | |
36 | ||
37 | /* | |
38 | * Given a DER-encoded cert, obtain a fully usable CSSM_KEY representing | |
39 | * the cert's public key. | |
40 | */ | |
41 | void | |
42 | AppleX509CLSession::CertGetKeyInfo( | |
43 | const CssmData &Cert, | |
44 | CSSM_KEY_PTR &Key) | |
45 | { | |
46 | DecodedCert decodedCert(*this, Cert); | |
47 | Key = decodedCert.extractCSSMKey(*this); | |
48 | } | |
49 | ||
50 | /* | |
51 | * Given a DER-encoded cert and a fully specified crypto context, verify | |
52 | * cert's TBS and signature. | |
53 | */ | |
54 | void | |
55 | AppleX509CLSession::CertVerifyWithKey( | |
56 | CSSM_CC_HANDLE CCHandle, | |
57 | const CssmData &CertToBeVerified) | |
58 | { | |
59 | CssmAutoData tbs(*this); | |
60 | CssmAutoData algId(*this); | |
61 | CssmAutoData sig(*this); | |
62 | CL_certDecodeComponents(CertToBeVerified, tbs, algId, sig); | |
63 | verifyData(CCHandle, tbs, sig); | |
64 | } | |
65 | ||
66 | /* | |
67 | * Verify a DER-encoded cert, obtaining crypto context from either | |
68 | * caller-specified context or by inference from SignerCert. | |
69 | */ | |
70 | void | |
71 | AppleX509CLSession::CertVerify( | |
72 | CSSM_CC_HANDLE CCHandle, | |
73 | const CssmData &CertToBeVerified, | |
74 | const CssmData *SignerCert, | |
75 | const CSSM_FIELD *VerifyScope, | |
76 | uint32 ScopeSize) | |
77 | { | |
78 | if((VerifyScope != NULL) || (ScopeSize != 0)) { | |
79 | CssmError::throwMe(CSSMERR_CL_SCOPE_NOT_SUPPORTED); | |
80 | } | |
81 | if((CCHandle == CSSM_INVALID_HANDLE) && (SignerCert == NULL)) { | |
82 | /* need one or the other */ | |
83 | CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE); | |
84 | } | |
85 | ||
86 | /* get top-level components */ | |
87 | CssmAutoData tbs(*this); // in DER format | |
88 | CssmAutoData algId(*this); // in DER format | |
89 | CssmAutoData sig(*this); // in DER format | |
90 | CL_certDecodeComponents(CertToBeVerified, tbs, algId, sig); | |
91 | ||
92 | /* these must be explicitly freed upon exit */ | |
93 | CSSM_KEY_PTR signerPubKey = NULL; | |
94 | CSSM_CONTEXT_PTR context = NULL; | |
95 | CSSM_CSP_HANDLE cspHand = CSSM_INVALID_HANDLE; | |
96 | CSSM_CC_HANDLE ourCcHand = CSSM_INVALID_HANDLE; | |
97 | ||
98 | /* SignerCert optional; if present, obtain its subject key */ | |
99 | if(SignerCert != NULL) { | |
100 | CertGetKeyInfo(*SignerCert, signerPubKey); | |
101 | } | |
102 | ||
103 | /* signerPubKey must be explicitly freed in any case */ | |
104 | try { | |
105 | if(CCHandle != CSSM_INVALID_HANDLE) { | |
106 | /* | |
107 | * We'll use this CCHandle for the sig verify, but | |
108 | * make sure it matches possible incoming SignerCert parameters | |
109 | */ | |
110 | if(SignerCert != NULL) { | |
111 | CSSM_RETURN crtn; | |
112 | ||
113 | /* extract signer's public key as a CSSM_KEY from context */ | |
114 | crtn = CSSM_GetContext(CCHandle, &context); | |
115 | if(crtn) { | |
116 | CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE); | |
117 | } | |
118 | CSSM_CONTEXT_ATTRIBUTE_PTR attr; | |
119 | crtn = CSSM_GetContextAttribute(context, | |
120 | CSSM_ATTRIBUTE_KEY, | |
121 | &attr); | |
122 | if(crtn) { | |
123 | errorLog0("CertVerify: valid CCHandle but no key!\n"); | |
124 | CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE); | |
125 | } | |
126 | /* require match */ | |
127 | CASSERT(signerPubKey != NULL); | |
128 | CSSM_KEY_PTR contextPubKey = attr->Attribute.Key; | |
129 | if(contextPubKey->KeyHeader.AlgorithmId != | |
130 | signerPubKey->KeyHeader.AlgorithmId) { | |
131 | errorLog0("CertVerify: AlgorithmId mismatch!\n"); | |
132 | CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE); | |
133 | } | |
134 | ||
135 | /* TBD - check key size, when we have a CSP which can report it */ | |
136 | /* TBD - anything else? */ | |
137 | } /* verifying multiple contexts */ | |
138 | /* OK to use CCHandle as is for verify context */ | |
139 | } /* valid CCHandle */ | |
140 | else { | |
141 | /* | |
142 | * All we have is signer cert. We already have its public key; | |
143 | * get signature alg from CertToBeVerified's Cert.algID (which | |
144 | * we currently have in DER form). | |
145 | */ | |
146 | CASSERT(SignerCert != NULL); | |
147 | CASSERT(signerPubKey != NULL); | |
148 | ||
149 | AlgorithmIdentifier snaccAlgId; | |
150 | //CL_decodeAlgId(algId, snaccAlgId); | |
151 | SC_decodeAsnObj(algId, snaccAlgId); | |
152 | CSSM_ALGORITHMS vfyAlg = CL_snaccOidToCssmAlg(snaccAlgId.algorithm); | |
153 | ||
154 | /* attach to CSP, cook up a context */ | |
155 | cspHand = getGlobalCspHand(true); | |
156 | CSSM_RETURN crtn; | |
157 | crtn = CSSM_CSP_CreateSignatureContext(cspHand, | |
158 | vfyAlg, | |
159 | NULL, // Access Creds | |
160 | signerPubKey, | |
161 | &ourCcHand); | |
162 | CCHandle = ourCcHand; | |
163 | } /* inferring sig verify context from SignerCert */ | |
164 | verifyData(CCHandle, tbs, sig); | |
165 | } | |
166 | catch(...) { | |
167 | /* FIXME - isn't there a better way to do this? Save the | |
168 | * exception as a CSSM_RETURN and throw it if nonzero later? | |
169 | */ | |
170 | if(context != NULL) { | |
171 | CSSM_FreeContext(context); | |
172 | } | |
29654253 | 173 | CL_freeCSSMKey(signerPubKey, *this); |
bac41a7b A |
174 | if(ourCcHand != CSSM_INVALID_HANDLE) { |
175 | CSSM_DeleteContext(ourCcHand); | |
176 | } | |
177 | throw; | |
178 | } | |
179 | if(context != NULL) { | |
180 | CSSM_FreeContext(context); | |
181 | } | |
29654253 | 182 | CL_freeCSSMKey(signerPubKey, *this); |
bac41a7b A |
183 | if(ourCcHand != CSSM_INVALID_HANDLE) { |
184 | CSSM_DeleteContext(ourCcHand); | |
185 | } | |
186 | } | |
187 | ||
188 | /* | |
189 | * Given a DER-encoded TBSCert and a fully specified crypto context, | |
190 | * sign the TBSCert and return the resulting DER-encoded Cert. | |
191 | */ | |
192 | void | |
193 | AppleX509CLSession::CertSign( | |
194 | CSSM_CC_HANDLE CCHandle, | |
195 | const CssmData &CertTemplate, | |
196 | const CSSM_FIELD *SignScope, | |
197 | uint32 ScopeSize, | |
198 | CssmData &SignedCert) | |
199 | { | |
200 | if((SignScope != NULL) || (ScopeSize != 0)) { | |
201 | CssmError::throwMe(CSSMERR_CL_SCOPE_NOT_SUPPORTED); | |
202 | } | |
203 | if(CCHandle == CSSM_INVALID_HANDLE) { | |
204 | CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE); | |
205 | } | |
206 | ||
207 | /* cook up algId from context->(signing key, sig algorithm) */ | |
208 | CSSM_CONTEXT_PTR context = NULL; // must be freed | |
209 | CSSM_RETURN crtn; | |
210 | crtn = CSSM_GetContext(CCHandle, &context); | |
211 | if(crtn) { | |
212 | CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE); | |
213 | } | |
214 | CSSM_CONTEXT_ATTRIBUTE_PTR attr; // not freed | |
215 | crtn = CSSM_GetContextAttribute(context, | |
216 | CSSM_ATTRIBUTE_KEY, | |
217 | &attr); | |
218 | if(crtn) { | |
219 | errorLog0("CertSign: valid CCHandle but no signing key!\n"); | |
220 | CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE); | |
221 | } | |
222 | CSSM_KEY_PTR signingKey = attr->Attribute.Key; | |
223 | if(signingKey == NULL) { | |
224 | errorLog0("CertSign: valid CCHandle, NULL signing key!\n"); | |
225 | CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE); | |
226 | } | |
227 | ||
228 | AlgorithmIdentifier snaccAlgId; | |
229 | CssmAutoData encAlgId(*this); | |
230 | CssmAutoData rawSig(*this); | |
231 | CssmAutoData fullCert(*this); | |
232 | try { | |
233 | /* CSSM alg --> snacc-style AlgorithmIdentifier object */ | |
234 | CL_cssmAlgToSnaccOid(context->AlgorithmType, | |
235 | snaccAlgId.algorithm); | |
236 | /* NULL params - FIXME - is this OK? */ | |
237 | CL_nullAlgParams(snaccAlgId); | |
238 | /* DER-encode the algID */ | |
239 | SC_encodeAsnObj(snaccAlgId, encAlgId, 128); | |
240 | /* sign TBS --> sig */ | |
241 | signData(CCHandle, CertTemplate, rawSig); | |
242 | /* put it all together */ | |
243 | CL_certEncodeComponents(CertTemplate, encAlgId, rawSig, fullCert); | |
244 | } | |
245 | catch (...) { | |
246 | CSSM_FreeContext(context); | |
247 | throw; | |
248 | } | |
249 | CSSM_FreeContext(context); | |
250 | SignedCert = fullCert.release(); | |
251 | } | |
252 | ||
253 | /*** Private functions ***/ | |
254 | ||
255 | /* | |
256 | * Sign a CssmData with the specified signing context. Used for | |
257 | * signing both certs and CRLs; this routine doesn't know anything | |
258 | * about either one. | |
259 | */ | |
260 | void | |
261 | AppleX509CLSession::signData( | |
262 | CSSM_CC_HANDLE ccHand, | |
263 | const CssmData &tbs, | |
264 | CssmOwnedData &sig) // mallocd and returned | |
265 | { | |
266 | CSSM_RETURN crtn; | |
267 | CssmData cSig; | |
268 | ||
269 | crtn = CSSM_SignData( | |
270 | ccHand, | |
271 | &tbs, | |
272 | 1, // DataBufCount | |
273 | CSSM_ALGID_NONE, // DigestAlgorithm, | |
274 | &cSig); | |
275 | if(crtn) { | |
276 | errorLog1("AppleX509CLSession::CSSM_SignData: %s\n", | |
277 | cssmErrorString(crtn).c_str()); | |
278 | CssmError::throwMe(crtn); | |
279 | } | |
280 | sig.set(cSig); | |
281 | } | |
282 | ||
283 | /* | |
284 | * Verify a block of data given a crypto context and a signature. | |
285 | * Used for verifying certs and CRLs. Returns a CSSM_RETURN (callers | |
286 | * always need to clean up after calling us). | |
287 | */ | |
288 | void AppleX509CLSession::verifyData( | |
289 | CSSM_CC_HANDLE ccHand, | |
290 | const CssmData &tbs, | |
291 | const CssmData &sig) | |
292 | { | |
293 | CSSM_RETURN crtn; | |
294 | ||
295 | crtn = CSSM_VerifyData(ccHand, | |
296 | &tbs, | |
297 | 1, | |
298 | CSSM_ALGID_NONE, // Digest alg | |
299 | &sig); | |
300 | if(crtn) { | |
301 | // errorLog1("AppleX509CLSession::verifyData: %s\n", | |
302 | // cssmErrorString(crtn).c_str()); | |
303 | if(crtn == CSSMERR_CSP_VERIFY_FAILED) { | |
304 | /* CSP and CL report this differently */ | |
305 | CssmError::throwMe(CSSMERR_CL_VERIFICATION_FAILURE); | |
306 | } | |
307 | else { | |
308 | CssmError::throwMe(crtn); | |
309 | } | |
310 | } | |
311 | } | |
312 |