X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/OSX/libsecurity_apple_csp/lib/RSA_asymmetric.cpp diff --git a/OSX/libsecurity_apple_csp/lib/RSA_asymmetric.cpp b/OSX/libsecurity_apple_csp/lib/RSA_asymmetric.cpp new file mode 100644 index 00000000..7d0f0222 --- /dev/null +++ b/OSX/libsecurity_apple_csp/lib/RSA_asymmetric.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2000-2001,2011-2012,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. + */ + + +/* + * RSA_asymmetric.cpp - CSPContext for RSA asymmetric encryption + */ + +#include "RSA_asymmetric.h" +#include "RSA_DSA_utils.h" +#include +#include + +#define rsaCryptDebug(args...) secdebug("rsaCrypt", ## args) +#define rbprintf(args...) secdebug("rsaBuf", ## args) + +static ModuleNexus gMutex; + +RSA_CryptContext::~RSA_CryptContext() +{ + StLock _(gMutex()); + if(mAllocdRsaKey) { + assert(mRsaKey != NULL); + RSA_free(mRsaKey); + mRsaKey = NULL; + mAllocdRsaKey = false; + } +} + +/* called by CSPFullPluginSession */ +void RSA_CryptContext::init(const Context &context, bool encoding /*= true*/) +{ + StLock _(gMutex()); + + if(mInitFlag && !opStarted()) { + /* reusing - e.g. query followed by encrypt */ + return; + } + + /* optional mode to use alternate key class (e.g., decrypt with public key) */ + CSSM_KEYCLASS keyClass; + switch (context.getInt(CSSM_ATTRIBUTE_MODE)) { + case CSSM_ALGMODE_PUBLIC_KEY: + keyClass = CSSM_KEYCLASS_PUBLIC_KEY; + break; + case CSSM_ALGMODE_PRIVATE_KEY: + keyClass = CSSM_KEYCLASS_PRIVATE_KEY; + break; + case CSSM_ALGMODE_NONE: + /* default, not present in context: infer from op type */ + keyClass = encoding ? CSSM_KEYCLASS_PUBLIC_KEY : CSSM_KEYCLASS_PRIVATE_KEY; + break; + default: + CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE); + } + + /* fetch key from context */ + if(mRsaKey == NULL) { + assert(!opStarted()); + CSSM_DATA label = {0, NULL}; + mRsaKey = contextToRsaKey(context, + session(), + keyClass, + encoding ? CSSM_KEYUSE_ENCRYPT : CSSM_KEYUSE_DECRYPT, + mAllocdRsaKey, + label); + if(label.Data) { + mLabel.copy(label); + mOaep = true; + free(label.Data); + } + } + else { + assert(opStarted()); + } + + unsigned cipherBlockSize = RSA_size(mRsaKey); + unsigned plainBlockSize; + + /* padding - not present means value zero, CSSM_PADDING_NONE */ + uint32 padding = context.getInt(CSSM_ATTRIBUTE_PADDING); + switch(padding) { + case CSSM_PADDING_NONE: + mPadding = RSA_NO_PADDING; + plainBlockSize = cipherBlockSize; + break; + case CSSM_PADDING_PKCS1: + mPadding = RSA_PKCS1_PADDING; + plainBlockSize = cipherBlockSize - 11; + break; + case CSSM_PADDING_APPLE_SSLv2: + rsaCryptDebug("RSA_CryptContext::init using CSSM_PADDING_APPLE_SSLv2"); + mPadding = RSA_SSLV23_PADDING; + plainBlockSize = cipherBlockSize - 11; + break; + default: + rsaCryptDebug("RSA_CryptContext::init bad padding (0x%x)", + (unsigned)padding); + CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING); + } + + /* optional blinding attribute */ + uint32 blinding = context.getInt(CSSM_ATTRIBUTE_RSA_BLINDING); + if(blinding) { + if(RSA_blinding_on(mRsaKey, NULL) <= 0) { + /* actually no legit failures */ + CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); + } + } + else { + RSA_blinding_off(mRsaKey); + } + + /* finally, have BlockCryptor set up its stuff. */ + setup(encoding ? plainBlockSize : cipherBlockSize, // blockSizeIn + encoding ? cipherBlockSize : plainBlockSize, // blockSizeOut + false, // pkcs5Pad + false, // needsFinal + BCM_ECB, + NULL); // IV + mInitFlag = true; + +} +/* called by BlockCryptor */ +void RSA_CryptContext::encryptBlock( + const void *plainText, // length implied (one block) + size_t plainTextLen, + void *cipherText, + size_t &cipherTextLen, // in/out, throws on overflow + bool final) +{ + StLock _(gMutex()); + + int irtn; + + /* FIXME do OAEP encoding here */ + if(mRsaKey->d == NULL) { + irtn = RSA_public_encrypt((int)plainTextLen, + (unsigned char *)plainText, + (unsigned char *)cipherText, + mRsaKey, + mPadding); + } + else { + irtn = RSA_private_encrypt((int)plainTextLen, + (unsigned char *)plainText, + (unsigned char *)cipherText, + mRsaKey, + mPadding); + } + if(irtn < 0) { + throwRsaDsa("RSA_public_encrypt"); + } + else if((unsigned)irtn > cipherTextLen) { + rsaCryptDebug("RSA_public_encrypt overflow"); + CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); + } + cipherTextLen = (size_t)irtn; +} + +void RSA_CryptContext::decryptBlock( + const void *cipherText, // length implied (one cipher block) + size_t cipherTextLen, + void *plainText, + size_t &plainTextLen, // in/out, throws on overflow + bool final) +{ + StLock _(gMutex()); + + int irtn; + + rsaCryptDebug("decryptBlock padding %d", mPadding); + /* FIXME do OAEP encoding here */ + if(mRsaKey->d == NULL) { + irtn = RSA_public_decrypt((int)inBlockSize(), + (unsigned char *)cipherText, + (unsigned char *)plainText, + mRsaKey, + mPadding); + } + else { + irtn = RSA_private_decrypt((int)inBlockSize(), + (unsigned char *)cipherText, + (unsigned char *)plainText, + mRsaKey, + mPadding); + } + if(irtn < 0) { + rsaCryptDebug("decryptBlock err"); + throwRsaDsa("RSA_private_decrypt"); + } + else if((unsigned)irtn > plainTextLen) { + rsaCryptDebug("RSA_private_decrypt overflow"); + CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); + } + plainTextLen = (size_t)irtn; +} + +size_t RSA_CryptContext::outputSize( + bool final, // ignored + size_t inSize /*= 0*/) // output for given input size +{ + StLock _(gMutex()); + + size_t rawBytes = inSize + inBufSize(); + size_t rawBlocks = (rawBytes + inBlockSize() - 1) / inBlockSize(); + rbprintf("--- RSA_CryptContext::outputSize inSize 0x%lux outSize 0x%lux mInBufSize 0x%lux", + (unsigned long)inSize, (unsigned long)(rawBlocks * outBlockSize()), (unsigned long)inBufSize()); + return rawBlocks * outBlockSize(); +}