sl@0: /* sl@0: * Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: #include "pkcs7signedobject.h" sl@0: #include sl@0: #include "pkcs7excert.h" sl@0: #include "pkcs7signerinfo.h" sl@0: #include "pkcs7issuerserial.h" sl@0: #include "pkcs7asn1.h" sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: const TInt KSignedDataCertificates = 0; sl@0: const TInt KSignedDataRevocationLists = 1; sl@0: sl@0: EXPORT_C CPKCS7SignedObject::~CPKCS7SignedObject(void) sl@0: { sl@0: iDigestAlgorithms.ResetAndDestroy(); sl@0: iCertificates.ResetAndDestroy(); sl@0: delete iContentInfo; sl@0: iSignerInfo.ResetAndDestroy(); sl@0: for(TInt i = 0; i < KPKCS7MaxDataElements; i++) sl@0: { sl@0: delete iDataElements.At(i); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C CPKCS7SignedObject::CPKCS7SignedObject(void) sl@0: { sl@0: } sl@0: sl@0: sl@0: EXPORT_C CPKCS7SignedObject* CPKCS7SignedObject::NewLC(const CPKCS7ContentInfo& aContentInfo) sl@0: { sl@0: CPKCS7SignedObject* self = new (ELeave) CPKCS7SignedObject(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aContentInfo); sl@0: return self; sl@0: } sl@0: sl@0: EXPORT_C CPKCS7SignedObject* CPKCS7SignedObject::NewL(const CPKCS7ContentInfo& aContentInfo) sl@0: { sl@0: CPKCS7SignedObject* self = NewLC(aContentInfo); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: EXPORT_C void CPKCS7SignedObject::ConstructL(const CPKCS7ContentInfo& aContentInfo) sl@0: { sl@0: if(aContentInfo.ContentType() != KPkcs7SignedData) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: TASN1DecGeneric decGen(aContentInfo.ContentData()); sl@0: decGen.InitL(); sl@0: sl@0: if(decGen.Tag() == EASN1Sequence) sl@0: { sl@0: InitSignedObjectL(decGen.Encoding()); sl@0: DecodeSignedDataL(*iEncoding); sl@0: } sl@0: else sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C const TPtrC8 CPKCS7SignedObject::SignedDataL() const sl@0: { sl@0: return iContentInfo->ContentData(); sl@0: } sl@0: sl@0: EXPORT_C void CPKCS7SignedObject::InternalizeL(RReadStream& /*aStream*/) sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: EXPORT_C const TPtrC8* CPKCS7SignedObject::DataElementEncoding(const TUint aIndex) const sl@0: { sl@0: return iDataElements.At(aIndex); sl@0: } sl@0: sl@0: sl@0: EXPORT_C const RPointerArray& CPKCS7SignedObject::DigestAlgorithms() const sl@0: { sl@0: return iDigestAlgorithms; sl@0: } sl@0: sl@0: EXPORT_C TInt CPKCS7SignedObject::Version() const sl@0: { sl@0: return iVersion; sl@0: } sl@0: sl@0: EXPORT_C const CPKCS7ContentInfo& CPKCS7SignedObject::ContentInfo() const sl@0: { sl@0: return *iContentInfo; sl@0: } sl@0: sl@0: EXPORT_C const RPointerArray& CPKCS7SignedObject::Certificates() const sl@0: { sl@0: return iCertificates; sl@0: } sl@0: sl@0: EXPORT_C const RPointerArray& CPKCS7SignedObject::SignerInfo() const sl@0: { sl@0: return iSignerInfo; sl@0: } sl@0: sl@0: void CPKCS7SignedObject::InitSignedObjectL(const TDesC8& aRawData) sl@0: { sl@0: // Populate CSignedObject data members sl@0: iKeyFactory = new (ELeave) TX509KeyFactory; sl@0: iEncoding = aRawData.AllocL(); sl@0: sl@0: CSHA1* hash = CSHA1::NewL(); sl@0: CleanupStack::PushL(hash); sl@0: iFingerprint = hash->Hash(Encoding()).AllocL(); sl@0: CleanupStack::PopAndDestroy(hash); sl@0: } sl@0: sl@0: void CPKCS7SignedObject::DecodeSignedDataL(const TDesC8& aRawData) sl@0: { sl@0: CArrayPtr* signedData = PKCS7ASN1::DecodeSequenceLC(aRawData, 4, KPKCS7MaxDataElements); sl@0: TInt totalItems = signedData->Count(); sl@0: TASN1DecInteger decInt; sl@0: sl@0: // decodes version sl@0: iDataElements.At(EVersionNumber) = new(ELeave) TPtrC8(signedData->At(0)->GetContentDER()); sl@0: iVersion = decInt.DecodeDERShortL(*signedData->At(0)); sl@0: // decodes algorithms sl@0: iDataElements.At(EDigestAlgorithms) = new(ELeave) TPtrC8(signedData->At(1)->GetContentDER()); sl@0: DecodeDigestAlgorithmsL(signedData->At(1)->Encoding()); sl@0: // decodes contentinfo sl@0: iDataElements.At(EContentInfo) = new(ELeave) TPtrC8(signedData->At(2)->GetContentDER()); sl@0: iContentInfo = CPKCS7ContentInfo::NewL(signedData->At(2)->Encoding()); sl@0: sl@0: // Checks for optional fields sl@0: TInt pos = 3; // Skip first non-optional fields sl@0: do sl@0: { sl@0: const TASN1DecGeneric& currentItem = *signedData->At(pos); sl@0: switch(currentItem.Tag()) sl@0: { sl@0: case KSignedDataCertificates: sl@0: { sl@0: iDataElements.At(ECertificates) = new(ELeave) TPtrC8(currentItem.GetContentDER()); sl@0: DecodeCertificatesL(currentItem.Encoding()); sl@0: break; sl@0: } sl@0: case KSignedDataRevocationLists: sl@0: { sl@0: sl@0: iDataElements.At(ERevocationLists) = new(ELeave) TPtrC8(currentItem.GetContentDER()); sl@0: DecodeRevocationListsL(currentItem.Encoding()); sl@0: break; sl@0: } sl@0: default: // Non-optional field sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: pos++; sl@0: } sl@0: while(pos < totalItems); sl@0: sl@0: iDataElements.At(ESignedInfo) = new(ELeave) TPtrC8(signedData->At(totalItems-1)->GetContentDER()); sl@0: DecodeSignerInfoL(signedData->At(totalItems-1)->Encoding()); sl@0: sl@0: CleanupStack::PopAndDestroy(signedData); sl@0: } sl@0: sl@0: sl@0: void CPKCS7SignedObject::DecodeDigestAlgorithmsL(const TDesC8& aRawData) sl@0: { sl@0: CArrayPtr* algsData = PKCS7ASN1::DecodeSequenceLC(aRawData); sl@0: TInt count = algsData->Count(); sl@0: CX509AlgorithmIdentifier* alIdent; sl@0: sl@0: for(TInt item = 0; item < count; item++) sl@0: { sl@0: alIdent = CX509AlgorithmIdentifier::NewLC(algsData->At(item)->Encoding()); sl@0: User::LeaveIfError(iDigestAlgorithms.Append(alIdent)); sl@0: CleanupStack::Pop(alIdent); sl@0: } sl@0: CleanupStack::PopAndDestroy(algsData); sl@0: } sl@0: sl@0: void CPKCS7SignedObject::DecodeCertificatesL(const TDesC8& aRawData) sl@0: { sl@0: CArrayPtr* items = NULL; sl@0: TASN1DecGeneric decGen(aRawData); sl@0: decGen.InitL(); sl@0: TASN1DecSequence decSeq; sl@0: // have to do manual decoding of sequence because field is optional sl@0: items = decSeq.DecodeDERLC(decGen); sl@0: TInt count = items->Count(); sl@0: sl@0: CPKCS7ExtendedCertificateOrCertificate* certificate; sl@0: sl@0: for(TInt item = 0; item < count; item++) sl@0: { sl@0: certificate = CPKCS7ExtendedCertificateOrCertificate::NewL(items->At(item)->Encoding()); sl@0: CleanupStack::PushL(certificate); sl@0: User::LeaveIfError(iCertificates.Append(certificate)); sl@0: CleanupStack::Pop(certificate); sl@0: } sl@0: sl@0: CleanupStack::PopAndDestroy(items); sl@0: } sl@0: sl@0: void CPKCS7SignedObject::DecodeRevocationListsL(const TDesC8& /*aRawData*/) sl@0: { sl@0: // not yet supported sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: void CPKCS7SignedObject::DecodeSignerInfoL(const TDesC8& aRawData) sl@0: { sl@0: CArrayPtr* signerInfo = PKCS7ASN1::DecodeSequenceLC(aRawData); sl@0: TInt total = signerInfo->Count(); sl@0: CPKCS7SignerInfo* signer; sl@0: sl@0: for(TInt item = 0; item < total; item ++) sl@0: { sl@0: signer = CPKCS7SignerInfo::NewL(signerInfo->At(item)->Encoding()); sl@0: CleanupStack::PushL(signer); sl@0: User::LeaveIfError(iSignerInfo.Append(signer)); sl@0: CleanupStack::Pop(signer); sl@0: } sl@0: CleanupStack::PopAndDestroy(signerInfo); sl@0: } sl@0: sl@0: EXPORT_C TBool CPKCS7SignedObject::ValidateSignerL(const CPKCS7SignerInfo& aSignerInfo, HBufC8*& aCertChainEncoding) sl@0: { sl@0: TInt certCount = iCertificates.Count(); sl@0: TInt endEntityPos = -1; sl@0: TInt endEncodingSize = 0; sl@0: TPtrC8 endEntityEncoding; sl@0: TInt cert; sl@0: TBool valid = EFalse; sl@0: sl@0: // looks for end entity certificate sl@0: for(cert = 0; cert < certCount; cert++) sl@0: { sl@0: const CX509Certificate& certificate = iCertificates[cert]->Certificate(); sl@0: sl@0: endEncodingSize+= certificate.Encoding().Length(); sl@0: if(certificate.IssuerName().ExactMatchL(aSignerInfo.IssuerAndSerialNumber().IssuerName())) sl@0: { sl@0: endEntityPos = cert; sl@0: endEntityEncoding.Set(certificate.Encoding()); sl@0: valid = ValidateSignatureL(aSignerInfo, certificate); sl@0: } sl@0: } sl@0: sl@0: // checks if end entity was found sl@0: if(endEntityPos != -1) sl@0: { sl@0: // builds the cert chain encoding by putting the end entity first then all remaining sl@0: // certs sl@0: aCertChainEncoding = HBufC8::NewLC(endEncodingSize); sl@0: TPtr8 encodingPtr(aCertChainEncoding->Des()); sl@0: encodingPtr.Copy(endEntityEncoding); sl@0: for(cert = 0; cert < certCount; cert++) sl@0: { sl@0: const CX509Certificate& certificate = iCertificates[cert]->Certificate(); sl@0: sl@0: if(cert != endEntityPos) sl@0: { sl@0: encodingPtr.Append(certificate.Encoding()); sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: return valid; sl@0: } sl@0: sl@0: TBool CPKCS7SignedObject::ValidateSignatureL(const CPKCS7SignerInfo& aSignerInfo, const CX509Certificate& aEndEntityCert) sl@0: { sl@0: iSigningAlgorithm = CX509SigningAlgorithmIdentifier::NewL(aSignerInfo.DigestEncryptionAlgorithm(), aSignerInfo.DigestAlgorithm()); sl@0: if(iSignature) sl@0: { sl@0: delete iSignature; sl@0: iSignature = NULL; sl@0: } sl@0: iSignature = aSignerInfo.EncryptedDigest().AllocL(); sl@0: return VerifySignatureL(aEndEntityCert.PublicKey().KeyData()); sl@0: }