/*
* Copyright (c) 2006-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:
*
*/
#include "cmsutils.h"
#include <asymmetric.h>
#include <asn1enc.h>
#include <asn1dec.h>
#include <cmsdefs.h>
#include <pkcs7excert.h>
#include <x509cert.h>
#include "pkcs7asn1.h"
TInt CmsUtils::DecodeContentTypeL(const TASN1DecGeneric* aASN1DecGeneric)
{
TInt type(0);
if(aASN1DecGeneric->Tag()==EASN1ObjectIdentifier || aASN1DecGeneric->Class() == EUniversal)
{
TASN1DecObjectIdentifier oidDec;
HBufC* oidVal = oidDec.DecodeDERL(*aASN1DecGeneric);
CleanupStack::PushL(oidVal);
// Checks if it is data OID.
if(*oidVal == KCmsDataOID)
{
// The Content Type is indicated by an Integer.
// Here if Content Type is equal to Data then,it is represented by 1
type = EContentTypeData;
}
else if(*oidVal == KCmsSignedDataOID)
{
// The Content Type is indicated by an Integer.
// Here if Content Type is equal to SignedData then,it is represented by 2
type = EContentTypeSignedData;
}
else if(*oidVal == KCmsEnvelopedDataOID)
{
// The Content Type is indicated by an Integer.
// Here if Content Type is equal to EnvelopedData then,it is represented by 3.
type = EContentTypeEnvelopedData;
}
else if(*oidVal == KCmsDigestedDataOID)
{
// The Content Type is indicated by an Integer.
// Here if Content Type is equal to DigestedData then,it is represented by 5.
type = EContentTypeDigestedData;
}
else if(*oidVal == KCmsEncryptedDataOID)
{
// The Content Type is indicated by an Integer.
// Here if Content Type is equal to EncryptedData then,it is represented by 6
type = EContentTypeEncryptedData;
}
else if(*oidVal == KCmsAuthenticatedDataOID)
{
// The Content Type is indicated by an Integer.
// Here if Content Type is equal to EncryptedData then,it is represented by 7
type = EContentTypeAuthenticatedData;
}
else
{
User::Leave(KErrArgument);
}
CleanupStack::PopAndDestroy(oidVal);
}
else
{
User::Leave(KErrArgument);
}
return type;
}
CASN1EncObjectIdentifier* CmsUtils::EncodeContentTypeLC(TInt aContentType)
{
TPtrC oidBuf;
switch (aContentType)
{
case EContentTypeData:
oidBuf.Set(KCmsDataOID());
break;
case EContentTypeSignedData:
oidBuf.Set(KCmsSignedDataOID());
break;
case EContentTypeEnvelopedData:
oidBuf.Set(KCmsEnvelopedDataOID());
break;
case EContentTypeDigestedData:
oidBuf.Set(KCmsDigestedDataOID());
break;
case EContentTypeEncryptedData:
oidBuf.Set(KCmsEncryptedDataOID());
break;
default:
User::Leave(KErrArgument);
}
//Encode the OID
CASN1EncObjectIdentifier* oid=CASN1EncObjectIdentifier::NewLC(oidBuf);
return oid;
}
void CmsUtils::AddCertificateL(RPointerArray<CCmsCertificateChoice>& aCertList, const TDesC8& aCert, CCmsCertificateChoice::TCertificateType aType)
{
TInt found(EFalse);
TInt count=aCertList.Count();
for (TInt i=0;i<count;i++)
{
if (aCertList[i]->CertificateType()==CCmsCertificateChoice::ECertificateAttribute
&& aCert.Compare(*aCertList[i]->AttributeCertificate())==0)
{
found=ETrue;
break;
}
}
if (!found)
{
CCmsCertificateChoice* cert=CCmsCertificateChoice::NewL(aType, aCert);
CleanupStack::PushL(cert);
aCertList.AppendL(cert);
CleanupStack::Pop(cert);
}
}
void CmsUtils::AddCertificateL(RPointerArray<CCmsCertificateChoice>& aCertList, const CX509Certificate& aCert)
{
TInt found(EFalse);
TInt count=aCertList.Count();
for (TInt i=0;i<count;i++)
{
if (aCertList[i]->CertificateType()==CCmsCertificateChoice::ECertificateX509
&& aCert.IsEqualL(aCertList[i]->Certificate()))
{
found=ETrue;
break;
}
}
if (!found)
{
CCmsCertificateChoice* cert=CCmsCertificateChoice::NewL(aCert);
CleanupStack::PushL(cert);
aCertList.AppendL(cert);
CleanupStack::Pop(cert);
}
}
void CmsUtils::AddAlgorithmIdentifierL(RPointerArray<CX509AlgorithmIdentifier>& aAlgorithmIdList, TAlgorithmId aDigestAlgorithm)
{
TInt found(EFalse);
TInt count=aAlgorithmIdList.Count();
for (TInt i=0;i<count;i++)
{
if (aAlgorithmIdList[i]->Algorithm()==aDigestAlgorithm)
{
found=ETrue;
break;
}
}
if (!found)
{
CX509AlgorithmIdentifier* digAlg=CX509AlgorithmIdentifier::NewLC(aDigestAlgorithm, KNullDesC8());
aAlgorithmIdList.AppendL(digAlg);
CleanupStack::Pop(digAlg);
}
}
void CmsUtils::DecodeDigestAlgorithmsL(RPointerArray<CX509AlgorithmIdentifier>& aDigestAlgorithms, const TDesC8& aRawData)
{
CArrayPtr<TASN1DecGeneric>* algsData = PKCS7ASN1::DecodeSequenceLC(aRawData);
TInt count = algsData->Count();
CX509AlgorithmIdentifier* alIdent;
for(TInt item = 0; item < count; item++)
{
alIdent = CX509AlgorithmIdentifier::NewLC(algsData->At(item)->Encoding());
aDigestAlgorithms.AppendL(alIdent);
CleanupStack::Pop(alIdent);
}
CleanupStack::PopAndDestroy(algsData);
}
void CmsUtils::DecodeCertificatesL(RPointerArray<CCmsCertificateChoice>& aCertificates, const TDesC8& aRawData)
{
TASN1DecGeneric decGen(aRawData);
decGen.InitL();
TASN1DecSequence decSeq;
// have to do manual decoding of sequence because field is optional
CArrayPtr<TASN1DecGeneric>* items = NULL;
items = decSeq.DecodeDERLC(decGen);
TInt count = items->Count();
CCmsCertificateChoice* certificate;
for(TInt item = 0; item < count; item++)
{
certificate = CCmsCertificateChoice::NewL(items->At(item)->Encoding());
CleanupStack::PushL(certificate);
aCertificates.AppendL(certificate);
CleanupStack::Pop(certificate);
}
CleanupStack::PopAndDestroy(items);
}
CASN1EncBase* CmsUtils::EncodeCertificatesLC(const RPointerArray<CCmsCertificateChoice>& aCertificates)
{
CASN1EncSet* certSet(NULL);
TInt count=aCertificates.Count();
if (count>0)
{
certSet = CASN1EncSet::NewLC();
for (TInt i=0;i<count;i++)
{
CASN1EncEncoding* cert=aCertificates[i]->EncodeASN1DERLC();
certSet->AddAndPopChildL(cert);
}
// [0] implicit
certSet->SetTag(0);
}
return certSet;
}
CASN1EncBase* CmsUtils::EncodeDigestAlgorithmsLC(const RPointerArray<CX509AlgorithmIdentifier>& aDigestAlgorithms)
{
CASN1EncSet* algorithmSet = CASN1EncSet::NewLC();
TInt count=aDigestAlgorithms.Count();
for (TInt i=0;i<count;i++)
{
CASN1EncSequence* tmp=aDigestAlgorithms[i]->EncodeASN1DERLC();
algorithmSet->AddAndPopChildL(tmp);
}
return algorithmSet;
}
void CmsUtils::DecodeOctetStringL(const TDesC8& aRawData, HBufC8*& aBuf)
{
TASN1DecGeneric decGen(aRawData);
decGen.InitL();
if(decGen.Tag()==EASN1OctetString && decGen.Class()==EUniversal)
{
TASN1DecOctetString decOct;
aBuf = decOct.DecodeDERL(decGen);
}
else
{
User::Leave(KErrArgument);
}
}
CMessageDigest* CmsUtils::CreateHashLC(TAlgorithmId aAlgorithm)
{
CMessageDigest* hash(NULL);
switch (aAlgorithm)
{
case EMD2:
hash=CMD2::NewL();
break;
case EMD5:
hash=CMD5::NewL();
break;
case ESHA1:
hash=CSHA1::NewL();
break;
default:
User::Leave(KErrNotSupported);
}
CleanupStack::PushL(hash);
return hash;
}
HBufC8* CmsUtils::CreateSignatureL(const TDesC8& aDataToBeSigned, TBool aIsHash, TAlgorithmId aAlgorithm, const CDSAPrivateKey& aKey)
{
HBufC8* signature(NULL);
if (!aIsHash)
{
TPtrC8 hashValue;
// Create hash first
CMessageDigest* hash=CreateHashLC(aAlgorithm);
hashValue.Set(hash->Hash(aDataToBeSigned));
signature=CreateSignatureL(hashValue, aKey);
CleanupStack::PopAndDestroy(); // hash
}
else
{
signature=CreateSignatureL(aDataToBeSigned, aKey);
}
return signature;
}
HBufC8* CmsUtils::CreateSignatureL(const TDesC8& aDataToBeSigned, TBool aIsHash, TAlgorithmId aAlgorithm, const CRSAPrivateKey& aKey)
{
HBufC8* signature(NULL);
TPtrC8 hashValue;
if (!aIsHash)
{
// Create hash first
CMessageDigest* hash=CreateHashLC(aAlgorithm);
hashValue.Set(hash->Hash(aDataToBeSigned));
}
else
{
hashValue.Set(aDataToBeSigned);
}
//Build the digestInfo Sequence
CASN1EncSequence* digestInfoSeq = CASN1EncSequence::NewLC();
//Encode the Algorithm
CX509AlgorithmIdentifier* digAlg=CX509AlgorithmIdentifier::NewLC(aAlgorithm, KNullDesC8());
CASN1EncSequence* sigAlg=digAlg->EncodeASN1DERLC();
digestInfoSeq->AddAndPopChildL(sigAlg);
CleanupStack::PopAndDestroy(digAlg);
//Encode the digest itself
CASN1EncOctetString* sigEnc=CASN1EncOctetString::NewLC(hashValue);
digestInfoSeq->AddAndPopChildL(sigEnc);
//Get the Encoding
HBufC8* digestInfo=CreateDEREncodingLC(*digestInfoSeq);
signature=CreateSignatureL(digestInfo->Des(), aKey);
CleanupStack::PopAndDestroy(2, digestInfoSeq); //digestInfo, digestInfoSeq
if (!aIsHash)
{
CleanupStack::PopAndDestroy(); // hash
}
return signature;
}
HBufC8* CmsUtils::CreateSignatureL(const TDesC8& aHash, const CDSAPrivateKey& aKey)
{
//Create Signer and sign the hash
CDSASigner* signer=CDSASigner::NewLC(aKey);
const CDSASignature* sig=signer->SignL(aHash);
CDSASignature* signonc=const_cast<CDSASignature*>(sig);
CleanupStack::PushL(signonc);
//The sequence
CASN1EncSequence* sigSeq = CASN1EncSequence::NewLC();
CASN1EncBigInt* r = CASN1EncBigInt::NewLC(static_cast<const RInteger&>(sig->R()));
sigSeq->AddAndPopChildL(r);
CASN1EncBigInt* s = CASN1EncBigInt::NewLC(static_cast<const RInteger&>(sig->S()));
sigSeq->AddAndPopChildL(s);
//Write the buffer
TUint len=sigSeq->LengthDER();
HBufC8* buf=HBufC8::NewMaxLC(len);
TPtr8 des=buf->Des();
TUint pos=0;
sigSeq->WriteDERL(des, pos);
//Clean up
CleanupStack::Pop(buf); //buf
CleanupStack::PopAndDestroy(3, signer); //sigSeq, signonc, signer
return buf;
}
HBufC8* CmsUtils::CreateSignatureL(const TDesC8& aHash, const CRSAPrivateKey& aKey)
{
//Create Signer and sign the hash
CRSAPKCS1v15Signer* signer=CRSAPKCS1v15Signer::NewLC(aKey);
const CRSASignature* sig=signer->SignL(aHash);
CRSASignature* signonc=const_cast<CRSASignature*>(sig);
CleanupStack::PushL(signonc);
HBufC8* sigData = sig->S().BufferWithNoTruncationLC();
//Clean up
CleanupStack::Pop(sigData);
CleanupStack::PopAndDestroy(2, signer);//signonc signer
return sigData;
}
HBufC8* CmsUtils::CreateDEREncodingLC(const CASN1EncBase& aEncoding)
{
TUint len = aEncoding.LengthDER();
HBufC8* buf = HBufC8::NewMaxLC(len);
TUint pos = 0;
TPtr8 bufptr(buf->Des());
aEncoding.WriteDERL(bufptr, pos);
return buf;
}