1/* 2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19/* 20 * RSA_asymmetric.cpp - CSPContext for RSA asymmetric encryption 21 */ 22 23#include "RSA_asymmetric.h" 24#include "RSA_DSA_utils.h" 25#include <security_utilities/debugging.h> 26#include <opensslUtils/opensslUtils.h> 27 28#define rsaCryptDebug(args...) secdebug("rsaCrypt", ## args) 29#define rbprintf(args...) secdebug("rsaBuf", ## args) 30 31static ModuleNexus<Mutex> gMutex; 32 33RSA_CryptContext::~RSA_CryptContext() 34{ 35 StLock<Mutex> _(gMutex()); 36 if(mAllocdRsaKey) { 37 assert(mRsaKey != NULL); 38 RSA_free(mRsaKey); 39 mRsaKey = NULL; 40 mAllocdRsaKey = false; 41 } 42} 43 44/* called by CSPFullPluginSession */ 45void RSA_CryptContext::init(const Context &context, bool encoding /*= true*/) 46{ 47 StLock<Mutex> _(gMutex()); 48 49 if(mInitFlag && !opStarted()) { 50 /* reusing - e.g. query followed by encrypt */ 51 return; 52 } 53 54 /* optional mode to use alternate key class (e.g., decrypt with public key) */ 55 CSSM_KEYCLASS keyClass; 56 switch (context.getInt(CSSM_ATTRIBUTE_MODE)) { 57 case CSSM_ALGMODE_PUBLIC_KEY: 58 keyClass = CSSM_KEYCLASS_PUBLIC_KEY; 59 break; 60 case CSSM_ALGMODE_PRIVATE_KEY: 61 keyClass = CSSM_KEYCLASS_PRIVATE_KEY; 62 break; 63 case CSSM_ALGMODE_NONE: 64 /* default, not present in context: infer from op type */ 65 keyClass = encoding ? CSSM_KEYCLASS_PUBLIC_KEY : CSSM_KEYCLASS_PRIVATE_KEY; 66 break; 67 default: 68 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE); 69 } 70 71 /* fetch key from context */ 72 if(mRsaKey == NULL) { 73 assert(!opStarted()); 74 CSSM_DATA label = {0, NULL}; 75 mRsaKey = contextToRsaKey(context, 76 session(), 77 keyClass, 78 encoding ? CSSM_KEYUSE_ENCRYPT : CSSM_KEYUSE_DECRYPT, 79 mAllocdRsaKey, 80 label); 81 if(label.Data) { 82 mLabel.copy(label); 83 mOaep = true; 84 free(label.Data); 85 } 86 } 87 else { 88 assert(opStarted()); 89 } 90 91 unsigned cipherBlockSize = RSA_size(mRsaKey); 92 unsigned plainBlockSize; 93 94 /* padding - not present means value zero, CSSM_PADDING_NONE */ 95 uint32 padding = context.getInt(CSSM_ATTRIBUTE_PADDING); 96 switch(padding) { 97 case CSSM_PADDING_NONE: 98 mPadding = RSA_NO_PADDING; 99 plainBlockSize = cipherBlockSize; 100 break; 101 case CSSM_PADDING_PKCS1: 102 mPadding = RSA_PKCS1_PADDING; 103 plainBlockSize = cipherBlockSize - 11; 104 break; 105 case CSSM_PADDING_APPLE_SSLv2: 106 rsaCryptDebug("RSA_CryptContext::init using CSSM_PADDING_APPLE_SSLv2"); 107 mPadding = RSA_SSLV23_PADDING; 108 plainBlockSize = cipherBlockSize - 11; 109 break; 110 default: 111 rsaCryptDebug("RSA_CryptContext::init bad padding (0x%x)", 112 (unsigned)padding); 113 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING); 114 } 115 116 /* optional blinding attribute */ 117 uint32 blinding = context.getInt(CSSM_ATTRIBUTE_RSA_BLINDING); 118 if(blinding) { 119 if(RSA_blinding_on(mRsaKey, NULL) <= 0) { 120 /* actually no legit failures */ 121 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); 122 } 123 } 124 else { 125 RSA_blinding_off(mRsaKey); 126 } 127 128 /* finally, have BlockCryptor set up its stuff. */ 129 setup(encoding ? plainBlockSize : cipherBlockSize, // blockSizeIn 130 encoding ? cipherBlockSize : plainBlockSize, // blockSizeOut 131 false, // pkcs5Pad 132 false, // needsFinal 133 BCM_ECB, 134 NULL); // IV 135 mInitFlag = true; 136 137} 138/* called by BlockCryptor */ 139void RSA_CryptContext::encryptBlock( 140 const void *plainText, // length implied (one block) 141 size_t plainTextLen, 142 void *cipherText, 143 size_t &cipherTextLen, // in/out, throws on overflow 144 bool final) 145{ 146 StLock<Mutex> _(gMutex()); 147 148 int irtn; 149 150 /* FIXME do OAEP encoding here */ 151 if(mRsaKey->d == NULL) { 152 irtn = RSA_public_encrypt((int)plainTextLen, 153 (unsigned char *)plainText, 154 (unsigned char *)cipherText, 155 mRsaKey, 156 mPadding); 157 } 158 else { 159 irtn = RSA_private_encrypt((int)plainTextLen, 160 (unsigned char *)plainText, 161 (unsigned char *)cipherText, 162 mRsaKey, 163 mPadding); 164 } 165 if(irtn < 0) { 166 throwRsaDsa("RSA_public_encrypt"); 167 } 168 else if((unsigned)irtn > cipherTextLen) { 169 rsaCryptDebug("RSA_public_encrypt overflow"); 170 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); 171 } 172 cipherTextLen = (size_t)irtn; 173} 174 175void RSA_CryptContext::decryptBlock( 176 const void *cipherText, // length implied (one cipher block) 177 size_t cipherTextLen, 178 void *plainText, 179 size_t &plainTextLen, // in/out, throws on overflow 180 bool final) 181{ 182 StLock<Mutex> _(gMutex()); 183 184 int irtn; 185 186 rsaCryptDebug("decryptBlock padding %d", mPadding); 187 /* FIXME do OAEP encoding here */ 188 if(mRsaKey->d == NULL) { 189 irtn = RSA_public_decrypt((int)inBlockSize(), 190 (unsigned char *)cipherText, 191 (unsigned char *)plainText, 192 mRsaKey, 193 mPadding); 194 } 195 else { 196 irtn = RSA_private_decrypt((int)inBlockSize(), 197 (unsigned char *)cipherText, 198 (unsigned char *)plainText, 199 mRsaKey, 200 mPadding); 201 } 202 if(irtn < 0) { 203 rsaCryptDebug("decryptBlock err"); 204 throwRsaDsa("RSA_private_decrypt"); 205 } 206 else if((unsigned)irtn > plainTextLen) { 207 rsaCryptDebug("RSA_private_decrypt overflow"); 208 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); 209 } 210 plainTextLen = (size_t)irtn; 211} 212 213size_t RSA_CryptContext::outputSize( 214 bool final, // ignored 215 size_t inSize /*= 0*/) // output for given input size 216{ 217 StLock<Mutex> _(gMutex()); 218 219 size_t rawBytes = inSize + inBufSize(); 220 size_t rawBlocks = (rawBytes + inBlockSize() - 1) / inBlockSize(); 221 rbprintf("--- RSA_CryptContext::outputSize inSize 0x%lux outSize 0x%lux mInBufSize 0x%lux", 222 (unsigned long)inSize, (unsigned long)(rawBlocks * outBlockSize()), (unsigned long)inBufSize()); 223 return rawBlocks * outBlockSize(); 224} 225