diff -r 000000000000 -r ba25891c3a9e secureswitools/swisistools/source/signsislib/sissignature.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/secureswitools/swisistools/source/signsislib/sissignature.cpp Thu Dec 17 08:51:10 2009 +0200 @@ -0,0 +1,492 @@ +/* +* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +/** + @file + @internalComponent + @released +*/ + +#ifdef _MSC_VER +#pragma warning (disable: 4786) +#endif // _MSC_VER + +#include +#include +#include + +#include "sissignature.h" +#include "siscontroller.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RSA_IDENTIFIER L"1.2.840.113549.1.1.5" +#define DSA_IDENTIFIER L"1.2.840.10040.4.3" +#define DSA_PRIME_SIZE 1024 +#define OLD_PEM_FORMAT_TAG "Proc-Type" +#define ENCRYPTION_ALGORITHM_TAG "DEK-Info" +#define PEM_HEADER "----" + +void CalculateHash (TSHADigest& aDigest, const TUint8* aBuffer, TUint32 aBufferSize) + { + assert (aBuffer); + assert (! IsBadReadPtr (aBuffer, aBufferSize)); + memset (&aDigest, 0, SHA_DIGEST_LENGTH); + SHA1 (aBuffer, aBufferSize, aDigest); + } + + +CSignature::CSignature (CSignatureData& aSISSignature): + iSISSignature(aSISSignature), + iSignatureAlgorithm(const_cast(iSISSignature.GetAlgorithm())) + { + } + +CSignature::~CSignature() + { + } + +void CSignature::Sign (const std::wstring& aPrivateKey, const std::wstring& aPassPhrase, const TUint8* aBuffer, const TUint32 aBufferSize) + { + assert (aBuffer); + TSHADigest digest; + CalculateHash (digest, aBuffer, aBufferSize); + void* key = LoadKey (aPrivateKey, aPassPhrase); + assert (key); + switch (iSISSignature.GetAlgorithm().Algorithm()) + { + case CSISSignatureAlgorithm::EAlgRSA : + RSASign (digest, key); + break; + case CSISSignatureAlgorithm::EAlgDSA : + DSASign (digest, key); + break; + default: + throw CSISException (CSISException::ECrypto, "unknown algorithm"); + } + } + + +void CSignature::DSASign (const TSHADigest& aDigest, void* aKey) + { + DSA* dsa = reinterpret_cast (aKey); + assert (dsa); + unsigned int written = 0; + int status = 0; + try + { + unsigned int max = DSA_size (dsa); + iSISSignature.SetDataByteCount(max); + status = DSA_sign (NID_sha1, aDigest, SHA_DIGEST_LENGTH, const_cast(iSISSignature.Data()), &written, dsa); + } + catch (...) + { + status = -1; + } + + if (status <= 0) + { + DSA_free (dsa); + throw CSISException (CSISException::ECrypto, L"cannot create DSA signature"); + } + + CSISException::ThrowIf (written > iSISSignature.DataSize (), CSISException::ECrypto, L"inconsistent DSA sizes"); + } + +void CSignature::RSASign (const TSHADigest& aDigest, void* aKey) + { + RSA* rsa = reinterpret_cast (aKey); + assert (rsa); + unsigned int written = 0; + int status = 0; + try + { + iSISSignature.SetDataByteCount(RSA_size (rsa)); + status = RSA_sign (NID_sha1, aDigest, SHA_DIGEST_LENGTH, const_cast(iSISSignature.Data()), &written, rsa); + } + catch (...) + { + status = -1; + } + + if (status <= 0) + { + RSA_free (rsa); + throw CSISException (CSISException::ECrypto, L"cannot create RSA signature"); + } + CSISException::ThrowIf (written > iSISSignature.DataSize (), CSISException::ECrypto, L"inconsistent RSA sizes"); + } + + +void CSignature::VerifySignature (X509* aX509, const TUint8* aBuffer, const TUint32 aBufferSize) const + { + assert (aBuffer); + TSHADigest digest; + + CalculateHash (digest, aBuffer, aBufferSize); + switch (iSISSignature.GetAlgorithm().Algorithm ()) + { + case CSISSignatureAlgorithm::EAlgRSA : + RSAVerify (digest, aX509); + break; + case CSISSignatureAlgorithm::EAlgDSA : + DSAVerify (digest, aX509); + break; + default: + throw CSISException (CSISException::ECrypto, "unknown algorithm"); + } + } + +void CSignature::DSAVerify (const TSHADigest& aDigest, X509* aX509) const + { + assert (aX509); + EVP_PKEY* pubkey = X509_get_pubkey (aX509); + if (! pubkey) + { + throw CSISException (CSISException::ECrypto, "no public key in certificate"); + } + DSA* dsa = EVP_PKEY_get1_DSA (pubkey); + if (! dsa) + { + throw CSISException (CSISException::ECrypto, "not a DSA certificate"); + } + TUint8* sig = const_cast (iSISSignature.Data()); + int status = DSA_verify (NID_sha1, aDigest, SHA_DIGEST_LENGTH, sig, iSISSignature.DataSize(), dsa); + if (status <= 0) + { + throw CSISException (CSISException::EVerification, "invalid signature"); + } + } + +void CSignature::RSAVerify (const TSHADigest& aDigest, X509* aX509) const + { + assert (aX509); + EVP_PKEY* pubkey = X509_get_pubkey (aX509); + if (! pubkey) + { + throw CSISException (CSISException::ECrypto, "no public key in certificate"); + } + RSA* rsa = EVP_PKEY_get1_RSA (pubkey); + if (! rsa) + { + throw CSISException (CSISException::ECrypto, "not an RSA certificate"); + } + TUint8* sig = const_cast (iSISSignature.Data()); + int status = RSA_verify (NID_sha1, aDigest, SHA_DIGEST_LENGTH, sig, iSISSignature.DataSize(), rsa); + if (! status) + { + throw CSISException (CSISException::EVerification, "invalid signature"); + } + } + + +void* CSignature::LoadKey (const std::wstring& aName, const std::wstring& aPassPhrase) + { + try + { + return LoadTextKey (aName, aPassPhrase); + } + catch (...) + { + try + { + return LoadBinaryKey (aName, aPassPhrase); + } + catch (...) + { + } + throw; + } + } + + // returns pointer to RSA or DSA, depending on algorithm. +void* CSignature::LoadBinaryKey (const std::wstring& aName, const std::wstring& aPassPhrase) + { + TUint64 size; + HANDLE file = OpenFileAndGetSize (aName, &size); + TUint8* buffer = NULL; + void* reply = NULL; + DSA* dsa = NULL; + RSA* rsa = NULL; + try + { + buffer = new TUint8 [size]; + ReadAndCloseFile (file, size, buffer); + file = NULL; + const TUint8* buf2 = buffer; + bool unknown = ! iSignatureAlgorithm.IsAlgorithmKnown (); + if (unknown || (iSignatureAlgorithm.Algorithm () == CSISSignatureAlgorithm::EAlgRSA)) + { + ERR_clear_error(); + rsa = RSA_new (); + if (! rsa) + { + std::cout << ERR_error_string (ERR_get_error (), NULL); + throw 2; + } + if (! d2i_RSAPrivateKey (&rsa, &buf2, size)) + { + if (! unknown) + { + std::cout << ERR_error_string (ERR_get_error (), NULL); + } + RSA_free (rsa); + rsa = NULL; + } + else + { + if (unknown) + { + iSignatureAlgorithm.SetAlgorithm (CSISSignatureAlgorithm::EAlgRSA); + unknown = false; + } + reply = rsa; + } + } + if (unknown || (iSignatureAlgorithm.Algorithm () == CSISSignatureAlgorithm::EAlgDSA)) + { + ERR_clear_error(); + dsa = DSA_generate_parameters (DSA_PRIME_SIZE, NULL, 0, NULL, NULL, NULL, NULL); + if (! dsa) + { + std::cout << ERR_error_string (ERR_get_error (), NULL); + throw 1; + } + if (! d2i_DSAPrivateKey (&dsa, &buf2, size)) + { + std::cout << ERR_error_string (ERR_get_error (), NULL); + DSA_free (dsa); + dsa = NULL; + } + else + { + if (unknown) + { + iSignatureAlgorithm.SetAlgorithm (CSISSignatureAlgorithm::EAlgDSA); + unknown = false; + } + reply = dsa; + } + } + if (! reply || unknown) + { + throw 3; + } + delete [] buffer; + } + catch (...) + { + if (rsa) + { + RSA_free (rsa); + } + if (dsa) + { + DSA_free (dsa); + } + delete [] buffer; + if (file) + { + ::CloseHandle(file); + } + throw CSISException (CSISException::ECrypto, std::wstring (L"Cannot read ") + aName); + } + return reply; + } + +void* CSignature::LoadTextKey (const std::wstring& aName, const std::wstring& aPassPhrase) + { + std::ifstream keyFile; + std::string line ; + std::string buffer; + bool oldPemFormat = false; + char *fName = NULL; + + keyFile.rdbuf()->open(wstring2string (aName).c_str (), std::ios::in); + + if(!keyFile.is_open()) + { + if((fName = Copy2TmpFile(aName.c_str(), CERTFILE)) != NULL) + { + keyFile.rdbuf()->open(fName, std::ios::in); + } + } + + //check if file is successfully opened. + if(keyFile.is_open()) + { + //scans the file until it encounters the first header. + do + { + getline(keyFile,line); + }while(!(line.find(PEM_HEADER , 0) != std::string::npos)); + + buffer.append(line); + buffer.append("\n"); + + //scanning the file until the next non blank line is obtained. + do + { + getline(keyFile,line); + }while(!(line.length())); + + //check whether the next non blank line contains the Proc Type Tag. + if((line.find(OLD_PEM_FORMAT_TAG , 0)) != std::string::npos) + { + oldPemFormat = true; + } + + buffer.append(line); + buffer.append("\n"); + + while(!keyFile.eof()) + { + getline(keyFile , line); + + //skips any blank line between the Proc Type tag and the encryption algorithm tag + //and appends a blank line.After which all the blank lines will be skipped. + if(oldPemFormat) + { + if((line.find(ENCRYPTION_ALGORITHM_TAG , 0) != std::string::npos)) + { + buffer.append(line); + buffer.append("\n\n"); + } + + else if(line.length()) + { + buffer.append(line); + buffer.append("\n"); + } + } + + else + { + //if key file in new format + if(line.length()) + { + buffer.append(line); + buffer.append("\n"); + } + } + + } + } + else + { + CSISException::ThrowIf (1, CSISException::EFileProblem, std::wstring (L"cannot open ") + aName); + } + + BIO* mem = NULL; + void* reply = NULL; + char* pass = NULL; + bool unknown = ! iSignatureAlgorithm.IsAlgorithmKnown (); + try + { + //pass = new char [aPassPhrase.size () + 1]; + //strcpy (pass, wstring2string (aPassPhrase).c_str ()); + DWORD ilen = aPassPhrase.length(); + int targetLen = ConvertWideCharToMultiByte(aPassPhrase.c_str(), -1, NULL, 0, CP_UTF8); + pass = new char[targetLen+1]; + ConvertWideCharToMultiByte(aPassPhrase.c_str(), -1, pass, targetLen+1, CP_UTF8); + if (unknown || (iSignatureAlgorithm.Algorithm () == CSISSignatureAlgorithm::EAlgRSA)) + { + ERR_clear_error(); + //creates a memory BIO and writes the buffer data into it. + mem = BIO_new(BIO_s_mem()); + BIO_puts(mem , buffer.c_str()); + RSA* rsa = RSA_new (); + + if (! PEM_read_bio_RSAPrivateKey (mem, &rsa, NULL, pass)) + { + if (! unknown) + { + std::cout << ERR_error_string (ERR_get_error (), NULL); + } + BIO_free(mem); + RSA_free (rsa); + } + else + { + if (unknown) + { + iSignatureAlgorithm.SetAlgorithm (CSISSignatureAlgorithm::EAlgRSA); + unknown = false; + } + reply = rsa; + } + } + if (unknown || (iSignatureAlgorithm.Algorithm () == CSISSignatureAlgorithm::EAlgDSA)) + { + ERR_clear_error(); + //creates a memory BIO and writes the buffer data into it. + mem = NULL; + mem = BIO_new(BIO_s_mem()); + BIO_puts(mem , buffer.c_str()); + DSA* dsa = DSA_generate_parameters (DSA_PRIME_SIZE, NULL, 0, NULL, NULL, NULL, NULL); + if (! PEM_read_bio_DSAPrivateKey (mem, &dsa, NULL, pass)) + { + std::cout << ERR_error_string (ERR_get_error (), NULL); + BIO_free(mem); + DSA_free (dsa); + } + else + { + if (unknown) + { + iSignatureAlgorithm.SetAlgorithm (CSISSignatureAlgorithm::EAlgDSA); + unknown = false; + } + reply = dsa; + } + } + if (unknown || ! reply) + { + throw 3; + } + } + catch (...) + { + if (keyFile.rdbuf()->is_open()) + { + keyFile.rdbuf()->close(); + } + if(mem) + { + BIO_free(mem); + } + + delete[] pass; + throw CSISException (CSISException::ECrypto, std::wstring (L"Cannot load ") + aName); + } + + BIO_free(mem); + delete pass; + return reply; + } + + +