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