os/security/cryptoservices/asnpkcs/source/asnpkcs8.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2 * Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
     3 * All rights reserved.
     4 * This component and the accompanying materials are made available
     5 * under the terms of the License "Eclipse Public License v1.0"
     6 * which accompanies this distribution, and is available
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
     8 *
     9 * Initial Contributors:
    10 * Nokia Corporation - initial contribution.
    11 *
    12 * Contributors:
    13 *
    14 * Description: 
    15 *
    16 */
    17 
    18 
    19 #include <asn1dec.h>
    20 #include <x509keys.h>
    21 #include <x509cert.h>
    22 #include "asnpkcs.h"
    23 #include <pbe.h>
    24 #include <pbedata.h>
    25 #include <keyidentifierutil.h>
    26 
    27 /*static*/ EXPORT_C CDecPKCS8Data* TASN1DecPKCS8::DecodeDERL(const TDesC8& aBinaryData)
    28 {
    29 	return (CDecPKCS8Data::NewL(aBinaryData));
    30 }
    31 
    32 /*
    33 EncryptedPrivateKeyInfo ::= SEQUENCE {
    34   encryptionAlgorithm EncryptionAlgorithmIdentifier,
    35   encryptedData EncryptedData }
    36 EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
    37 EncryptedData ::= OCTET STRING
    38 */
    39 
    40 /*static*/ EXPORT_C CDecPKCS8Data* TASN1DecPKCS8::DecodeEncryptedDERL(const TDesC8& aBinaryData, const TDesC8& aPassword)
    41 {
    42 	TASN1DecGeneric seqGen(aBinaryData);
    43 	seqGen.InitL();
    44 	if (seqGen.Tag() != EASN1Sequence)
    45 		{
    46 		User::Leave(KErrArgument);
    47 		}
    48 	
    49 	TASN1DecSequence dec;
    50 	CArrayPtrFlat<TASN1DecGeneric>* theData = dec.DecodeDERLC(seqGen);
    51 	TInt seqIndex = 0;
    52 	TInt count = theData->Count();
    53 	if (seqIndex >= count)
    54 		{
    55 		User::Leave(KErrArgument);		
    56 		}
    57 
    58 //	Get the first part of the sequence -> PKCS5 data
    59 	TASN1DecGeneric* pkcs5 = theData->operator[](seqIndex);
    60 	TPtrC8 theContent(pkcs5->Encoding());	//	expect this to be a sequence
    61 	CPBEncryptParms* encryptParams = TASN1DecPKCS5::DecodeDERL(theContent);
    62 	CleanupStack::PushL(encryptParams);
    63 
    64 //	Create the decryptor	
    65 	CPBEncryptElement* encryptElement = CPBEncryptElement::NewLC(aPassword, *encryptParams);
    66 	CPBDecryptor* decryptor = encryptElement->NewDecryptLC();
    67 //	Decrypt the final part of the sequence -> encrypted PKCS8 object
    68 	TASN1DecGeneric* pkcs8 = theData->operator[](count-1);
    69 	if (pkcs8->Tag() != EASN1OctetString)
    70 		{
    71 		User::Leave(KErrArgument);
    72 		}
    73 	TPtrC8 encryptedKey(pkcs8->GetContentDER());
    74 	TUint encryptLength = encryptedKey.Length();
    75 	TUint maxDecryptLength = decryptor->MaxOutputLength(encryptLength);
    76 	if (maxDecryptLength<=0)
    77 		{
    78 		User::Leave(KErrGeneral);		
    79 		}
    80 	
    81 	HBufC8* decryptOutput = HBufC8::NewLC(encryptLength);
    82 	TPtr8 decryptOutputPtr(decryptOutput->Des());
    83 	decryptOutputPtr.FillZ();
    84 	decryptor->Process(encryptedKey, decryptOutputPtr);
    85 			
    86 	CDecPKCS8Data* pkcs8Data = CDecPKCS8Data::NewL(decryptOutputPtr);
    87 
    88 	//	decryptOutput decryptor encryptElement 
    89 	//	encryptParams theData
    90 	CleanupStack::PopAndDestroy(5, theData);
    91 	
    92 	return (pkcs8Data);
    93 }
    94 
    95 /*
    96 Sample cleartext pkcs8 data from pkcs8dsa.001:
    97 
    98           SEQUENCE
    99 30          Tag: Constructed sequence
   100 81 c8       Length (may be one or more bytes)
   101 
   102             INTEGER
   103 02            Tag: Integer
   104 01            Length: 1 byte
   105 00            Value: 0
   106 
   107             SEQUENCE    
   108 30            Tag: Constructed sequence
   109 81 a9         Length (may be one or more bytes)
   110 
   111               OID
   112 06              Tag: OID
   113 07              Length: 7 bytes
   114 2a 86 48 ce 38 04 01
   115                 Value: dsa (1 2 840 10040 4 1)
   116 */
   117 
   118 _LIT8(KPKCS8DataVersion0, "\x02\x01\x00");
   119 _LIT8(KPKCS8DataOIDDSA, "\x06\x07\x2a\x86\x48\xce\x38\x04\x01");
   120 _LIT8(KPKCS8DataOIDRSA, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01");
   121 
   122 /*static*/ EXPORT_C TBool TASN1DecPKCS8::IsPKCS8Data(const TDesC8& aBinaryData)
   123 	{
   124 	// We don't decode the data because we may only have the first few bytes -
   125 	// instead we check the ASN1 by hand.
   126 
   127 	ASSERT(aBinaryData.Length() >= KIsPKCS8DataMinLength);
   128 	TInt pos = 0;
   129 
   130 	return
   131 		IsASN1Sequence(aBinaryData, pos) &&
   132 		IsExpectedData(aBinaryData, pos, KPKCS8DataVersion0) &&
   133 		IsASN1Sequence(aBinaryData, pos) &&
   134 		(IsExpectedData(aBinaryData, pos, KPKCS8DataOIDDSA) ||
   135 		 IsExpectedData(aBinaryData, pos, KPKCS8DataOIDRSA));
   136 	}
   137 
   138 /*
   139 Sample encrypted pkcs8 data from encryptPK8rsa1.txt
   140 
   141           SEQUENCE
   142 30          Tag: Constructed sequence
   143 82 01 a3    Length (may be one or more bytes)
   144 
   145             SEQUENCE
   146 30            Tag: Constructed sequence
   147 3d            Length (may be one or more bytes)
   148 
   149               OID
   150 06              Tag: OID
   151 09              Length: 9 bytes
   152 2a 86 48 86 f7 0d 01 05 0d
   153                 Value: pkcs5PBES2 (1 2 840 113549 1 5 13)
   154 
   155               SEQUENCE
   156 30              Tag: Constructed sequence
   157 30              Length (may be one or more bytes)
   158 
   159                 SEQUENCE
   160 30                Tag: Constructed sequence
   161 1b                Length (may be one or more bytes)
   162 
   163                   OID
   164 06                  Tag: OID
   165 09                  Length: 9 bytes
   166 2a 86 48 86 f7 0d 01 05 0c
   167                     Value: pkcs5PBKDF2 (1 2 840 113549 1 5 12)
   168 */
   169 
   170 _LIT8(KEncryptedPKCS8DataOIDpkcs5PBES2, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0d");
   171 _LIT8(KEncryptedPKCS8DataOIDpkcs5PBKDF2, "\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x05\x0c");
   172 
   173 EXPORT_C TBool TASN1DecPKCS8::IsEncryptedPKCS8Data(const TDesC8& aBinaryData)
   174 	{
   175 	// We don't decode the data because we may only have the first few bytes -
   176 	// instead we check the ASN1 by hand.
   177 
   178 	ASSERT(aBinaryData.Length() >= KIsEncryptedPKCS8DataMinLength);
   179 	TInt pos = 0;
   180 
   181 	return
   182 		IsASN1Sequence(aBinaryData, pos) &&
   183 		IsASN1Sequence(aBinaryData, pos) &&
   184 		IsExpectedData(aBinaryData, pos, KEncryptedPKCS8DataOIDpkcs5PBES2) &&
   185 		IsASN1Sequence(aBinaryData, pos) &&
   186 		IsASN1Sequence(aBinaryData, pos) &&
   187 		IsExpectedData(aBinaryData, pos, KEncryptedPKCS8DataOIDpkcs5PBKDF2);
   188 	}
   189 
   190 /**
   191  * Determine if the some data represents the start of an ASN1 sequence.  The
   192  * data is specified by a descriptor and an offset.  If the data matches, the
   193  * offset is advanced to point to the contents of the sequence.
   194  */
   195 TBool TASN1DecPKCS8::IsASN1Sequence(const TDesC8& aBinaryData, TInt& aPos)
   196 	{
   197 	// Check we have enough data
   198 	if ((aPos + 2) >= aBinaryData.Length())
   199 		{
   200 		return EFalse;
   201 		}
   202 	// Check the outermost sequence is valid
   203 	if (aBinaryData[aPos++] != 0x30 /* constructed sequence */)
   204 		{
   205 		return EFalse;
   206 		}
   207 	// Skip sequence length
   208 	TInt length0 = aBinaryData[aPos++];
   209 	if (length0 & 0x80)
   210 		{
   211 		aPos += length0 & 0x7f;
   212 		}
   213 	return ETrue;
   214 	}
   215 
   216 /**
   217  * Determine if some data starts with an expected string.  The data is specified
   218  * by a descriptor and an offset.  If the data matches, the offset is advanced
   219  * to point after the match.
   220  */
   221 TBool TASN1DecPKCS8::IsExpectedData(const TDesC8& aBinaryData, TInt& aPos, const TDesC8& aExpectedData)
   222 	{
   223 	TInt length = aExpectedData.Length();
   224 	// Check we have enough data
   225 	if (aPos + length >= aBinaryData.Length())
   226 		{
   227 		return EFalse;
   228 		}
   229 	// Check data matches	
   230 	if (aBinaryData.Mid(aPos, length) != aExpectedData)
   231 		{
   232 		return EFalse;
   233 		}
   234 	aPos += length;
   235 	return ETrue;
   236 	}
   237 
   238 //	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
   239 //	PKCS#8 object data representation
   240 //	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
   241 
   242 /*static*/ CDecPKCS8Data* CDecPKCS8Data::NewL(const TDesC8& aData)
   243 {
   244 	CDecPKCS8Data* me = new (ELeave) CDecPKCS8Data();
   245 	CleanupStack::PushL(me);
   246 	me->ConstructL(aData);
   247 	CleanupStack::Pop(me);
   248 	return (me);
   249 }
   250 
   251 CDecPKCS8Data::CDecPKCS8Data()
   252 {}
   253 
   254 CDecPKCS8Data::~CDecPKCS8Data()
   255 {
   256 	if (iKeyPairData)
   257 	{
   258 		iKeyPairData->Release();
   259 		iKeyPairData = NULL;
   260 	}
   261 
   262 	if (iAttributes)
   263 	{
   264 		delete iAttributes;
   265 		iAttributes = NULL;
   266 	}
   267 }
   268 
   269 //	Because this is part of construction, don't rely on
   270 //	cleanup of partially constructed items...
   271 void CDecPKCS8Data::ConstructL(const TDesC8& aData)
   272 	{
   273 	TASN1DecGeneric seqGen(aData);
   274 	seqGen.InitL();
   275 	if (seqGen.Tag() != EASN1Sequence)
   276 		{
   277 		User::Leave(KErrArgument);
   278 		}
   279 
   280 	TASN1DecSequence seq;
   281 	CArrayPtrFlat<TASN1DecGeneric>* seqContents = seq.DecodeDERLC(seqGen);
   282 	if (seqContents->Count() < 3 || seqContents->Count() > 4)
   283 		{
   284 		User::Leave(KErrArgument);
   285 		}
   286 				
   287 //	VERSION
   288 	if (seqContents->At(0)->Tag() != EASN1Integer)
   289 		{
   290 		User::Leave(KErrArgument);
   291 		}
   292 	TASN1DecInteger intDecoder;
   293 	iVersion = intDecoder.DecodeDERShortL(*(seqContents->At(0)));
   294 	if (iVersion!=0)
   295 		{
   296 		User::Leave(KErrArgument);
   297 		}
   298 	
   299 //	ALGORITHM
   300 	CX509AlgorithmIdentifier* algorithm = CX509AlgorithmIdentifier::NewLC(seqContents->At(1)->Encoding());
   301 	iAlgorithmID = algorithm->Algorithm();
   302 		
   303 //	KEY DATA
   304 	switch (iAlgorithmID)
   305 		{//	Only support RSA, DSA, DH
   306 		case ERSA:
   307 			iKeyPairData = CPKCS8KeyPairRSA::NewL(*(seqContents->At(2)));
   308 			break;
   309 			
   310 		case EDSA:
   311 			{
   312 			TPtrC8 params(algorithm->EncodedParams());		
   313 			iKeyPairData = CPKCS8KeyPairDSA::NewL(params, *(seqContents->At(2)));
   314 			break;
   315 			}
   316 			
   317 		case EDH: // Currently not supported because no test data is available
   318 		default:
   319 			User::Leave(KErrNotSupported);
   320 			break;
   321 		}
   322 
   323 	CleanupStack::PopAndDestroy(algorithm);
   324 
   325 	if (seqContents->Count() == 4)
   326 		{
   327 		// I think we should check the tag is zero here, but we're going to be
   328 		// lenient due to lack of real test data
   329 		
   330 		//if (seqContents->At(3)->Tag() != 0) // Implicitly tagged
   331 		//	{
   332 		//	User::Leave(KErrArgument);
   333 		//	}
   334 		
   335 		iAttributes = seqContents->At(3)->Encoding().AllocL();
   336 		}
   337 
   338 	CleanupStack::PopAndDestroy(seqContents);
   339 	}
   340 
   341 //	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
   342 //	RSA decoding
   343 //	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
   344 
   345 /*static*/ MPKCS8DecodedKeyPairData* CPKCS8KeyPairRSA::NewL(const TASN1DecGeneric& aSource)
   346 {
   347 	CPKCS8KeyPairRSA* me = new (ELeave) CPKCS8KeyPairRSA();
   348 	CleanupStack::PushL(me);
   349 	me->ConstructL(aSource);
   350 	CleanupStack::Pop(me);
   351 
   352 	return (me);
   353 }
   354 
   355 MPKCS8DecodedKeyPairData::~MPKCS8DecodedKeyPairData()
   356 	{	
   357 	}
   358 
   359 CPKCS8KeyPairRSA::~CPKCS8KeyPairRSA()
   360 {
   361 	delete iPublicKey;
   362 	delete iPrivateKey;
   363 }
   364 
   365 void CPKCS8KeyPairRSA::Release()
   366 {
   367 	delete this;
   368 }
   369 
   370 void CPKCS8KeyPairRSA::GetKeyIdentifierL(TKeyIdentifier& aKeyIdentifier) const
   371 {
   372 	if (iPublicKey)
   373 		KeyIdentifierUtil::RSAKeyIdentifierL(*iPublicKey, aKeyIdentifier);	
   374 	else
   375 		User::Leave(KErrNotReady);
   376 }
   377 
   378 TUint CPKCS8KeyPairRSA::KeySize() const
   379 {
   380 	if (!iPublicKey)
   381 	{
   382 		ASSERT(EFalse);
   383 		return (0xffffffff);
   384 	}
   385 	
   386 	const TInteger& modulus = iPublicKey->N();
   387 
   388 	TUint size = modulus.BitCount();
   389 	return (size);
   390 }
   391 
   392 void CPKCS8KeyPairRSA::ConstructL(const TASN1DecGeneric& aSource)
   393 {
   394 	TPtrC8 theContent(aSource.GetContentDER());
   395 	TASN1DecRSAKeyPair keyPairDecoder;
   396 	TInt tempPos = 0;
   397 	keyPairDecoder.DecodeDERL(theContent, tempPos, iPublicKey, iPrivateKey);
   398 }
   399 
   400 
   401 //	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
   402 //	DSA decoding
   403 //	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	//	\\	
   404 
   405 /*static*/ MPKCS8DecodedKeyPairData* CPKCS8KeyPairDSA::NewL(const TDesC8& aParamsData, const TASN1DecGeneric& aSource)
   406 {
   407 	CPKCS8KeyPairDSA* me = new (ELeave) CPKCS8KeyPairDSA();
   408 	CleanupStack::PushL(me);
   409 	me->ConstructL(aParamsData, aSource);
   410 	CleanupStack::Pop(me);
   411 
   412 	return (me);
   413 }
   414 
   415 CPKCS8KeyPairDSA::~CPKCS8KeyPairDSA()
   416 {
   417 	delete iPublicKey;
   418 	delete iPrivateKey;
   419 }
   420 
   421 void CPKCS8KeyPairDSA::Release()
   422 {
   423 	delete this;
   424 }
   425 
   426 void CPKCS8KeyPairDSA::GetKeyIdentifierL(TKeyIdentifier& aKeyIdentifier) const
   427 {
   428 	if (iPublicKey)
   429 		KeyIdentifierUtil::DSAKeyIdentifierL(*iPublicKey, aKeyIdentifier);	
   430 	else
   431 		User::Leave(KErrNotReady);
   432 }
   433 
   434 TUint CPKCS8KeyPairDSA::KeySize() const
   435 {
   436 	if (!iPublicKey)
   437 	{
   438 		ASSERT(EFalse);
   439 		return (0xffffffff);
   440 	}
   441 	
   442 	const TInteger& P = iPublicKey->P();
   443 
   444 	TUint size = P.BitCount();
   445 	return (size);
   446 }
   447 
   448 void CPKCS8KeyPairDSA::ConstructL(const TDesC8& aParamsData, const TASN1DecGeneric& aSource)
   449 {
   450 	TX509KeyFactory keyFactory;
   451 	CDSAParameters* params = keyFactory.DSAParametersL(aParamsData);
   452 	CleanupStack::PushL(params);
   453 
   454 	RInteger P = RInteger::NewL(params->P());
   455 	CleanupStack::PushL(P);
   456 
   457 	RInteger Q = RInteger::NewL(params->Q());
   458 	CleanupStack::PushL(Q);
   459 
   460 	RInteger G = RInteger::NewL(params->G());
   461 	CleanupStack::PushL(G);
   462 
   463 	if (aSource.Tag() != EASN1OctetString)
   464 		{
   465 		User::Leave(KErrArgument);
   466 		}
   467 	TASN1DecOctetString  octetDecoder;
   468 	HBufC8* wrapped = octetDecoder.DecodeDERL(aSource);
   469 	CleanupStack::PushL(wrapped);	
   470 
   471 	TASN1DecGeneric integer(*wrapped);
   472 	integer.InitL();
   473 	if (integer.Tag() != EASN1Integer)
   474 		{
   475 		User::Leave(KErrArgument);
   476 		}		
   477 	TASN1DecInteger decInt;
   478 	RInteger X = decInt.DecodeDERLongL(integer);
   479 	CleanupStack::PopAndDestroy(wrapped);
   480 	CleanupStack::PushL(X);
   481 			
   482 	RInteger P1 = RInteger::NewL(params->P());
   483 	CleanupStack::PushL(P1);
   484 	
   485 	RInteger Q1 = RInteger::NewL(params->Q());
   486 	CleanupStack::PushL(Q1);
   487 	
   488 	RInteger G1 = RInteger::NewL(params->G());
   489 	CleanupStack::PushL(G1);
   490 
   491 	RInteger Y = TInteger::ModularExponentiateL(G, X, P);
   492 	CleanupStack::PushL(Y);
   493 
   494 	iPublicKey = CDSAPublicKey::NewL(P1, Q1, G1, Y);
   495 
   496 	// Now have to pop everything owned by iPublicKey otherwise it will be
   497 	// deleted twice if the CDSAPrivateKey::NewL leaves
   498 
   499 	CleanupStack::Pop(4, &P1);	// now owned by iPublicKey
   500 	
   501 	iPrivateKey = CDSAPrivateKey::NewL(P, Q, G, X);
   502 
   503 	CleanupStack::Pop(4, &P);	// now owned by iPrivateKey
   504 		
   505 	CleanupStack::PopAndDestroy(params);
   506 }