/*
 * Unwrap a shrouded key.
 */
CSSM_RETURN p12UnwrapKey(
	CSSM_CSP_HANDLE		cspHand,
	CSSM_DL_DB_HANDLE_PTR	dlDbHand,		// optional
	int					keyIsPermanent,		// nonzero - store in DB
	const CSSM_DATA		&shroudedKeyBits,
	CSSM_ALGORITHMS		keyAlg,				// of the unwrapping key
	CSSM_ALGORITHMS		encrAlg,
	CSSM_ALGORITHMS		pbeHashAlg,			// SHA1, MD5 only
	uint32				keySizeInBits,
	uint32				blockSizeInBytes,	// for IV
	CSSM_PADDING		padding,			// CSSM_PADDING_PKCS7, etc.
	CSSM_ENCRYPT_MODE	mode,				// CSSM_ALGMODE_CBCPadIV8, etc.
	uint32				iterCount,
	const CSSM_DATA		&salt,
	const CSSM_DATA		*pwd,		// unicode external representation
	const CSSM_KEY		*passKey,
	SecNssCoder			&coder,		// for mallocing privKey
	const CSSM_DATA		&labelData,
	SecAccessRef		access,		// optional 
	bool				noAcl,
	CSSM_KEYUSE			keyUsage,
	CSSM_KEYATTR_FLAGS	keyAttrs,

	/*
	 * Result: a private key, reference format, optionaly stored
	 * in dlDbHand
	 */
	CSSM_KEY_PTR		&privKey)
{
	CSSM_RETURN crtn;
	CSSM_KEY ckey;
	CSSM_CC_HANDLE ccHand = 0;
	CSSM_KEY wrappedKey;
	CSSM_KEY unwrappedKey;
	CSSM_KEYHEADER &hdr = wrappedKey.KeyHeader;
	CSSM_DATA descrData = {0, NULL};	// not used for PKCS8 wrap 
	CSSM_KEYATTR_FLAGS reqAttr = keyAttrs;
	
	ResourceControlContext rcc;
	ResourceControlContext *rccPtr = NULL;
	Security::KeychainCore::Access::Maker maker;
	
	/* P12 style IV derivation, optional */
	CSSM_DATA iv = {0, NULL};
	CSSM_DATA_PTR ivPtr = NULL;
	if(blockSizeInBytes) {
		coder.allocItem(iv, blockSizeInBytes);
		ivPtr = &iv;
	}
	
	/* P12 style key derivation */
	crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg,
		keySizeInBits, iterCount, salt, pwd, passKey, iv);
	if(crtn) {
		return crtn;
	}	
	/* subsequent errors to errOut: */
		
	/* CSSM context */
	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
		encrAlg,
		mode,
		NULL,			// access cred
		&ckey,
		ivPtr,			// InitVector, optional
		padding,	
		NULL,			// Params
		&ccHand);
	if(crtn) {
		p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn);
		goto errOut;
	}
	if(dlDbHand) {
		crtn = p12AddContextAttribute(ccHand, 
			CSSM_ATTRIBUTE_DL_DB_HANDLE,
			sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
			dlDbHand);
		if(crtn) {
			p12LogCssmError("AddContextAttribute", crtn);
			goto errOut;
		}
	}
	
	/*
	 * Cook up minimal WrappedKey header fields
	 */
	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
	memset(&unwrappedKey, 0, sizeof(CSSM_KEY));
	
	hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
	hdr.BlobType = CSSM_KEYBLOB_WRAPPED;
	hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
	
	/* 
	 * This one we do not know. The CSP will figure out the format 
	 * of the unwrapped key after it decrypts the raw key material. 
	 */
	hdr.AlgorithmId = CSSM_ALGID_NONE;
	hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
	
	/* also inferred by CSP */
	hdr.LogicalKeySizeInBits = 0;
	hdr.KeyAttr = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE;
	hdr.KeyUsage = CSSM_KEYUSE_ANY;
	hdr.WrapAlgorithmId = encrAlg;
	hdr.WrapMode = mode;
	
	if(dlDbHand && keyIsPermanent) {
		reqAttr |= CSSM_KEYATTR_PERMANENT;
	}

	wrappedKey.KeyData = shroudedKeyBits;
	
	if(!noAcl) {
		// Create a Access::Maker for the initial owner of the private key.
		memset(&rcc, 0, sizeof(rcc));
		maker.initialOwner(rcc);
		rccPtr = &rcc;
	}
	
	crtn = CSSM_UnwrapKey(ccHand,
		NULL,				// PublicKey
		&wrappedKey,
		keyUsage,
		reqAttr,
		&labelData,
		rccPtr,					// CredAndAclEntry
		privKey,
		&descrData);			// required
	if(crtn) {
		p12LogCssmError("CSSM_UnwrapKey", crtn);
		if(crtn == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) {
			/* report in a keychain-friendly way */
			crtn = errSecDuplicateItem;
		}
	}
	
	// Finally fix the acl and owner of the private key to the 
	// specified access control settings.
	if((crtn == CSSM_OK) && !noAcl) {
		try {
			CssmClient::KeyAclBearer bearer(
				cspHand, *privKey, Allocator::standard());
			SecPointer<KeychainCore::Access> initialAccess(access ?
				KeychainCore::Access::required(access) :		/* caller-supplied */
				new KeychainCore::Access("privateKey"));		/* default */
			initialAccess->setAccess(bearer, maker);
		}
		catch (const CssmError &e) {
			/* not implemented means we're talking to the CSP which does
			 * not implement ACLs */
			if(e.error != CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED) {
				crtn = e.error;
			}
		}
		catch(...) {
			p12ErrorLog("p12 exception on setAccess\n");
			crtn = errSecAuthFailed;	/* ??? */
		}
	}

errOut:
	if(ccHand) {
		CSSM_DeleteContext(ccHand);
	}
	CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE);
	return crtn;
}
// ---------------------------------------------------------
// CActiveDisconnectDlgPlugin::IsConnectionL
// ---------------------------------------------------------
//
TBool CActiveDisconnectDlgPlugin::IsConnectionL( 
                                            CConnectionInfo* aConnectionInfo )
    {
    CLOG_ENTERFN( "CActiveDisconnectDlgPlugin::IsConnectionL" );
    
    TBool result( EFalse );
    
    TUint i( 0 );
    TUint connectionCount( 0 );
    TUint connNum( 0 );
    TUint subConnectionCount( 0 );
    TUint connId( 0 );    
    TInt bearer( 0 );
    TInt connStatus( 0 );

    //TRequestStatus status;
    TName apName;

    RConnectionMonitor connMon;
    result = connMon.ConnectL();
    CLOG_WRITEF( _L( "result: %d" ), result );     
    
    CDisconnectDlgActiveWaiter* waiter = CDisconnectDlgActiveWaiter::NewL();
    CleanupStack::PushL( waiter );
    
    connMon.GetConnectionCount( connNum, waiter->iStatus );
    waiter->WaitForRequest();
    //User::WaitForRequest( status );
    CLOG_WRITEF( _L( "status: %d" ), waiter->iStatus.Int() );  
    CLOG_WRITEF( _L( "connNum: %d" ), connNum );     
           
    for( i = 1; i < ( connNum + 1 ) && !connectionCount; ++i )
        {
        connMon.GetConnectionInfo( i, connId, subConnectionCount );

        connMon.GetStringAttribute( connId, 0, KIAPName, apName, waiter->iStatus );
        waiter->WaitForRequest();
        //User::WaitForRequest( status );
        CLOG_WRITEF( _L( "KIAPName status: %d" ), waiter->iStatus.Int() );     
         
    
        connMon.GetIntAttribute( connId, 0, KBearer, bearer, waiter->iStatus );
        waiter->WaitForRequest();
        //User::WaitForRequest( status );
        CLOG_WRITEF( _L( "KBearer status: %d" ), waiter->iStatus.Int() );     
        

        connMon.GetIntAttribute( connId, 0, KConnectionStatus, connStatus, 
                                 waiter->iStatus );
        waiter->WaitForRequest();
        //User::WaitForRequest( status );
        CLOG_WRITEF( _L( "KConnectionStatus status: %d" ), waiter->iStatus.Int() );     
        
        TUint iapId( 0 );
        connMon.GetUintAttribute( connId, 0, KIAPId, iapId, waiter->iStatus ); 
        waiter->WaitForRequest();
        //User::WaitForRequest( status );
        CLOG_WRITEF(_L( "KIAPId status: %d" ), waiter->iStatus.Int() );  
        CLOG_WRITEF(_L( "iapId: %d" ), iapId );
        
        TConnMonTimeBuf timeBuf;
        connMon.GetPckgAttribute( connId, 0, KStartTime, timeBuf, waiter->iStatus );
        waiter->WaitForRequest();
        CLOG_WRITEF(_L( "KStartTime status: %d" ), waiter->iStatus.Int() ); 
       
        switch( bearer )
            {
            case EBearerGPRS :
            case EBearerEdgeGPRS :
            case EBearerExternalGPRS : 
            case EBearerExternalEdgeGPRS :
            case EBearerWCDMA :
            case EBearerExternalWCDMA :
#ifdef __WINS__
            case EBearerLAN :
#endif // WINS
                {
                if ( ( connStatus == KLinkLayerOpen ) ||
                     ( connStatus == KConnectionOpen && 
                       bearer >= EBearerExternalCSD ) )
                    {      
                    apName.Trim();
                    if( apName.Left( KMrouterName().Length() ).
                        CompareF( KMrouterName ) )
                        {
                        ++connectionCount;
                        aConnectionInfo->SetIapNameL( apName );
                        aConnectionInfo->SetBearerType( bearer );
                        aConnectionInfo->SetConnId( connId );
                        aConnectionInfo->SetIAPId( iapId );
                        aConnectionInfo->SetStartTime( timeBuf() );
                        
                        TConnMonClientEnumBuf clientEnum;
                        connMon.GetPckgAttribute( connId, 0, KClientInfo,
                                                    clientEnum, waiter->iStatus );
                        waiter->WaitForRequest();
                        //User::WaitForRequest( status );
                        aConnectionInfo->SetClientInfo( clientEnum() );

                        CLOG_WRITEF( _L( "KClientInfo status: %d" ), waiter->iStatus.Int() );
                        }                    
                    }
                break;
                }
            default :
                {
                break;
                }                
            }
        }
    CleanupStack::PopAndDestroy( waiter );    
    connMon.Close();
    result = connectionCount ? ETrue : EFalse;

    CLOG_WRITEF( _L( "connectionCount: %d" ), connectionCount );     
    CLOG_WRITEF( _L( "result: %d" ), result );     
    CLOG_LEAVEFN( "CActiveDisconnectDlgPlugin::IsConnectionL" );

    return result;      
    }