2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 * Session_Crypto.cpp: CL session functions: sign, verify, CSSM_KEY extraction.
22 * Created 9/1/2000 by Doug Mitchell.
23 * Copyright (c) 2000 by Apple Computer.
26 #include "AppleX509CLSession.h"
27 #include "DecodedCert.h"
28 #include "SnaccUtils.h"
29 #include "cldebugging.h"
30 #include "CSPAttacher.h"
31 #include "CertBuilder.h"
32 #include <Security/oidscert.h>
33 #include <Security/cssmapple.h>
34 #include <Security/cssmerrno.h>
35 #include <Security/cdsaUtils.h>
38 * Given a DER-encoded cert, obtain a fully usable CSSM_KEY representing
39 * the cert's public key.
42 AppleX509CLSession::CertGetKeyInfo(
46 DecodedCert
decodedCert(*this, Cert
);
47 Key
= decodedCert
.extractCSSMKey(*this);
51 * Given a DER-encoded cert and a fully specified crypto context, verify
52 * cert's TBS and signature.
55 AppleX509CLSession::CertVerifyWithKey(
56 CSSM_CC_HANDLE CCHandle
,
57 const CssmData
&CertToBeVerified
)
59 CssmAutoData
tbs(*this);
60 CssmAutoData
algId(*this);
61 CssmAutoData
sig(*this);
62 CL_certDecodeComponents(CertToBeVerified
, tbs
, algId
, sig
);
63 verifyData(CCHandle
, tbs
, sig
);
67 * Verify a DER-encoded cert, obtaining crypto context from either
68 * caller-specified context or by inference from SignerCert.
71 AppleX509CLSession::CertVerify(
72 CSSM_CC_HANDLE CCHandle
,
73 const CssmData
&CertToBeVerified
,
74 const CssmData
*SignerCert
,
75 const CSSM_FIELD
*VerifyScope
,
78 if((VerifyScope
!= NULL
) || (ScopeSize
!= 0)) {
79 CssmError::throwMe(CSSMERR_CL_SCOPE_NOT_SUPPORTED
);
81 if((CCHandle
== CSSM_INVALID_HANDLE
) && (SignerCert
== NULL
)) {
82 /* need one or the other */
83 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE
);
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
);
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
;
98 /* SignerCert optional; if present, obtain its subject key */
99 if(SignerCert
!= NULL
) {
100 CertGetKeyInfo(*SignerCert
, signerPubKey
);
103 /* signerPubKey must be explicitly freed in any case */
105 if(CCHandle
!= CSSM_INVALID_HANDLE
) {
107 * We'll use this CCHandle for the sig verify, but
108 * make sure it matches possible incoming SignerCert parameters
110 if(SignerCert
!= NULL
) {
113 /* extract signer's public key as a CSSM_KEY from context */
114 crtn
= CSSM_GetContext(CCHandle
, &context
);
116 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE
);
118 CSSM_CONTEXT_ATTRIBUTE_PTR attr
;
119 crtn
= CSSM_GetContextAttribute(context
,
123 errorLog0("CertVerify: valid CCHandle but no key!\n");
124 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE
);
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
);
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 */
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).
146 CASSERT(SignerCert
!= NULL
);
147 CASSERT(signerPubKey
!= NULL
);
149 AlgorithmIdentifier snaccAlgId
;
150 //CL_decodeAlgId(algId, snaccAlgId);
151 SC_decodeAsnObj(algId
, snaccAlgId
);
152 CSSM_ALGORITHMS vfyAlg
= CL_snaccOidToCssmAlg(snaccAlgId
.algorithm
);
154 /* attach to CSP, cook up a context */
155 cspHand
= getGlobalCspHand(true);
157 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
159 NULL
, // Access Creds
162 CCHandle
= ourCcHand
;
163 } /* inferring sig verify context from SignerCert */
164 verifyData(CCHandle
, tbs
, sig
);
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?
170 if(context
!= NULL
) {
171 CSSM_FreeContext(context
);
173 CL_freeCSSMKey(signerPubKey
, *this);
174 if(ourCcHand
!= CSSM_INVALID_HANDLE
) {
175 CSSM_DeleteContext(ourCcHand
);
179 if(context
!= NULL
) {
180 CSSM_FreeContext(context
);
182 CL_freeCSSMKey(signerPubKey
, *this);
183 if(ourCcHand
!= CSSM_INVALID_HANDLE
) {
184 CSSM_DeleteContext(ourCcHand
);
189 * Given a DER-encoded TBSCert and a fully specified crypto context,
190 * sign the TBSCert and return the resulting DER-encoded Cert.
193 AppleX509CLSession::CertSign(
194 CSSM_CC_HANDLE CCHandle
,
195 const CssmData
&CertTemplate
,
196 const CSSM_FIELD
*SignScope
,
198 CssmData
&SignedCert
)
200 if((SignScope
!= NULL
) || (ScopeSize
!= 0)) {
201 CssmError::throwMe(CSSMERR_CL_SCOPE_NOT_SUPPORTED
);
203 if(CCHandle
== CSSM_INVALID_HANDLE
) {
204 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE
);
207 /* cook up algId from context->(signing key, sig algorithm) */
208 CSSM_CONTEXT_PTR context
= NULL
; // must be freed
210 crtn
= CSSM_GetContext(CCHandle
, &context
);
212 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE
);
214 CSSM_CONTEXT_ATTRIBUTE_PTR attr
; // not freed
215 crtn
= CSSM_GetContextAttribute(context
,
219 errorLog0("CertSign: valid CCHandle but no signing key!\n");
220 CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE
);
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
);
228 AlgorithmIdentifier snaccAlgId
;
229 CssmAutoData
encAlgId(*this);
230 CssmAutoData
rawSig(*this);
231 CssmAutoData
fullCert(*this);
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
);
246 CSSM_FreeContext(context
);
249 CSSM_FreeContext(context
);
250 SignedCert
= fullCert
.release();
253 /*** Private functions ***/
256 * Sign a CssmData with the specified signing context. Used for
257 * signing both certs and CRLs; this routine doesn't know anything
261 AppleX509CLSession::signData(
262 CSSM_CC_HANDLE ccHand
,
264 CssmOwnedData
&sig
) // mallocd and returned
269 crtn
= CSSM_SignData(
273 CSSM_ALGID_NONE
, // DigestAlgorithm,
276 errorLog1("AppleX509CLSession::CSSM_SignData: %s\n",
277 cssmErrorString(crtn
).c_str());
278 CssmError::throwMe(crtn
);
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).
288 void AppleX509CLSession::verifyData(
289 CSSM_CC_HANDLE ccHand
,
295 crtn
= CSSM_VerifyData(ccHand
,
298 CSSM_ALGID_NONE
, // Digest alg
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
);
308 CssmError::throwMe(crtn
);