sl@0: /* sl@0: * Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include "CertRecog.h" sl@0: #include "x509cert.h" sl@0: #include "x509certext.h" sl@0: sl@0: sl@0: sl@0: const TInt KCertificateRecognizerValue = 0x101F4A71; sl@0: const TUid KUidMimeCertRecognizer = { KCertificateRecognizerValue }; sl@0: sl@0: // User certs sl@0: _LIT8( KDataTypeWAPCertificateResponse, "application/vnd.wap.cert-response" ); sl@0: _LIT8( KDataTypeX509_USER_Certificate, "application/x-x509-user-cert" ); sl@0: sl@0: // CA certs sl@0: _LIT8( KDataTypeX509_CA_Certificate, "application/x-x509-ca-cert" ); sl@0: _LIT8( KDataTypeWAP_WTLS_CA_Certificate, "application/vnd.wap.wtls-ca-certificate" ); sl@0: sl@0: const TInt KSupportedDataTypesTotal = 3; sl@0: sl@0: const TInt KX509MinBufferLength = 30; sl@0: const TInt KCertRecMaxBufferLength = 80; sl@0: sl@0: const TInt KASN1SequenceTagValue = 0x30; sl@0: const TInt KASN1SequenceTwoBytesLength = 0x82; sl@0: const TInt KASN1SequenceThreeBytesLength = 0x83; sl@0: const TInt KASN1VersionWrapperTagValue = 0xA0; sl@0: const TInt KASN1VersionWrapperLengthValue = 0x03; sl@0: const TInt KASN1VersionLengthValue = 0x01; sl@0: enum { EX509VersionValue1 = 0x00, EX509VersionValue2 = 0x01, EX509VersionValue3 = 0x02 }; sl@0: const TInt KWTLSCertificateVersionValue = 0x01; sl@0: sl@0: sl@0: sl@0: // ---------------------------------------------------------------------------- sl@0: // CApaCertificateRecognizer sl@0: // sl@0: sl@0: CApaCertificateRecognizer::CApaCertificateRecognizer() sl@0: : CApaDataRecognizerType( KUidMimeCertRecognizer, CApaDataRecognizerType::ENormal ) sl@0: { sl@0: iCountDataTypes = KSupportedDataTypesTotal; sl@0: } sl@0: sl@0: sl@0: sl@0: TUint CApaCertificateRecognizer::PreferredBufSize() sl@0: { sl@0: return KCertRecMaxBufferLength; sl@0: } sl@0: sl@0: sl@0: sl@0: TDataType CApaCertificateRecognizer::SupportedDataTypeL( TInt aIndex ) const sl@0: { sl@0: __ASSERT_DEBUG( aIndex >= 0 && aIndex < KSupportedDataTypesTotal, sl@0: User::Panic( _L("RECCERT"), 0 ) ); sl@0: switch ( aIndex ) sl@0: { sl@0: case 0: sl@0: return TDataType( KDataTypeX509_CA_Certificate ); sl@0: case 1: sl@0: return TDataType( KDataTypeWAP_WTLS_CA_Certificate ); sl@0: // Used to prevent warning about return paths not all returning a value sl@0: default: sl@0: return TDataType( KDataTypeWAPCertificateResponse ); sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: void CApaCertificateRecognizer::DoRecognizeL( const TDesC& aName, const TDesC8& aBuffer ) sl@0: { sl@0: sl@0: RFile* filePtr = FilePassedByHandleL(); sl@0: if (filePtr) sl@0: { sl@0: ReadFileAndRecognizeL(*filePtr); sl@0: return; sl@0: } sl@0: sl@0: //Connect to file server sl@0: RFs fs; sl@0: User::LeaveIfError(fs.Connect()); sl@0: CleanupClosePushL(fs); sl@0: sl@0: // See if the data is passed by filename sl@0: RFile fileToRead; sl@0: TInt ret = fileToRead.Open(fs, aName, EFileRead | EFileShareReadersOnly | EFileStream); sl@0: CleanupClosePushL(fileToRead); sl@0: if (ret == KErrNone) sl@0: { sl@0: //Try the preferred buffer size first sl@0: ReadFileAndRecognizeL(fileToRead); sl@0: } sl@0: else sl@0: // If not passed by file name, can try to recognize buffer. sl@0: { sl@0: DoRecognizeBufferL(aBuffer, EFalse, fileToRead); sl@0: } sl@0: sl@0: CleanupStack::PopAndDestroy(2); //fileToRead, fs sl@0: sl@0: } sl@0: sl@0: void CApaCertificateRecognizer::ReadFileAndRecognizeL(RFile& aFileToRead) sl@0: { sl@0: TInt size=PreferredBufSize(); sl@0: HBufC8* memForFile = HBufC8::NewLC(size); sl@0: TPtr8 preferredBuffer(memForFile->Des()); sl@0: User::LeaveIfError(aFileToRead.Read(preferredBuffer, size)); sl@0: DoRecognizeBufferL(preferredBuffer, ETrue, aFileToRead); sl@0: CleanupStack::PopAndDestroy(memForFile); //memForFile sl@0: } sl@0: sl@0: void CApaCertificateRecognizer::DoRecognizeBufferL(const TDesC8& aBuffer, TBool aIsFile, RFile& aFile) sl@0: { sl@0: // Ensure length is sufficient for checking type sl@0: if ( aBuffer.Size() >= 1 ) sl@0: { sl@0: // First byte of X.509 certificate is an ANS.1 SEQUENCE tag sl@0: if ( aBuffer[0] == KASN1SequenceTagValue ) sl@0: { sl@0: RecognizeX509CertL( aBuffer, aIsFile, aFile); sl@0: } sl@0: // First byte of WTLS certificate is version == 1 sl@0: else if ( aBuffer[0] == KWTLSCertificateVersionValue ) sl@0: { sl@0: RecognizeWTLSCertOrCertResponse( aBuffer, aIsFile, aFile); sl@0: } sl@0: sl@0: } sl@0: } sl@0: sl@0: void CApaCertificateRecognizer::RecognizeX509CertL( const TDesC8& aBuffer, TBool aIsFile, RFile& aFile ) sl@0: { sl@0: sl@0: //Basic check if this is a X509 certificate sl@0: TBool isCertV1orV2(EFalse); sl@0: TInt bufferSize = aBuffer.Size(); sl@0: if ( bufferSize < KX509MinBufferLength ) sl@0: { sl@0: return; sl@0: } sl@0: TInt index = 1; sl@0: // Check first sequence length byte and skip over the length value bytes sl@0: if ( aBuffer[index] == KASN1SequenceTwoBytesLength ) sl@0: { sl@0: index += 3; sl@0: } sl@0: else if ( aBuffer[index] == KASN1SequenceThreeBytesLength ) sl@0: { sl@0: index += 4; sl@0: } sl@0: else sl@0: { sl@0: return; sl@0: } sl@0: // Check next byte that is another sequence start sl@0: if ( aBuffer[index] != KASN1SequenceTagValue ) sl@0: { sl@0: return; sl@0: } sl@0: ++index; sl@0: // Check second sequence length byte and skip over the length value bytes sl@0: if ( aBuffer[index] == KASN1SequenceTwoBytesLength ) sl@0: { sl@0: index += 3; sl@0: } sl@0: else if ( aBuffer[index] == KASN1SequenceThreeBytesLength ) sl@0: { sl@0: index += 4; sl@0: } sl@0: else sl@0: { sl@0: return; sl@0: } sl@0: // Check for VERSION field sl@0: if ( aBuffer[index] == KASN1VersionWrapperTagValue ) sl@0: { sl@0: ++index; sl@0: if ( aBuffer[index] != KASN1VersionWrapperLengthValue ) sl@0: { sl@0: return; sl@0: } sl@0: ++index; sl@0: if ( aBuffer[index] != EASN1Integer ) sl@0: { sl@0: return; sl@0: } sl@0: ++index; sl@0: if ( aBuffer[index] != KASN1VersionLengthValue ) sl@0: { sl@0: return; sl@0: } sl@0: ++index; sl@0: sl@0: // The cert is X509 v1 or v2 sl@0: if (aBuffer[index] == EX509VersionValue1 || sl@0: aBuffer[index] == EX509VersionValue2) sl@0: { sl@0: isCertV1orV2=ETrue; sl@0: } sl@0: else sl@0: // The cert is neither X509 v1 nor v2 sl@0: { sl@0: // The cert is not v3 as well sl@0: if (aBuffer[index] != EX509VersionValue3) sl@0: { sl@0: return; sl@0: } sl@0: } sl@0: sl@0: ++index; sl@0: } sl@0: else sl@0: { sl@0: isCertV1orV2=ETrue; sl@0: } sl@0: // Check for SerialNumber field sl@0: if ( aBuffer[index] != EASN1Integer ) sl@0: { sl@0: return; sl@0: } sl@0: ++index; sl@0: TInt serialNumberSize = aBuffer[index]; sl@0: ++index; sl@0: index += serialNumberSize; sl@0: // 1 is added for the next increments of index sl@0: if((index + 1) >= bufferSize) sl@0: { sl@0: return; sl@0: } sl@0: // Check for SIGNATURE field sl@0: if ( aBuffer[index] != KASN1SequenceTagValue ) sl@0: { sl@0: return; sl@0: } sl@0: ++index; sl@0: TInt signatureSize = aBuffer[index]; sl@0: ++index; sl@0: index += signatureSize; sl@0: if(index >= bufferSize) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: // if the certificate is passed by the buffer, but not file name sl@0: if (!aIsFile) sl@0: { sl@0: // Check only the starting TAG byte of the NAME field sl@0: if ( aBuffer[index] == KASN1SequenceTagValue ) sl@0: { sl@0: iDataType = TDataType( KDataTypeX509_CA_Certificate ); sl@0: iConfidence = EProbable; sl@0: } sl@0: } sl@0: else sl@0: // if the certificate is passed by file name sl@0: { sl@0: if (!isCertV1orV2) // x509 V3 certificate sl@0: { sl@0: //Get the file size sl@0: TInt size; sl@0: User::LeaveIfError(aFile.Size(size)); sl@0: HBufC8* memForFile = HBufC8::NewLC(size); sl@0: TPtr8 fileContent(memForFile->Des()); sl@0: TInt pos=0; sl@0: aFile.Seek(ESeekStart, pos); sl@0: User::LeaveIfError(aFile.Read(fileContent, size)); sl@0: RecognizeWholeX509CertificateL(fileContent); sl@0: CleanupStack::PopAndDestroy(memForFile);//memForFile sl@0: } sl@0: else // x509 V1 or V2 certificate sl@0: { sl@0: iDataType = TDataType( KDataTypeX509_CA_Certificate ); sl@0: iConfidence = EProbable; sl@0: } sl@0: sl@0: } sl@0: } sl@0: sl@0: void CApaCertificateRecognizer::RecognizeWholeX509CertificateL(const TDesC8& aBuffer) sl@0: { sl@0: CX509Certificate* cert = CX509Certificate::NewLC(aBuffer); sl@0: if (cert) sl@0: { sl@0: const CX509CertExtension* certExt = cert->Extension(KBasicConstraints); sl@0: if (certExt) sl@0: { sl@0: CX509BasicConstraintsExt* basic = CX509BasicConstraintsExt::NewLC(certExt->Data()); sl@0: if (basic->IsCA()) sl@0: { sl@0: iDataType = TDataType( KDataTypeX509_CA_Certificate ); sl@0: iConfidence = EProbable; sl@0: } sl@0: else sl@0: { sl@0: iDataType = TDataType( KDataTypeX509_USER_Certificate ); sl@0: iConfidence = EProbable; sl@0: } sl@0: CleanupStack::PopAndDestroy(basic); //basic sl@0: } sl@0: else sl@0: { sl@0: iDataType = TDataType( KDataTypeX509_USER_Certificate ); sl@0: iConfidence = EProbable; sl@0: } sl@0: } sl@0: CleanupStack::PopAndDestroy(cert); //cert sl@0: } sl@0: sl@0: sl@0: sl@0: void CApaCertificateRecognizer::RecognizeWTLSCertOrCertResponse( const TDesC8& aBuffer, TBool /*aIsFile*/, RFile& /*aFile*/ ) sl@0: { sl@0: if ( aBuffer.Size() >= 3 ) sl@0: { sl@0: // Check next byte is signature algorithm value from 0 - 2 sl@0: if ( aBuffer[1] == 0x00 || aBuffer[1] == 0x01 || aBuffer[1] == 0x02 ) sl@0: { sl@0: // Check Identifier Type for Issuer Identifier sl@0: if ( aBuffer[2] == 0x01 ) sl@0: { sl@0: iDataType = TDataType( KDataTypeWAP_WTLS_CA_Certificate ); sl@0: } sl@0: else sl@0: { sl@0: iDataType = TDataType( KDataTypeWAPCertificateResponse ); sl@0: } sl@0: iConfidence = EPossible; sl@0: } sl@0: } sl@0: } sl@0: sl@0: CApaDataRecognizerType* CApaCertificateRecognizer::CreateRecognizerL() sl@0: { sl@0: return new (ELeave) CApaCertificateRecognizer(); sl@0: } sl@0: sl@0: const TImplementationProxy ImplementationTable[] = sl@0: { sl@0: IMPLEMENTATION_PROXY_ENTRY(0x102034A2, CApaCertificateRecognizer::CreateRecognizerL) sl@0: }; sl@0: sl@0: EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount) sl@0: { sl@0: aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy); sl@0: return ImplementationTable; sl@0: } sl@0: