2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
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
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.
20 * RSA_asymmetric.cpp - CSPContext for RSA asymmetric encryption
23 #include "RSA_asymmetric.h"
24 #include "RSA_DSA_utils.h"
25 #include <security_utilities/debugging.h>
26 #include <opensslUtils/opensslUtils.h>
28 #define rsaCryptDebug(args...) secdebug("rsaCrypt", ## args)
29 #define rbprintf(args...) secdebug("rsaBuf", ## args)
31 static ModuleNexus
<Mutex
> gMutex
;
33 RSA_CryptContext::~RSA_CryptContext()
35 StLock
<Mutex
> _(gMutex());
37 assert(mRsaKey
!= NULL
);
40 mAllocdRsaKey
= false;
44 /* called by CSPFullPluginSession */
45 void RSA_CryptContext::init(const Context
&context
, bool encoding
/*= true*/)
47 StLock
<Mutex
> _(gMutex());
49 if(mInitFlag
&& !opStarted()) {
50 /* reusing - e.g. query followed by encrypt */
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
;
60 case CSSM_ALGMODE_PRIVATE_KEY
:
61 keyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
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
;
68 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_MODE
);
71 /* fetch key from context */
74 CSSM_DATA label
= {0, NULL
};
75 mRsaKey
= contextToRsaKey(context
,
78 encoding
? CSSM_KEYUSE_ENCRYPT
: CSSM_KEYUSE_DECRYPT
,
91 unsigned cipherBlockSize
= RSA_size(mRsaKey
);
92 unsigned plainBlockSize
;
94 /* padding - not present means value zero, CSSM_PADDING_NONE */
95 uint32 padding
= context
.getInt(CSSM_ATTRIBUTE_PADDING
);
97 case CSSM_PADDING_NONE
:
98 mPadding
= RSA_NO_PADDING
;
99 plainBlockSize
= cipherBlockSize
;
101 case CSSM_PADDING_PKCS1
:
102 mPadding
= RSA_PKCS1_PADDING
;
103 plainBlockSize
= cipherBlockSize
- 11;
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;
111 rsaCryptDebug("RSA_CryptContext::init bad padding (0x%x)",
113 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PADDING
);
116 /* optional blinding attribute */
117 uint32 blinding
= context
.getInt(CSSM_ATTRIBUTE_RSA_BLINDING
);
119 if(RSA_blinding_on(mRsaKey
, NULL
) <= 0) {
120 /* actually no legit failures */
121 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
125 RSA_blinding_off(mRsaKey
);
128 /* finally, have BlockCryptor set up its stuff. */
129 setup(encoding
? plainBlockSize
: cipherBlockSize
, // blockSizeIn
130 encoding
? cipherBlockSize
: plainBlockSize
, // blockSizeOut
138 /* called by BlockCryptor */
139 void RSA_CryptContext::encryptBlock(
140 const void *plainText
, // length implied (one block)
143 size_t &cipherTextLen
, // in/out, throws on overflow
146 StLock
<Mutex
> _(gMutex());
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
,
159 irtn
= RSA_private_encrypt((int)plainTextLen
,
160 (unsigned char *)plainText
,
161 (unsigned char *)cipherText
,
166 throwRsaDsa("RSA_public_encrypt");
168 else if((unsigned)irtn
> cipherTextLen
) {
169 rsaCryptDebug("RSA_public_encrypt overflow");
170 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
);
172 cipherTextLen
= (size_t)irtn
;
175 void RSA_CryptContext::decryptBlock(
176 const void *cipherText
, // length implied (one cipher block)
177 size_t cipherTextLen
,
179 size_t &plainTextLen
, // in/out, throws on overflow
182 StLock
<Mutex
> _(gMutex());
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
,
196 irtn
= RSA_private_decrypt((int)inBlockSize(),
197 (unsigned char *)cipherText
,
198 (unsigned char *)plainText
,
203 rsaCryptDebug("decryptBlock err");
204 throwRsaDsa("RSA_private_decrypt");
206 else if((unsigned)irtn
> plainTextLen
) {
207 rsaCryptDebug("RSA_private_decrypt overflow");
208 CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
);
210 plainTextLen
= (size_t)irtn
;
213 size_t RSA_CryptContext::outputSize(
214 bool final
, // ignored
215 size_t inSize
/*= 0*/) // output for given input size
217 StLock
<Mutex
> _(gMutex());
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();