+++ /dev/null
-/*
- * 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_Crypto.cpp: CL session functions: sign, verify, CSSM_KEY extraction.
- *
- * Created 9/1/2000 by Doug Mitchell.
- * Copyright (c) 2000 by Apple Computer.
- */
-
-#include "AppleX509CLSession.h"
-#include "DecodedCert.h"
-#include "cldebugging.h"
-#include "CSPAttacher.h"
-#include "clNssUtils.h"
-#include <Security/keyTemplates.h>
-#include <security_asn1/nssUtils.h>
-#include <Security/oidscert.h>
-#include <Security/cssmapple.h>
-
-/*
- * Given a DER-encoded cert, obtain a fully usable CSSM_KEY representing
- * the cert's public key.
- */
-void
-AppleX509CLSession::CertGetKeyInfo(
- const CssmData &Cert,
- CSSM_KEY_PTR &Key)
-{
- DecodedCert decodedCert(*this, Cert);
- Key = decodedCert.extractCSSMKey(*this);
-}
-
-/*
- * Given a DER-encoded cert and a fully specified crypto context, verify
- * cert's TBS and signature.
- */
-void
-AppleX509CLSession::CertVerifyWithKey(
- CSSM_CC_HANDLE CCHandle,
- const CssmData &CertToBeVerified)
-{
- CssmAutoData tbs(*this);
- CssmAutoData algId(*this);
- CssmAutoData sig(*this);
- CL_certCrlDecodeComponents(CertToBeVerified, tbs, algId, sig);
- verifyData(CCHandle, tbs, sig);
-}
-
-/*
- * Verify a DER-encoded cert, obtaining crypto context from either
- * caller-specified context or by inference from SignerCert.
- */
-void
-AppleX509CLSession::CertVerify(
- CSSM_CC_HANDLE CCHandle,
- const CssmData &CertToBeVerified,
- const CssmData *SignerCert,
- const CSSM_FIELD *VerifyScope,
- uint32 ScopeSize)
-{
- if((VerifyScope != NULL) || (ScopeSize != 0)) {
- CssmError::throwMe(CSSMERR_CL_SCOPE_NOT_SUPPORTED);
- }
- if((CCHandle == CSSM_INVALID_HANDLE) && (SignerCert == NULL)) {
- /* need one or the other */
- CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
- }
-
- /* get top-level components */
- CssmAutoData tbs(*this); // in DER format
- CssmAutoData algId(*this); // in DER format
- CssmAutoData sig(*this); // in DER format
- CL_certCrlDecodeComponents(CertToBeVerified, tbs, algId, sig);
-
- /* these must be explicitly freed upon exit */
- CSSM_KEY_PTR signerPubKey = NULL;
- CSSM_CONTEXT_PTR context = NULL;
- CSSM_CSP_HANDLE cspHand = CSSM_INVALID_HANDLE;
- CSSM_CC_HANDLE ourCcHand = CSSM_INVALID_HANDLE;
-
- /* SignerCert optional; if present, obtain its subject key */
- if(SignerCert != NULL) {
- CertGetKeyInfo(*SignerCert, signerPubKey);
- }
-
- /* signerPubKey must be explicitly freed in any case */
- try {
- if(CCHandle != CSSM_INVALID_HANDLE) {
- /*
- * We'll use this CCHandle for the sig verify, but
- * make sure it matches possible incoming SignerCert parameters
- */
- if(SignerCert != NULL) {
- CSSM_RETURN crtn;
-
- /* extract signer's public key as a CSSM_KEY from context */
- crtn = CSSM_GetContext(CCHandle, &context);
- if(crtn) {
- CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
- }
- CSSM_CONTEXT_ATTRIBUTE_PTR attr;
- crtn = CSSM_GetContextAttribute(context,
- CSSM_ATTRIBUTE_KEY,
- &attr);
- if(crtn) {
- clErrorLog("CertVerify: valid CCHandle but no key!\n");
- CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
- }
- /* require match */
- assert(signerPubKey != NULL);
- CSSM_KEY_PTR contextPubKey = attr->Attribute.Key;
- if(contextPubKey->KeyHeader.AlgorithmId !=
- signerPubKey->KeyHeader.AlgorithmId) {
- clErrorLog("CertVerify: AlgorithmId mismatch!\n");
- CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
- }
-
- /* TBD - check key size, when we have a CSP which can report it */
- /* TBD - anything else? */
- } /* verifying multiple contexts */
- /* OK to use CCHandle as is for verify context */
- } /* valid CCHandle */
- else {
- /*
- * All we have is signer cert. We already have its public key;
- * get signature alg from CertToBeVerified's Cert.algID, which
- * we currently have in DER form. Decode it into temp memory.
- */
- assert(SignerCert != NULL);
- assert(signerPubKey != NULL);
-
- CSSM_X509_ALGORITHM_IDENTIFIER cssmAlgId;
- SecNssCoder coder;
- PRErrorCode prtn;
-
- CssmData &algIdData = algId.get();
- memset(&cssmAlgId, 0, sizeof(cssmAlgId));
- prtn = coder.decode(algIdData.data(), algIdData.length(),
- kSecAsn1AlgorithmIDTemplate, &cssmAlgId);
- if(prtn) {
- CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
- }
-
- CSSM_ALGORITHMS vfyAlg = CL_oidToAlg(cssmAlgId.algorithm);
-
- /*
- * Handle CSSMOID_ECDSA_WithSpecified, which requires additional
- * decode to get the digest algorithm.
- */
- if(vfyAlg == CSSM_ALGID_ECDSA_SPECIFIED) {
- vfyAlg = CL_nssDecodeECDSASigAlgParams(cssmAlgId.parameters, coder);
- }
-
- /* attach to CSP, cook up a context */
- cspHand = getGlobalCspHand(true);
- CSSM_RETURN crtn;
- crtn = CSSM_CSP_CreateSignatureContext(cspHand,
- vfyAlg,
- NULL, // Access Creds
- signerPubKey,
- &ourCcHand);
- CCHandle = ourCcHand;
- } /* inferring sig verify context from SignerCert */
- verifyData(CCHandle, tbs, sig);
- }
- catch(...) {
- /* FIXME - isn't there a better way to do this? Save the
- * exception as a CSSM_RETURN and throw it if nonzero later?
- */
- if(context != NULL) {
- CSSM_FreeContext(context);
- }
- CL_freeCSSMKey(signerPubKey, *this);
- if(ourCcHand != CSSM_INVALID_HANDLE) {
- CSSM_DeleteContext(ourCcHand);
- }
- throw;
- }
- if(context != NULL) {
- CSSM_FreeContext(context);
- }
- CL_freeCSSMKey(signerPubKey, *this);
- if(ourCcHand != CSSM_INVALID_HANDLE) {
- CSSM_DeleteContext(ourCcHand);
- }
-}
-
-/*
- * Given a DER-encoded TBSCert and a fully specified crypto context,
- * sign the TBSCert and return the resulting DER-encoded Cert.
- */
-void
-AppleX509CLSession::CertSign(
- CSSM_CC_HANDLE CCHandle,
- const CssmData &CertTemplate,
- const CSSM_FIELD *SignScope,
- uint32 ScopeSize,
- CssmData &SignedCert)
-{
- if((SignScope != NULL) || (ScopeSize != 0)) {
- CssmError::throwMe(CSSMERR_CL_SCOPE_NOT_SUPPORTED);
- }
- if(CCHandle == CSSM_INVALID_HANDLE) {
- CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
- }
-
- /* cook up algId from context->(signing key, sig algorithm) */
- CSSM_CONTEXT_PTR context = NULL; // must be freed
- CSSM_RETURN crtn;
- crtn = CSSM_GetContext(CCHandle, &context);
- if(crtn) {
- CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
- }
- CSSM_CONTEXT_ATTRIBUTE_PTR attr; // not freed
- crtn = CSSM_GetContextAttribute(context,
- CSSM_ATTRIBUTE_KEY,
- &attr);
- if(crtn) {
- clErrorLog("CertSign: valid CCHandle but no signing key!\n");
- CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
- }
- CSSM_KEY_PTR signingKey = attr->Attribute.Key;
- if(signingKey == NULL) {
- clErrorLog("CertSign: valid CCHandle, NULL signing key!\n");
- CssmError::throwMe(CSSMERR_CL_INVALID_CONTEXT_HANDLE);
- }
-
- CssmAutoData encAlgId(*this);
- CssmAutoData rawSig(*this);
- CssmAutoData fullCert(*this);
- try {
- /*
- * FIXME: we really should break up the template and ensure that its
- * signature algId matches the one we're signing with, or just use
- * that algId here....for now, this is up to the app to make sure.
- */
-
- /* temp allocs/encode into here */
- SecNssCoder coder;
-
- /* CSSM alg --> CSSM_X509_ALGORITHM_IDENTIFIER */
- /***
- *** Note: some ECDSA implementations use CSSMOID_ECDSA_WithSpecified for
- *** the algorithm followed by an encoded digest algorithm. We'll handle
- *** that on *decode* but we're going to do it the sensible way - with
- *** one unique OID to specify the whole thing (e.g. CSSMOID_ECDSA_WithSHA512
- *** which we get from cssmAlgToOid()) unless we're forced to do
- *** otherwise by cranky servers.
- ***/
- CSSM_X509_ALGORITHM_IDENTIFIER algId;
- memset(&algId, 0, sizeof(algId));
- const CSSM_OID *oid = cssmAlgToOid(context->AlgorithmType);
-
- if(oid == NULL) {
- clErrorLog("CertSIgn: unknown alg (%u)\n",
- (unsigned)context->AlgorithmType);
- CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
- }
- algId.algorithm = *oid;
-
- /* NULL params - skip for ECDSA */
- switch(context->AlgorithmType) {
- case CSSM_ALGID_SHA1WithECDSA:
- case CSSM_ALGID_SHA224WithECDSA:
- case CSSM_ALGID_SHA256WithECDSA:
- case CSSM_ALGID_SHA384WithECDSA:
- case CSSM_ALGID_SHA512WithECDSA:
- case CSSM_ALGID_ECDSA_SPECIFIED:
- break;
- default:
- CL_nullAlgParams(algId);
- break;
- }
- /* DER-encode the algID */
- PRErrorCode prtn;
- prtn = SecNssEncodeItemOdata(&algId, kSecAsn1AlgorithmIDTemplate,
- encAlgId);
- if(prtn) {
- CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
- }
-
- /* sign TBS --> rawSig */
- signData(CCHandle, CertTemplate, rawSig);
- /* put it all together */
- CL_certEncodeComponents(CertTemplate, encAlgId, rawSig, fullCert);
- }
- catch (...) {
- CSSM_FreeContext(context);
- throw;
- }
- CSSM_FreeContext(context);
- SignedCert = fullCert.release();
-}
-
-/*** Private functions ***/
-
-/*
- * Sign a CssmData with the specified signing context. Used for
- * signing both certs and CRLs; this routine doesn't know anything
- * about either one.
- */
-void
-AppleX509CLSession::signData(
- CSSM_CC_HANDLE ccHand,
- const CssmData &tbs,
- CssmOwnedData &sig) // mallocd and returned
-{
- CSSM_RETURN crtn;
- CssmData cSig;
-
- crtn = CSSM_SignData(
- ccHand,
- &tbs,
- 1, // DataBufCount
- CSSM_ALGID_NONE, // DigestAlgorithm,
- &cSig);
- if(crtn) {
- clErrorLog("AppleX509CLSession::CSSM_SignData: %ld\n", (long)crtn);
- CssmError::throwMe(crtn);
- }
- sig.set(cSig);
-}
-
-/*
- * Verify a block of data given a crypto context and a signature.
- * Used for verifying certs and CRLs. Returns a CSSM_RETURN (callers
- * always need to clean up after calling us).
- */
-void AppleX509CLSession::verifyData(
- CSSM_CC_HANDLE ccHand,
- const CssmData &tbs,
- const CssmData &sig)
-{
- CSSM_RETURN crtn;
-
- crtn = CSSM_VerifyData(ccHand,
- &tbs,
- 1,
- CSSM_ALGID_NONE, // Digest alg
- &sig);
- if(crtn) {
- if(crtn == CSSMERR_CSP_VERIFY_FAILED) {
- /* CSP and CL report this differently */
- CssmError::throwMe(CSSMERR_CL_VERIFICATION_FAILURE);
- }
- else {
- CssmError::throwMe(crtn);
- }
- }
-}
-