cryptoservices/certificateandkeymgmt/pkcs12recog/pkcs12recog.cpp
changeset 0 2c201484c85f
child 8 35751d3474b7
equal deleted inserted replaced
-1:000000000000 0:2c201484c85f
       
     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 	}