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