diff -r 000000000000 -r 164170e6151a wim/WimServer/src/WimCertHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wim/WimServer/src/WimCertHandler.cpp Tue Jan 26 15:20:08 2010 +0200 @@ -0,0 +1,1232 @@ +/* +* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Certificate management methods +* +*/ + + + +// INCLUDE FILES +#include "Wimi.h" // wimi definitions +#include "WimCertHandler.h" +#include "WimMemMgmt.h" +#include "WimSession.h" +#include "WimResponse.h" +#include "WimUtilityFuncs.h" +#include // asn.1 encoding +#include // asn.1 decoding +#include // cx509certificate +#ifndef SYMBIAN_ENABLE_SPLIT_HEADERS +#include // cx509rsapublickey +#else +#include // cx509rsapublickey +#include // cx509rsapublickey +#endif +#include // cwtlscertificate +#include // cwtlsrsapublickey +#include "WimTrace.h" +#include "WimCallbackImpl.h" +#include "WimCleanup.h" + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CWimCertHandler::CWimCertHandler +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CWimCertHandler::CWimCertHandler() + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::CWimCertHandler | Begin")); + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CWimCertHandler::ConstructL() + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::ConstructL | Begin")); + iWimUtilFuncs = CWimUtilityFuncs::NewL(); + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CWimCertHandler* CWimCertHandler::NewL() + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::NewL | Begin")); + CWimCertHandler* self = new( ELeave ) CWimCertHandler; + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + + +// Destructor +CWimCertHandler::~CWimCertHandler() + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::~CWimCertHandler | Begin")); + delete iWimUtilFuncs; + + for( TInt index = 0; index < iCertRefLst.Count(); ++index ) + { + WIMI_Ref_t* ref = reinterpret_cast< WIMI_Ref_t* >( iCertRefLst[ index ] ); + _WIMTRACE2(_L("WIM | WIMServer | CWimCertHandler::~CWimCertHandler, -ref 0x%08x"), ref); + free_WIMI_Ref_t( ref ); + iCertRefLst[ index ] = 0; + } + iCertRefLst.Reset(); + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::GetCertificatesFromWimL +// Fetches certificates from WIM card. +// ----------------------------------------------------------------------------- +// +void CWimCertHandler::GetCertificatesFromWimL( + const RMessage2& aMessage, + CWimMemMgmt* aWimMgmt ) + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::GetCertificatesFromWimL | Begin")); + WIMI_STAT callStatus = WIMI_Ok; + TUint8 certNum = 0; + WIMI_Ref_t* temp = NULL; + + HBufC8* certRefLst = iWimUtilFuncs->DesLC( 0, aMessage ); + HBufC8* certInfoLst = iWimUtilFuncs->DesLC( 1, aMessage ); + + TWimEntryType certEntryType = ( TWimEntryType ) aMessage.Int2(); + + TUint32* pCertRefLst = ( TUint32* )( certRefLst->Des().Ptr() ); + TWimCertInfo* pCertInfoLst = ( TWimCertInfo* )( certInfoLst->Des().Ptr() ); + + temp = aWimMgmt->WimRef(); + if ( !temp ) + { + temp = WIMI_GetWIMRef( 0 ); + aWimMgmt->SetWIMRef( temp ); // takes ownership + } + + if ( temp ) + { + if ( EWimEntryTypeAll == certEntryType || + EWimEntryTypeCA == certEntryType ) + { + callStatus = GetCertificateFromWimRefL( temp, WIMI_CU_CA, + certNum, pCertRefLst, + pCertInfoLst, aMessage ); + + } + if ( callStatus == WIMI_Ok && ( EWimEntryTypeAll == certEntryType || + EWimEntryTypePersonal == certEntryType ) ) + { + callStatus = GetCertificateFromWimRefL( temp, WIMI_CU_Client, + certNum, pCertRefLst, + pCertInfoLst, aMessage ); + + } + + //record the ref for sanity checking, deallocate old refs first + for( TInt index = 0; index < iCertRefLst.Count(); ++index ) + { + WIMI_Ref_t* ref = reinterpret_cast< WIMI_Ref_t* >( iCertRefLst[ index ] ); + _WIMTRACE2(_L("WIM | WIMServer | CWimCertHandler::GetCertificatesFromWimL, -ref 0x%08x"), ref); + free_WIMI_Ref_t( ref ); + iCertRefLst[ index ] = 0; + } + iCertRefLst.Reset(); + for( TInt index = 0; index < certNum; ++index ) + { + _WIMTRACE2(_L("WIM | WIMServer | CWimCertHandler::GetCertificatesFromWimL, +ref 0x%08x"), pCertRefLst[ index ]); + iCertRefLst.AppendL( pCertRefLst[ index ] ); + } + + aMessage.WriteL( 0, certRefLst->Des() ); + aMessage.WriteL( 1, certInfoLst->Des() ); + } + else + { + callStatus = WIMI_ERR_OutOfMemory; + } + CleanupStack::PopAndDestroy( 2, certRefLst ); // certInfoLst, certRefLst + aMessage.Complete( CWimUtilityFuncs::MapWIMError( callStatus ) ); + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::GetCertificateFromWimRefL +// Fetches certificate from the WIM card. +// ----------------------------------------------------------------------------- +// +WIMI_STAT CWimCertHandler::GetCertificateFromWimRefL( + WIMI_Ref_t* aTmpWimRef, + TInt8 aUsage, + TUint8& aCertNum, + TUint32* aCertRefLst, + TWimCertInfo* aCertInfoLst, + const RMessage2& aMessage ) + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::GetCertificateFromWimRefL | Begin")); + TUint8 tempCrtCount; + WIMI_RefList_t refList = NULL; + WIMI_STAT callStatus = WIMI_Ok; + + if ( aTmpWimRef ) + { + callStatus = WIMI_GetCertificateListByWIM( aTmpWimRef, + aUsage, + &tempCrtCount, + &refList ); + + if ( callStatus == WIMI_Ok ) + { + // If the certifcate length is 0, + // the step increases by 1. + TInt step = 0; + TInt err = KErrNone; + for ( TUint8 certIndex = 0; certIndex < tempCrtCount; certIndex++ ) + { + TInt current = aCertNum + certIndex - step; + err = CopyCertificateInfo( aCertInfoLst[current], refList[certIndex], aMessage ); + + if ( err == KErrNone ) + { + // transfers ownership of refList item to aCertRefLst + aCertRefLst[current] = reinterpret_cast< TUint32 >( refList[certIndex] ); + refList[certIndex] = NULL; + } + else // KErrArgument + { + // ingore certificate info and continue with the next + step++; + free_WIMI_Ref_t( refList[certIndex] ); + } + } + //variable step is equal to the number of certificate in CDF whose + //length is set as 0. + aCertNum = static_cast< TUint8 >( aCertNum + tempCrtCount - step ); + + // Because list items are moved to aCertRefLst, only refList array + // needs to be freed. Cannot use free_WIMI_RefList_t() as it would + // delete also items contained in refList. + WSL_OS_Free( refList ); + } + } + + return callStatus; + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::CopyCertificateInfo +// Copies certificate information to client's allocated memory area. +// This function MAY NOT leave. +// ----------------------------------------------------------------------------- +// +TInt CWimCertHandler::CopyCertificateInfo( + TWimCertInfo& aCertInfo, + WIMI_Ref_t* aCert, + const RMessage2& /*aMessage*/ ) + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::CopyCertificateInfo | Begin")); + WIMI_Ref_t* tempRef = NULL; + WIMI_BinData_t ptLabel; + WIMI_BinData_t ptKeyID; + WIMI_BinData_t ptCAID; + WIMI_BinData_t ptIssuerHash; + WIMI_BinData_t ptTrustedUsage; + TUint8 uiCDFRefs; + TUint8 usage; + TUint8 type; + TUint16 certLen; + TUint8 modifiable = 0; + WIMI_STAT callStatus = WIMI_GetCertificateInfo( + aCert, + &tempRef, + &ptLabel, + &ptKeyID, /* Key Id (hash)*/ + &ptCAID, + &ptIssuerHash, + &ptTrustedUsage, + &uiCDFRefs, + &usage, /* 0 = client, 1 = CA */ + &type, /* WTLSCert(1), + X509Cert(2), + X968Cert(3), + CertURL(4) */ + &certLen, /* cert. content or URL length */ + &modifiable ); + + if ( callStatus == WIMI_Ok ) + { + free_WIMI_Ref_t( tempRef ); + + // To make sure the length of the certificate is not zero + _WIMTRACE2(_L("WIM | WIMServer | CWimCertHandler::CopyCertificateInfoL | certLen %d"), certLen); + if ( certLen == 0 ) + { + WSL_OS_Free( ptLabel.pb_buf ); + WSL_OS_Free( ptKeyID.pb_buf ); + WSL_OS_Free( ptCAID.pb_buf ); + WSL_OS_Free( ptIssuerHash.pb_buf ); + WSL_OS_Free( ptTrustedUsage.pb_buf ); + return KErrArgument; + } + + // it is x509cert + if ( type == 2 && certLen != 0 ) + { + //use this rough sanity checking for temp + if ( certLen < 10 ) + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::CopyCertificateInfoL | cert is malformated, return KErrArgument")); + WSL_OS_Free( ptLabel.pb_buf ); + WSL_OS_Free( ptKeyID.pb_buf ); + WSL_OS_Free( ptCAID.pb_buf ); + WSL_OS_Free( ptIssuerHash.pb_buf ); + WSL_OS_Free( ptTrustedUsage.pb_buf ); + return KErrArgument; + } + } + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::CopyCertificateInfoL | X509 check ok")); + + aCertInfo.iLabel.Copy( + TPtr8( + ptLabel.pb_buf, + ptLabel.ui_buf_length, + ptLabel.ui_buf_length ) ); + + aCertInfo.iKeyId.Copy( + TPtr8( + ptKeyID.pb_buf, + ptKeyID.ui_buf_length, + ptKeyID.ui_buf_length ) ); + + aCertInfo.iCAId.Copy( + TPtr8( + ptCAID.pb_buf, + ptCAID.ui_buf_length, + ptCAID.ui_buf_length ) ); + + aCertInfo.iIssuerHash.Copy( + TPtr8( + ptIssuerHash.pb_buf, + ptIssuerHash.ui_buf_length, + ptIssuerHash.ui_buf_length ) ); + + aCertInfo.iUsage = usage; + aCertInfo.iType = type; + aCertInfo.iCertlen = certLen; + aCertInfo.iModifiable = modifiable; + + // Certificate location + aCertInfo.iCDFRefs = iWimUtilFuncs->MapCertLocation( uiCDFRefs ); + + //Allocate enough memory for OID + aCertInfo.iTrustedUsageLength = ptTrustedUsage.ui_buf_length * 16; + + WSL_OS_Free( ptLabel.pb_buf ); + WSL_OS_Free( ptKeyID.pb_buf ); + WSL_OS_Free( ptCAID.pb_buf ); + WSL_OS_Free( ptIssuerHash.pb_buf ); + WSL_OS_Free( ptTrustedUsage.pb_buf ); + } + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::GetExtrasFromWimL +// Fetches certificate's extra info from WIM card. In this case it is +// trusted usage info. +// ----------------------------------------------------------------------------- +// +void CWimCertHandler::GetExtrasFromWimL( + const RMessage2& aMessage, + CWimMemMgmt* aWimMgmt ) + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::GetExtrasFromWimL | Begin")); + + WIMI_STAT callStatus = WIMI_Ok; + TInt8 certUsage = 0; + + HBufC8* keyIdBuf = iWimUtilFuncs->DesLC( 0, aMessage ); + TPtrC8 keyIdHash = keyIdBuf->Des(); + + WIMI_Ref_t* wimTempRef = aWimMgmt->WimRef(); + if ( !wimTempRef ) + { + wimTempRef = WIMI_GetWIMRef( 0 ); + aWimMgmt->SetWIMRef( wimTempRef ); // takes ownership + } + + if ( wimTempRef ) + { + TWimEntryType certEntryType = static_cast< TWimEntryType >( aMessage.Int2() ); + switch ( certEntryType ) + { + case EWimEntryTypeCA: + { + certUsage = WIMI_CU_CA; + break; + } + case EWimEntryTypeAll: //Flow through + case EWimEntryTypePersonal: + { + certUsage = WIMI_CU_Client; + break; + } + default: + { + callStatus = WIMI_ERR_BadParameters; + break; + } + } + + if ( callStatus == WIMI_Ok ) + { + callStatus = GetExtrasFromWimRefL( wimTempRef, + certUsage, + keyIdHash, + aMessage ); + } + } + else + { + callStatus = WIMI_ERR_BadReference; + } + + CleanupStack::PopAndDestroy( keyIdBuf ); + aMessage.Complete( CWimUtilityFuncs::MapWIMError( callStatus ) ); + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::GetExtrasFromWimRefL +// Fetches extra information (e.g. certs trusted usage) from the WIM card. +// ----------------------------------------------------------------------------- +// +WIMI_STAT CWimCertHandler::GetExtrasFromWimRefL( + WIMI_Ref_t* aTmpWimRef, + TInt8 aUsage, + TDesC8& aKeyHash, + const RMessage2& aMessage ) + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::GetExtrasFromWimRefL | Begin")); + + TUint8 tempCertCount = 0; + WIMI_RefList_t certRefList = NULL; + WIMI_STAT callStatus = WIMI_Ok; + TInt certIndex = 0; + TPtrC8 keyHash; + + if ( aTmpWimRef ) + { + // List all certificates (by WIM and usage) + callStatus = WIMI_GetCertificateListByWIM( aTmpWimRef, + aUsage, + &tempCertCount, + &certRefList ); + } + else + { + callStatus = WIMI_ERR_BadReference; + } + CleanupPushWimRefListL( certRefList ); + + if ( callStatus == WIMI_Ok ) + { + WIMI_Ref_t* tempRef = NULL; + WIMI_BinData_t ptLabel; + WIMI_BinData_t ptKeyID; + WIMI_BinData_t ptCAID; + WIMI_BinData_t ptIssuerHash; + WIMI_BinData_t ptTrustedUsage; + TUint8 uiCDFRefs; + TUint8 usage; + TUint8 certType; + TUint16 certLen; + TUint8 modifiable = 0; + + for ( TInt i = 0; i < tempCertCount; i++ ) + { + // Get info for each certificate until we find valid cert + callStatus = WIMI_GetCertificateInfo( certRefList[i], + &tempRef, + &ptLabel, + &ptKeyID, + &ptCAID, + &ptIssuerHash, + &ptTrustedUsage, + &uiCDFRefs, + &usage, + &certType, + &certLen, + &modifiable ); + if ( callStatus == WIMI_Ok ) + { + free_WIMI_Ref_t( tempRef ); + + // Code MAY NOT leave before ptLabel.pb_buf, ptKeyID.pb_buf, + // ptCAID.pb_buf, ptIssuerHash.pt_buf, and ptTrustedUsage.pb_buf + // are deallocated. + + keyHash.Set( ptKeyID.pb_buf, ptKeyID.ui_buf_length ); + + // Compare given and fetched key hash + if ( keyHash.Compare( aKeyHash ) == 0 && + certType == WIMI_CT_X509 ) //Match + { + certIndex = i; // Found one + i = tempCertCount; // Stop looping + callStatus = WIMI_Ok; + } + else // Cert not supported + { + callStatus = WIMI_ERR_UnsupportedCertificate; + } + + WSL_OS_Free( ptLabel.pb_buf ); + WSL_OS_Free( ptKeyID.pb_buf ); + WSL_OS_Free( ptCAID.pb_buf ); + WSL_OS_Free( ptIssuerHash.pb_buf ); + WSL_OS_Free( ptTrustedUsage.pb_buf ); + // Code can leave after this point. + } + } + + if ( callStatus == WIMI_Ok ) + { + CopyCertExtrasInfoL( certRefList[certIndex], aMessage ); + } + + CleanupStack::PopAndDestroy( certRefList ); + } + + return callStatus; + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::CopyCertExtrasInfoL +// Copies certs extra information to client's allocated memory area. +// ----------------------------------------------------------------------------- +// +void CWimCertHandler::CopyCertExtrasInfoL( + WIMI_Ref_t* aCert, + const RMessage2& aMessage ) + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::CopyCertExtrasInfoL | Begin")); + TUint8 pushedItemCount = 0; + WIMI_Ref_t* tempref = NULL; + WIMI_BinData_t ptLabel; + WIMI_BinData_t ptKeyID; + WIMI_BinData_t ptCAID; + WIMI_BinData_t ptIssuerHash; + WIMI_BinData_t ptTrustedUsage; + TUint8 uiCDFRefs; + TUint8 usage; + TUint8 type; + TUint16 certlen; + TUint8 modifiable = 0; + TBool found = ETrue; + + TCertExtrasInfo certExtraInfo; + certExtraInfo.iCDFRefs = 0; + certExtraInfo.iTrustedUsage = NULL; + + WIMI_STAT callStatus = WIMI_GetCertificateInfo( + aCert, + &tempref, + &ptLabel, + &ptKeyID, /* Key Id (hash)*/ + &ptCAID, + &ptIssuerHash, + &ptTrustedUsage, + &uiCDFRefs, + &usage, /* 0 = client, 1 = CA */ + &type, + &certlen, /* cert. content or URL length */ + &modifiable); + if ( callStatus == WIMI_Ok ) + { + free_WIMI_Ref_t( tempref ); + WSL_OS_Free( ptLabel.pb_buf ); + WSL_OS_Free( ptKeyID.pb_buf ); + WSL_OS_Free( ptCAID.pb_buf ); + WSL_OS_Free( ptIssuerHash.pb_buf ); + + CleanupPushWimBufL( ptTrustedUsage ); + pushedItemCount++; + + TPtrC8 undecodedUsage; + undecodedUsage.Set( ptTrustedUsage.pb_buf ); + + if ( ptTrustedUsage.ui_buf_length == 0 ) // No OIDs + { + found = EFalse; + } + + // DECODE OIDs + TASN1DecObjectIdentifier decoder; + RPointerArray decodedOIDArray; + CleanupResetAndDestroyPushL( decodedOIDArray ); + pushedItemCount++; + HBufC* decodedOIDs = NULL; + TInt oidsLength = 0; // length of total OID buffer + TInt err; + + for ( TInt position = 0; found; ) //Loop until no OIDs found anymore + { + if ( undecodedUsage.Length() > position ) //Don't go over buffer + { + TRAP( err, decodedOIDs = decoder.DecodeDERL( undecodedUsage, position ) ); + if ( err == KErrNone ) //Found OID + { + CleanupStack::PushL( decodedOIDs ); + if ( decodedOIDs->Length() ) + { + found = ETrue; + decodedOIDArray.AppendL( decodedOIDs ); + oidsLength += decodedOIDs->Length(); + CleanupStack::Pop( decodedOIDs ); + } + else // Not found OID from buffer + { + found = EFalse; + CleanupStack::PopAndDestroy( decodedOIDs ); + } + decodedOIDs = NULL; + } + else // Error in OID parsing -> Not found OID + { + found = EFalse; + } + } + else // undecoded OID buffer seeked through + { + found = EFalse; + } + } + + _LIT( KDelimeter16, " " ); //Delimeter between OIDs + TInt trustedUsagesBufMaxLength = oidsLength + decodedOIDArray.Count(); + TPtr trustedUsage( NULL, 0, trustedUsagesBufMaxLength ); + + if ( oidsLength > 0 ) // OID's found + { + // Alloc new buffer for all OID's + HBufC* trustedUsagesBuf = HBufC::NewLC( trustedUsagesBufMaxLength ); + pushedItemCount++; + + trustedUsage.Set( trustedUsagesBuf->Des() ); + + // Add OID's to one buffer from separate buffers + for ( TInt i = 0; i < decodedOIDArray.Count(); i++ ) + { + if ( i == 0 ) //First one + { + trustedUsage.Copy( decodedOIDArray[i]->Des() ); + } + else // Append other OIDs, with delimeter + { + trustedUsage.Append( KDelimeter16 ); + trustedUsage.Append( decodedOIDArray[i]->Des() ); + } + } + } + + TPckgBuf wimCertExtraPckg( certExtraInfo ); + aMessage.ReadL( 1, wimCertExtraPckg ); + + wimCertExtraPckg().iCDFRefs = iWimUtilFuncs->MapCertLocation( uiCDFRefs ); + + if ( oidsLength > 0 ) // OID's found, write buffer to client + { + aMessage.WriteL( 3, trustedUsage ); + } + aMessage.WriteL( 1, wimCertExtraPckg ); + + CleanupStack::PopAndDestroy( pushedItemCount, ptTrustedUsage.pb_buf ); + } + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::GetCerticateCountL +// Fetches count of certicates in certain WIM card. +// ----------------------------------------------------------------------------- +// +void CWimCertHandler::GetCerticateCountL( + const RMessage2& aMessage, + CWimMemMgmt* aWimMgmt ) const + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::GetCerticateCountL | Begin")); + WIMI_STAT callStatus = WIMI_Ok; + TWimEntryType certEntryType = ( TWimEntryType )aMessage.Int1(); + + __ASSERT_ALWAYS( certEntryType != EWimEntryTypeAll || + certEntryType != EWimEntryTypeCA || + certEntryType != EWimEntryTypePersonal, User::Leave( KErrArgument ) ); + + WIMI_Ref_t* wimRef = NULL; + TUint8 certCount = 0; + + wimRef = aWimMgmt->WimRef(); + if ( !wimRef ) + { + wimRef = WIMI_GetWIMRef( 0 ); + aWimMgmt->SetWIMRef( wimRef ); // takes ownership + } + + if ( wimRef ) + { + if ( EWimEntryTypeAll == certEntryType || + EWimEntryTypeCA == certEntryType ) + { + callStatus = GetCertificateCountByWIM( wimRef, + certCount, + WIMI_CU_CA ); + } + + if ( callStatus == WIMI_Ok && ( EWimEntryTypeAll == certEntryType || + EWimEntryTypePersonal == certEntryType ) ) + { + callStatus = GetCertificateCountByWIM( wimRef, + certCount, + WIMI_CU_Client ); + } + } + else + { + callStatus = WIMI_ERR_OutOfMemory; + } + + if ( callStatus == WIMI_Ok ) + { + _WIMTRACE2(_L("WIM | WIMServer | CWimCertHandler::GetCerticateCountL | count=%d"), certCount); + TPckgBuf pckg( certCount ); + aMessage.WriteL( 0, pckg ); + } + aMessage.Complete( CWimUtilityFuncs::MapWIMError( callStatus ) ); + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::GetCertificateCountByWIM +// Fetches count of certicates in certain WIM card. +// This function MAY NOT leave. +// ----------------------------------------------------------------------------- +// +WIMI_STAT CWimCertHandler::GetCertificateCountByWIM( + WIMI_Ref_t* aRef, + TUint8& aCertCount, + TUint8 aUsage ) const + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::GetCertificateCountByWIM | Begin")); + + // Get the number of certificates from smart card. + TUint8 certNum = 0; + WIMI_RefList_t refList ; + WIMI_STAT callStatus = WIMI_GetCertificateListByWIM( aRef, + aUsage, + &certNum, + &refList ); + + if ( callStatus != WIMI_Ok ) + { + return callStatus; + } + + // Find out how many certificate has zero length + TInt certLenZero = 0; + TInt certMalformat = 0; + for ( TInt i = 0; i < certNum ; i++ ) + { + WIMI_Ref_t* tempRef = NULL; + WIMI_BinData_t ptLabel; + WIMI_BinData_t ptKeyID; + WIMI_BinData_t ptCAID; + WIMI_BinData_t ptIssuerHash; + WIMI_BinData_t ptTrustedUsage; + TUint8 uiCDFRefs; + TUint8 usage; + TUint8 type; + TUint16 certLen; + TUint8 modifiable = 0; + callStatus = WIMI_GetCertificateInfo( + refList[i], + &tempRef, + &ptLabel, + &ptKeyID, /* Key Id (hash)*/ + &ptCAID, + &ptIssuerHash, + &ptTrustedUsage, + &uiCDFRefs, + &usage, /* 0 = client, 1 = CA */ + &type, /* WTLSCert(1), + X509Cert(2), + X968Cert(3), + CertURL(4) */ + &certLen, /* cert. content or URL length */ + &modifiable ); + + if ( callStatus == WIMI_Ok ) + { + free_WIMI_Ref_t( tempRef ); + + if ( certLen == 0 ) + { + certLenZero++; + } + + // it is x509cert + if ( type == 2 && certLen != 0 ) + { + + //use this rough sanity checking + if ( certLen < 10 ) + { + certMalformat++; + } + } + + WSL_OS_Free( ptLabel.pb_buf ); + WSL_OS_Free( ptKeyID.pb_buf ); + WSL_OS_Free( ptCAID.pb_buf ); + WSL_OS_Free( ptIssuerHash.pb_buf ); + WSL_OS_Free( ptTrustedUsage.pb_buf ); + } + } + + // only return the number of ceritifcates that have non-zero length + if ( callStatus == WIMI_Ok ) + { + aCertCount = static_cast< TUint8 >( aCertCount + certNum - certLenZero - certMalformat ); + } + + free_WIMI_RefList_t( refList ); + + return callStatus; + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::StoreCertificateL +// Stores certificate to the WIM card. +// ----------------------------------------------------------------------------- +// +void CWimCertHandler::StoreCertificateL( + TWimServRqst /*aOpcode*/, + const RMessage2& aMessage ) const + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::StoreCertificateL | Begin")); + aMessage.Complete( KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::RemoveCertificateL +// Removes certificate from a WIM card. +// ----------------------------------------------------------------------------- +// +void CWimCertHandler::RemoveCertificateL( + const RMessage2& aMessage, + CWimMemMgmt* /*aWimMgmt*/ ) const + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::RemoveCertificateL | Begin")); + aMessage.Complete( KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::SanityCheck +// ----------------------------------------------------------------------------- +// +TBool CWimCertHandler::SanityCheck( TUint32 aCertRef ) + { + TInt certNum = iCertRefLst.Count(); + if ( certNum == 0 ) + { + return EFalse; + } + + for ( TInt index = 0; index < certNum; ++index ) + { + if( aCertRef == iCertRefLst[ index ] ) + { + return ETrue; + } + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::GetCertificateDetailsL +// Fetches certificate details. +// ----------------------------------------------------------------------------- +// +void CWimCertHandler::GetCertificateDetailsL( + TWimServRqst aOpCode, + const RMessage2& aMessage ) + { + _WIMTRACE(_L("WIM | WIMServer | CWimCertHandler::GetCertificateDetailsL | Begin")); + TBool IsOk = SanityCheck( (TUint32)aMessage.Ptr0() ); + if ( ! IsOk ) + { + aMessage.Panic(_L("WIM"), KErrBadHandle ); + return; + } + + //capability checking + TUint8 usage = 255; + WIMI_STAT callStatus = ResolveCertUsage( aMessage, usage ); + if ( WIMI_Ok == callStatus ) + { + if( !CheckReadCapsForUsage( aMessage, usage ) ) + { + aMessage.Complete(KErrPermissionDenied); + return; + } + } + + //capabilty ok, go to fetch the details of the certificate. + WIMI_Ref_pt pCertRef = const_cast( aMessage.Ptr0() ); + CWimResponse* responseID = new( ELeave ) CWimResponse( aMessage ); + CleanupStack::PushL( responseID ); + TWimReqTrId* trId = iWimUtilFuncs->TrIdLC( responseID, EWimMgmtReq ); + responseID->iOpcode = aOpCode; + CleanupStack::Pop( 2, responseID ); // trId, responseID + + WIMI_STAT certReqStatus = WIMI_CertificateReq( trId, pCertRef ); + if ( certReqStatus != WIMI_Ok ) + { + responseID->iStatus = certReqStatus; + responseID->CompleteMsgAndDelete(); + delete trId; + } + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::ResolveCertUsage +// Resolves usage (CA/User) for a certificate. +// ----------------------------------------------------------------------------- +// +WIMI_STAT CWimCertHandler::ResolveCertUsage( const RMessage2& aMsg, + TUint8& aUsage ) + { + _WIMTRACE(_L("CWimServer::ResolveCertUsage | Begin")); + + // aMsg.Ptr0 contains reference to certificate + + WIMI_Ref_pt pCertRef = const_cast< WIMI_Ref_pt >( aMsg.Ptr0() ); + _WIMTRACE2(_L("CWimServer::ResolveCertUsage | Begin aMsg.Ptr0() = %d"), aMsg.Ptr0()); + + WIMI_STAT callStatus = GetCertificateInfo( pCertRef, aUsage ); + + _WIMTRACE(_L("CWimServer::ResolveCertUsage | End")); + return callStatus; + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::GetCertificateInfo +// Fetches certificate info. Wrapper for WIMI call. +// ----------------------------------------------------------------------------- +// +WIMI_STAT CWimCertHandler::GetCertificateInfo( WIMI_Ref_pt aCertRef, + TUint8& aUsage ) + { + _WIMTRACE(_L("CWimServer::GetCertificateInfo | Begin")); + + WIMI_Ref_pt pWimRef = NULL; + WIMI_BinData_t ptLabel; + WIMI_BinData_t ptKeyID; + WIMI_BinData_t ptCAID; + WIMI_BinData_t ptIssuerHash; + WIMI_BinData_t ptTrustedUsage; + TUint8 uiCDFRefs; + TUint8 type; + TUint16 certLen; + TUint8 modifiable = 0; + _WIMTRACE(_L("CWimServer::GetCertificateInfo | Begin 1")); + WIMI_STAT callStatus = WIMI_GetCertificateInfo( + aCertRef, + &pWimRef, + &ptLabel, + &ptKeyID, // Key Id (hash) + &ptCAID, + &ptIssuerHash, + &ptTrustedUsage, + &uiCDFRefs, + &aUsage, // 0 = client, 1 = CA + &type, // WTLSCert(1), + // X509Cert(2), + // X968Cert(3), + // CertURL(4) + &certLen, // cert. content or URL length + &modifiable ); + _WIMTRACE(_L("CWimServer::GetCertificateInfo | Begin 2")); + // Don't need references anymore + if ( callStatus == WIMI_Ok ) + { + free_WIMI_Ref_t( pWimRef ); + WSL_OS_Free( ptLabel.pb_buf ); + WSL_OS_Free( ptKeyID.pb_buf ); + WSL_OS_Free( ptCAID.pb_buf ); + WSL_OS_Free( ptIssuerHash.pb_buf ); + WSL_OS_Free( ptTrustedUsage.pb_buf ); + } + + _WIMTRACE(_L("CWimServer::GetCertificateInfo | End")); + return callStatus; + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::GetCertificateInfo +// Fetches certificate info. Wrapper for WIMI call. +// ----------------------------------------------------------------------------- +// +TBool CWimCertHandler::CheckReadCapsForUsage( const RMessage2& aMsg, + TUint8 aUsage ) + { + TBool result = EFalse; + + switch ( aUsage ) + { + case WIMI_CU_CA: + { + // CA certificate reading doesn't require any capability. + _WIMTRACE(_L("CWimCertHandler::CheckReadCapsForUsage: CA cert read req, OK.")); + result = ETrue; + break; + } + case WIMI_CU_Client: + { + // User certificate reading requires ReadUserData capability. + if ( aMsg.HasCapability( ECapabilityReadUserData )) + { + result = ETrue; + _WIMTRACE(_L("CWimCertHandler::CheckReadCapsForUsage: User cert read capa PASS")); + } + else + { + result = EFalse; + _WIMTRACE(_L("CWimCertHandler::CheckReadCapsForUsage: User cert read capa FAIL")); + } + break; + } + default: + { + _WIMTRACE(_L("CWimCertHandler::CheckReadCapsAccordingToUsage: FAIL:Unknown usage.")); + result = EFalse; + break; + } + } + _WIMTRACE(_L("CWimCertHandler::CheckReadCapsForUsage | End")); + return result; + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::ExportPublicKeyL +// Export public key from certificate. +// ----------------------------------------------------------------------------- +// +void CWimCertHandler::ExportPublicKeyL( const RMessage2& aMessage ) const + { + _WIMTRACE(_L("WIM | WIMServer | CWimPublicKeyHandler::ExportPublicKeyParamsL | Begin")); + + TUint8 certType = 0; + + TPckgBuf keyExportPckg; + aMessage.ReadL( 0, keyExportPckg ); + + HBufC8* publicKeyBuf = HBufC8::NewLC( KPublicKeyLength ); + + TBuf8 keyIdBuf = keyExportPckg().iKeyId; + + WIMI_STAT callStatus = WIMI_Ok; + WIMI_BinData_t ptCertData; + ptCertData.pb_buf = NULL; + ptCertData.ui_buf_length = 0; + WIMI_Ref_t* pCert = NULL; + WIMI_TransactId_t trId = ( void* )EInitializationCertListHashing; + TUint8 certCount = 0; + WIMI_RefList_t certRefList = NULL; + + // Check firs the Client certs + callStatus = WIMI_GetCertificateListByKeyHash( ( TUint8* )keyIdBuf.Ptr(), + WIMI_CU_Client, + &certCount, + &certRefList ); + if ( callStatus == WIMI_Ok ) + { + if ( certCount == 0 ) // Not found client certs + { + free_WIMI_RefList_t( certRefList ); + certRefList = NULL; + + // Check CA certs + callStatus = WIMI_GetCertificateListByKeyHash( + ( TUint8* )keyIdBuf.Ptr(), + WIMI_CU_CA, + &certCount, + &certRefList ); + } + } + + if ( callStatus == WIMI_Ok ) + { + CleanupPushWimRefListL( certRefList ); + if ( certCount == 0 ) // No certificates found for key + { + CleanupStack::PopAndDestroy( certRefList ); + callStatus = WIMI_ERR_CertNotFound; + } + } + + if ( callStatus == WIMI_Ok ) + { + WIMI_Ref_t* tempRef = NULL; + WIMI_BinData_t ptLabel; + WIMI_BinData_t ptKeyID; + WIMI_BinData_t ptCAID; + WIMI_BinData_t ptIssuerHash; + WIMI_BinData_t ptTrustedUsage; + TUint8 uiCDFRefs; + TUint8 usage; + + TUint16 certLen; + TUint8 modifiable = 0; + + for ( TInt i = 0; i < certCount; i++ ) + { + // Get info for each certificate until we find valid cert + callStatus = WIMI_GetCertificateInfo( certRefList[i], + &tempRef, + &ptLabel, + &ptKeyID, + &ptCAID, + &ptIssuerHash, + &ptTrustedUsage, + &uiCDFRefs, + &usage, + &certType, + &certLen, + &modifiable ); + if ( callStatus == WIMI_Ok ) + { + WSL_OS_Free( ptLabel.pb_buf ); + WSL_OS_Free( ptKeyID.pb_buf ); + WSL_OS_Free( ptCAID.pb_buf ); + WSL_OS_Free( ptIssuerHash.pb_buf ); + WSL_OS_Free( ptTrustedUsage.pb_buf ); + free_WIMI_Ref_t( tempRef ); + + // Certificate has to be WTLS or X509, not URL + if ( certType == WIMI_CT_X509 || certType == WIMI_CT_WTLS ) + { + pCert = certRefList[i]; // Found one + i = certCount; // Stop looping + } + else // Cert not supported + { + callStatus = WIMI_ERR_UnsupportedCertificate; + } + } + } + + // Retrieve certificate data from WIM + if ( callStatus == WIMI_Ok ) + { + callStatus = WIMI_CertificateReqT( trId, pCert, &ptCertData ); + if ( callStatus == WIMI_Ok ) + { + CleanupPushWimBufL( ptCertData ); + + TPtrC8 certPtr( ptCertData.pb_buf, ptCertData.ui_buf_length ); + TPtr8 publicKeyPtr = publicKeyBuf->Des(); + + TRAPD( parseOk, ParseCertPublicKeyL( certPtr, publicKeyPtr, certType ) ); + if ( parseOk ) + { + aMessage.WriteL( 1, publicKeyPtr ); + } + else + { + callStatus = WIMI_ERR_CertParseError; + } + + CleanupStack::PopAndDestroy( ptCertData.pb_buf ); + } + } + + CleanupStack::PopAndDestroy( certRefList ); + } + + CleanupStack::PopAndDestroy( publicKeyBuf ); + + aMessage.Complete( CWimUtilityFuncs::MapWIMError( callStatus ) ); + } + +// ----------------------------------------------------------------------------- +// CWimCertHandler::ParseCertPublicKeyL +// Parse public key from certificate. +// ----------------------------------------------------------------------------- +// +void CWimCertHandler::ParseCertPublicKeyL( + const TDesC8& aCertData, + TDes8& aPublicKey, + const TUint8 aCertType ) const + { + CCertificate* certificate = NULL; + CRSAPublicKey* publicKey = NULL; + + switch ( aCertType ) + { + case WIMI_CT_WTLS: + { + certificate = CWTLSCertificate::NewLC( aCertData ); + publicKey = CWTLSRSAPublicKey::NewLC( certificate->PublicKey().KeyData() ); + break; + } + + case WIMI_CT_X509: + { + certificate = CX509Certificate::NewLC( aCertData ); + publicKey = CX509RSAPublicKey::NewLC( certificate->PublicKey().KeyData() ); + break; + } + default: + { + _WIMTRACE2(_L("WIM|WIMServer|CWimCertHandler::ParseCertPublicKeyL, type %d not supported"), aCertType); + User::Leave( KErrNotSupported ); + break; + } + } + + TX509RSAKeyEncoder encoder( *publicKey, ESHA1 ); + CASN1EncBase* encoded = encoder.EncodeKeyLC(); + + TUint pos = 0; + aPublicKey.SetLength( KPublicKeyLength ); + // Check that Max. length is not exceeded + if ( encoded->LengthDER() > static_cast< TUint >( KPublicKeyLength ) ) + { + _WIMTRACE(_L("WIM|WIMServer|CWimCertHandler::ParseCertPublicKeyL, too long public key")); + User::Leave( KErrBadDescriptor ); + } + // Write encoded key to prealloced buffer + encoded->WriteDERL( aPublicKey, pos ); + + CleanupStack::PopAndDestroy( 3, certificate ); // encoded, publicKey, certificate + } + +// End of File