os/security/cryptoservices/certificateandkeymgmt/recog/CertRecog.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) 2001-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 <apmrec.h>
    20 #include <apmstd.h>
    21 #include <asn1cons.h>
    22 #include <ecom/ecom.h>
    23 #include <ecom/implementationproxy.h>
    24 
    25 #include "CertRecog.h"
    26 #include "x509cert.h"
    27 #include "x509certext.h"
    28 
    29 
    30 
    31 const TInt KCertificateRecognizerValue = 0x101F4A71;
    32 const TUid KUidMimeCertRecognizer = { KCertificateRecognizerValue };
    33 
    34 // User certs
    35 _LIT8( KDataTypeWAPCertificateResponse, "application/vnd.wap.cert-response" );
    36 _LIT8( KDataTypeX509_USER_Certificate, "application/x-x509-user-cert" );
    37 
    38 // CA certs
    39 _LIT8( KDataTypeX509_CA_Certificate, "application/x-x509-ca-cert" );
    40 _LIT8( KDataTypeWAP_WTLS_CA_Certificate, "application/vnd.wap.wtls-ca-certificate" );
    41 
    42 const TInt KSupportedDataTypesTotal = 3;
    43 
    44 const TInt KX509MinBufferLength = 30;
    45 const TInt KCertRecMaxBufferLength = 80;
    46 
    47 const TInt KASN1SequenceTagValue = 0x30;
    48 const TInt KASN1SequenceTwoBytesLength = 0x82;
    49 const TInt KASN1SequenceThreeBytesLength = 0x83;
    50 const TInt KASN1VersionWrapperTagValue = 0xA0;
    51 const TInt KASN1VersionWrapperLengthValue = 0x03;
    52 const TInt KASN1VersionLengthValue = 0x01;
    53 enum { EX509VersionValue1 = 0x00, EX509VersionValue2 = 0x01, EX509VersionValue3 = 0x02 };
    54 const TInt KWTLSCertificateVersionValue = 0x01;
    55 
    56 
    57 
    58 // ----------------------------------------------------------------------------
    59 // CApaCertificateRecognizer
    60 //
    61 
    62 CApaCertificateRecognizer::CApaCertificateRecognizer()
    63 	: CApaDataRecognizerType( KUidMimeCertRecognizer, CApaDataRecognizerType::ENormal )
    64 	{
    65 	iCountDataTypes = KSupportedDataTypesTotal;
    66 	}
    67 
    68 
    69 
    70 TUint CApaCertificateRecognizer::PreferredBufSize()
    71 	{
    72 	return KCertRecMaxBufferLength;
    73 	}
    74 
    75 
    76 
    77 TDataType CApaCertificateRecognizer::SupportedDataTypeL( TInt aIndex ) const
    78 	{
    79 	__ASSERT_DEBUG( aIndex >= 0 && aIndex < KSupportedDataTypesTotal,
    80 					User::Panic( _L("RECCERT"), 0 ) );
    81 	switch ( aIndex )
    82 		{
    83 		case 0:
    84 			return TDataType( KDataTypeX509_CA_Certificate );
    85 		case 1:
    86 			return TDataType( KDataTypeWAP_WTLS_CA_Certificate );
    87 		// Used to prevent warning about return paths not all returning a value
    88 		default:
    89 			return TDataType( KDataTypeWAPCertificateResponse );
    90 		}
    91 	}
    92 
    93 
    94 
    95 void CApaCertificateRecognizer::DoRecognizeL( const TDesC& aName, const TDesC8& aBuffer )
    96 	{
    97  	
    98  	RFile* filePtr = FilePassedByHandleL();
    99  	if (filePtr)
   100  		{
   101  		ReadFileAndRecognizeL(*filePtr);
   102  		return;	
   103  		}
   104  	
   105  	//Connect to file server
   106  	RFs fs;
   107  	User::LeaveIfError(fs.Connect());	
   108  	CleanupClosePushL(fs);
   109  	
   110  	// See if the data is passed by filename
   111  	RFile fileToRead;	
   112  	TInt ret = fileToRead.Open(fs, aName, EFileRead | EFileShareReadersOnly | EFileStream);
   113  	CleanupClosePushL(fileToRead);
   114  	if (ret == KErrNone)
   115  		{
   116  		//Try the preferred buffer size first
   117  		ReadFileAndRecognizeL(fileToRead);
   118  		}
   119  	else
   120  		// If not passed by file name, can try to recognize buffer.
   121  		{
   122  		DoRecognizeBufferL(aBuffer, EFalse, fileToRead);
   123  		}
   124  	
   125  	CleanupStack::PopAndDestroy(2); //fileToRead, fs		
   126  	
   127  	}
   128 
   129 void CApaCertificateRecognizer::ReadFileAndRecognizeL(RFile& aFileToRead)
   130  	{
   131  	TInt size=PreferredBufSize();
   132  	HBufC8* memForFile = HBufC8::NewLC(size);
   133  	TPtr8 preferredBuffer(memForFile->Des());
   134  	User::LeaveIfError(aFileToRead.Read(preferredBuffer, size));
   135  	DoRecognizeBufferL(preferredBuffer, ETrue, aFileToRead);		
   136  	CleanupStack::PopAndDestroy(memForFile); //memForFile	
   137  	}
   138  
   139 void CApaCertificateRecognizer::DoRecognizeBufferL(const TDesC8& aBuffer,  TBool aIsFile, RFile& aFile)
   140 	{
   141 	// Ensure length is sufficient for checking type
   142    	if ( aBuffer.Size() >= 1 )
   143    		{
   144    		// First byte of X.509 certificate is an ANS.1 SEQUENCE tag
   145    		if ( aBuffer[0] == KASN1SequenceTagValue )
   146    			{
   147   			RecognizeX509CertL( aBuffer, aIsFile, aFile);
   148    			}
   149    		// First byte of WTLS certificate is version == 1
   150    		else if ( aBuffer[0] == KWTLSCertificateVersionValue )
   151    			{
   152   			RecognizeWTLSCertOrCertResponse( aBuffer, aIsFile, aFile);
   153    			}
   154   		
   155  		}						
   156    	}
   157 
   158 void CApaCertificateRecognizer::RecognizeX509CertL( const TDesC8& aBuffer,  TBool aIsFile, RFile& aFile )
   159 		{
   160 
   161 	//Basic check if this is a X509 certificate
   162 	TBool isCertV1orV2(EFalse);
   163 	TInt bufferSize = aBuffer.Size();
   164 	if ( bufferSize < KX509MinBufferLength )
   165 		{
   166 		return;
   167 		}
   168 	TInt index = 1;
   169 	// Check first sequence length byte and skip over the length value bytes
   170 	if ( aBuffer[index] == KASN1SequenceTwoBytesLength )
   171 		{
   172 		index += 3;
   173 		}
   174 	else if ( aBuffer[index] == KASN1SequenceThreeBytesLength )
   175 		{
   176 		index += 4;
   177 		}
   178 	else
   179 		{
   180 		return;
   181 		}
   182 	// Check next byte that is another sequence start
   183 	if ( aBuffer[index] != KASN1SequenceTagValue )
   184 		{
   185 		return;
   186 		}
   187 	++index;
   188 	// Check second sequence length byte and skip over the length value bytes
   189 	if ( aBuffer[index] == KASN1SequenceTwoBytesLength )
   190 		{
   191 		index += 3;
   192 		}
   193 	else if ( aBuffer[index] == KASN1SequenceThreeBytesLength )
   194 		{
   195 		index += 4;
   196 		}
   197 	else
   198 		{
   199 		return;
   200 		}
   201 	// Check for VERSION field
   202 	if ( aBuffer[index] == KASN1VersionWrapperTagValue )
   203 		{
   204 		++index;
   205 		if ( aBuffer[index] != KASN1VersionWrapperLengthValue )
   206 			{
   207 			return;
   208 			}
   209 		++index;
   210 		if ( aBuffer[index] != EASN1Integer )
   211 			{
   212 			return;
   213 			}
   214 		++index;
   215 		if ( aBuffer[index] != KASN1VersionLengthValue )
   216 			{
   217 			return;
   218 			}
   219 		++index;
   220 
   221 		// The cert is X509 v1 or v2
   222  		if (aBuffer[index] == EX509VersionValue1 ||
   223  		    aBuffer[index] == EX509VersionValue2)
   224 		    {
   225 		    isCertV1orV2=ETrue;
   226 		    }
   227 		else
   228 	 	   // The cert is neither X509 v1 nor v2
   229  		    {
   230  		   // The cert is not v3 as well 
   231  		   if (aBuffer[index] != EX509VersionValue3)
   232  			{
   233  			return;	
   234 			}
   235  		    }		
   236 
   237 		++index;
   238 		}
   239 	else
   240 		{
   241 		isCertV1orV2=ETrue;	
   242 		}
   243 	// Check for SerialNumber field
   244 	if ( aBuffer[index] != EASN1Integer )
   245 		{
   246 		return;
   247 		}
   248 	++index;
   249 	TInt serialNumberSize = aBuffer[index];
   250 	++index;
   251 	index += serialNumberSize;
   252 	// 1 is added for the next increments of index
   253 	if((index + 1) >= bufferSize)
   254 		{
   255 		return;
   256 		}
   257 	// Check for SIGNATURE field
   258 	if ( aBuffer[index] != KASN1SequenceTagValue )
   259 		{
   260 		return;
   261 		}
   262 	++index;
   263 	TInt signatureSize = aBuffer[index];
   264 	++index;
   265 	index += signatureSize;
   266 	if(index >= bufferSize)
   267 		{
   268 		return;
   269 		}
   270 	 	
   271  	// if the certificate is passed by the buffer, but not file name 
   272  	if (!aIsFile)	
   273  		{
   274  		// Check only the starting TAG byte of the NAME field
   275  		if ( aBuffer[index] == KASN1SequenceTagValue )
   276  			{
   277  			iDataType = TDataType( KDataTypeX509_CA_Certificate );
   278  			iConfidence = EProbable;
   279  			}			
   280  		}
   281  	else
   282  		// if the certificate is passed by file name
   283 		{
   284 		if (!isCertV1orV2) // x509 V3 certificate
   285  			{ 
   286  			//Get the file size
   287  			TInt size;
   288  			User::LeaveIfError(aFile.Size(size));
   289  			HBufC8* memForFile = HBufC8::NewLC(size);
   290  			TPtr8 fileContent(memForFile->Des());
   291  			TInt pos=0;
   292  			aFile.Seek(ESeekStart, pos);
   293  			User::LeaveIfError(aFile.Read(fileContent, size));
   294  			RecognizeWholeX509CertificateL(fileContent);
   295  			CleanupStack::PopAndDestroy(memForFile);//memForFile
   296 			}									
   297  		else  // x509 V1 or V2 certificate
   298  			{ 
   299  			iDataType = TDataType( KDataTypeX509_CA_Certificate );
   300  			iConfidence = EProbable;				
   301  			}
   302 	
   303 		}
   304 	}
   305 
   306 void CApaCertificateRecognizer::RecognizeWholeX509CertificateL(const TDesC8& aBuffer)
   307  	{
   308  	CX509Certificate* cert = CX509Certificate::NewLC(aBuffer);
   309  	if (cert)
   310  		{
   311  		const CX509CertExtension* certExt = cert->Extension(KBasicConstraints);
   312  		if (certExt)
   313  			{
   314  			CX509BasicConstraintsExt* basic = CX509BasicConstraintsExt::NewLC(certExt->Data());
   315  			if (basic->IsCA())
   316  				{
   317  				iDataType = TDataType( KDataTypeX509_CA_Certificate );
   318  				iConfidence = EProbable;					
   319  				}
   320  			else
   321  				{
   322  				iDataType = TDataType( KDataTypeX509_USER_Certificate );
   323  				iConfidence = EProbable;										
   324  				}
   325  			CleanupStack::PopAndDestroy(basic); //basic				
   326 			}
   327  		else
   328  			{
   329  			iDataType = TDataType( KDataTypeX509_USER_Certificate );
   330  			iConfidence = EProbable;														
   331  			}
   332  		}
   333  	CleanupStack::PopAndDestroy(cert); //cert
   334  	}
   335 
   336 
   337 
   338 void CApaCertificateRecognizer::RecognizeWTLSCertOrCertResponse( const TDesC8& aBuffer, TBool /*aIsFile*/, RFile& /*aFile*/ )
   339 	{
   340 	if ( aBuffer.Size() >= 3 )
   341 		{
   342 		// Check next byte is signature algorithm value from 0 - 2
   343 		if ( aBuffer[1] == 0x00 || aBuffer[1] == 0x01 || aBuffer[1] == 0x02 )
   344 			{
   345 			// Check Identifier Type for Issuer Identifier
   346 			if ( aBuffer[2] == 0x01 )
   347 				{
   348 				iDataType = TDataType( KDataTypeWAP_WTLS_CA_Certificate );
   349 				}
   350 			else
   351 				{
   352 				iDataType = TDataType( KDataTypeWAPCertificateResponse );
   353 				}
   354 			iConfidence = EPossible;
   355 			}
   356 		}
   357 	}
   358 
   359 CApaDataRecognizerType* CApaCertificateRecognizer::CreateRecognizerL()
   360 	{
   361 	return new (ELeave) CApaCertificateRecognizer();
   362 	}
   363 
   364 const TImplementationProxy ImplementationTable[] = 
   365 	{
   366 		IMPLEMENTATION_PROXY_ENTRY(0x102034A2, CApaCertificateRecognizer::CreateRecognizerL)
   367 	};
   368 
   369 EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
   370 	{
   371 	aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
   372 	return ImplementationTable;
   373 	}	
   374