/* * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the * specific language governing rights and limitations under the License. */ // // Session_CSP.cpp - CSR-related session functions. // #include "AppleX509CLSession.h" #include "DecodedCert.h" #include "clNameUtils.h" #include "clNssUtils.h" #include "cldebugging.h" #include "CSPAttacher.h" #include "clNssUtils.h" #include #include #include #include #include /* * Generate a DER-encoded CSR. */ void AppleX509CLSession::generateCsr( CSSM_CC_HANDLE CCHandle, const CSSM_APPLE_CL_CSR_REQUEST *csrReq, CSSM_DATA_PTR &csrPtr) { /* * We use the full NSSCertRequest here; we encode the * NSSCertRequestInfo component separately to calculate * its signature, then we encode the whole NSSCertRequest * after dropping in the signature and SignatureAlgorithmIdentifier. */ NSSCertRequest certReq; NSSCertRequestInfo &reqInfo = certReq.reqInfo; PRErrorCode prtn; memset(&certReq, 0, sizeof(certReq)); /* * Step 1: convert CSSM_APPLE_CL_CSR_REQUEST to CertificationRequestInfo. * All allocs via local arena pool. */ SecNssCoder coder; ArenaAllocator alloc(coder); clIntToData(0, reqInfo.version, alloc); /* subject Name, required */ if(csrReq->subjectNameX509 == NULL) { CssmError::throwMe(CSSMERR_CL_INVALID_POINTER); } CL_cssmNameToNss(*csrReq->subjectNameX509, reqInfo.subject, coder); /* key --> CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */ CL_CSSMKeyToSubjPubKeyInfoNSS(*csrReq->subjectPublicKey, reqInfo.subjectPublicKeyInfo, coder); /* attributes - see sm_x501if - we support one, CSSMOID_ChallengePassword, * as a printable string */ if(csrReq->challengeString) { /* alloc a NULL_terminated array of NSS_Attribute pointers */ reqInfo.attributes = (NSS_Attribute **)coder.malloc(2 * sizeof(NSS_Attribute *)); reqInfo.attributes[1] = NULL; /* alloc one NSS_Attribute */ reqInfo.attributes[0] = (NSS_Attribute *)coder.malloc(sizeof(NSS_Attribute)); NSS_Attribute *attr = reqInfo.attributes[0]; memset(attr, 0, sizeof(NSS_Attribute)); /* NULL_terminated array of attrValues */ attr->attrValue = (CSSM_DATA **)coder.malloc(2 * sizeof(CSSM_DATA *)); attr->attrValue[1] = NULL; /* one value - we're almost there */ attr->attrValue[0] = (CSSM_DATA *)coder.malloc(sizeof(CSSM_DATA)); /* attrType is an OID, temp, use static OID */ attr->attrType = CSSMOID_ChallengePassword; /* one value, spec'd as AsnAny, we have to encode first. */ CSSM_DATA strData; strData.Data = (uint8 *)csrReq->challengeString; strData.Length = strlen(csrReq->challengeString); prtn = coder.encodeItem(&strData, kSecAsn1PrintableStringTemplate, *attr->attrValue[0]); if(prtn) { clErrorLog("generateCsr: error encoding challengeString\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } } /* * Step 2: DER-encode the NSSCertRequestInfo prior to signing. */ CSSM_DATA encReqInfo; prtn = coder.encodeItem(&reqInfo, kSecAsn1CertRequestInfoTemplate, encReqInfo); if(prtn) { clErrorLog("generateCsr: error encoding CertRequestInfo\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } /* * Step 3: sign the encoded NSSCertRequestInfo. */ CssmAutoData sig(*this); CssmData &infoData = CssmData::overlay(encReqInfo); signData(CCHandle, infoData, sig); /* * Step 4: finish up NSSCertRequest - signatureAlgorithm, signature */ certReq.signatureAlgorithm.algorithm = csrReq->signatureOid; /* FIXME - for now assume NULL alg params */ CL_nullAlgParams(certReq.signatureAlgorithm); certReq.signature.Data = (uint8 *)sig.data(); certReq.signature.Length = sig.length() * 8; /* * Step 5: DER-encode the finished NSSCertRequest into app space. */ CssmAutoData encCsr(*this); prtn = SecNssEncodeItemOdata(&certReq, kSecAsn1CertRequestTemplate, encCsr); if(prtn) { clErrorLog("generateCsr: error encoding CertRequestInfo\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } /* TBD - enc64 the result, when we have this much working */ csrPtr = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA)); csrPtr->Data = (uint8 *)encCsr.data(); csrPtr->Length = encCsr.length(); encCsr.release(); } /* * Verify CSR with its own public key. */ void AppleX509CLSession::verifyCsr( const CSSM_DATA *csrPtr) { /* * 1. Extract the public key from the CSR. We do this by decoding * the whole thing and getting a CSSM_KEY from the * SubjectPublicKeyInfo. */ NSSCertRequest certReq; SecNssCoder coder; PRErrorCode prtn; memset(&certReq, 0, sizeof(certReq)); prtn = coder.decodeItem(*csrPtr, kSecAsn1CertRequestTemplate, &certReq); if(prtn) { CssmError::throwMe(CSSMERR_CL_INVALID_DATA); } NSSCertRequestInfo &reqInfo = certReq.reqInfo; CSSM_KEY_PTR cssmKey = CL_extractCSSMKeyNSS(reqInfo.subjectPublicKeyInfo, *this, // alloc NULL); // no DecodedCert /* * 2. Obtain signature algorithm and parameters. */ CSSM_X509_ALGORITHM_IDENTIFIER sigAlgId = certReq.signatureAlgorithm; CSSM_ALGORITHMS vfyAlg = CL_oidToAlg(sigAlgId.algorithm); /* * Handle CSSMOID_ECDSA_WithSpecified, which requires additional * decode to get the digest algorithm. */ if(vfyAlg == CSSM_ALGID_ECDSA_SPECIFIED) { vfyAlg = CL_nssDecodeECDSASigAlgParams(sigAlgId.parameters, coder); } /* * 3. Extract the raw bits to be verified and the signature. We * decode the CSR as a CertificationRequestSigned for this, which * avoids the decode of the CertificationRequestInfo. */ NSS_SignedCertRequest certReqSigned; memset(&certReqSigned, 0, sizeof(certReqSigned)); prtn = coder.decodeItem(*csrPtr, kSecAsn1SignedCertRequestTemplate, &certReqSigned); if(prtn) { CssmError::throwMe(CSSMERR_CL_INVALID_DATA); } CSSM_DATA sigBytes = certReqSigned.signature; sigBytes.Length = (sigBytes.Length + 7 ) / 8; CssmData &sigCdata = CssmData::overlay(sigBytes); CssmData &toVerify = CssmData::overlay(certReqSigned.certRequestBlob); /* * 4. Attach to CSP, cook up signature context, verify signature. */ CSSM_CSP_HANDLE cspHand = getGlobalCspHand(true); CSSM_RETURN crtn; CSSM_CC_HANDLE ccHand; crtn = CSSM_CSP_CreateSignatureContext(cspHand, vfyAlg, NULL, // Access Creds cssmKey, &ccHand); if(crtn) { CssmError::throwMe(crtn); } verifyData(ccHand, toVerify, sigCdata); CL_freeCSSMKey(cssmKey, *this); }