diff -r 000000000000 -r 2c201484c85f cryptoservices/certificateandkeymgmt/x509/x509cert.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cryptoservices/certificateandkeymgmt/x509/x509cert.cpp Wed Jul 08 11:25:26 2009 +0100 @@ -0,0 +1,1248 @@ +/* +* Copyright (c) 1998-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: +* -- FingerPrint Note: +* Developers have to be aware that if they are going to change the fingerprint for this certificate +* for a different hash, then there are other places that need to reflect this change +* -- Location +* void CX509Certificate::ConstructL(const TDesC8& aBinaryData, TInt& aPos) +* EXPORT_C void CX509Certificate::InternalizeL(RReadStream& aStream) +* Also change the CWTLSCertificate and search for other occurences of the current +* hash. +* -- TeletexString type support Note: +* If the certificate has decoded the members from TeletexString then the return value +* may be incorrect because TeletexString type is not fully supported by this library. +* Instead the decode methods perform a direct conversion from 8 to 16bits by adding +* null characters in the second byte of each character. This will work as expected +* for cases where the string contains ASCII data. +* +*/ + + + + +#include +#include +#include "X509time.h" +#include +#include +#include +#include + +EXPORT_C CPKCS1SignatureResult* CPKCS1SignatureResult::NewL(const CAlgorithmIdentifier& aDigestAlgorithm, const TDesC8& aDigest) + { + CPKCS1SignatureResult* self = CPKCS1SignatureResult::NewLC(aDigestAlgorithm, aDigest); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CPKCS1SignatureResult* CPKCS1SignatureResult::NewLC(const CAlgorithmIdentifier& aDigestAlgorithm, const TDesC8& aDigest) + { + CPKCS1SignatureResult* self = new(ELeave) CPKCS1SignatureResult; + CleanupStack::PushL(self); + self->ConstructL(aDigestAlgorithm, aDigest); + return self; + } + +void CPKCS1SignatureResult::ConstructL(const CAlgorithmIdentifier& aDigestAlgorithm, const TDesC8& aDigest) + { + iDigestAlgorithm = CAlgorithmIdentifier::NewL(aDigestAlgorithm); + iDigest = aDigest.AllocL(); + } + +EXPORT_C TBool CPKCS1SignatureResult::VerifyL(const TDesC8& aResult) + { + + TBool res = EFalse; + TRAPD(err, res = DoVerifyL(aResult)); + if ((err != KErrNone) && (err != KErrArgument)) + { + User::Leave(err); + } + return res; + } + +TBool CPKCS1SignatureResult::DoVerifyL(const TDesC8& aResult) + { + TBool res = EFalse; + TASN1DecSequence decSeq; + TInt pos = 0; + TInt len = aResult.Length(); + + const CArrayPtrFlat* seq = decSeq.DecodeDERLC(aResult, pos); + if (seq->Count() == 2) + { + const TASN1DecGeneric* gen1 = seq->At(0); + const TASN1DecGeneric* gen2 = seq->At(1); + CAlgorithmIdentifier* algId = CX509AlgorithmIdentifier::NewLC(gen1->Encoding()); + HBufC8* digest = gen2->GetContentDER().AllocL(); + if ((*algId == *iDigestAlgorithm) && (*digest == *iDigest) && (pos == len)) + { + res = ETrue; + } + delete digest; + CleanupStack::PopAndDestroy(); + } + CleanupStack::PopAndDestroy(); + return res; + } + + +EXPORT_C CRSAPublicKey* TX509KeyFactory::RSAPublicKeyL(const TDesC8& aEncoding) const + { + return CX509RSAPublicKey::NewL(aEncoding); + } + +EXPORT_C CRSASignatureResult* TX509KeyFactory::RSASignatureResultL(const CAlgorithmIdentifier& aDigestAlgorithm, TDesC8& aDigest) const + { + return CPKCS1SignatureResult::NewL(aDigestAlgorithm, aDigest); + } + +EXPORT_C CDSAPublicKey* TX509KeyFactory::DSAPublicKeyL(const TDesC8& aParamsEncoding, const TDesC8& aEncoding) const + { + return CX509DSAPublicKey::NewL(aParamsEncoding, aEncoding); + } + +EXPORT_C CDSAPublicKey* TX509KeyFactory::DSAPublicKeyL(const CDSAParameters& aParams, const TDesC8& aEncoding) const + { + return CX509DSAPublicKey::NewL(aParams, aEncoding); + } + + +EXPORT_C CDSASignature* TX509KeyFactory::DSASignatureL(const TDesC8& aEncoding) const + { + return CX509DSASignature::NewL(aEncoding); + } + +EXPORT_C CDSAParameters* TX509KeyFactory::DSAParametersL(const TDesC8& aParamsEncoding) const +{ + return (CX509DSAPublicKey::DSAParametersL(aParamsEncoding)); +} + +//CX509ValidityPeriod +EXPORT_C CX509ValidityPeriod* CX509ValidityPeriod::NewL(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509ValidityPeriod::NewL(aBinaryData, pos); + } + +EXPORT_C CX509ValidityPeriod* CX509ValidityPeriod::NewLC(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509ValidityPeriod::NewLC(aBinaryData, pos); + } + +EXPORT_C CX509ValidityPeriod* CX509ValidityPeriod::NewL(const TDesC8& aBinaryData, TInt& aPos) + { + CX509ValidityPeriod* self = CX509ValidityPeriod::NewLC(aBinaryData, aPos); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509ValidityPeriod* CX509ValidityPeriod::NewLC(const TDesC8& aBinaryData, TInt& aPos) + { + CX509ValidityPeriod* self = new(ELeave) CX509ValidityPeriod; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData, aPos); + return self; + } + +CX509ValidityPeriod::CX509ValidityPeriod() + { + } + +void CX509ValidityPeriod::ConstructL(const TDesC8& aBinaryData, TInt& aPos) + { + TASN1DecSequence encSeq; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(aBinaryData, aPos); + if (seq->Count() != 2) + { + User::Leave(KErrArgument); + } + TASN1DecX509Time decTime; + iStart = decTime.DecodeDERL(*(seq->At(0))); + iFinish = decTime.DecodeDERL(*(seq->At(1))); + CleanupStack::PopAndDestroy();//seq + contents + } + +//algorithm id +EXPORT_C CX509AlgorithmIdentifier* CX509AlgorithmIdentifier::NewL(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509AlgorithmIdentifier::NewL(aBinaryData, pos); + } + +EXPORT_C CX509AlgorithmIdentifier* CX509AlgorithmIdentifier::NewLC(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509AlgorithmIdentifier::NewLC(aBinaryData, pos); + } + +EXPORT_C CX509AlgorithmIdentifier* CX509AlgorithmIdentifier::NewL(const TDesC8& aBinaryData, TInt& aPos) + { + CX509AlgorithmIdentifier* self = CX509AlgorithmIdentifier::NewLC(aBinaryData, aPos); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509AlgorithmIdentifier* CX509AlgorithmIdentifier::NewLC(const TDesC8& aBinaryData, TInt& aPos) + { + CX509AlgorithmIdentifier* self = new(ELeave) CX509AlgorithmIdentifier; + CleanupStack::PushL(self); + self->InitializeL(aBinaryData, aPos); + return self; + } + +EXPORT_C CX509AlgorithmIdentifier* CX509AlgorithmIdentifier::NewL(TAlgorithmId aAlgorithmId, const TDesC8& aEncodedParams) + { + CX509AlgorithmIdentifier* self = CX509AlgorithmIdentifier::NewLC(aAlgorithmId, aEncodedParams); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509AlgorithmIdentifier* CX509AlgorithmIdentifier::NewLC(TAlgorithmId aAlgorithmId, const TDesC8& aEncodedParams) + { + CX509AlgorithmIdentifier* self = new(ELeave) CX509AlgorithmIdentifier(aAlgorithmId); + CleanupStack::PushL(self); + self->ConstructL(aEncodedParams); + return self; + } + +CX509AlgorithmIdentifier::CX509AlgorithmIdentifier(TAlgorithmId& aAlgorithmId):CAlgorithmIdentifier(aAlgorithmId) + { + } + + +CX509AlgorithmIdentifier::CX509AlgorithmIdentifier() + { + } + +void CX509AlgorithmIdentifier::InitializeL(const TDesC8& aBinaryData, TInt& aPos) + { + TASN1DecSequence encSeq; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(aBinaryData, aPos, 1, KMaxTInt); + TInt count = seq->Count(); + TASN1DecObjectIdentifier encOID; + HBufC* oid = encOID.DecodeDERL(*(seq->At(0))); + CleanupStack::PushL(oid); + TPtrC oidDes(oid->Des()); + if (oidDes == KDSA) + { + //optional params + if (count > 1)//if we still have stuff left + { + TASN1DecGeneric* gen = seq->At(1); + iEncodedParams = gen->Encoding().AllocL(); + } + else + { + iEncodedParams = HBufC8::NewL(1); + *iEncodedParams = KNullDesC8; + } + iAlgorithmId = EDSA; + CleanupStack::PopAndDestroy(2);//seq, oid + return; + } + if (count > 1) + { + TASN1DecGeneric* gen = seq->At(1); + if (oidDes == KDH) + { + iEncodedParams = gen->Encoding().AllocL(); + iAlgorithmId = EDH; + CleanupStack::PopAndDestroy(2);//seq, oid + return; + } + if (oidDes == KRSA) + { + iAlgorithmId = ERSA; + TASN1DecNull null; + null.DecodeDERL(*gen);//just to check the syntax is OK + iEncodedParams = HBufC8::NewL(1); + *iEncodedParams = KNullDesC8; + CleanupStack::PopAndDestroy(2);//seq, oid + return; + } + if (oidDes == KMD5) + { + iAlgorithmId = EMD5; + TASN1DecNull null; + null.DecodeDERL(*gen);//just to check the syntax is OK + iEncodedParams = HBufC8::NewL(1); + *iEncodedParams = KNullDesC8; + CleanupStack::PopAndDestroy(2);//seq, oid + return; + } + if (oidDes == KMD2) + { + iAlgorithmId = EMD2; + TASN1DecNull null; + null.DecodeDERL(*gen);//just to check the syntax is OK + iEncodedParams = HBufC8::NewL(1); + *iEncodedParams = KNullDesC8; + CleanupStack::PopAndDestroy(2);//seq, oid + return; + } + if (oidDes == KSHA1) + { + iAlgorithmId = ESHA1; + TASN1DecNull null; + null.DecodeDERL(*gen);//just to check the syntax is OK + iEncodedParams = HBufC8::NewL(1); + *iEncodedParams = KNullDesC8; + CleanupStack::PopAndDestroy(2);//seq, oid + return; + } + } + User::Leave(KErrNotSupported); + } + +EXPORT_C CASN1EncSequence* CX509AlgorithmIdentifier::EncodeASN1DERLC() const + { + // the root sequence contains the signed object + CASN1EncSequence* root = CASN1EncSequence::NewLC(); + + //encode the oid + CASN1EncObjectIdentifier* oid(NULL); + switch (iAlgorithmId) + { + case EDSA: + oid=CASN1EncObjectIdentifier::NewLC(KDSA); + break; + + case EDH: + oid=CASN1EncObjectIdentifier::NewLC(KDH); + break; + + case ERSA: + oid=CASN1EncObjectIdentifier::NewLC(KRSA); + break; + + case EMD5: + oid=CASN1EncObjectIdentifier::NewLC(KMD5); + break; + + case EMD2: + oid=CASN1EncObjectIdentifier::NewLC(KMD2); + break; + + case ESHA1: + oid=CASN1EncObjectIdentifier::NewLC(KSHA1); + break; + + default: + User::Leave(KErrNotSupported); + } + + root->AddAndPopChildL(oid); + + //Encode parameters + if (*iEncodedParams!=KNullDesC8) + { + CASN1EncEncoding* enc=CASN1EncEncoding::NewLC(*iEncodedParams); + root->AddAndPopChildL(enc); + } + else + { + if (iAlgorithmId!=EDSA) + { + CASN1EncNull* enc=CASN1EncNull::NewLC(); + root->AddAndPopChildL(enc); + } + } + + return root; + } + + +//signing algorithm id +EXPORT_C CX509SigningAlgorithmIdentifier* CX509SigningAlgorithmIdentifier::NewL(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509SigningAlgorithmIdentifier::NewL(aBinaryData, pos); + } + +EXPORT_C CX509SigningAlgorithmIdentifier* CX509SigningAlgorithmIdentifier::NewLC(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509SigningAlgorithmIdentifier::NewLC(aBinaryData, pos); + } + +EXPORT_C CX509SigningAlgorithmIdentifier* CX509SigningAlgorithmIdentifier::NewL(const TDesC8& aBinaryData, TInt& aPos) + { + CX509SigningAlgorithmIdentifier* self = CX509SigningAlgorithmIdentifier::NewLC(aBinaryData, aPos); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509SigningAlgorithmIdentifier* CX509SigningAlgorithmIdentifier::NewLC(const TDesC8& aBinaryData, TInt& aPos) + { + CX509SigningAlgorithmIdentifier* self = new(ELeave) CX509SigningAlgorithmIdentifier; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData, aPos); + return self; + } + +EXPORT_C CX509SigningAlgorithmIdentifier* CX509SigningAlgorithmIdentifier::NewL(const CAlgorithmIdentifier& aAsymmetricAlgorithm, const CAlgorithmIdentifier& aDigestAlgorithm) + { + CX509SigningAlgorithmIdentifier* self = CX509SigningAlgorithmIdentifier::NewLC(aAsymmetricAlgorithm, aDigestAlgorithm); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509SigningAlgorithmIdentifier* CX509SigningAlgorithmIdentifier::NewLC(const CAlgorithmIdentifier& aAsymmetricAlgorithm, const CAlgorithmIdentifier& aDigestAlgorithm) + { + CX509SigningAlgorithmIdentifier* self = new(ELeave) CX509SigningAlgorithmIdentifier; + CleanupStack::PushL(self); + self->ConstructL(aAsymmetricAlgorithm, aDigestAlgorithm); + return self; + } + +CX509SigningAlgorithmIdentifier::CX509SigningAlgorithmIdentifier() + { + } + +void CX509SigningAlgorithmIdentifier::ConstructL(const TDesC8& aBinaryData, TInt& aPos) + { + TASN1DecSequence encSeq; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(aBinaryData, aPos, 1, KMaxTInt); + TInt count = seq->Count(); + TASN1DecObjectIdentifier encOID; + HBufC* oid = encOID.DecodeDERL(*(seq->At(0))); + CleanupStack::PushL(oid); + TPtrC oidDes(oid->Des()); + //none of the signing algorithms we support have parameters here... + HBufC8* encodedParams = HBufC8::NewLC(1); + *encodedParams = KNullDesC8; + + if (oidDes == KDSAWithSHA1) + { + //should be no params, but we allow params encoded as NULL for interop reasons + TAlgorithmId algId = EDSA; + TAlgorithmId digestId = ESHA1; + iDigestAlgorithm = CAlgorithmIdentifier::NewL(digestId, encodedParams->Des()); + iAsymmetricAlgorithm = CAlgorithmIdentifier::NewL(algId, encodedParams->Des()); + if (count == 1) + { + CleanupStack::PopAndDestroy(3);//seq, oid, encodedParams + return; + } + } + + if (oidDes == KMD2WithRSA) + { + TAlgorithmId algId = ERSA; + TAlgorithmId digestId = EMD2; + iDigestAlgorithm = CAlgorithmIdentifier::NewL(digestId, encodedParams->Des()); + iAsymmetricAlgorithm = CAlgorithmIdentifier::NewL(algId, encodedParams->Des()); + } + + if (oidDes == KMD5WithRSA) + { + TAlgorithmId algId = ERSA; + TAlgorithmId digestId = EMD5; + iDigestAlgorithm = CAlgorithmIdentifier::NewL(digestId, encodedParams->Des()); + iAsymmetricAlgorithm = CAlgorithmIdentifier::NewL(algId, encodedParams->Des()); + } + + if (oidDes == KSHA1WithRSA) + { + TAlgorithmId algId = ERSA; + TAlgorithmId digestId = ESHA1; + iDigestAlgorithm = CAlgorithmIdentifier::NewL(digestId, encodedParams->Des()); + iAsymmetricAlgorithm = CAlgorithmIdentifier::NewL(algId, encodedParams->Des()); + } + //???not sure if we should just leave here... + if (iDigestAlgorithm == NULL) + { + User::Leave(KErrNotSupported); + } + else + { + if (count != 2) + { + // Shouldn't ever get here, since RFC2459 mandates having 2 + // data items. However, some people miss out the second + // when it's NULL, so we'll not report and error here + } + else + { + TASN1DecGeneric* gen = seq->At(1); + TASN1DecNull null; + null.DecodeDERL(*gen);//just to check the syntax is OK + } + } + CleanupStack::PopAndDestroy(3);//seq, oid, encodedParams + } + +void CX509SigningAlgorithmIdentifier::ConstructL(const CAlgorithmIdentifier& aAsymmetricAlgorithm, const CAlgorithmIdentifier& aDigestAlgorithm) + { + iDigestAlgorithm = CAlgorithmIdentifier::NewL(aDigestAlgorithm); + iAsymmetricAlgorithm = CAlgorithmIdentifier::NewL(aAsymmetricAlgorithm); + }; + +//subject public key info +EXPORT_C CX509SubjectPublicKeyInfo* CX509SubjectPublicKeyInfo::NewL(const TDesC8& aBinaryData, TInt& aPos) + { + CX509SubjectPublicKeyInfo* self = CX509SubjectPublicKeyInfo::NewLC(aBinaryData, aPos); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509SubjectPublicKeyInfo* CX509SubjectPublicKeyInfo::NewLC(const TDesC8& aBinaryData, TInt& aPos) + { + CX509SubjectPublicKeyInfo* self = new(ELeave) CX509SubjectPublicKeyInfo; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData, aPos); + return self; + } + +EXPORT_C CX509SubjectPublicKeyInfo* CX509SubjectPublicKeyInfo::NewL(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509SubjectPublicKeyInfo::NewL(aBinaryData, pos); + } + +EXPORT_C CX509SubjectPublicKeyInfo* CX509SubjectPublicKeyInfo::NewLC(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509SubjectPublicKeyInfo::NewLC(aBinaryData, pos); + } + +CX509SubjectPublicKeyInfo::CX509SubjectPublicKeyInfo() + { + } + +void CX509SubjectPublicKeyInfo::ConstructL(const TDesC8& aBinaryData, TInt& aPos) + { + TASN1DecSequence encSeq; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(aBinaryData, aPos, 2, KMaxTInt); + iAlgId = CX509AlgorithmIdentifier::NewL(seq->At(0)->Encoding()); + TASN1DecBitString encBS; + iEncodedKeyData = encBS.ExtractOctetStringL(*(seq->At(1))); + CleanupStack::PopAndDestroy();//seq + } + +//generic X 509 extension syntax +EXPORT_C CX509CertExtension* CX509CertExtension::NewL(const CX509CertExtension& aExtension) + { + CX509CertExtension* self = CX509CertExtension::NewLC(aExtension); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509CertExtension* CX509CertExtension::NewLC(const CX509CertExtension& aExtension) + { + CX509CertExtension* self = new(ELeave) CX509CertExtension; + CleanupStack::PushL(self); + self->ConstructL(aExtension); + return self; + } + +EXPORT_C CX509CertExtension* CX509CertExtension::NewL(const TDesC8& aBinaryData, TInt& aPos) + { + CX509CertExtension* self = CX509CertExtension::NewLC(aBinaryData, aPos); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509CertExtension* CX509CertExtension::NewLC(const TDesC8& aBinaryData, TInt& aPos) + { + CX509CertExtension* self = new(ELeave) CX509CertExtension; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData, aPos); + return self; + } + +EXPORT_C CX509CertExtension* CX509CertExtension::NewL(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509CertExtension::NewL(aBinaryData, pos); + } + +EXPORT_C CX509CertExtension* CX509CertExtension::NewLC(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509CertExtension::NewLC(aBinaryData, pos); + } + +EXPORT_C CX509CertExtension* CX509CertExtension::NewL(const TDesC& aCertExtOID, + const TBool aCritical, + const TDesC8& aCertExtValue) + { + CX509CertExtension* self = CX509CertExtension::NewLC(aCertExtOID, aCritical, aCertExtValue); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509CertExtension* CX509CertExtension::NewLC(const TDesC& aCertExtOID, + const TBool aCritical, + const TDesC8& aCertExtValue) + { + CX509CertExtension* self = new(ELeave) CX509CertExtension; + CleanupStack::PushL(self); + self->ConstructL(aCertExtOID, aCritical, aCertExtValue); + return self; + } + +void CX509CertExtension::ConstructL(const CX509CertExtension& aExtension) + { + iCritical = aExtension.iCritical; + iId = aExtension.iId->Des().AllocL(); + iData = aExtension.iData->Des().AllocL(); + } + +void CX509CertExtension::ConstructL(const TDesC8& aBinaryData, TInt& aPos) + { + TASN1DecSequence encSeq; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(aBinaryData, aPos, 2, KMaxTInt); + + TASN1DecObjectIdentifier encOID; + iId = encOID.DecodeDERL(*(seq->At(0))); + //second is either critical flag, or the ext + TASN1DecGeneric* second = seq->At(1); + if (second->Tag() != EASN1Boolean) + { + iData = second->Encoding().AllocL(); + aPos += second->LengthDER(); + } + else + { + TASN1DecBoolean encBool; + iCritical = encBool.DecodeDERL(*second); + if (seq->Count() != 3) + { + User::Leave(KErrArgument); + } + + TASN1DecGeneric* third = seq->At(2); + iData = third->Encoding().AllocL(); + } + CleanupStack::PopAndDestroy();//seq + } + +void CX509CertExtension::ConstructL(const TDesC& aCertExtOID, + const TBool aCritical, + const TDesC8& aCertExtValue) + { + iId = aCertExtOID.AllocL(); + iCritical = aCritical; + iData = aCertExtValue.AllocL(); + } + +EXPORT_C CX509CertExtension::~CX509CertExtension() + { + delete iData; + delete iId; + } + +EXPORT_C TBool CX509CertExtension::Critical() const + { + return iCritical; + } + +EXPORT_C TPtrC CX509CertExtension::Id() const //OID for the extension + { + return iId->Des(); + } + +EXPORT_C TPtrC8 CX509CertExtension::Data() const //the extension itself + { + return iData->Des(); + } + +EXPORT_C CASN1EncSequence* CX509CertExtension::EncodeASN1DERLC() const + { + CASN1EncSequence *result = CASN1EncSequence::NewLC(); + CASN1EncObjectIdentifier* oid = CASN1EncObjectIdentifier::NewLC(*iId); + result->AddAndPopChildL(oid); + // Encode critical flag only if true + if (iCritical) + { + CASN1EncBoolean *critical = CASN1EncBoolean::NewLC(iCritical); + result->AddAndPopChildL(critical); + } + CASN1EncOctetString *data = CASN1EncOctetString::NewLC(*iData); + result->AddAndPopChildL(data); + return result; + } + +CX509CertExtension::CX509CertExtension() + :iCritical(EFalse) + { + } + +//CX509Certificate +EXPORT_C CX509Certificate* CX509Certificate::NewL(const CX509Certificate& aCert) + { + CX509Certificate* self = CX509Certificate::NewLC(aCert); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CX509Certificate* CX509Certificate::NewLC(const CX509Certificate& aCert) + { + CX509Certificate* self = new(ELeave) CX509Certificate; + CleanupStack::PushL(self); + self->ConstructL(aCert); + return self; + } + +EXPORT_C CX509Certificate* CX509Certificate::NewL(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509Certificate::NewL(aBinaryData, pos); + } + +EXPORT_C CX509Certificate* CX509Certificate::NewLC(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509Certificate::NewLC(aBinaryData, pos); + } + +EXPORT_C CX509Certificate* CX509Certificate::NewL(const TDesC8& aBinaryData, TInt& aPos) + { + CX509Certificate* self = CX509Certificate::NewLC(aBinaryData, aPos); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509Certificate* CX509Certificate::NewLC(const TDesC8& aBinaryData, TInt& aPos) + { + CX509Certificate* self = new(ELeave) CX509Certificate(); + CleanupStack::PushL(self); + self->ConstructL(aBinaryData, aPos); + return self; + } + +EXPORT_C CX509Certificate* CX509Certificate::NewL(RReadStream& aStream) + { + CX509Certificate* self = CX509Certificate::NewLC(aStream); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CX509Certificate* CX509Certificate::NewLC(RReadStream& aStream) + { + CX509Certificate* self = new(ELeave) CX509Certificate; + CleanupStack::PushL(self); + self->InternalizeL(aStream); + return self; + } + +void CX509Certificate::ConstructL(const TDesC8& aBinaryData, TInt& aPos) + { + TASN1DecGeneric gen(aBinaryData.Right(aBinaryData.Length() - aPos)); + gen.InitL(); + + // The outermost tag for X509 certificates is always a sequence. + // Since this tag does not form part of the signed data it is possible + // to corrupt the tag by changing it to any other ASN.1 tag and process + // the rest of the certificate as normal. + // However, we still reject the certificate anyway to avoid + // confusion because the data does not match the X.509 specification. + if (gen.Tag() != EASN1Sequence) + { + User::Leave(KErrArgument); + } + + aPos += gen.LengthDER(); + iKeyFactory = new(ELeave) TX509KeyFactory; + + iEncoding = gen.Encoding().AllocL(); + + TASN1DecSequence encSeq; + TInt pos = 0; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(*iEncoding, pos, 3, 3); + TASN1DecGeneric* encSigAlg = seq->At(1); + iSigningAlgorithm = CX509SigningAlgorithmIdentifier::NewL(encSigAlg->Encoding()); + TASN1DecBitString encBS; + iSignature = encBS.ExtractOctetStringL(*(seq->At(2))); + CleanupStack::PopAndDestroy();//seq + + CSHA1* hash = CSHA1::NewL(); + CleanupStack::PushL(hash); + iFingerprint = hash->Final(Encoding()).AllocL(); + CleanupStack::PopAndDestroy();//hash + ConstructCertL(); + } + +void CX509Certificate::ConstructL(const CX509Certificate& aCertificate) + { + iKeyFactory = new(ELeave) TX509KeyFactory; + + iEncoding = aCertificate.iEncoding->AllocL(); + iSignature = aCertificate.iSignature->AllocL(); + iFingerprint = aCertificate.iFingerprint->AllocL(); + iSigningAlgorithm = CSigningAlgorithmIdentifier::NewL(aCertificate.SigningAlgorithm()); + iSerialNumber = aCertificate.iSerialNumber->Des().AllocL(); + iIssuerName = CX500DistinguishedName::NewL(*(aCertificate.iIssuerName)); + iValidityPeriod = new(ELeave) CValidityPeriod(*(aCertificate.iValidityPeriod)); + iSubjectName = CX500DistinguishedName::NewL(*(aCertificate.iSubjectName)); + iSubjectPublicKeyInfo = CSubjectPublicKeyInfo::NewL(*(aCertificate.iSubjectPublicKeyInfo)); + iIssuerUid = aCertificate.iIssuerUid->Des().AllocL(); + iSubjectUid = aCertificate.iSubjectUid->Des().AllocL(); + iExtensions = new(ELeave) CArrayPtrFlat (1); + TInt count = aCertificate.iExtensions->Count(); + for (TInt i = 0; i < count; i++) + { + CX509CertExtension* ext = CX509CertExtension::NewLC(*aCertificate.iExtensions->At(i)); + iExtensions->AppendL(ext); + CleanupStack::Pop();//ext + } + iVersion = aCertificate.Version(); + InitDataElementsL(aCertificate); + } + +void CX509Certificate::InitDataElementsL(const CX509Certificate& aCertificate) + { + iDataElements = new(ELeave) TFixedArray; + iDataElements->Reset(); + TPtrC8 signedData = SignedDataL(); + TASN1DecSequence encSeq; + TInt pos = 0; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(signedData, pos, 6, KMaxTInt);//6 is the minimum number of elements in an x509 cert + pos = 0; + + TPtrC8** pElement = iDataElements->Begin(); + *pElement++ = aCertificate.DataElementEncoding(CX509Certificate::EVersionNumber)? new(ELeave) TPtrC8(seq->At(pos++)->Encoding()):NULL; + for (TInt i = 0; i < 6; i++) //init all the non-optional elements + { + *pElement++ = new(ELeave) TPtrC8(seq->At(pos++)->Encoding()); + } + *pElement++ = aCertificate.DataElementEncoding(CX509Certificate::EIssuerUID)? new(ELeave) TPtrC8(seq->At(pos++)->Encoding()):NULL; + *pElement++ = aCertificate.DataElementEncoding(CX509Certificate::ESubjectUID)? new(ELeave) TPtrC8(seq->At(pos++)->Encoding()):NULL; + *pElement++ = aCertificate.DataElementEncoding(CX509Certificate::EExtensionList)? new(ELeave) TPtrC8(seq->At(pos++)->Encoding()):NULL; + CleanupStack::PopAndDestroy(); + } + +void CX509Certificate::ConstructCertL() + { + TPtrC8 signedData = SignedDataL(); + TASN1DecSequence encSeq; + TInt pos = 0; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(signedData, pos, 6, KMaxTInt);//6 is the minimum number of elements in an x509 cert + TInt count = seq->Count(); + pos = 0; + TASN1DecGeneric* curr = seq->At(pos); + pos++; + iDataElements = new(ELeave) TFixedArray; + iDataElements->Reset(); + TPtrC8** pElement = iDataElements->Begin(); + if ((curr->Class() == EContextSpecific) && (curr->Tag() == 0)) + { + //version! + TASN1DecGeneric ver(curr->GetContentDER()); + ver.InitL(); + TPtrC8 pVer8 = ver.GetContentDER(); + if(pVer8.Length() != 1) + { + User::Leave(KErrArgument); + } + iVersion = (pVer8[0]) + 1; + if ((iVersion < 1) || (iVersion > 3) || (count < 7)) + { + User::Leave(KErrArgument); + } + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + curr = seq->At(pos); + pos++; + } + else + { + *pElement++ = NULL; + } + if (curr->Tag() != EASN1Integer) + { + User::Leave(KErrArgument); + } + iSerialNumber = (curr->GetContentDER()).AllocL(); + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + curr = seq->At(pos); + pos++; + CX509SigningAlgorithmIdentifier* algorithmId = CX509SigningAlgorithmIdentifier::NewLC(curr->Encoding()); + if (!(SigningAlgorithm() == *(algorithmId))) + { + User::Leave(KErrArgument); + } + CleanupStack::PopAndDestroy();//algorithmId + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + + curr = seq->At(pos); + pos++; + iIssuerName = CX500DistinguishedName::NewL(curr->Encoding()); + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + curr = seq->At(pos); + pos++; + iValidityPeriod = CX509ValidityPeriod::NewL(curr->Encoding()); + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + curr = seq->At(pos); + pos++; + iSubjectName = CX500DistinguishedName::NewL(curr->Encoding()); + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + curr = seq->At(pos); + pos++; + iSubjectPublicKeyInfo = CX509SubjectPublicKeyInfo::NewL(curr->Encoding()); + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + //do issuer uid, subject uid, exts + //these are all optional + TBool hasIssuerUid = EFalse; + TBool hasSubjectUid = EFalse; + TBool hasExts = EFalse; + iExtensions = new(ELeave)CArrayPtrFlat (1); + if (pos < count)//otherwise there aren't any of 'em + { + curr = seq->At(pos); + pos++; + if (curr->Class() != EContextSpecific) + { + User::Leave(KErrArgument); + } + switch(curr->Tag()) + { + case 1: + { + iIssuerUid = DecodeUidL(curr->GetContentDER(), hasIssuerUid); + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + break; + } + case 2: + { + iSubjectUid = DecodeUidL(curr->GetContentDER(), hasSubjectUid); + *pElement++ = NULL; + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + break; + } + case 3: + { + DecodeExtsL(curr->GetContentDER(), hasExts); + *pElement++ = NULL; + *pElement++ = NULL; + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + break; + } + default: + { + User::Leave(KErrArgument); + } + } + if (pos < count) + { + curr = seq->At(pos); + pos++; + switch(curr->Tag()) + { + case 2: + { + iSubjectUid = DecodeUidL(curr->GetContentDER(), hasSubjectUid); + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + break; + } + case 3: + { + DecodeExtsL(curr->GetContentDER(), hasExts); + *pElement++ = NULL; + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + break; + } + default: + { + User::Leave(KErrArgument); + } + } + if (pos < count) + { + curr = seq->At(pos); + pos++; + if (curr->Tag() == 3) + { + DecodeExtsL(curr->GetContentDER(), hasExts); + *pElement++ = new(ELeave) TPtrC8(curr->Encoding()); + } + else + { + User::Leave(KErrArgument); + } + } + } + } + if (pos != count) + { + User::Leave(KErrArgument); + } + if (!iIssuerUid) + { + iIssuerUid = HBufC8::NewL(1); + *iIssuerUid = KNullDesC8; + } + if (!iSubjectUid) + { + iSubjectUid = HBufC8::NewL(1); + *iSubjectUid = KNullDesC8; + } + + // we have not checked for the certificate version number based on + // the certificate contents. This is primarily done to avoid BC for + // clients who are still using malformed certificates. + + CleanupStack::PopAndDestroy();//seq + } + +CX509Certificate::CX509Certificate() + :iVersion(1) + { + } + +EXPORT_C CX509Certificate::~CX509Certificate() + { + delete iIssuerName; + delete iSubjectName; + delete iIssuerUid; + delete iSubjectUid; + + if (iDataElements != NULL) + { + for (TInt i = 0; i < KX509MaxDataElements; i++) + { + delete iDataElements->At(i); + } + delete iDataElements; + } + if (iExtensions != NULL) + { + iExtensions->ResetAndDestroy(); + } + delete iExtensions; + } + +EXPORT_C TBool CX509Certificate::IsEqualL(const CX509Certificate& aCert) const + { + return ( (*(iSerialNumber) == *(aCert.iSerialNumber)) && + (iIssuerName->ExactMatchL(*(aCert.iIssuerName))) ); + } + +EXPORT_C void CX509Certificate::InternalizeL(RReadStream& aStream) + { + if (iIssuerName != NULL) //just to check cert is uninitialised + { + User::Leave(KErrArgument); + } + iKeyFactory = new(ELeave) TX509KeyFactory; + + TInt len = aStream.ReadInt32L(); //Read the length of the streamed encoding + HBufC8* temp= HBufC8::NewLC(len); + TPtr8 ptr=temp->Des(); + aStream.ReadL(ptr,len); + iEncoding=temp->AllocL(); + CleanupStack::PopAndDestroy(); // temp + + TASN1DecSequence encSeq; + TInt pos = 0; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(*iEncoding, pos, 3, 3); + TASN1DecGeneric* encSigAlg = seq->At(1); + iSigningAlgorithm = CX509SigningAlgorithmIdentifier::NewL(encSigAlg->Encoding()); + TASN1DecBitString encBS; + iSignature = encBS.ExtractOctetStringL(*(seq->At(2))); + CleanupStack::PopAndDestroy();//seq + + CSHA1* hash = CSHA1::NewL(); + CleanupStack::PushL(hash); + iFingerprint = hash->Final(Encoding()).AllocL(); + CleanupStack::PopAndDestroy();//hash + + ConstructCertL(); + } + +void CX509Certificate::DecodeExtsL(const TDesC8& aBinaryData, TBool& aHasElementAlready) + { + TASN1DecSequence encSeq; + TInt pos = 0; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(aBinaryData, pos); + TInt count = seq->Count(); + for (TInt i = 0; i < count; i++) + { + TASN1DecGeneric* gen = seq->At(i); + CX509CertExtension* ext = CX509CertExtension::NewLC(gen->Encoding()); + iExtensions->AppendL(ext); + CleanupStack::Pop();//ext + } + CleanupStack::PopAndDestroy();// + aHasElementAlready = ETrue; + } + +HBufC8* CX509Certificate::DecodeUidL(const TDesC8& aBinaryData, TBool& aHasElementAlready) + { + if ((aHasElementAlready) || (iVersion ==1)) + { + User::Leave(KErrArgument); + } + aHasElementAlready = ETrue; + return aBinaryData.AllocL(); + } + +//***************************************************************************************// +//extra accessors +EXPORT_C const TPtrC8 CX509Certificate::SignedDataL() const + { + TASN1DecSequence encSeq; + TInt pos = 0; + CArrayPtrFlat* seq = encSeq.DecodeDERLC(*iEncoding, pos, 3, 3); + TASN1DecGeneric* gen = seq->At(0); + TPtrC8 res = gen->Encoding(); + CleanupStack::PopAndDestroy(); + return res; + } + +EXPORT_C TInt CX509Certificate::Version() const + { + return iVersion; + } + +/** +* If the certificate has decoded the members from TeletexString then the return value +* may be incorrect because TeletexString type is not fully supported by this library. +* Instead the decode methods perform a direct conversion from 8 to 16bits by adding +* null characters in the second byte of each character. This will work as expected +* for cases where the string contains ASCII data. +*/ +EXPORT_C const CX500DistinguishedName& CX509Certificate::IssuerName() const + { + return *iIssuerName; + } + +/** +* If the certificate has decoded the members from TeletexString then the return value +* may be incorrect because TeletexString type is not fully supported by this library. +* Instead the decode methods perform a direct conversion from 8 to 16bits by adding +* null characters in the second byte of each character. This will work as expected +* for cases where the string contains ASCII data. +*/ +EXPORT_C const CX500DistinguishedName& CX509Certificate::SubjectName() const + { + return *iSubjectName; + } + +EXPORT_C const CArrayPtrFlat& CX509Certificate::Extensions() const + { + return *iExtensions; + } + +EXPORT_C const CX509CertExtension* CX509Certificate::Extension(const TDesC& aExtensionName) const + { + TInt count = iExtensions->Count(); + for (TInt i = 0; i < count; i++) + { + CX509CertExtension* ext = iExtensions->At(i); + if (ext->Id() == aExtensionName) + return ext; + } + return NULL; + } + +EXPORT_C const TPtrC8* CX509Certificate::DataElementEncoding(const TUint aIndex) const + { + return iDataElements->At(aIndex); + } + +/** +* If the certificate has decoded the members from TeletexString then the return value +* may be incorrect because TeletexString type is not fully supported by this library. +* Instead the decode methods perform a direct conversion from 8 to 16bits by adding +* null characters in the second byte of each character. This will work as expected +* for cases where the string contains ASCII data. +*/ +EXPORT_C HBufC* CX509Certificate::IssuerL() const + { + return iIssuerName->DisplayNameL(); + } + +/** +* If the certificate has decoded the members from TeletexString then the return value +* may be incorrect because TeletexString type is not fully supported by this library. +* Instead the decode methods perform a direct conversion from 8 to 16bits by adding +* null characters in the second byte of each character. This will work as expected +* for cases where the string contains ASCII data. +*/ +EXPORT_C HBufC* CX509Certificate::SubjectL() const + { + return iSubjectName->DisplayNameL(); + } + +EXPORT_C TBool CX509Certificate::IsSelfSignedL() const + { + if (iSubjectName->Count() > 0) + { + return iSubjectName->ExactMatchL(*iIssuerName); + } + else + { + TBool res = EFalse; + const CX509CertExtension* subjectExt = Extension(KIssuerAltName); + const CX509CertExtension* issuerExt = Extension(KSubjectAltName); + if ((subjectExt) && (issuerExt)) + { + const CX509AltNameExt* issuerAltName = CX509AltNameExt::NewLC(subjectExt->Data()); + const CX509AltNameExt* subjectAltName = CX509AltNameExt::NewLC(issuerExt->Data()); + if (subjectAltName->Match(*issuerAltName)) + { + res = ETrue; + } + CleanupStack::PopAndDestroy(2);//subjectAltName, issuerAltName + } + return res; + } + } + + +EXPORT_C TKeyIdentifier CX509Certificate::KeyIdentifierL() const + { + if (iSubjectPublicKeyInfo->AlgorithmId() != EDSA) + { + // The base class handles the RSA case and leaves with KErrNotSupported if + // it is not RSA. + return CCertificate::KeyIdentifierL(); + } + else + { + // This handles the DSA case + CDSAPublicKey* dsaKey = + iKeyFactory->DSAPublicKeyL(iSubjectPublicKeyInfo->EncodedParams(), + iSubjectPublicKeyInfo->KeyData()); + CleanupStack::PushL(dsaKey); + TKeyIdentifier retVal; + KeyIdentifierUtil::DSAKeyIdentifierL(*dsaKey, retVal); + CleanupStack::PopAndDestroy(dsaKey); + return retVal; + } + } + +EXPORT_C TKeyIdentifier CX509Certificate::SubjectKeyIdentifierL() const + { + const CX509CertExtension* subjectKeyIdExtStr = this->Extension(KSubjectKeyId); + if (subjectKeyIdExtStr) + { + TKeyIdentifier ret; + CX509SubjectKeyIdExt *subjectKeyIdExt = CX509SubjectKeyIdExt::NewLC(subjectKeyIdExtStr->Data()); + // Currently, we do not support key identifiers larger than 160 bits - make sure not to overflow the descriptor + if (subjectKeyIdExt->KeyId().Length() <= ret.MaxLength()) + { + ret.Copy(subjectKeyIdExt->KeyId()); + CleanupStack::PopAndDestroy(subjectKeyIdExt); + return ret; + } + CleanupStack::PopAndDestroy(subjectKeyIdExt); + } + + return KeyIdentifierL(); + }