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