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_CSP.cpp - CSR-related session functions.
23 #include "AppleX509CLSession.h"
24 #include "DecodedCert.h"
25 #include "SnaccUtils.h"
26 #include "cldebugging.h"
27 #include "CSPAttacher.h"
28 #include "CertBuilder.h"
29 #include <Security/oidscert.h>
30 #include <Security/cssmapple.h>
31 #include <Security/cssmerrno.h>
32 #include <Security/cdsaUtils.h>
33 #include <Security/pkcs10.h>
36 * Generate a DER-encoded CSR.
38 void AppleX509CLSession::generateCsr(
39 CSSM_CC_HANDLE CCHandle
,
40 const CSSM_APPLE_CL_CSR_REQUEST
*csrReq
,
41 CSSM_DATA_PTR
&csrPtr
)
44 * We use the full CertificationRequest here; we encode the
45 * CertificationRequestInfo component separately to calculate
46 * its signature, then we encode the whole CertificationRequest
47 * after dropping in the signature and SignatureAlgorithmIdentifier.
49 * CertificationRequestInfo, CertificationRequest from pkcs10
51 CertificationRequest certReq
;
52 CertificationRequestInfo
*reqInfo
= new CertificationRequestInfo
;
53 certReq
.certificationRequestInfo
= reqInfo
;
56 * Step 1: convert CSSM_APPLE_CL_CSR_REQUEST to CertificationRequestInfo.
58 reqInfo
->version
.Set(0);
61 NameBuilder
*subject
= new NameBuilder
;
62 reqInfo
->subject
= subject
;
63 subject
->addX509Name(csrReq
->subjectNameX509
);
65 /* SubjectPublicKeyInfo, AlgorithmIdentifier from sm_x509af */
66 SubjectPublicKeyInfo
*snaccKeyInfo
= new SubjectPublicKeyInfo
;
67 reqInfo
->subjectPublicKeyInfo
= snaccKeyInfo
;
68 AlgorithmIdentifier
*snaccAlgId
= new AlgorithmIdentifier
;
69 snaccKeyInfo
->algorithm
= snaccAlgId
;
70 CL_cssmAlgToSnaccOid(csrReq
->subjectPublicKey
->KeyHeader
.AlgorithmId
,
71 snaccAlgId
->algorithm
);
72 /* FIXME - for now assume NULL alg params */
73 CL_nullAlgParams(*snaccAlgId
);
75 /* actual public key blob - AsnBits */
76 snaccKeyInfo
->subjectPublicKey
.Set(reinterpret_cast<char *>
77 (csrReq
->subjectPublicKey
->KeyData
.Data
),
78 csrReq
->subjectPublicKey
->KeyData
.Length
* 8);
80 /* attributes - see sm_x501if - we support one, CSSMOID_ChallengePassword,
81 * as a printable string */
82 if(csrReq
->challengeString
) {
83 Attribute
*attr
= reqInfo
->attributes
.Append();
84 /* attr->type is an OID */
85 attr
->type
.Set(challengePassword_arc
);
86 /* one value, spec'd as AsnAny, we have to encode first. */
87 PrintableString
snaccStr(csrReq
->challengeString
);
88 CssmAutoData
encChallenge(*this);
89 SC_encodeAsnObj(snaccStr
, encChallenge
,
90 strlen(csrReq
->challengeString
) + 32);
91 /* AttributeValue is an AsnAny as far as SNACC is concerned */
92 AttributeValue
*av
= attr
->values
.Append();
93 CSM_Buffer
*cbuf
= new CSM_Buffer((char *)encChallenge
.data(),
94 encChallenge
.length());
99 * Step 2: DER-encode the CertificationRequestInfo.
101 CssmAutoData
encReqInfo(*this);
102 SC_encodeAsnObj(*reqInfo
, encReqInfo
, 8 * 1024); // totally wild guess
105 * Step 3: sign the encoded CertificationRequestInfo.
107 CssmAutoData
sig(*this);
108 signData(CCHandle
, encReqInfo
, sig
);
111 * Step 4: finish up CertificationRequest - signatureAlgorithm, signature
113 certReq
.signatureAlgorithm
= new SignatureAlgorithmIdentifier
;
114 certReq
.signatureAlgorithm
->algorithm
.Set(reinterpret_cast<char *>(
115 csrReq
->signatureOid
.Data
), csrReq
->signatureOid
.Length
);
116 /* FIXME - for now assume NULL alg params */
117 CL_nullAlgParams(*certReq
.signatureAlgorithm
);
118 certReq
.signature
.Set((char *)sig
.data(), sig
.length() * 8);
121 * Step 5: DER-encode the finished CertificationRequestSigned.
123 CssmAutoData
encCsr(*this);
124 SC_encodeAsnObj(certReq
, encCsr
,
125 encReqInfo
.length() + // size of the thing we signed
126 sig
.length() + // size of signature
127 100); // sigAlgId plus encoding overhead
129 /* TBD - enc64 the result, when we have this much working */
130 csrPtr
= (CSSM_DATA_PTR
)malloc(sizeof(CSSM_DATA
));
131 csrPtr
->Data
= (uint8
*)malloc(encCsr
.length());
132 csrPtr
->Length
= encCsr
.length();
133 memmove(csrPtr
->Data
, encCsr
.data(), encCsr
.length());
137 * Verify CSR with its own public key.
139 void AppleX509CLSession::verifyCsr(
140 const CSSM_DATA
*csrPtr
)
143 * 1. Extract the public key from the CSR. We do this by decoding
144 * the whole thing and getting a CSSM_KEY from the
145 * SubjectPublicKeyInfo.
147 CertificationRequest certReq
;
148 const CssmData
&csrEnc
= CssmData::overlay(*csrPtr
);
149 SC_decodeAsnObj(csrEnc
, certReq
);
150 CertificationRequestInfo
*certReqInfo
= certReq
.certificationRequestInfo
;
151 if(certReqInfo
== NULL
) {
152 CssmError::throwMe(CSSMERR_CL_INVALID_DATA
);
154 CSSM_KEY_PTR cssmKey
= CL_extractCSSMKey(*certReqInfo
->subjectPublicKeyInfo
,
156 NULL
); // no DecodedCert
159 * 2. Obtain signature algorithm and parameters.
161 SignatureAlgorithmIdentifier
*snaccAlgId
= certReq
.signatureAlgorithm
;
162 if(snaccAlgId
== NULL
) {
163 CssmError::throwMe(CSSMERR_CL_INVALID_DATA
);
165 CSSM_ALGORITHMS vfyAlg
= CL_snaccOidToCssmAlg(snaccAlgId
->algorithm
);
168 * 3. Extract the raw bits to be verified and the signature. We
169 * decode the CSR as a CertificationRequestSigned for this, which
170 * avoids the decode of the CertificationRequestInfo.
172 CertificationRequestSigned certReqSigned
;
173 SC_decodeAsnObj(csrEnc
, certReqSigned
);
175 CSM_Buffer
*cbuf
= certReqSigned
.certificationRequestInfo
.value
;
176 char *cbufData
= const_cast<char *>(cbuf
->Access());
177 CssmData
toVerify(cbufData
, cbuf
->Length());
178 AsnBits sigBits
= certReqSigned
.signature
;
179 size_t sigBytes
= (sigBits
.BitLen() + 7) / 8;
180 CssmData
sig(const_cast<char *>(sigBits
.BitOcts()), sigBytes
);
183 * 4. Attach to CSP, cook up signature context, verify signature.
185 CSSM_CSP_HANDLE cspHand
= getGlobalCspHand(true);
187 CSSM_CC_HANDLE ccHand
;
188 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
190 NULL
, // Access Creds
194 CssmError::throwMe(crtn
);
196 verifyData(ccHand
, toVerify
, sig
);
197 CL_freeCSSMKey(cssmKey
, *this);