secureswitools/swisistools/source/signsislib/sissignature.cpp
changeset 0 ba25891c3a9e
child 50 c6e8afe0ba85
--- /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 <iostream>
+#include <fstream>
+#include <string>
+
+#include "sissignature.h"
+#include "siscontroller.h"
+
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+
+#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<CSISSignatureAlgorithm&>(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 <DSA*> (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<unsigned char*>(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 <RSA*> (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<unsigned char*>(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 <TUint8*> (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 <TUint8*> (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;
+	}
+
+
+