X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/OSX/libsecurity_apple_x509_cl/lib/Session_CSR.cpp diff --git a/OSX/libsecurity_apple_x509_cl/lib/Session_CSR.cpp b/OSX/libsecurity_apple_x509_cl/lib/Session_CSR.cpp new file mode 100644 index 00000000..ba20ba66 --- /dev/null +++ b/OSX/libsecurity_apple_x509_cl/lib/Session_CSR.cpp @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2000-2001,2011,2014 Apple 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); +} +