os/security/cryptoservices/certificateandkeymgmt/pkcs12recog/pkcs12recog.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 /*
     2 * Copyright (c) 2006-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 "pkcs12recog.h"
    20 
    21 #include <apmrec.h>
    22 #include <apmstd.h>
    23 #include <ecom/ecom.h>
    24 #include <ecom/implementationproxy.h>
    25 #include <f32file.h>
    26 
    27 /** UID for PKCS#12 mime-type recognizer */
    28 static const TUint KPkcs12RecognizerImplementationId = 0x20001520;
    29 static const TUid KUidMimePkcs12Recognizer = { KPkcs12RecognizerImplementationId };
    30 
    31 /** 
    32 Minimum buffer size assuming worst-case 3 byte lengths for variable
    33 length fields. The file will never be smaller that this because it must
    34 also contain either the MacData or be a signed object.
    35 
    36 SEQ 5 bytes
    37 INTEGER 3 bytes
    38 SEQ 5 bytes
    39 OID 11 bytes
    40 
    41 total = 24
    42 */
    43 static const TInt KPkcs12MinBufSize = 24;
    44 
    45 /** Mime-type for PKCS#12 */
    46 _LIT8(KDataTypePkcs12, "application/x-pkcs12");
    47 /** The number of mime-types recognised */
    48 static const TInt KSupportedDataTypesTotal = 1;
    49 
    50 // ASN.1 / DER constants
    51 /** DER encoding of an ASN.1 sequence tag */
    52 static const TUint8 KDerSequenceOctet = 0x30;
    53 /** DER encoding of an ASN.1 integer tag */
    54 static const TUint8 KDerIntegerOctet = 0x02;
    55 /** Expected PKCS#12 version number */
    56 static const TInt KPkcs12Version = 3;
    57 
    58 /**
    59 DER encoding of PKCS#7 data content type OID
    60 OID = 1.2.840.113549.1.7.1
    61 */		
    62 static const TUint8 KPkcs7DataOid[] = 
    63 	{
    64 	0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01
    65 	};	
    66 /** Length of encoded PKCS#7 data OID */	
    67 static const TUint KPkcs7DataOidLen = sizeof(KPkcs7DataOid);		
    68 
    69 /**
    70 DER encoding of PKCS#7 signed data content type OID
    71 OID = 1.2.840.113549.1.7.2
    72 */	
    73 static const TUint8 KPkcs7SignedDataOid[] = 
    74 	{
    75 	0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02
    76 	};	
    77 /** Length of encoded PKCS#7 signed data OID */	
    78 static const TUint KPkcs7SignedDataOidLen = sizeof(KPkcs7SignedDataOid);	
    79 
    80 /** PKCS#12 recognizer panic identifier */
    81 _LIT(KPkcs12RecogPanic, "PKCS12RECOG");	
    82 	
    83 CPkcs12Recognizer::CPkcs12Recognizer()
    84 	: CApaDataRecognizerType(KUidMimePkcs12Recognizer, CApaDataRecognizerType::ENormal)
    85 	{
    86 	iCountDataTypes = KSupportedDataTypesTotal;
    87 	}
    88 
    89 TUint CPkcs12Recognizer::PreferredBufSize()
    90 	{
    91 	return KPkcs12MinBufSize;
    92 	}
    93 
    94 TDataType CPkcs12Recognizer::SupportedDataTypeL(TInt aIndex) const
    95 	{
    96 	__ASSERT_DEBUG(aIndex >= 0 && aIndex < KSupportedDataTypesTotal,
    97 					Panic(EPanicInvalidDataType));
    98 	
    99 	if (aIndex < 0 || aIndex >= KSupportedDataTypesTotal)
   100 		{
   101 		User::Leave(KErrArgument);
   102 		}
   103 						
   104 	return TDataType(KDataTypePkcs12);
   105 	}
   106 
   107 void CPkcs12Recognizer::DoRecognizeL(const TDesC& aName, const TDesC8& aBuffer)
   108 	{
   109 	__UHEAP_MARK;
   110 	iConfidence = ENotRecognized;
   111 	
   112 	TPtrC8 pkcs12Buffer(aBuffer);
   113 	TBuf8<KPkcs12MinBufSize> fileBuffer;
   114 	
   115 	if (aBuffer.Length() < KPkcs12MinBufSize)
   116 		{										
   117 		if (RFile* fh = FilePassedByHandleL()) 
   118 			{
   119 			User::LeaveIfError(fh->Read(0, fileBuffer, KPkcs12MinBufSize));
   120 			}
   121 		else 
   122 			{
   123 			// no file handle so attempt to read the file. This may
   124 			// fail if the file is in a private directory
   125 			RFs fs;
   126 			User::LeaveIfError(fs.Connect());
   127 			CleanupClosePushL(fs);
   128 			RFile file;			
   129 			TInt err = file.Open(fs, aName, EFileRead | EFileShareAny | EFileStream);
   130 			
   131 			// do nothing if the file fails to open, for any reason
   132 			if (err == KErrNone)
   133 				{
   134 				CleanupClosePushL(file);
   135 				User::LeaveIfError(file.Read(0, fileBuffer, KPkcs12MinBufSize));
   136 				CleanupStack::PopAndDestroy(&file);
   137 				}
   138 			CleanupStack::PopAndDestroy(&fs);
   139 			}		
   140 		// buffer does not exist or is too small so attempt to 
   141 		// read a buffer from the file		
   142 		pkcs12Buffer.Set(fileBuffer);			
   143 		}
   144 		
   145 
   146 	if (pkcs12Buffer.Length() > 0 && DoRecognizeBufferL(pkcs12Buffer))
   147 		{
   148 		iDataType = TDataType(KDataTypePkcs12);
   149 		iConfidence = EProbable;
   150 		if (HasPkcs12Extension(aName)) 
   151 			{
   152 			iConfidence = ECertain;
   153 			}
   154 		}
   155 	__UHEAP_MARKEND;
   156  	}
   157 	
   158 TBool CPkcs12Recognizer::HasPkcs12Extension(const TDesC& aName)
   159 	{
   160 	_LIT(KPfxExt, ".pfx");
   161 	_LIT(KP12Ext, ".p12");
   162 	
   163 	TBool match = EFalse;
   164 	
   165 	// It is not possible to use a TParse/TParsePtr here because the filename
   166 	// supplied when a file-handle is passed is of the form ::filename.ext and
   167 	// is not recognised as a valid filename
   168 	if (aName.Length() > 4)
   169 		{		
   170 		const TPtrC ext = aName.Right(4);
   171 		if (ext.CompareF(KPfxExt) == 0 || ext.CompareF(KP12Ext) == 0)
   172 			{
   173 			match = ETrue;
   174 			}
   175 		}
   176 	return match;
   177 	}
   178 
   179 TBool CPkcs12Recognizer::DoRecognizeBufferL(const TDesC8& aBuffer)
   180  	{
   181  	TBool isPkcs12 = EFalse;
   182  	TUint offset = 0;
   183  	
   184  	if (aBuffer.Length() >= KPkcs12MinBufSize)
   185  		{
   186 		// PFX
   187 	 	if (ConsumeSequenceL(aBuffer, offset))
   188  			{
   189  			// Version
   190  			TInt version; 
   191 			if (ConsumeIntegerL(aBuffer, offset, version)) 
   192 				{
   193 				if (version == KPkcs12Version)
   194 					{
   195 					// authSafe
   196 					if (ConsumeSequenceL(aBuffer, offset))
   197 						{
   198 						const TPtrC8 dataOid(KPkcs7DataOid, KPkcs7DataOidLen);
   199 						const TPtrC8 signedDataOid(KPkcs7SignedDataOid, KPkcs7SignedDataOidLen);
   200 						// check whether content-type is data or signed data					
   201 						if ((aBuffer.Mid(offset, KPkcs7DataOidLen).Compare(dataOid) == 0) ||
   202 							(aBuffer.Mid(offset, KPkcs7SignedDataOidLen).Compare(signedDataOid) == 0))
   203 							{
   204 							isPkcs12 = ETrue;
   205 							}
   206 						}
   207 					}
   208 				}
   209  			} 		
   210  		}
   211  	return isPkcs12;
   212  	}
   213 
   214 TBool CPkcs12Recognizer::ConsumeSequenceL(const TDesC8& aBuffer, TUint& aOffset) const
   215 	{
   216 	TBool isSequence = EFalse;
   217 	if (aBuffer[aOffset] == KDerSequenceOctet)
   218 		{
   219 		// sequence tag found, skip tag and length
   220 		aOffset++;
   221 		TInt length;
   222 		isSequence = ConsumeLengthL(aBuffer, aOffset, length);
   223 		}
   224 	return isSequence;
   225 	}
   226 
   227 TBool CPkcs12Recognizer::ConsumeLengthL(const TDesC8& aBuffer, TUint& aOffset, TInt& aLengthOctets) const
   228 	{	
   229 	TBool isValidLength = EFalse;	
   230 	TUint8 lengthOctet = aBuffer[aOffset];
   231 	if (lengthOctet & 0x80)
   232 		{
   233 		// The top bit is set so assume the length encoding is in long form
   234 		TUint numOctets = lengthOctet & 0x7f;
   235 		aOffset++;
   236 		
   237 		if (ConsumeBase256L(aBuffer, aOffset, numOctets, aLengthOctets))
   238 			{			
   239 			if (aLengthOctets >= 0)
   240 				{
   241 				// lengths must not be -ve
   242 				isValidLength = ETrue;
   243 				}
   244 			}
   245 		}
   246 	else 
   247 		{
   248 		// Top bit zero so assume short form encoding i.e. one octet
   249 		aLengthOctets = lengthOctet & 0x7f;
   250 		aOffset++;
   251 		isValidLength = ETrue;
   252 		}
   253 	return isValidLength;
   254 	}
   255 	
   256 TBool CPkcs12Recognizer::ConsumeIntegerL(const TDesC8& aBuffer, TUint& aOffset, TInt& aIntVal) const
   257 	{
   258 	TBool isValidInteger = EFalse;
   259 	if (aBuffer[aOffset] == KDerIntegerOctet) 
   260 		{
   261 		aOffset++;
   262 		TInt length;
   263 		if (ConsumeLengthL(aBuffer, aOffset, length))
   264 			{			
   265 			isValidInteger = ConsumeBase256L(aBuffer, aOffset, length, aIntVal);
   266 			}
   267 		}
   268 	return isValidInteger;
   269 	}
   270 
   271 TBool CPkcs12Recognizer::ConsumeBase256L(const TDesC8& aBuffer, TUint& aOffset, TInt aLengthOctets, TInt& aIntVal) const
   272 	{	
   273 	TInt isValid = EFalse;
   274 	if (aLengthOctets <= 4) 
   275 		{
   276 		aIntVal = 0;
   277 		while (aLengthOctets-- > 0)
   278 			{
   279 			aIntVal <<= 8;
   280 			aIntVal |= aBuffer[aOffset++];
   281 			}
   282 		isValid = ETrue;
   283 		}
   284 	return isValid;	
   285 	}	
   286 
   287 CApaDataRecognizerType* CPkcs12Recognizer::CreateRecognizerL()
   288 	{
   289 	return new (ELeave) CPkcs12Recognizer();
   290 	}
   291 
   292 static const TImplementationProxy ImplementationTable[] = 
   293 	{
   294 		IMPLEMENTATION_PROXY_ENTRY(KPkcs12RecognizerImplementationId, CPkcs12Recognizer::CreateRecognizerL)
   295 	};
   296 
   297 EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
   298 	{
   299 	aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
   300 	return ImplementationTable;
   301 	}	
   302 
   303 void CPkcs12Recognizer::Panic(TPkcs12RecogPanic aReason) const
   304 	{
   305 	User::Panic(KPkcs12RecogPanic, aReason);
   306 	}