sl@0: /* sl@0: * Copyright (c) 2004-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 sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include "asnpkcs.h" sl@0: sl@0: #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS sl@0: sl@0: /** OpenSSL PKCS8 Effective Key Length Compatibility.*/ sl@0: const TUint KPkcs8CompatibilityBits = 128; sl@0: sl@0: #endif sl@0: sl@0: sl@0: _LIT(Kpkcs5PBES2, "1.2.840.113549.1.5.13"); sl@0: _LIT(Kpkcs5PBKDF2, "1.2.840.113549.1.5.12"); sl@0: _LIT(KDESCBC, "1.3.14.3.2.7"); sl@0: _LIT(K3DESCBC, "1.2.840.113549.3.7"); sl@0: _LIT(KRC2CBC, "1.2.840.113549.3.2"); sl@0: sl@0: // pbe12Algorithm Ids sl@0: _LIT(KPbeWithSHA1And128BitRC4, "1.2.840.113549.1.12.1.1"); sl@0: _LIT(KPbeWithSHA1And40BitRC4, "1.2.840.113549.1.12.1.2"); sl@0: _LIT(KPbeWithSHA1And3_KeyTripleDES_CBC, "1.2.840.113549.1.12.1.3"); sl@0: _LIT(KPbeWithSHA1And2_KeyTripleDES_CBC, "1.2.840.113549.1.12.1.4"); sl@0: _LIT(KPbeWithSHA1And128BitRC2_CBC, "1.2.840.113549.1.12.1.5"); sl@0: _LIT(KPbeWithSHA1And40BitRC2_CBC, "1.2.840.113549.1.12.1.6"); sl@0: //The size of the Initialization vector sl@0: const TInt KIvSize = 8; sl@0: sl@0: sl@0: /* sl@0: * //For RC2 sl@0: * SEQUENCE sl@0: * OID -- pkcs5PBES2 sl@0: * SEQUENCE sl@0: * SEQUENCE sl@0: * OID -- pkcs5PBKDF2 sl@0: * SEQUENCE sl@0: * OCTET STRING -- salt sl@0: * INTEGER -- iteration count sl@0: * INTEGER -- effective key length in octets sl@0: * SEQUENCE sl@0: * OID -- algorithm id (rc2) sl@0: * SEQUENCE sl@0: * INTEGER -- RC2 parameter version 58 = 128, 160 = 40 sl@0: * OCTET STRING -- iv sl@0: * sl@0: * //For DES and 3DES sl@0: * SEQUENCE sl@0: * OID -- pkcs5PBES2 sl@0: * SEQUENCE sl@0: * SEQUENCE sl@0: * OID -- pkcs5PBKDF2 sl@0: * SEQUENCE sl@0: * OCTET STRING -- salt sl@0: * INTEGER -- iteration count sl@0: * SEQUENCE sl@0: * OID -- algorithm id (des, 3des) sl@0: * OCTET STRING -- iv sl@0: */ sl@0: sl@0: EXPORT_C CASN1EncSequence* TASN1EncPKCS5::EncodeDERL(const CPBEncryptParms& aParms) sl@0: { sl@0: CASN1EncSequence* seq = CASN1EncSequence::NewLC(); sl@0: CASN1EncObjectIdentifier* pbes2 = CASN1EncObjectIdentifier::NewLC(Kpkcs5PBES2); sl@0: seq->AddChildL(pbes2); sl@0: CleanupStack::Pop(pbes2); sl@0: sl@0: CASN1EncSequence* seq1 = CASN1EncSequence::NewLC(); sl@0: seq->AddChildL(seq1); sl@0: CleanupStack::Pop(seq1); sl@0: sl@0: CASN1EncSequence* seq2 = CASN1EncSequence::NewLC(); sl@0: seq1->AddChildL(seq2); sl@0: CleanupStack::Pop(seq2); sl@0: sl@0: CASN1EncObjectIdentifier* pbkdf2 = CASN1EncObjectIdentifier::NewLC(Kpkcs5PBKDF2); sl@0: seq2->AddChildL(pbkdf2); sl@0: CleanupStack::Pop(pbkdf2); sl@0: sl@0: CASN1EncSequence* seq3 = CASN1EncSequence::NewLC(); sl@0: seq2->AddChildL(seq3); sl@0: CleanupStack::Pop(seq3); sl@0: sl@0: CASN1EncOctetString* salt = CASN1EncOctetString::NewLC(aParms.Salt()); sl@0: seq3->AddChildL(salt); sl@0: CleanupStack::Pop(salt); sl@0: sl@0: CASN1EncInt* iterations = CASN1EncInt::NewLC(aParms.Iterations()); sl@0: seq3->AddChildL(iterations); sl@0: CleanupStack::Pop(iterations); sl@0: sl@0: CASN1EncInt* keysize = 0; sl@0: switch(aParms.Cipher()) sl@0: { sl@0: case ECipherDES_CBC: sl@0: case ECipher3DES_CBC: sl@0: break; sl@0: case ECipherRC2_CBC_40: sl@0: keysize = CASN1EncInt::NewLC(KSSLCompatibilityBits/8); // effective key length in *octets* sl@0: seq3->AddChildL(keysize); sl@0: CleanupStack::Pop(keysize); sl@0: break; sl@0: case ECipherRC2_CBC_128: sl@0: keysize = CASN1EncInt::NewLC(KSSLCompatibilityBits/8); // effective key length in *octets* sl@0: seq3->AddChildL(keysize); sl@0: CleanupStack::Pop(keysize); sl@0: break; sl@0: case ECipherRC2_CBC_40_16: sl@0: keysize = CASN1EncInt::NewLC(KPkcs8CompatibilityBits/8); // effective key length in *octets* sl@0: seq3->AddChildL(keysize); sl@0: CleanupStack::Pop(keysize); sl@0: break; sl@0: case ECipherRC2_CBC_128_16: sl@0: keysize = CASN1EncInt::NewLC(KPkcs8CompatibilityBits/8); // effective key length in *octets* sl@0: seq3->AddChildL(keysize); sl@0: CleanupStack::Pop(keysize); sl@0: break; sl@0: default: sl@0: User::Leave(KErrNotSupported); sl@0: break; sl@0: } sl@0: sl@0: CASN1EncSequence* seq4 = CASN1EncSequence::NewLC(); sl@0: seq1->AddChildL(seq4); sl@0: CleanupStack::Pop(seq4); sl@0: sl@0: CASN1EncObjectIdentifier* algid = 0; sl@0: switch(aParms.Cipher()) sl@0: { sl@0: case ECipherDES_CBC: sl@0: algid = CASN1EncObjectIdentifier::NewLC(KDESCBC); sl@0: break; sl@0: case ECipher3DES_CBC: sl@0: algid = CASN1EncObjectIdentifier::NewLC(K3DESCBC); sl@0: break; sl@0: case ECipherRC2_CBC_40: sl@0: case ECipherRC2_CBC_128: sl@0: case ECipherRC2_CBC_40_16: sl@0: case ECipherRC2_CBC_128_16: sl@0: algid = CASN1EncObjectIdentifier::NewLC(KRC2CBC); sl@0: break; sl@0: default: sl@0: User::Leave(KErrNotSupported); sl@0: break; sl@0: } sl@0: seq4->AddChildL(algid); sl@0: CleanupStack::Pop(algid); sl@0: sl@0: CASN1EncSequence* seq5 = 0; sl@0: CASN1EncInt* keysize1 = 0; sl@0: CASN1EncOctetString* iv = 0; sl@0: switch(aParms.Cipher()) sl@0: { sl@0: case ECipherDES_CBC: sl@0: case ECipher3DES_CBC: sl@0: iv = CASN1EncOctetString::NewLC(aParms.IV()); sl@0: seq4->AddChildL(iv); sl@0: CleanupStack::Pop(iv); sl@0: break; sl@0: case ECipherRC2_CBC_40: sl@0: case ECipherRC2_CBC_40_16: sl@0: seq5 = CASN1EncSequence::NewLC(); sl@0: seq4->AddChildL(seq5); sl@0: CleanupStack::Pop(seq5); sl@0: sl@0: keysize1 = CASN1EncInt::NewLC(160); //encoding for 40 bit sl@0: seq5->AddChildL(keysize1); sl@0: CleanupStack::Pop(keysize1); sl@0: sl@0: iv = CASN1EncOctetString::NewLC(aParms.IV()); sl@0: seq5->AddChildL(iv); sl@0: CleanupStack::Pop(iv); sl@0: break; sl@0: case ECipherRC2_CBC_128: sl@0: case ECipherRC2_CBC_128_16: sl@0: seq5 = CASN1EncSequence::NewLC(); sl@0: seq4->AddChildL(seq5); sl@0: CleanupStack::Pop(seq5); sl@0: sl@0: keysize1 = CASN1EncInt::NewLC(58); //encoding for 128 bit sl@0: seq5->AddChildL(keysize1); sl@0: CleanupStack::Pop(keysize1); sl@0: sl@0: iv = CASN1EncOctetString::NewLC(aParms.IV()); sl@0: seq5->AddChildL(iv); sl@0: CleanupStack::Pop(iv); sl@0: break; sl@0: default: sl@0: User::Leave(KErrNotSupported); sl@0: break; sl@0: } sl@0: CleanupStack::Pop(seq); sl@0: return seq; sl@0: } sl@0: sl@0: EXPORT_C CPBEncryptParms* TASN1DecPKCS5::DecodeDERL(const TDesC8& aBinaryData) sl@0: { sl@0: TASN1DecGeneric seqGen(aBinaryData); sl@0: seqGen.InitL(); sl@0: if (seqGen.Tag() != EASN1Sequence) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: //Decode the Algorithm Identifier Sequence sl@0: TASN1DecSequence seq; sl@0: CArrayPtrFlat* seqContents = seq.DecodeDERLC(seqGen); sl@0: sl@0: //PbeAlgorithm Id sl@0: if (seqContents->At(0)->Tag() != EASN1ObjectIdentifier) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: CPBEncryptParms* params = NULL; sl@0: TASN1DecObjectIdentifier oid; sl@0: HBufC* oiddes = oid.DecodeDERL(*(seqContents->At(0))); sl@0: CleanupStack::PushL(oiddes); sl@0: //Algorithm Id is a pkcs-12Pbe Algorithm Id. sl@0: if(*oiddes != Kpkcs5PBES2) sl@0: { sl@0: // Initialise to impossible value sl@0: TPBECipher cipher = (TPBECipher) -1; sl@0: // Pbe12Algorithm Ids sl@0: if(*oiddes == KPbeWithSHA1And128BitRC4) sl@0: { sl@0: cipher = ECipherARC4_128; sl@0: } sl@0: else if(*oiddes == KPbeWithSHA1And40BitRC4) sl@0: { sl@0: cipher = ECipherARC4_40; sl@0: } sl@0: else if(*oiddes == KPbeWithSHA1And3_KeyTripleDES_CBC) sl@0: { sl@0: cipher = ECipher3DES_CBC; sl@0: } sl@0: else if(*oiddes == KPbeWithSHA1And2_KeyTripleDES_CBC) sl@0: { sl@0: cipher = ECipher2Key3DES_CBC; sl@0: } sl@0: else if(*oiddes == KPbeWithSHA1And128BitRC2_CBC) sl@0: { sl@0: cipher = ECipherRC2_CBC_128_16; sl@0: } sl@0: else if(*oiddes == KPbeWithSHA1And40BitRC2_CBC) sl@0: { sl@0: cipher = ECipherRC2_CBC_40_5; sl@0: } sl@0: else sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: TInt seqContentsCount = seqContents->Count(); sl@0: sl@0: //All pkcs-12Pbe algorithms require the Algorithm Parameters. sl@0: //Algorithm Parameters are not OPTIONAL for pkcs-12Pbe algorithms. sl@0: sl@0: //seqContentsCount should be equal to 2.That is, the Algorithm Id sl@0: //and associated Algorithm Parameters have to be present. sl@0: if(seqContentsCount != 2) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: //This if statement checks if the pkcs-12PbeParams Sequence is present in the sl@0: //AlgorithmIdentifier Sequence Since pkcs-12PbeParams are OPTIONAL sl@0: else sl@0: { sl@0: //Set the Initialization vector size to 8 bytes. sl@0: TBuf8 iv(KIvSize); sl@0: // Initialized to NULL, if salt is not present. sl@0: TPtrC8 salt; sl@0: TInt iterations; sl@0: sl@0: const TASN1DecGeneric* seqContentsAt1 = seqContents->At(1); sl@0: if (seqContentsAt1->Tag() != EASN1Sequence || seqContentsAt1->Class() != EUniversal) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: CArrayPtrFlat* seq1Contents = seq.DecodeDERLC(*seqContentsAt1); sl@0: const TASN1DecGeneric* seq1ContentsAt0 = seq1Contents->At(0); sl@0: if (seq1ContentsAt0->Tag() != EASN1OctetString || seq1ContentsAt0->Class() != EUniversal) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: salt.Set(seq1ContentsAt0->GetContentDER()); sl@0: const TASN1DecGeneric* seq1ContentsAt1 = seq1Contents->At(1); sl@0: if (seq1ContentsAt1->Tag() != EASN1Integer || seq1ContentsAt1->Class() != EUniversal) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: TASN1DecInteger integer; sl@0: iterations = integer.DecodeDERShortL(*seq1ContentsAt1); sl@0: if (iterations <= 0) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: params = CPBEncryptParms::NewL(cipher, salt, iv, iterations); sl@0: params->SetKdf(CPBEncryptParms::EKdfPkcs12); sl@0: CleanupStack::PopAndDestroy(seq1Contents); sl@0: } sl@0: } sl@0: //Algorithm Id is a pkcs-5Pbe Algorithm Id. sl@0: else if (*oiddes == Kpkcs5PBES2) sl@0: { sl@0: if (seqContents->At(1)->Tag() != EASN1Sequence) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: CArrayPtrFlat* seq1Contents = seq.DecodeDERLC(*(seqContents->At(1))); sl@0: sl@0: if (seq1Contents->At(0)->Tag() != EASN1Sequence) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: CArrayPtrFlat* seq2Contents = seq.DecodeDERLC(*(seq1Contents->At(0))); sl@0: sl@0: if (seq2Contents->At(0)->Tag() != EASN1ObjectIdentifier) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: HBufC* oid1des = oid.DecodeDERL(*(seq2Contents->At(0))); sl@0: CleanupStack::PushL(oid1des); sl@0: sl@0: if(*oid1des != Kpkcs5PBKDF2) sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: if (seq2Contents->At(1)->Tag() != EASN1Sequence) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: CArrayPtrFlat* seq3Contents = seq.DecodeDERLC(*(seq2Contents->At(1))); sl@0: sl@0: if (seq3Contents->At(0)->Tag() != EASN1OctetString) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: TASN1DecOctetString octet; sl@0: HBufC8* salt = octet.DecodeDERL(*(seq3Contents->At(0))); sl@0: CleanupStack::PushL(salt); sl@0: sl@0: if (seq3Contents->At(1)->Tag() != EASN1Integer) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: TASN1DecInteger integer; sl@0: TInt iterations = integer.DecodeDERShortL(*(seq3Contents->At(1))); sl@0: sl@0: if (seq1Contents->At(1)->Tag() != EASN1Sequence) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: CArrayPtrFlat* seq4Contents = seq.DecodeDERLC(*(seq1Contents->At(1))); sl@0: sl@0: TPBECipher cipher = (TPBECipher) -1; // Initialise to impossible value sl@0: if (seq4Contents->At(0)->Tag() != EASN1ObjectIdentifier) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: HBufC* oid2des = oid.DecodeDERL(*(seq4Contents->At(0))); sl@0: CleanupStack::PushL(oid2des); sl@0: sl@0: CArrayPtrFlat* seq5Contents = 0; sl@0: sl@0: if(*oid2des == K3DESCBC) sl@0: { sl@0: cipher = ECipher3DES_CBC; sl@0: CleanupStack::PushL(seq5Contents); sl@0: } sl@0: else if(*oid2des == KDESCBC) sl@0: { sl@0: cipher = ECipherDES_CBC; sl@0: CleanupStack::PushL(seq5Contents); sl@0: } sl@0: else if(*oid2des == KRC2CBC) sl@0: { sl@0: // RC2 has an additional parameter, the effective key lenght in octets. sl@0: if (seq3Contents->At(2)->Tag() != EASN1Integer) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: TInt effectiveKeyLength = integer.DecodeDERShortL(*(seq3Contents->At(2))); sl@0: sl@0: if (seq4Contents->At(1)->Tag() != EASN1Sequence) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: seq5Contents = seq.DecodeDERLC(*(seq4Contents->At(1))); sl@0: if (seq5Contents->At(0)->Tag() != EASN1Integer) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: TInt keysize = integer.DecodeDERShortL(*(seq5Contents->At(0))); sl@0: switch(keysize) sl@0: { sl@0: // These values come from the PKCS#5 v2 specs sl@0: case 160: sl@0: if (effectiveKeyLength == 16) sl@0: { sl@0: cipher = ECipherRC2_CBC_40_16; sl@0: } sl@0: else sl@0: { sl@0: if (effectiveKeyLength == 128) sl@0: { sl@0: cipher = ECipherRC2_CBC_40; sl@0: } sl@0: else sl@0: { sl@0: User::Leave(KErrNotSupported); // Unsupported effective key length! sl@0: } sl@0: } sl@0: break; sl@0: case 58: sl@0: if (effectiveKeyLength == 16) sl@0: { sl@0: cipher = ECipherRC2_CBC_128_16; sl@0: } sl@0: else sl@0: { sl@0: if (effectiveKeyLength == 128) sl@0: { sl@0: cipher = ECipherRC2_CBC_128; sl@0: } sl@0: else sl@0: { sl@0: User::Leave(KErrNotSupported); // Unsupported effective key length! sl@0: } sl@0: } sl@0: break; sl@0: case 120: sl@0: //would be RC_CBC_64 but we don't support that sl@0: default: sl@0: User::Leave(KErrNotSupported); sl@0: break; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: HBufC8* iv = 0; sl@0: switch(cipher) sl@0: { sl@0: case ECipher3DES_CBC: sl@0: case ECipherDES_CBC: sl@0: if (seq4Contents->At(1)->Tag() != EASN1OctetString) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: iv = octet.DecodeDERL(*(seq4Contents->At(1))); sl@0: CleanupStack::PushL(iv); sl@0: break; sl@0: case ECipherRC2_CBC_40: sl@0: case ECipherRC2_CBC_128: sl@0: case ECipherRC2_CBC_40_16: sl@0: case ECipherRC2_CBC_128_16: sl@0: if (seq5Contents->At(1)->Tag() != EASN1OctetString) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: iv = octet.DecodeDERL(*(seq5Contents->At(1))); sl@0: CleanupStack::PushL(iv); sl@0: break; sl@0: default: sl@0: User::Leave(KErrNotSupported); sl@0: break; sl@0: } sl@0: sl@0: params = CPBEncryptParms::NewL(cipher, *salt, *iv, sl@0: iterations); sl@0: CleanupStack::PopAndDestroy(9); //iv, seq5contents, oid2des, seq4Contents, sl@0: //salt, seq3Contents, oid1des, seq2Contents, seq1Contents sl@0: } sl@0: else sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: CleanupStack::PopAndDestroy(2, seqContents); sl@0: return params; sl@0: }