X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_apple_csp/lib/RSA_DSA_utils.cpp diff --git a/libsecurity_apple_csp/lib/RSA_DSA_utils.cpp b/libsecurity_apple_csp/lib/RSA_DSA_utils.cpp deleted file mode 100644 index f85ecfa9..00000000 --- a/libsecurity_apple_csp/lib/RSA_DSA_utils.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/* - * 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. - */ - - -/* - * RSA_DSA_utils.cpp - */ - -#include "RSA_DSA_utils.h" -#include "RSA_DSA_keys.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define rsaMiscDebug(args...) secdebug("rsaMisc", ## args) - -/* - * Obtain and cache max key sizes. System preferences only consulted - * at most once per process. - */ - -/* - * Do dictionary lookup, convert possible CFNumber to uint32. - * Does not alter val if valid number is not found. - */ -static void rsaLookupVal( - Dictionary &prefs, - CFStringRef key, - uint32 &val) -{ - CFNumberRef cfVal = (CFNumberRef)prefs.getValue(key); - if(cfVal == NULL) { - return; - } - if(CFGetTypeID(cfVal) != CFNumberGetTypeID()) { - return; - } - - /* ensure the number is positive, not relying on gcc 64-bit arithmetic */ - SInt32 s32 = 0; - CFNumberRef cfLimit = CFNumberCreate(NULL, kCFNumberSInt32Type, &s32); - CFComparisonResult result = CFNumberCompare(cfVal, cfLimit, NULL); - CFRelease(cfLimit); - if(result == kCFCompareLessThan) { - /* negative value in preference */ - return; - } - - /* ensure the number fits in 31 bits (the useful size of a SInt32 for us) */ - s32 = 0x7fffffff; - cfLimit = CFNumberCreate(NULL, kCFNumberSInt32Type, &s32); - result = CFNumberCompare(cfVal, cfLimit, NULL); - CFRelease(cfLimit); - if(result == kCFCompareGreaterThan) { - /* too large; discard it */ - return; - } - SInt64 s64; - if(!CFNumberGetValue(cfVal, kCFNumberSInt64Type, &s64)) { - /* impossible, right? We already range checked */ - return; - } - val = (uint32)s64; -} - -struct RSAKeySizes { - uint32 maxKeySize; - uint32 maxPubExponentSize; - RSAKeySizes(); -}; - -/* one-time only prefs lookup */ -RSAKeySizes::RSAKeySizes() -{ - /* set defaults, these might get overridden */ - maxKeySize = RSA_MAX_KEY_SIZE; - maxPubExponentSize = RSA_MAX_PUB_EXPONENT_SIZE; - - /* now see if there are prefs set for either of these */ - Dictionary* d = Dictionary::CreateDictionary(kRSAKeySizePrefsDomain, Dictionary::US_System, true); - if (!d) - { - return; - } - - if (d->dict()) - { - auto_ptrapd(d); - rsaLookupVal(*apd, kRSAMaxKeySizePref, maxKeySize); - rsaLookupVal(*apd, kRSAMaxPublicExponentPref, maxPubExponentSize); - } - else - { - delete d; - } -} - -static ModuleNexus rsaKeySizes; - -/* - * Public functions to obtain the currently configured max sizes of - * RSA key and public exponent. - */ -uint32 rsaMaxKeySize() -{ - return rsaKeySizes().maxKeySize; -} - -uint32 rsaMaxPubExponentSize() -{ - return rsaKeySizes().maxPubExponentSize; -} - -/* - * Given a Context: - * -- obtain CSSM key (there must only be one) - * -- validate keyClass - * -- validate keyUsage - * -- convert to RSA *, allocating the RSA key if necessary - */ -RSA *contextToRsaKey( - const Context &context, - AppleCSPSession &session, - CSSM_KEYCLASS keyClass, // CSSM_KEYCLASS_{PUBLIC,PRIVATE}_KEY - CSSM_KEYUSE usage, // CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_SIGN, etc. - bool &mallocdKey, // RETURNED - CSSM_DATA &label) // mallocd and RETURNED for OAEP -{ - CssmKey &cssmKey = - context.get(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY); - const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader; - if(hdr.AlgorithmId != CSSM_ALGID_RSA) { - CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH); - } - if(hdr.KeyClass != keyClass) { - CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); - } - cspValidateIntendedKeyUsage(&hdr, usage); - cspVerifyKeyTimes(hdr); - return cssmKeyToRsa(cssmKey, session, mallocdKey, label); -} -/* - * Convert a CssmKey to an RSA * key. May result in the creation of a new - * RSA (when cssmKey is a raw key); allocdKey is true in that case - * in which case the caller generally has to free the allocd key). - */ -RSA *cssmKeyToRsa( - const CssmKey &cssmKey, - AppleCSPSession &session, - bool &allocdKey, // RETURNED - CSSM_DATA &label) // mallocd and RETURNED for OAEP -{ - RSA *rsaKey = NULL; - allocdKey = false; - - const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader; - if(hdr->AlgorithmId != CSSM_ALGID_RSA) { - // someone else's key (should never happen) - CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); - } - switch(hdr->BlobType) { - case CSSM_KEYBLOB_RAW: - rsaKey = rawCssmKeyToRsa(cssmKey, label); - allocdKey = true; - break; - case CSSM_KEYBLOB_REFERENCE: - { - BinaryKey &binKey = session.lookupRefKey(cssmKey); - RSABinaryKey *rsaBinKey = dynamic_cast(&binKey); - /* this cast failing means that this is some other - * kind of binary key */ - if(rsaBinKey == NULL) { - rsaMiscDebug("cssmKeyToRsa: wrong BinaryKey subclass\n"); - CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); - } - assert(rsaBinKey->mRsaKey != NULL); - rsaKey = rsaBinKey->mRsaKey; - break; - } - default: - CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT); - } - return rsaKey; -} - -/* - * Convert a raw CssmKey to a newly alloc'd RSA key. - */ -RSA *rawCssmKeyToRsa( - const CssmKey &cssmKey, - CSSM_DATA &label) // mallocd and RETURNED for OAEP keys -{ - const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader; - bool isPub; - bool isOaep = false; - - assert(hdr->BlobType == CSSM_KEYBLOB_RAW); - - switch(hdr->AlgorithmId) { - case CSSM_ALGID_RSA: - break; - case CSSM_ALGMODE_PKCS1_EME_OAEP: - isOaep = true; - break; - default: - // someone else's key (should never happen) - CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); - } - - /* validate and figure out what we're dealing with */ - switch(hdr->KeyClass) { - case CSSM_KEYCLASS_PUBLIC_KEY: - switch(hdr->Format) { - case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: - case CSSM_KEYBLOB_RAW_FORMAT_X509: - case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH: - case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2: - break; - default: - CssmError::throwMe( - CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT); - } - if(isOaep && (hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_X509)) { - CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT); - } - isPub = true; - break; - case CSSM_KEYCLASS_PRIVATE_KEY: - switch(hdr->Format) { - case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: // default - case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: // openssl style - case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH: - break; - default: - CssmError::throwMe( - CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT); - } - if(isOaep && (hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_PKCS8)) { - CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT); - } - isPub = false; - break; - default: - CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); - } - - RSA *rsaKey = RSA_new(); - if(rsaKey == NULL) { - CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); - } - CSSM_RETURN crtn; - if(isOaep) { - if(isPub) { - crtn = RSAOAEPPublicKeyDecode(rsaKey, - cssmKey.KeyData.Data, cssmKey.KeyData.Length, - &label); - } - else { - crtn = RSAOAEPPrivateKeyDecode(rsaKey, - cssmKey.KeyData.Data, cssmKey.KeyData.Length, - &label); - } - } - else { - if(isPub) { - crtn = RSAPublicKeyDecode(rsaKey, hdr->Format, - cssmKey.KeyData.Data, cssmKey.KeyData.Length); - } - else { - crtn = RSAPrivateKeyDecode(rsaKey, hdr->Format, - cssmKey.KeyData.Data, cssmKey.KeyData.Length); - } - } - if(crtn) { - RSA_free(rsaKey); - CssmError::throwMe(crtn); - } - - /* enforce max key size and max public exponent size */ - bool badKey = false; - uint32 keySize = RSA_size(rsaKey) * 8; - if(keySize > rsaMaxKeySize()) { - rsaMiscDebug("rawCssmKeyToRsa: key size exceeded"); - badKey = true; - } - else { - keySize = BN_num_bytes(rsaKey->e) * 8; - if(keySize > rsaMaxPubExponentSize()) { - badKey = true; - rsaMiscDebug("rawCssmKeyToRsa: pub exponent size exceeded"); - } - } - if(badKey) { - RSA_free(rsaKey); - CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH); - } - return rsaKey; -} - -/* - * Given a partially formed DSA public key (with no p, q, or g) and a - * CssmKey representing a supposedly fully-formed DSA key, populate - * the public key's p, g, and q with values from the fully formed key. - */ -CSSM_RETURN dsaGetParamsFromKey( - DSA *partialKey, - const CssmKey ¶mKey, - AppleCSPSession &session) -{ - bool allocdKey; - DSA *dsaParamKey = cssmKeyToDsa(paramKey, session, allocdKey); - if(dsaParamKey == NULL) { - errorLog0("dsaGetParamsFromKey: bad paramKey\n"); - return CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE; - } - CSSM_RETURN crtn = CSSM_OK; - - /* require fully formed other key of course... */ - if((dsaParamKey->p == NULL) || - (dsaParamKey->q == NULL) || - (dsaParamKey->g == NULL)) { - errorLog0("dsaGetParamsFromKey: incomplete paramKey\n"); - crtn = CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE; - goto abort; - } - rsaMiscDebug("dsaGetParamsFromKey: partialKey %p paramKey %p", - partialKey, dsaParamKey); - - partialKey->q = BN_dup(dsaParamKey->q); - partialKey->p = BN_dup(dsaParamKey->p); - partialKey->g = BN_dup(dsaParamKey->g); - -abort: - if(allocdKey) { - DSA_free(dsaParamKey); - } - return crtn; -} - -/* - * Given a Context: - * -- obtain CSSM key (there must only be one) - * -- validate keyClass - * -- validate keyUsage - * -- convert to DSA *, allocating the DSA key if necessary - */ -DSA *contextToDsaKey( - const Context &context, - AppleCSPSession &session, - CSSM_KEYCLASS keyClass, // CSSM_KEYCLASS_{PUBLIC,PRIVATE}_KEY - CSSM_KEYUSE usage, // CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_SIGN, etc. - bool &mallocdKey) // RETURNED -{ - CssmKey &cssmKey = - context.get(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY); - const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader; - if(hdr.AlgorithmId != CSSM_ALGID_DSA) { - CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH); - } - if(hdr.KeyClass != keyClass) { - CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); - } - cspValidateIntendedKeyUsage(&hdr, usage); - cspVerifyKeyTimes(hdr); - DSA *rtnDsa = cssmKeyToDsa(cssmKey, session, mallocdKey); - if((keyClass == CSSM_KEYCLASS_PUBLIC_KEY) && - (rtnDsa->p == NULL)) { - /* - * Special case: this specific key is only partially formed; - * it's missing the DSA parameters p, g, and q. To proceed with this - * key, the caller must pass in another fully formned DSA public key - * in raw form in the context. If it's there we use those parameters. - */ - rsaMiscDebug("contextToDsaKey; partial DSA key %p", rtnDsa); - CssmKey *paramKey = context.get(CSSM_ATTRIBUTE_PARAM_KEY); - if(paramKey == NULL) { - rsaMiscDebug("contextToDsaKey: missing DSA params, no pub key in " - "context"); - if(mallocdKey) { - DSA_free(rtnDsa); - mallocdKey = false; - } - CssmError::throwMe(CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE); - } - - /* - * If this is a ref key, we have to cook up a new DSA key to - * avoid modifying the existing key. If we started with a raw key, - * we can modify it directly since the underlying DSA key has - * a lifetime only as long as this context (and since the context - * contains the parameter-bearing key, the params are valid - * as long as the DSA key). - */ - if(!mallocdKey) { - DSA *existKey = rtnDsa; - rtnDsa = DSA_new(); - if(rtnDsa == NULL) { - CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); - } - rtnDsa->pub_key = BN_dup(existKey->pub_key); - rsaMiscDebug("contextToDsaKey; temp partial copy %p", rtnDsa); - mallocdKey = true; - } - - /* - * Add params from paramKey into rtnDsa - */ - CSSM_RETURN crtn = dsaGetParamsFromKey(rtnDsa, *paramKey, session); - if(crtn) { - if(mallocdKey) { - DSA_free(rtnDsa); - mallocdKey = false; - } - CssmError::throwMe(crtn); - } - } - return rtnDsa; -} - -/* - * Convert a CssmKey to an DSA * key. May result in the creation of a new - * DSA (when cssmKey is a raw key); allocdKey is true in that case - * in which case the caller generally has to free the allocd key). - */ -DSA *cssmKeyToDsa( - const CssmKey &cssmKey, - AppleCSPSession &session, - bool &allocdKey) // RETURNED -{ - DSA *dsaKey = NULL; - allocdKey = false; - - const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader; - if(hdr->AlgorithmId != CSSM_ALGID_DSA) { - // someone else's key (should never happen) - CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); - } - switch(hdr->BlobType) { - case CSSM_KEYBLOB_RAW: - dsaKey = rawCssmKeyToDsa(cssmKey, session, NULL); - allocdKey = true; - break; - case CSSM_KEYBLOB_REFERENCE: - { - BinaryKey &binKey = session.lookupRefKey(cssmKey); - DSABinaryKey *dsaBinKey = dynamic_cast(&binKey); - /* this cast failing means that this is some other - * kind of binary key */ - if(dsaBinKey == NULL) { - rsaMiscDebug("cssmKeyToDsa: wrong BinaryKey subclass\n"); - CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); - } - assert(dsaBinKey->mDsaKey != NULL); - dsaKey = dsaBinKey->mDsaKey; - break; - } - default: - CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT); - } - return dsaKey; -} - -/* - * Convert a raw CssmKey to a newly alloc'd DSA key. - */ -DSA *rawCssmKeyToDsa( - const CssmKey &cssmKey, - AppleCSPSession &session, - const CssmKey *paramKey) // optional -{ - const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader; - bool isPub; - - assert(hdr->BlobType == CSSM_KEYBLOB_RAW); - - if(hdr->AlgorithmId != CSSM_ALGID_DSA) { - // someone else's key (should never happen) - CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); - } - /* validate and figure out what we're dealing with */ - switch(hdr->KeyClass) { - case CSSM_KEYCLASS_PUBLIC_KEY: - switch(hdr->Format) { - case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: - case CSSM_KEYBLOB_RAW_FORMAT_X509: - case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2: - break; - default: - CssmError::throwMe( - CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT); - } - isPub = true; - break; - case CSSM_KEYCLASS_PRIVATE_KEY: - switch(hdr->Format) { - case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: // default - case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: // openssl style - case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: // SMIME style - break; - /* openssh real soon now */ - case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH: - default: - CssmError::throwMe( - CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT); - } - isPub = false; - break; - default: - CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); - } - - CSSM_RETURN crtn; - DSA *dsaKey = DSA_new(); - - if (dsaKey == NULL) { - crtn = CSSMERR_CSP_MEMORY_ERROR; - } - else { - if(dsaKey == NULL) { - CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); - } - if(isPub) { - crtn = DSAPublicKeyDecode(dsaKey, hdr->Format, - cssmKey.KeyData.Data, - cssmKey.KeyData.Length); - } - else { - crtn = DSAPrivateKeyDecode(dsaKey, hdr->Format, - cssmKey.KeyData.Data, - cssmKey.KeyData.Length); - } - } - - if(crtn) { - if (dsaKey != NULL) { - DSA_free(dsaKey); - } - - CssmError::throwMe(crtn); - } - /* - * Add in optional external parameters if this is not fully formed. - * This path is only taken from DSAKeyInfoProvider::CssmKeyToBinary, - * e.g., when doing a NULL unwrap of a partially formed DSA public - * key with the "complete the key with these params" option. - */ - if(isPub && (dsaKey->p == NULL) && (paramKey != NULL)) { - rsaMiscDebug("rawCssmKeyToDsa; updating dsaKey %p", dsaKey); - crtn = dsaGetParamsFromKey(dsaKey, *paramKey, session); - if(crtn) { - DSA_free(dsaKey); - CssmError::throwMe(crtn); - } - } - - if(dsaKey->p != NULL) { - /* avoid use of provided DSA key which exceeds the max size */ - uint32 keySize = BN_num_bits(dsaKey->p); - if(keySize > DSA_MAX_KEY_SIZE) { - DSA_free(dsaKey); - CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH); - } - } - return dsaKey; -} - -/* - * Given a DSA private key, calculate its public component if it - * doesn't already exist. Used for calculating the key digest of - * an incoming raw private key. - */ -void dsaKeyPrivToPub( - DSA *dsaKey) -{ - assert(dsaKey != NULL); - assert(dsaKey->priv_key != NULL); - - if(dsaKey->pub_key != NULL) { - return; - } - - /* logic copied from DSA_generate_key() */ - dsaKey->pub_key = BN_new(); - if(dsaKey->pub_key == NULL) { - CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); - } - BN_CTX *ctx = BN_CTX_new(); - if (ctx == NULL) { - CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); - } - int rtn = BN_mod_exp(dsaKey->pub_key, - dsaKey->g, - dsaKey->priv_key, - dsaKey->p, - ctx); - BN_CTX_free(ctx); - if(rtn == 0) { - CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); - } -}