]> git.saurik.com Git - apple/security.git/blob - AppleX509CL/Session_Crypto.cpp
Security-179.tar.gz
[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 "cldebugging.h"
29 #include "CSPAttacher.h"
30 #include "clNssUtils.h"
31 #include <SecurityNssAsn1/keyTemplates.h>
32 #include <SecurityNssAsn1/nssUtils.h>
33 #include <Security/oidscert.h>
34 #include <Security/cssmapple.h>
35 #include <Security/cssmerrno.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_certCrlDecodeComponents(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_certCrlDecodeComponents(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 clErrorLog("CertVerify: valid CCHandle but no key!\n");
124 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
125 }
126 /* require match */
127 assert(signerPubKey != NULL);
128 CSSM_KEY_PTR contextPubKey = attr->Attribute.Key;
129 if(contextPubKey->KeyHeader.AlgorithmId !=
130 signerPubKey->KeyHeader.AlgorithmId) {
131 clErrorLog("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. Decode it into temp memory.
145 */
146 assert(SignerCert != NULL);
147 assert(signerPubKey != NULL);
148
149 CSSM_X509_ALGORITHM_IDENTIFIER cssmAlgId;
150 SecNssCoder coder;
151 PRErrorCode prtn;
152
153 CssmData &algIdData = algId.get();
154 memset(&cssmAlgId, 0, sizeof(cssmAlgId));
155 prtn = coder.decode(algIdData.data(), algIdData.length(),
156 NSS_AlgorithmIDTemplate, &cssmAlgId);
157 if(prtn) {
158 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
159 }
160
161 CSSM_ALGORITHMS vfyAlg = CL_oidToAlg(cssmAlgId.algorithm);
162
163 /* attach to CSP, cook up a context */
164 cspHand = getGlobalCspHand(true);
165 CSSM_RETURN crtn;
166 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
167 vfyAlg,
168 NULL, // Access Creds
169 signerPubKey,
170 &ourCcHand);
171 CCHandle = ourCcHand;
172 } /* inferring sig verify context from SignerCert */
173 verifyData(CCHandle, tbs, sig);
174 }
175 catch(...) {
176 /* FIXME - isn't there a better way to do this? Save the
177 * exception as a CSSM_RETURN and throw it if nonzero later?
178 */
179 if(context != NULL) {
180 CSSM_FreeContext(context);
181 }
182 CL_freeCSSMKey(signerPubKey, *this);
183 if(ourCcHand != CSSM_INVALID_HANDLE) {
184 CSSM_DeleteContext(ourCcHand);
185 }
186 throw;
187 }
188 if(context != NULL) {
189 CSSM_FreeContext(context);
190 }
191 CL_freeCSSMKey(signerPubKey, *this);
192 if(ourCcHand != CSSM_INVALID_HANDLE) {
193 CSSM_DeleteContext(ourCcHand);
194 }
195 }
196
197 /*
198 * Given a DER-encoded TBSCert and a fully specified crypto context,
199 * sign the TBSCert and return the resulting DER-encoded Cert.
200 */
201 void
202 AppleX509CLSession::CertSign(
203 CSSM_CC_HANDLE CCHandle,
204 const CssmData &CertTemplate,
205 const CSSM_FIELD *SignScope,
206 uint32 ScopeSize,
207 CssmData &SignedCert)
208 {
209 if((SignScope != NULL) || (ScopeSize != 0)) {
210 CssmError::throwMe(CSSMERR_CL_SCOPE_NOT_SUPPORTED);
211 }
212 if(CCHandle == CSSM_INVALID_HANDLE) {
213 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
214 }
215
216 /* cook up algId from context->(signing key, sig algorithm) */
217 CSSM_CONTEXT_PTR context = NULL; // must be freed
218 CSSM_RETURN crtn;
219 crtn = CSSM_GetContext(CCHandle, &context);
220 if(crtn) {
221 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
222 }
223 CSSM_CONTEXT_ATTRIBUTE_PTR attr; // not freed
224 crtn = CSSM_GetContextAttribute(context,
225 CSSM_ATTRIBUTE_KEY,
226 &attr);
227 if(crtn) {
228 clErrorLog("CertSign: valid CCHandle but no signing key!\n");
229 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
230 }
231 CSSM_KEY_PTR signingKey = attr->Attribute.Key;
232 if(signingKey == NULL) {
233 clErrorLog("CertSign: valid CCHandle, NULL signing key!\n");
234 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
235 }
236
237 CssmAutoData encAlgId(*this);
238 CssmAutoData rawSig(*this);
239 CssmAutoData fullCert(*this);
240 try {
241 /*
242 * FIXME: we really should break up the template and ensure that its
243 * signature algId matches the one we're signing with, or just use
244 * that algId here....for now, this is up to the app to make sure.
245 */
246
247 /* temp allocs/encode into here */
248 SecNssCoder coder;
249
250 /* CSSM alg --> CSSM_X509_ALGORITHM_IDENTIFIER */
251 CSSM_X509_ALGORITHM_IDENTIFIER algId;
252 memset(&algId, 0, sizeof(algId));
253 const CSSM_OID *oid = cssmAlgToOid(context->AlgorithmType);
254
255 if(oid == NULL) {
256 clErrorLog("CertSIgn: unknown alg (%u)\n",
257 (unsigned)context->AlgorithmType);
258 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
259 }
260 algId.algorithm = *oid;
261
262 /* NULL params - FIXME - is this OK? */
263 CL_nullAlgParams(algId);
264 /* DER-encode the algID */
265 PRErrorCode prtn;
266 prtn = SecNssEncodeItemOdata(&algId, NSS_AlgorithmIDTemplate,
267 encAlgId);
268 if(prtn) {
269 CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
270 }
271
272 /* sign TBS --> rawSig */
273 signData(CCHandle, CertTemplate, rawSig);
274 /* put it all together */
275 CL_certEncodeComponents(CertTemplate, encAlgId, rawSig, fullCert);
276 }
277 catch (...) {
278 CSSM_FreeContext(context);
279 throw;
280 }
281 CSSM_FreeContext(context);
282 SignedCert = fullCert.release();
283 }
284
285 /*** Private functions ***/
286
287 /*
288 * Sign a CssmData with the specified signing context. Used for
289 * signing both certs and CRLs; this routine doesn't know anything
290 * about either one.
291 */
292 void
293 AppleX509CLSession::signData(
294 CSSM_CC_HANDLE ccHand,
295 const CssmData &tbs,
296 CssmOwnedData &sig) // mallocd and returned
297 {
298 CSSM_RETURN crtn;
299 CssmData cSig;
300
301 crtn = CSSM_SignData(
302 ccHand,
303 &tbs,
304 1, // DataBufCount
305 CSSM_ALGID_NONE, // DigestAlgorithm,
306 &cSig);
307 if(crtn) {
308 clErrorLog("AppleX509CLSession::CSSM_SignData: %s\n",
309 cssmErrorString(crtn).c_str());
310 CssmError::throwMe(crtn);
311 }
312 sig.set(cSig);
313 }
314
315 /*
316 * Verify a block of data given a crypto context and a signature.
317 * Used for verifying certs and CRLs. Returns a CSSM_RETURN (callers
318 * always need to clean up after calling us).
319 */
320 void AppleX509CLSession::verifyData(
321 CSSM_CC_HANDLE ccHand,
322 const CssmData &tbs,
323 const CssmData &sig)
324 {
325 CSSM_RETURN crtn;
326
327 crtn = CSSM_VerifyData(ccHand,
328 &tbs,
329 1,
330 CSSM_ALGID_NONE, // Digest alg
331 &sig);
332 if(crtn) {
333 if(crtn == CSSMERR_CSP_VERIFY_FAILED) {
334 /* CSP and CL report this differently */
335 CssmError::throwMe(CSSMERR_CL_VERIFICATION_FAILURE);
336 }
337 else {
338 CssmError::throwMe(crtn);
339 }
340 }
341 }
342