Merge "Fix accessing freed memory in X509CertificateStore::Update()" into tizen
[platform/framework/native/appfw.git] / src / security / crypto / FSecCryptoRsaSignature.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                FSecCryptoRsaSignature.cpp
19  * @brief               This file contains the implementation for Tizen::Security::Crypto::RsaSignature 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 <FSecCryptoRsaSignature.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 RsaSignature::RsaSignature(void)
39         : __pRsaSignatureImpl(null)
40 {
41 }
42
43 RsaSignature::~RsaSignature(void)
44 {
45 }
46
47 result
48 RsaSignature::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 RsaSignature::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 RsaSignature::SignN(const ByteBuffer& input)
83 {
84         return SignN(input, L"SHA1");
85 }
86
87 ByteBuffer*
88 RsaSignature::SignN(const ByteBuffer& input, const Tizen::Base::String& algorithm)
89 {
90         result r = E_SUCCESS;
91         int ret = 0;
92         int keyLen = 0;
93         unsigned int dataLen = 0;
94         unsigned int outLen = 0;
95         byte buffer[_MAX_ARRAY_LENGTH];
96         byte* pTempBuf = null;
97         const byte* pData = null;
98         const byte* pKey = null;
99         ByteBuffer* pOutput = null;
100         EVP_PKEY* pEvpKey = null;
101         RSA* pRsa = null;
102         BIO* pBio = null;
103         int localNid = NID_sha1;
104
105         ClearLastResult();
106
107         pData = input.GetPointer();
108         SysTryReturn(NID_SEC_CRYPTO, pData != null, null, E_INVALID_ARG, "[E_INVALID_ARG] Input data value should be valid.");
109
110         dataLen = input.GetRemaining();
111         SysTryReturn(NID_SEC_CRYPTO, dataLen > 0, null, E_INVALID_ARG, "[E_INVALID_ARG] Input data length should be positive.");
112
113         pKey = __privateKey.GetPointer();
114         SysTryReturn(NID_SEC_CRYPTO, pKey != null, null, E_KEY_NOT_FOUND, "[E_KEY_NOT_FOUND] Key value should be valid.");
115
116         keyLen = __privateKey.GetRemaining();
117         SysTryReturn(NID_SEC_CRYPTO, keyLen > 0, null, E_KEY_NOT_FOUND, "[E_KEY_NOT_FOUND] Key length should be positive.");
118
119         pEvpKey = d2i_PrivateKey(EVP_PKEY_RSA, null, &pKey, keyLen);
120
121         if (pEvpKey == null)
122         {
123                 PKCS8_PRIV_KEY_INFO* pPrivKeyInfo = d2i_PKCS8_PRIV_KEY_INFO(null, &pKey, keyLen);
124                 if (pPrivKeyInfo != null)
125                 {
126                         pEvpKey = EVP_PKCS82PKEY(pPrivKeyInfo);
127                         PKCS8_PRIV_KEY_INFO_free(pPrivKeyInfo);
128                 }
129
130         }
131         if (pEvpKey == null)
132         {
133                 pBio = BIO_new(BIO_s_mem());
134                 SysTryReturn(NID_SEC_CRYPTO, pBio != null, null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
135
136                 int readCount = BIO_write(pBio, (const void*) pKey, keyLen);
137                 SysTryCatch(NID_SEC_CRYPTO, readCount > 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
138
139                 pEvpKey = PEM_read_bio_PrivateKey(pBio, null, 0, null);
140         }
141
142         SysTryCatch(NID_SEC_CRYPTO, pEvpKey != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
143
144         pRsa = EVP_PKEY_get1_RSA(pEvpKey);
145         SysTryCatch(NID_SEC_CRYPTO, pRsa != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
146
147         outLen = BN_bn2bin(pRsa->n, buffer);
148         SysTryCatch(NID_SEC_CRYPTO, outLen > 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
149
150         pTempBuf = new (std::nothrow) byte[outLen];
151         SysTryCatch(NID_SEC_CRYPTO, pTempBuf != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
152
153         memset(pTempBuf, 0, outLen);
154
155         if (algorithm.CompareTo(L"MD5WITHSHA1") == 0) //for ssl padding
156         {
157                 localNid = NID_md5_sha1;
158         }
159         else if (algorithm.CompareTo(L"MD5") == 0)
160         {
161                 localNid = NID_md5;
162         }
163         else if (algorithm.CompareTo(L"SHA1") == 0)
164         {
165                 localNid = NID_sha1;
166         }
167         else if (algorithm.CompareTo(L"SHA2/224") == 0)
168         {
169                 localNid = NID_sha224;
170         }
171         else if (algorithm.CompareTo(L"SHA2/256") == 0)
172         {
173                 localNid = NID_sha256;
174         }
175         else if (algorithm.CompareTo(L"SHA2/384") == 0)
176         {
177                 localNid = NID_sha384;
178         }
179         else if (algorithm.CompareTo(L"SHA2/512") == 0)
180         {
181                 localNid = NID_sha512;
182         }
183         else
184         {
185                 SysTryCatch(NID_SEC_CRYPTO, false, r = E_UNSUPPORTED_ALGORITHM, E_UNSUPPORTED_ALGORITHM, "[E_UNSUPPORTED_ALGORITHM] An unsupported algorithm.");
186         }
187
188         ret = RSA_sign(localNid, pData, dataLen, pTempBuf, &outLen, pRsa);
189         SysTryCatch(NID_SEC_CRYPTO, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
190         SysTryCatch(NID_SEC_CRYPTO, outLen > 0, r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Output length should be positive.");
191
192         pOutput = new (std::nothrow) ByteBuffer();
193         SysTryCatch(NID_SEC_CRYPTO, pOutput != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allocate memory.");
194
195         r = pOutput->Construct(outLen);
196         SysTryCatch(NID_SEC_CRYPTO, !IsFailed(r), r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Failed to allovate memory.");
197
198         r = pOutput->SetArray(pTempBuf, 0, outLen);
199         SysTryCatch(NID_SEC_CRYPTO, !IsFailed(r), r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
200
201         pOutput->Flip();
202
203 CATCH:
204
205         if (IsFailed(r))
206         {
207                 delete pOutput;
208                 pOutput = null;
209         }
210         if (pRsa)
211         {
212                 RSA_free(pRsa);
213         }
214         if (pEvpKey)
215         {
216                 EVP_PKEY_free(pEvpKey);
217         }
218         if (pBio)
219         {
220                 BIO_free(pBio);
221         }
222
223         delete[] pTempBuf;
224         return pOutput;
225 }
226
227 bool
228 RsaSignature::Verify(const Tizen::Base::ByteBuffer& data, const Tizen::Base::ByteBuffer& signedData)
229 {
230         return Verify(data, signedData, L"SHA1");
231 }
232
233 bool
234 RsaSignature::Verify(const Tizen::Base::ByteBuffer& data, const Tizen::Base::ByteBuffer& signedData, const Tizen::Base::String& algorithm)
235 {
236         result r = E_SUCCESS;
237         int ret = 0;
238         int keyLen = 0;
239         unsigned int dataLen = 0;
240         unsigned int signedDataLen = 0;
241         byte* pSignedData = null;
242         const byte* pData = null;
243         const byte* pKey = null;
244         EVP_PKEY* pEvpKey = null;
245         RSA* pRsa = null;
246         BIO* pBio = null;
247         int localNid = NID_sha1;
248
249         ClearLastResult();
250
251         pData = data.GetPointer();
252         SysTryReturn(NID_SEC_CRYPTO, pData != null, false, E_INVALID_ARG, "[E_INVALID_ARG] Input data value should be valid.");
253
254         dataLen = data.GetRemaining();
255         SysTryReturn(NID_SEC_CRYPTO, dataLen > 0, false, E_INVALID_ARG, "[E_INVALID_ARG] Input data length should be positive.");
256
257         pSignedData = const_cast< byte* >(signedData.GetPointer());
258         SysTryReturn(NID_SEC_CRYPTO, pSignedData != null, false, E_INVALID_ARG, "[E_INVALID_ARG] Signed data value should be valid.");
259
260         signedDataLen = static_cast< unsigned int >(signedData.GetRemaining());
261         SysTryReturn(NID_SEC_CRYPTO, signedDataLen > 0, false, E_INVALID_ARG, "[E_INVALID_ARG] Signed data length should be positive.");
262
263         pKey = __publicKey.GetPointer();
264         SysTryReturn(NID_SEC_CRYPTO, pKey != null, false, E_KEY_NOT_FOUND, "[E_KEY_NOT_FOUND] Key value should be valid.");
265
266         keyLen = __publicKey.GetRemaining();
267         SysTryReturn(NID_SEC_CRYPTO, keyLen > 0, false, E_KEY_NOT_FOUND, "[E_KEY_NOT_FOUND] Key length should be positive.");
268
269         pEvpKey = d2i_PublicKey(EVP_PKEY_RSA, null, &pKey, keyLen);
270
271         if (pEvpKey == null)
272         {
273                 pEvpKey = d2i_PUBKEY(null, &pKey, keyLen);
274         }
275
276         if (pEvpKey == null)
277         {
278                 pBio = BIO_new(BIO_s_mem());
279                 SysTryReturn(NID_SEC_CRYPTO, pBio != null, false, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
280
281                 int readCount = BIO_write(pBio, (const void*) pKey, keyLen);
282                 if (readCount > 0)
283                 {
284                         pEvpKey = PEM_read_bio_PUBKEY(pBio, null, 0, null);
285                 }
286         }
287
288         SysTryCatch(NID_SEC_CRYPTO, pEvpKey != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
289
290         pRsa = EVP_PKEY_get1_RSA(pEvpKey);
291         SysTryCatch(NID_SEC_CRYPTO, pRsa != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
292
293         if (algorithm.CompareTo(L"MD5WITHSHA1") == 0) //for ssl padding
294         {
295                 localNid = NID_md5_sha1;
296         }
297         else if (algorithm.CompareTo(L"MD5") == 0)
298         {
299                 localNid = NID_md5;
300         }
301         else if (algorithm.CompareTo(L"SHA1") == 0)
302         {
303                 localNid = NID_sha1;
304         }
305         else if (algorithm.CompareTo(L"SHA2/224") == 0)
306         {
307                 localNid = NID_sha224;
308         }
309         else if (algorithm.CompareTo(L"SHA2/256") == 0)
310         {
311                 localNid = NID_sha256;
312         }
313         else if (algorithm.CompareTo(L"SHA2/384") == 0)
314         {
315                 localNid = NID_sha384;
316         }
317         else if (algorithm.CompareTo(L"SHA2/512") == 0)
318         {
319                 localNid = NID_sha512;
320         }
321         else
322         {
323                 SysTryCatch(NID_SEC_CRYPTO, false, r = E_UNSUPPORTED_ALGORITHM, E_UNSUPPORTED_ALGORITHM, "[E_UNSUPPORTED_ALGORITHM] An unsupported algorithm.");
324         }
325
326         ret = RSA_verify(localNid, pData, dataLen, pSignedData, signedDataLen, pRsa);
327         SysTryCatch(NID_SEC_CRYPTO, ret == 1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] An unexpected system error occurred.");
328
329 CATCH:
330
331         if (pRsa)
332         {
333                 RSA_free(pRsa);
334         }
335         if (pEvpKey)
336         {
337                 EVP_PKEY_free(pEvpKey);
338         }
339         if (pBio)
340         {
341                 BIO_free(pBio);
342         }
343         if (IsFailed(r))
344         {
345                 return false;
346         }
347         else
348         {
349                 return true;
350         }
351 }
352
353 } } } //Tizen::Security::Crypto