Merge "Fix accessing freed memory in X509CertificateStore::Update()" into tizen
[platform/framework/native/appfw.git] / src / security / crypto / FSecCryptoRsaCipher.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Apache License, Version 2.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 /**
18  * @file                FSecCryptoRsaCipher.cpp
19  * @brief               This file contains the implementation of Tizen::Security::Crypto::RsaCipher class.
20  *
21  */
22 #include <openssl/rsa.h>
23 #include <openssl/evp.h>
24 #include <openssl/pem.h>
25 #include <openssl/x509.h>
26 #include <FBaseResult.h>
27 #include <FBaseErrors.h>
28 #include <FSecCryptoRsaCipher.h>
29 #include <FBaseSysLog.h>
30
31 using namespace Tizen::Base;
32
33
34 namespace Tizen { namespace Security { namespace Crypto
35 {
36 static const int _MAX_ARRAY_LENGTH = 4096;
37
38 RsaCipher::RsaCipher(void)
39         : __pRsaCipherImpl(null)
40 {
41 }
42
43 RsaCipher::~RsaCipher(void)
44 {
45 }
46
47 result
48 RsaCipher::SetPrivateKey(const Tizen::Security::IKey& key)
49 {
50         result r = E_SUCCESS;
51         ByteBuffer* pBuffer = null;
52
53         pBuffer = key.GetEncodedN();
54         SysTryReturn(NID_SEC_CRYPTO, pBuffer != null, GetLastResult(), GetLastResult(), "[%s] Failed to fill the key buffer.", GetErrorMessage(GetLastResult()));
55
56         r = __privateKey.Construct(*pBuffer);
57         SysTryCatch(NID_SEC_CRYPTO, !IsFailed(r), , r, "[%s] Input key buffer should be valid.", GetErrorMessage(r));
58
59 CATCH:
60         delete pBuffer;
61         return r;
62 }
63
64 result
65 RsaCipher::SetPublicKey(const Tizen::Security::IKey& key)
66 {
67         result r = E_SUCCESS;
68         ByteBuffer* pBuffer = null;
69
70         pBuffer = key.GetEncodedN();
71         SysTryReturn(NID_SEC_CRYPTO, pBuffer != null, GetLastResult(), GetLastResult(), "[%s] Failed to fill the key buffer.", GetErrorMessage(GetLastResult()));
72
73         r = __publicKey.Construct(*pBuffer);
74         SysTryCatch(NID_SEC_CRYPTO, !IsFailed(r), , r, "[%s] Input key buffer should be valid.", GetErrorMessage(r));
75
76 CATCH:
77         delete pBuffer;
78         return r;
79 }
80
81 ByteBuffer*
82 RsaCipher::EncryptN(const Tizen::Base::ByteBuffer& input)
83 {
84         result r = E_SUCCESS;
85         int dataLen = 0;
86         int keyLen = 0;
87         int outLen = 0;
88         int tempLen = 0;
89         byte* pData = null;
90         byte* pTempBuf = null;
91         byte buffer[_MAX_ARRAY_LENGTH];
92         const byte* pKey = null;
93         ByteBuffer* pOutput = null;
94         EVP_PKEY* pEvpKey = null;
95         RSA* pRsa = null;
96         BIO* pBio = null;
97
98         ClearLastResult();
99
100         pData = const_cast< byte* >(input.GetPointer());
101         SysTryReturn(NID_SEC_CRYPTO, pData != null, null, E_INVALID_ARG, "[E_INVALID_ARG] Input data value should be valid.");
102
103         dataLen = input.GetRemaining();
104         SysTryReturn(NID_SEC_CRYPTO, dataLen > 0, null, E_INVALID_ARG, "[E_INVALID_ARG] Input data length should be positive.");
105
106         pKey = __publicKey.GetPointer();
107         SysTryReturn(NID_SEC_CRYPTO, pKey != null, null, E_KEY_NOT_FOUND, "[E_KEY_NOT_FOUND] Key value should be valid.");
108
109         keyLen = __publicKey.GetRemaining();
110         SysTryReturn(NID_SEC_CRYPTO, keyLen > 0, null, E_KEY_NOT_FOUND, "[E_KEY_NOT_FOUND] Key length should be positive.");
111
112         pEvpKey = d2i_PublicKey(EVP_PKEY_RSA, null, &pKey, keyLen);
113
114         if (pEvpKey == null)
115         {
116                 pEvpKey = d2i_PUBKEY(null, &pKey, keyLen);
117         }
118
119         if (pEvpKey == null)
120         {
121                 pBio = BIO_new(BIO_s_mem());
122                 SysTryReturn(NID_SEC_CRYPTO, pBio != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
123
124                 int readCount = BIO_write(pBio, (const void*) pKey, keyLen);
125                 if (readCount > 0)
126                 {
127                         pEvpKey = PEM_read_bio_PUBKEY(pBio, null, 0, null);
128                 }
129         }
130
131         SysTryCatch(NID_SEC_CRYPTO, pEvpKey != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
132
133         pRsa = EVP_PKEY_get1_RSA(pEvpKey);
134         SysTryCatch(NID_SEC_CRYPTO, pRsa != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
135
136         tempLen = BN_bn2bin(pRsa->n, buffer);
137         SysTryCatch(NID_SEC_CRYPTO, tempLen > 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
138
139         pTempBuf = new (std::nothrow) byte[tempLen];
140         SysTryCatch(NID_SEC_CRYPTO, pTempBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
141
142         memset(pTempBuf, 0, tempLen);
143
144         outLen = RSA_public_encrypt(dataLen, pData, pTempBuf, pRsa, RSA_PKCS1_PADDING);
145         SysTryCatch(NID_SEC_CRYPTO, outLen > 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
146
147         SysTryCatch(NID_SEC_CRYPTO, outLen <= tempLen, r = E_OVERFLOW, E_OVERFLOW, "[E_OVERFLOW] Overflow as output data length > input data length.");
148
149         pOutput = new (std::nothrow) ByteBuffer();
150         SysTryCatch(NID_SEC_CRYPTO, pOutput != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
151
152         r = pOutput->Construct(outLen);
153         SysTryCatch(NID_SEC_CRYPTO, !IsFailed(r), r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
154
155         r = pOutput->SetArray(pTempBuf, 0, outLen);
156         SysTryCatch(NID_SEC_CRYPTO, !IsFailed(r), r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
157
158         pOutput->Flip();
159
160 CATCH:
161
162         if (IsFailed(r))
163         {
164                 delete pOutput;
165                 pOutput = null;
166         }
167         if (pRsa)
168         {
169                 RSA_free(pRsa);
170         }
171         if (pBio)
172         {
173                 BIO_free(pBio);
174         }
175         if (pEvpKey)
176         {
177                 EVP_PKEY_free(pEvpKey);
178         }
179
180         delete[] pTempBuf;
181         return pOutput;
182 }
183
184 ByteBuffer*
185 RsaCipher::DecryptN(const Tizen::Base::ByteBuffer& input)
186 {
187         result r = E_SUCCESS;
188         int dataLen = 0;
189         int keyLen = 0;
190         int outLen = 0;
191         int tempLen = 0;
192         byte* pData = null;
193         byte* pTempBuf = null;
194         byte buffer[_MAX_ARRAY_LENGTH];
195         const byte* pKey = null;
196         ByteBuffer* pOutput = null;
197         EVP_PKEY* pEvpKey = null;
198         RSA* pRsa = null;
199         BIO* pBio = null;
200
201         ClearLastResult();
202
203         pData = const_cast< byte* >(input.GetPointer());
204         SysTryReturn(NID_SEC_CRYPTO, pData != null, null, E_INVALID_ARG, "[E_INVALID_ARG] Input data value should be valid.");
205
206         dataLen = input.GetRemaining();
207         SysTryReturn(NID_SEC_CRYPTO, dataLen > 0, null, E_INVALID_ARG, "[E_INVALID_ARG] Input data length should be positive.");
208
209         pKey = __privateKey.GetPointer();
210         SysTryReturn(NID_SEC_CRYPTO, pKey != null, null, E_KEY_NOT_FOUND, "[E_KEY_NOT_FOUND] Key data should be valid.");
211
212         keyLen = __privateKey.GetRemaining();
213         SysTryReturn(NID_SEC_CRYPTO, keyLen > 0, null, E_KEY_NOT_FOUND, "[E_KEY_NOT_FOUND] Key length should be positive.");
214
215         //res = __SecCrDecodeRSAPrivateKey(&pPriKey, (CrUINT8 *)pKey, (CrUINT32)keyLen);
216         pEvpKey = d2i_PrivateKey(EVP_PKEY_RSA, null, &pKey, keyLen);
217
218         if (pEvpKey == null)
219         {
220                 PKCS8_PRIV_KEY_INFO* pPrivKeyInfo = d2i_PKCS8_PRIV_KEY_INFO(null, &pKey, keyLen);
221                 if (pPrivKeyInfo != null)
222                 {
223                         pEvpKey = EVP_PKCS82PKEY(pPrivKeyInfo);
224                         PKCS8_PRIV_KEY_INFO_free(pPrivKeyInfo);
225                 }
226         }
227         if (pEvpKey == null)
228         {
229                 pBio = BIO_new(BIO_s_mem());
230                 SysTryReturn(NID_SEC_CRYPTO, pBio != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
231
232                 int readCount = BIO_write(pBio, (const void*) pKey, keyLen);
233                 if (readCount > 0)
234                 {
235                         pEvpKey = PEM_read_bio_PrivateKey(pBio, null, 0, null);
236                 }
237         }
238
239         SysTryCatch(NID_SEC_CRYPTO, pEvpKey != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
240
241         pRsa = EVP_PKEY_get1_RSA(pEvpKey);
242         SysTryCatch(NID_SEC_CRYPTO, pRsa != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
243
244         tempLen = BN_bn2bin(pRsa->n, buffer);
245         SysTryCatch(NID_SEC_CRYPTO, tempLen > 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
246
247         pTempBuf = new (std::nothrow) byte[tempLen];
248         SysTryCatch(NID_SEC_CRYPTO, pTempBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_SYSTEM] An unexpected system error occurred.");
249
250         memset(pTempBuf, 0, tempLen);
251
252         outLen = RSA_private_decrypt(dataLen, pData, pTempBuf, pRsa, RSA_PKCS1_PADDING);
253         SysTryCatch(NID_SEC_CRYPTO, outLen > 0, r = E_INVALID_ARG, E_INVALID_ARG, "[E_SYSTEM] An unexpected system error occurred.");
254         SysTryCatch(NID_SEC_CRYPTO, outLen <= tempLen, r = E_OVERFLOW, E_OVERFLOW, "[E_OVERFLOW] Overflow as output data length > input data length.");
255
256         pOutput = new (std::nothrow) ByteBuffer();
257         SysTryCatch(NID_SEC_CRYPTO, pOutput != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
258
259         r = pOutput->Construct(outLen);
260         SysTryCatch(NID_SEC_CRYPTO, !IsFailed(r), r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
261
262         r = pOutput->SetArray(pTempBuf, 0, outLen);
263         SysTryCatch(NID_SEC_CRYPTO, !IsFailed(r), r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
264
265         pOutput->Flip();
266
267 CATCH:
268
269         if (IsFailed(r))
270         {
271                 delete pOutput;
272                 pOutput = null;
273         }
274         if (pRsa)
275         {
276                 RSA_free(pRsa);
277         }
278         if (pEvpKey)
279         {
280                 EVP_PKEY_free(pEvpKey);
281         }
282         if (pBio)
283         {
284                 BIO_free(pBio);
285         }
286
287         delete[] pTempBuf;
288         return pOutput;
289 }
290
291 } } } //Tizen::Security::Crypto