|
1 /* |
|
2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 /** |
|
20 @file |
|
21 @internalComponent |
|
22 @released |
|
23 */ |
|
24 |
|
25 #ifdef _MSC_VER |
|
26 #pragma warning (disable: 4786) |
|
27 #endif // _MSC_VER |
|
28 |
|
29 #include <iostream> |
|
30 #include <fstream> |
|
31 #include <string> |
|
32 |
|
33 #include "sissignature.h" |
|
34 #include "siscontroller.h" |
|
35 |
|
36 #include <openssl/dsa.h> |
|
37 #include <openssl/rsa.h> |
|
38 #include <openssl/sha.h> |
|
39 #include <openssl/evp.h> |
|
40 #include <openssl/objects.h> |
|
41 #include <openssl/x509.h> |
|
42 #include <openssl/err.h> |
|
43 #include <openssl/pem.h> |
|
44 #include <openssl/evp.h> |
|
45 |
|
46 #define RSA_IDENTIFIER L"1.2.840.113549.1.1.5" |
|
47 #define DSA_IDENTIFIER L"1.2.840.10040.4.3" |
|
48 #define DSA_PRIME_SIZE 1024 |
|
49 #define OLD_PEM_FORMAT_TAG "Proc-Type" |
|
50 #define ENCRYPTION_ALGORITHM_TAG "DEK-Info" |
|
51 #define PEM_HEADER "----" |
|
52 |
|
53 void CalculateHash (TSHADigest& aDigest, const TUint8* aBuffer, TUint32 aBufferSize) |
|
54 { |
|
55 assert (aBuffer); |
|
56 assert (! IsBadReadPtr (aBuffer, aBufferSize)); |
|
57 memset (&aDigest, 0, SHA_DIGEST_LENGTH); |
|
58 SHA1 (aBuffer, aBufferSize, aDigest); |
|
59 } |
|
60 |
|
61 |
|
62 CSignature::CSignature (CSignatureData& aSISSignature): |
|
63 iSISSignature(aSISSignature), |
|
64 iSignatureAlgorithm(const_cast<CSISSignatureAlgorithm&>(iSISSignature.GetAlgorithm())) |
|
65 { |
|
66 } |
|
67 |
|
68 CSignature::~CSignature() |
|
69 { |
|
70 } |
|
71 |
|
72 void CSignature::Sign (const std::wstring& aPrivateKey, const std::wstring& aPassPhrase, const TUint8* aBuffer, const TUint32 aBufferSize) |
|
73 { |
|
74 assert (aBuffer); |
|
75 TSHADigest digest; |
|
76 CalculateHash (digest, aBuffer, aBufferSize); |
|
77 void* key = LoadKey (aPrivateKey, aPassPhrase); |
|
78 assert (key); |
|
79 switch (iSISSignature.GetAlgorithm().Algorithm()) |
|
80 { |
|
81 case CSISSignatureAlgorithm::EAlgRSA : |
|
82 RSASign (digest, key); |
|
83 break; |
|
84 case CSISSignatureAlgorithm::EAlgDSA : |
|
85 DSASign (digest, key); |
|
86 break; |
|
87 default: |
|
88 throw CSISException (CSISException::ECrypto, "unknown algorithm"); |
|
89 } |
|
90 } |
|
91 |
|
92 |
|
93 void CSignature::DSASign (const TSHADigest& aDigest, void* aKey) |
|
94 { |
|
95 DSA* dsa = reinterpret_cast <DSA*> (aKey); |
|
96 assert (dsa); |
|
97 unsigned int written = 0; |
|
98 int status = 0; |
|
99 try |
|
100 { |
|
101 unsigned int max = DSA_size (dsa); |
|
102 iSISSignature.SetDataByteCount(max); |
|
103 status = DSA_sign (NID_sha1, aDigest, SHA_DIGEST_LENGTH, const_cast<unsigned char*>(iSISSignature.Data()), &written, dsa); |
|
104 } |
|
105 catch (...) |
|
106 { |
|
107 status = -1; |
|
108 } |
|
109 |
|
110 if (status <= 0) |
|
111 { |
|
112 DSA_free (dsa); |
|
113 throw CSISException (CSISException::ECrypto, L"cannot create DSA signature"); |
|
114 } |
|
115 |
|
116 CSISException::ThrowIf (written > iSISSignature.DataSize (), CSISException::ECrypto, L"inconsistent DSA sizes"); |
|
117 } |
|
118 |
|
119 void CSignature::RSASign (const TSHADigest& aDigest, void* aKey) |
|
120 { |
|
121 RSA* rsa = reinterpret_cast <RSA*> (aKey); |
|
122 assert (rsa); |
|
123 unsigned int written = 0; |
|
124 int status = 0; |
|
125 try |
|
126 { |
|
127 iSISSignature.SetDataByteCount(RSA_size (rsa)); |
|
128 status = RSA_sign (NID_sha1, aDigest, SHA_DIGEST_LENGTH, const_cast<unsigned char*>(iSISSignature.Data()), &written, rsa); |
|
129 } |
|
130 catch (...) |
|
131 { |
|
132 status = -1; |
|
133 } |
|
134 |
|
135 if (status <= 0) |
|
136 { |
|
137 RSA_free (rsa); |
|
138 throw CSISException (CSISException::ECrypto, L"cannot create RSA signature"); |
|
139 } |
|
140 CSISException::ThrowIf (written > iSISSignature.DataSize (), CSISException::ECrypto, L"inconsistent RSA sizes"); |
|
141 } |
|
142 |
|
143 |
|
144 void CSignature::VerifySignature (X509* aX509, const TUint8* aBuffer, const TUint32 aBufferSize) const |
|
145 { |
|
146 assert (aBuffer); |
|
147 TSHADigest digest; |
|
148 |
|
149 CalculateHash (digest, aBuffer, aBufferSize); |
|
150 switch (iSISSignature.GetAlgorithm().Algorithm ()) |
|
151 { |
|
152 case CSISSignatureAlgorithm::EAlgRSA : |
|
153 RSAVerify (digest, aX509); |
|
154 break; |
|
155 case CSISSignatureAlgorithm::EAlgDSA : |
|
156 DSAVerify (digest, aX509); |
|
157 break; |
|
158 default: |
|
159 throw CSISException (CSISException::ECrypto, "unknown algorithm"); |
|
160 } |
|
161 } |
|
162 |
|
163 void CSignature::DSAVerify (const TSHADigest& aDigest, X509* aX509) const |
|
164 { |
|
165 assert (aX509); |
|
166 EVP_PKEY* pubkey = X509_get_pubkey (aX509); |
|
167 if (! pubkey) |
|
168 { |
|
169 throw CSISException (CSISException::ECrypto, "no public key in certificate"); |
|
170 } |
|
171 DSA* dsa = EVP_PKEY_get1_DSA (pubkey); |
|
172 if (! dsa) |
|
173 { |
|
174 throw CSISException (CSISException::ECrypto, "not a DSA certificate"); |
|
175 } |
|
176 TUint8* sig = const_cast <TUint8*> (iSISSignature.Data()); |
|
177 int status = DSA_verify (NID_sha1, aDigest, SHA_DIGEST_LENGTH, sig, iSISSignature.DataSize(), dsa); |
|
178 if (status <= 0) |
|
179 { |
|
180 throw CSISException (CSISException::EVerification, "invalid signature"); |
|
181 } |
|
182 } |
|
183 |
|
184 void CSignature::RSAVerify (const TSHADigest& aDigest, X509* aX509) const |
|
185 { |
|
186 assert (aX509); |
|
187 EVP_PKEY* pubkey = X509_get_pubkey (aX509); |
|
188 if (! pubkey) |
|
189 { |
|
190 throw CSISException (CSISException::ECrypto, "no public key in certificate"); |
|
191 } |
|
192 RSA* rsa = EVP_PKEY_get1_RSA (pubkey); |
|
193 if (! rsa) |
|
194 { |
|
195 throw CSISException (CSISException::ECrypto, "not an RSA certificate"); |
|
196 } |
|
197 TUint8* sig = const_cast <TUint8*> (iSISSignature.Data()); |
|
198 int status = RSA_verify (NID_sha1, aDigest, SHA_DIGEST_LENGTH, sig, iSISSignature.DataSize(), rsa); |
|
199 if (! status) |
|
200 { |
|
201 throw CSISException (CSISException::EVerification, "invalid signature"); |
|
202 } |
|
203 } |
|
204 |
|
205 |
|
206 void* CSignature::LoadKey (const std::wstring& aName, const std::wstring& aPassPhrase) |
|
207 { |
|
208 try |
|
209 { |
|
210 return LoadTextKey (aName, aPassPhrase); |
|
211 } |
|
212 catch (...) |
|
213 { |
|
214 try |
|
215 { |
|
216 return LoadBinaryKey (aName, aPassPhrase); |
|
217 } |
|
218 catch (...) |
|
219 { |
|
220 } |
|
221 throw; |
|
222 } |
|
223 } |
|
224 |
|
225 // returns pointer to RSA or DSA, depending on algorithm. |
|
226 void* CSignature::LoadBinaryKey (const std::wstring& aName, const std::wstring& aPassPhrase) |
|
227 { |
|
228 TUint64 size; |
|
229 HANDLE file = OpenFileAndGetSize (aName, &size); |
|
230 TUint8* buffer = NULL; |
|
231 void* reply = NULL; |
|
232 DSA* dsa = NULL; |
|
233 RSA* rsa = NULL; |
|
234 try |
|
235 { |
|
236 buffer = new TUint8 [size]; |
|
237 ReadAndCloseFile (file, size, buffer); |
|
238 file = NULL; |
|
239 const TUint8* buf2 = buffer; |
|
240 bool unknown = ! iSignatureAlgorithm.IsAlgorithmKnown (); |
|
241 if (unknown || (iSignatureAlgorithm.Algorithm () == CSISSignatureAlgorithm::EAlgRSA)) |
|
242 { |
|
243 ERR_clear_error(); |
|
244 rsa = RSA_new (); |
|
245 if (! rsa) |
|
246 { |
|
247 std::cout << ERR_error_string (ERR_get_error (), NULL); |
|
248 throw 2; |
|
249 } |
|
250 if (! d2i_RSAPrivateKey (&rsa, &buf2, size)) |
|
251 { |
|
252 if (! unknown) |
|
253 { |
|
254 std::cout << ERR_error_string (ERR_get_error (), NULL); |
|
255 } |
|
256 RSA_free (rsa); |
|
257 rsa = NULL; |
|
258 } |
|
259 else |
|
260 { |
|
261 if (unknown) |
|
262 { |
|
263 iSignatureAlgorithm.SetAlgorithm (CSISSignatureAlgorithm::EAlgRSA); |
|
264 unknown = false; |
|
265 } |
|
266 reply = rsa; |
|
267 } |
|
268 } |
|
269 if (unknown || (iSignatureAlgorithm.Algorithm () == CSISSignatureAlgorithm::EAlgDSA)) |
|
270 { |
|
271 ERR_clear_error(); |
|
272 dsa = DSA_generate_parameters (DSA_PRIME_SIZE, NULL, 0, NULL, NULL, NULL, NULL); |
|
273 if (! dsa) |
|
274 { |
|
275 std::cout << ERR_error_string (ERR_get_error (), NULL); |
|
276 throw 1; |
|
277 } |
|
278 if (! d2i_DSAPrivateKey (&dsa, &buf2, size)) |
|
279 { |
|
280 std::cout << ERR_error_string (ERR_get_error (), NULL); |
|
281 DSA_free (dsa); |
|
282 dsa = NULL; |
|
283 } |
|
284 else |
|
285 { |
|
286 if (unknown) |
|
287 { |
|
288 iSignatureAlgorithm.SetAlgorithm (CSISSignatureAlgorithm::EAlgDSA); |
|
289 unknown = false; |
|
290 } |
|
291 reply = dsa; |
|
292 } |
|
293 } |
|
294 if (! reply || unknown) |
|
295 { |
|
296 throw 3; |
|
297 } |
|
298 delete [] buffer; |
|
299 } |
|
300 catch (...) |
|
301 { |
|
302 if (rsa) |
|
303 { |
|
304 RSA_free (rsa); |
|
305 } |
|
306 if (dsa) |
|
307 { |
|
308 DSA_free (dsa); |
|
309 } |
|
310 delete [] buffer; |
|
311 if (file) |
|
312 { |
|
313 ::CloseHandle(file); |
|
314 } |
|
315 throw CSISException (CSISException::ECrypto, std::wstring (L"Cannot read ") + aName); |
|
316 } |
|
317 return reply; |
|
318 } |
|
319 |
|
320 void* CSignature::LoadTextKey (const std::wstring& aName, const std::wstring& aPassPhrase) |
|
321 { |
|
322 std::ifstream keyFile; |
|
323 std::string line ; |
|
324 std::string buffer; |
|
325 bool oldPemFormat = false; |
|
326 char *fName = NULL; |
|
327 |
|
328 keyFile.rdbuf()->open(wstring2string (aName).c_str (), std::ios::in); |
|
329 |
|
330 if(!keyFile.is_open()) |
|
331 { |
|
332 if((fName = Copy2TmpFile(aName.c_str(), CERTFILE)) != NULL) |
|
333 { |
|
334 keyFile.rdbuf()->open(fName, std::ios::in); |
|
335 } |
|
336 } |
|
337 |
|
338 //check if file is successfully opened. |
|
339 if(keyFile.is_open()) |
|
340 { |
|
341 //scans the file until it encounters the first header. |
|
342 do |
|
343 { |
|
344 getline(keyFile,line); |
|
345 }while(!(line.find(PEM_HEADER , 0) != std::string::npos)); |
|
346 |
|
347 buffer.append(line); |
|
348 buffer.append("\n"); |
|
349 |
|
350 //scanning the file until the next non blank line is obtained. |
|
351 do |
|
352 { |
|
353 getline(keyFile,line); |
|
354 }while(!(line.length())); |
|
355 |
|
356 //check whether the next non blank line contains the Proc Type Tag. |
|
357 if((line.find(OLD_PEM_FORMAT_TAG , 0)) != std::string::npos) |
|
358 { |
|
359 oldPemFormat = true; |
|
360 } |
|
361 |
|
362 buffer.append(line); |
|
363 buffer.append("\n"); |
|
364 |
|
365 while(!keyFile.eof()) |
|
366 { |
|
367 getline(keyFile , line); |
|
368 |
|
369 //skips any blank line between the Proc Type tag and the encryption algorithm tag |
|
370 //and appends a blank line.After which all the blank lines will be skipped. |
|
371 if(oldPemFormat) |
|
372 { |
|
373 if((line.find(ENCRYPTION_ALGORITHM_TAG , 0) != std::string::npos)) |
|
374 { |
|
375 buffer.append(line); |
|
376 buffer.append("\n\n"); |
|
377 } |
|
378 |
|
379 else if(line.length()) |
|
380 { |
|
381 buffer.append(line); |
|
382 buffer.append("\n"); |
|
383 } |
|
384 } |
|
385 |
|
386 else |
|
387 { |
|
388 //if key file in new format |
|
389 if(line.length()) |
|
390 { |
|
391 buffer.append(line); |
|
392 buffer.append("\n"); |
|
393 } |
|
394 } |
|
395 |
|
396 } |
|
397 } |
|
398 else |
|
399 { |
|
400 CSISException::ThrowIf (1, CSISException::EFileProblem, std::wstring (L"cannot open ") + aName); |
|
401 } |
|
402 |
|
403 BIO* mem = NULL; |
|
404 void* reply = NULL; |
|
405 char* pass = NULL; |
|
406 bool unknown = ! iSignatureAlgorithm.IsAlgorithmKnown (); |
|
407 try |
|
408 { |
|
409 //pass = new char [aPassPhrase.size () + 1]; |
|
410 //strcpy (pass, wstring2string (aPassPhrase).c_str ()); |
|
411 DWORD ilen = aPassPhrase.length(); |
|
412 int targetLen = ConvertWideCharToMultiByte(aPassPhrase.c_str(), -1, NULL, 0, CP_UTF8); |
|
413 pass = new char[targetLen+1]; |
|
414 ConvertWideCharToMultiByte(aPassPhrase.c_str(), -1, pass, targetLen+1, CP_UTF8); |
|
415 if (unknown || (iSignatureAlgorithm.Algorithm () == CSISSignatureAlgorithm::EAlgRSA)) |
|
416 { |
|
417 ERR_clear_error(); |
|
418 //creates a memory BIO and writes the buffer data into it. |
|
419 mem = BIO_new(BIO_s_mem()); |
|
420 BIO_puts(mem , buffer.c_str()); |
|
421 RSA* rsa = RSA_new (); |
|
422 |
|
423 if (! PEM_read_bio_RSAPrivateKey (mem, &rsa, NULL, pass)) |
|
424 { |
|
425 if (! unknown) |
|
426 { |
|
427 std::cout << ERR_error_string (ERR_get_error (), NULL); |
|
428 } |
|
429 BIO_free(mem); |
|
430 RSA_free (rsa); |
|
431 } |
|
432 else |
|
433 { |
|
434 if (unknown) |
|
435 { |
|
436 iSignatureAlgorithm.SetAlgorithm (CSISSignatureAlgorithm::EAlgRSA); |
|
437 unknown = false; |
|
438 } |
|
439 reply = rsa; |
|
440 } |
|
441 } |
|
442 if (unknown || (iSignatureAlgorithm.Algorithm () == CSISSignatureAlgorithm::EAlgDSA)) |
|
443 { |
|
444 ERR_clear_error(); |
|
445 //creates a memory BIO and writes the buffer data into it. |
|
446 mem = NULL; |
|
447 mem = BIO_new(BIO_s_mem()); |
|
448 BIO_puts(mem , buffer.c_str()); |
|
449 DSA* dsa = DSA_generate_parameters (DSA_PRIME_SIZE, NULL, 0, NULL, NULL, NULL, NULL); |
|
450 if (! PEM_read_bio_DSAPrivateKey (mem, &dsa, NULL, pass)) |
|
451 { |
|
452 std::cout << ERR_error_string (ERR_get_error (), NULL); |
|
453 BIO_free(mem); |
|
454 DSA_free (dsa); |
|
455 } |
|
456 else |
|
457 { |
|
458 if (unknown) |
|
459 { |
|
460 iSignatureAlgorithm.SetAlgorithm (CSISSignatureAlgorithm::EAlgDSA); |
|
461 unknown = false; |
|
462 } |
|
463 reply = dsa; |
|
464 } |
|
465 } |
|
466 if (unknown || ! reply) |
|
467 { |
|
468 throw 3; |
|
469 } |
|
470 } |
|
471 catch (...) |
|
472 { |
|
473 if (keyFile.rdbuf()->is_open()) |
|
474 { |
|
475 keyFile.rdbuf()->close(); |
|
476 } |
|
477 if(mem) |
|
478 { |
|
479 BIO_free(mem); |
|
480 } |
|
481 |
|
482 delete[] pass; |
|
483 throw CSISException (CSISException::ECrypto, std::wstring (L"Cannot load ") + aName); |
|
484 } |
|
485 |
|
486 BIO_free(mem); |
|
487 delete pass; |
|
488 return reply; |
|
489 } |
|
490 |
|
491 |
|
492 |