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_CSP.cpp - CSR-related session functions.
21//
22
23#include "AppleX509CLSession.h"
24#include "DecodedCert.h"
25#include "clNameUtils.h"
26#include "clNssUtils.h"
27#include "cldebugging.h"
28#include "CSPAttacher.h"
29#include "clNssUtils.h"
30#include <Security/oidsattr.h>
31#include <Security/oidscert.h>
32#include <Security/cssmapple.h>
33#include <Security/csrTemplates.h>
34#include <Security/SecAsn1Templates.h>
35
36/*
37 * Generate a DER-encoded CSR.
38 */
39void AppleX509CLSession::generateCsr(
40	CSSM_CC_HANDLE 		CCHandle,
41	const CSSM_APPLE_CL_CSR_REQUEST *csrReq,
42	CSSM_DATA_PTR		&csrPtr)
43{
44	/*
45	 * We use the full NSSCertRequest here; we encode the
46	 * NSSCertRequestInfo component separately to calculate
47	 * its signature, then we encode the whole NSSCertRequest
48	 * after dropping in the signature and SignatureAlgorithmIdentifier.
49	 */
50	NSSCertRequest certReq;
51	NSSCertRequestInfo &reqInfo = certReq.reqInfo;
52	PRErrorCode prtn;
53
54	memset(&certReq, 0, sizeof(certReq));
55
56	/*
57	 * Step 1: convert CSSM_APPLE_CL_CSR_REQUEST to CertificationRequestInfo.
58	 * All allocs via local arena pool.
59	 */
60	SecNssCoder coder;
61	ArenaAllocator alloc(coder);
62	clIntToData(0, reqInfo.version, alloc);
63
64	/* subject Name, required  */
65	if(csrReq->subjectNameX509 == NULL) {
66		CssmError::throwMe(CSSMERR_CL_INVALID_POINTER);
67	}
68	CL_cssmNameToNss(*csrReq->subjectNameX509, reqInfo.subject, coder);
69
70	/* key --> CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */
71	CL_CSSMKeyToSubjPubKeyInfoNSS(*csrReq->subjectPublicKey,
72		reqInfo.subjectPublicKeyInfo, coder);
73
74	/* attributes - see sm_x501if - we support one, CSSMOID_ChallengePassword,
75 	 * as a printable string */
76	if(csrReq->challengeString) {
77		/* alloc a NULL_terminated array of NSS_Attribute pointers */
78		reqInfo.attributes = (NSS_Attribute **)coder.malloc(2 * sizeof(NSS_Attribute *));
79		reqInfo.attributes[1] = NULL;
80
81		/* alloc one NSS_Attribute */
82		reqInfo.attributes[0] = (NSS_Attribute *)coder.malloc(sizeof(NSS_Attribute));
83		NSS_Attribute *attr = reqInfo.attributes[0];
84		memset(attr, 0, sizeof(NSS_Attribute));
85
86		 /* NULL_terminated array of attrValues */
87		attr->attrValue = (CSSM_DATA **)coder.malloc(2 * sizeof(CSSM_DATA *));
88		attr->attrValue[1] = NULL;
89
90		/* one value - we're almost there */
91		attr->attrValue[0] = (CSSM_DATA *)coder.malloc(sizeof(CSSM_DATA));
92
93		/* attrType is an OID, temp, use static OID */
94		attr->attrType = CSSMOID_ChallengePassword;
95
96		/* one value, spec'd as AsnAny, we have to encode first. */
97		CSSM_DATA strData;
98		strData.Data = (uint8 *)csrReq->challengeString;
99		strData.Length = strlen(csrReq->challengeString);
100		prtn = coder.encodeItem(&strData, kSecAsn1PrintableStringTemplate,
101			*attr->attrValue[0]);
102		if(prtn) {
103			clErrorLog("generateCsr: error encoding challengeString\n");
104			CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
105		}
106	}
107
108	/*
109	 * Step 2: DER-encode the NSSCertRequestInfo prior to signing.
110	 */
111	CSSM_DATA encReqInfo;
112	prtn = coder.encodeItem(&reqInfo, kSecAsn1CertRequestInfoTemplate, encReqInfo);
113	if(prtn) {
114		clErrorLog("generateCsr: error encoding CertRequestInfo\n");
115		CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
116	}
117
118	/*
119	 * Step 3: sign the encoded NSSCertRequestInfo.
120	 */
121	CssmAutoData sig(*this);
122	CssmData &infoData = CssmData::overlay(encReqInfo);
123	signData(CCHandle, infoData, sig);
124
125	/*
126	 * Step 4: finish up NSSCertRequest - signatureAlgorithm, signature
127	 */
128	certReq.signatureAlgorithm.algorithm = csrReq->signatureOid;
129	/* FIXME - for now assume NULL alg params */
130	CL_nullAlgParams(certReq.signatureAlgorithm);
131	certReq.signature.Data = (uint8 *)sig.data();
132	certReq.signature.Length = sig.length() * 8;
133
134	/*
135	 * Step 5: DER-encode the finished NSSCertRequest into app space.
136	 */
137	CssmAutoData encCsr(*this);
138	prtn = SecNssEncodeItemOdata(&certReq, kSecAsn1CertRequestTemplate, encCsr);
139	if(prtn) {
140		clErrorLog("generateCsr: error encoding CertRequestInfo\n");
141		CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
142	}
143
144	/* TBD - enc64 the result, when we have this much working */
145	csrPtr = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
146	csrPtr->Data = (uint8 *)encCsr.data();
147	csrPtr->Length = encCsr.length();
148	encCsr.release();
149}
150
151/*
152 * Verify CSR with its own public key.
153 */
154void AppleX509CLSession::verifyCsr(
155	const CSSM_DATA		*csrPtr)
156{
157	/*
158	 * 1. Extract the public key from the CSR. We do this by decoding
159	 *    the whole thing and getting a CSSM_KEY from the
160	 *    SubjectPublicKeyInfo.
161	 */
162	NSSCertRequest certReq;
163	SecNssCoder coder;
164	PRErrorCode prtn;
165
166	memset(&certReq, 0, sizeof(certReq));
167	prtn = coder.decodeItem(*csrPtr, kSecAsn1CertRequestTemplate, &certReq);
168	if(prtn) {
169		CssmError::throwMe(CSSMERR_CL_INVALID_DATA);
170	}
171
172	NSSCertRequestInfo &reqInfo = certReq.reqInfo;
173	CSSM_KEY_PTR cssmKey = CL_extractCSSMKeyNSS(reqInfo.subjectPublicKeyInfo,
174		*this,		// alloc
175		NULL);		// no DecodedCert
176
177	/*
178	 * 2. Obtain signature algorithm and parameters.
179	 */
180	CSSM_X509_ALGORITHM_IDENTIFIER sigAlgId = certReq.signatureAlgorithm;
181	CSSM_ALGORITHMS vfyAlg = CL_oidToAlg(sigAlgId.algorithm);
182
183	/*
184	 * Handle CSSMOID_ECDSA_WithSpecified, which requires additional
185	 * decode to get the digest algorithm.
186	 */
187	if(vfyAlg == CSSM_ALGID_ECDSA_SPECIFIED) {
188		vfyAlg = CL_nssDecodeECDSASigAlgParams(sigAlgId.parameters, coder);
189	}
190
191	/*
192	 * 3. Extract the raw bits to be verified and the signature. We
193	 *    decode the CSR as a CertificationRequestSigned for this, which
194	 *    avoids the decode of the CertificationRequestInfo.
195	 */
196	NSS_SignedCertRequest certReqSigned;
197	memset(&certReqSigned, 0, sizeof(certReqSigned));
198	prtn = coder.decodeItem(*csrPtr, kSecAsn1SignedCertRequestTemplate, &certReqSigned);
199	if(prtn) {
200		CssmError::throwMe(CSSMERR_CL_INVALID_DATA);
201	}
202
203	CSSM_DATA sigBytes = certReqSigned.signature;
204	sigBytes.Length = (sigBytes.Length + 7 ) / 8;
205	CssmData &sigCdata = CssmData::overlay(sigBytes);
206	CssmData &toVerify = CssmData::overlay(certReqSigned.certRequestBlob);
207
208	/*
209	 * 4. Attach to CSP, cook up signature context, verify signature.
210	 */
211	CSSM_CSP_HANDLE cspHand = getGlobalCspHand(true);
212	CSSM_RETURN crtn;
213	CSSM_CC_HANDLE ccHand;
214	crtn = CSSM_CSP_CreateSignatureContext(cspHand,
215		vfyAlg,
216		NULL,			// Access Creds
217		cssmKey,
218		&ccHand);
219	if(crtn) {
220		CssmError::throwMe(crtn);
221	}
222	verifyData(ccHand, toVerify, sigCdata);
223	CL_freeCSSMKey(cssmKey, *this);
224}
225
226