]> git.saurik.com Git - apple/security.git/blame - AppleX509CL/Session_Crypto.cpp
Security-54.1.3.tar.gz
[apple/security.git] / AppleX509CL / Session_Crypto.cpp
CommitLineData
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 */
41void
42AppleX509CLSession::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 */
54void
55AppleX509CLSession::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 */
70void
71AppleX509CLSession::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 */
192void
193AppleX509CLSession::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 */
260void
261AppleX509CLSession::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 */
288void 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