--- /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.
+ */
+
+
+/*
+ * RSA_asymmetric.cpp - CSPContext for RSA asymmetric encryption
+ */
+
+#include "RSA_asymmetric.h"
+#include "RSA_DSA_utils.h"
+#include <security_utilities/debugging.h>
+#include <opensslUtils/opensslUtils.h>
+
+#define rsaCryptDebug(args...) secdebug("rsaCrypt", ## args)
+#define rbprintf(args...) secdebug("rsaBuf", ## args)
+
+static ModuleNexus<Mutex> gMutex;
+
+RSA_CryptContext::~RSA_CryptContext()
+{
+ StLock<Mutex> _(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<Mutex> _(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<Mutex> _(gMutex());
+
+ int irtn;
+
+ /* FIXME do OAEP encoding here */
+ if(mRsaKey->d == NULL) {
+ irtn = RSA_public_encrypt(plainTextLen,
+ (unsigned char *)plainText,
+ (unsigned char *)cipherText,
+ mRsaKey,
+ mPadding);
+ }
+ else {
+ irtn = RSA_private_encrypt(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<Mutex> _(gMutex());
+
+ int irtn;
+
+ rsaCryptDebug("decryptBlock padding %d", mPadding);
+ /* FIXME do OAEP encoding here */
+ if(mRsaKey->d == NULL) {
+ irtn = RSA_public_decrypt(inBlockSize(),
+ (unsigned char *)cipherText,
+ (unsigned char *)plainText,
+ mRsaKey,
+ mPadding);
+ }
+ else {
+ irtn = RSA_private_decrypt(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<Mutex> _(gMutex());
+
+ uint32 rawBytes = inSize + inBufSize();
+ uint32 rawBlocks = (rawBytes + inBlockSize() - 1) / inBlockSize();
+ rbprintf("--- RSA_CryptContext::outputSize inSize 0x%lx outSize 0x%lx mInBufSize 0x%lx",
+ inSize, rawBlocks * outBlockSize(), inBufSize());
+ return rawBlocks * outBlockSize();
+}