How to handle an incorrect password for ImportPfxDataAsync which gives __fastfail ?


  • String^ pfxDataBase64= CryptographicBuffer::EncodeToBase64String( theIBuffer ); String^ password= this->Password->Text; // The code signing cert for an application has no password. try { // Incorrect password stops execution, not known how to catch this exception. task<void> importPfxTask( CertificateEnrollmentManager::ImportPfxDataAsync( pfxDataBase64, password, ExportOption::NotExportable, KeyProtectionLevel::NoConsent, InstallOptions::None, "friendlyName" ) ); importPfxTask.then( [=] () { Password->Text= "Made it."; // The certificate is installed in the app container MY store }); } catch ( InvalidArgumentException^ e) { Password->Text= "InvalidArgumentException exception"; } catch ( FailureException ^ e ) { Password->Text= "FailureException exception"; } catch ( Exception ^ e ) { Password->Text= "Exception exception"; } catch ( ... ) { Password->Text= "... exception"; }

    If the password is correct, then this code works correctly.

    If the password is not correct, in the debugger I see a message box with:

    Unhandled exception at 0x5D7F8AE3 (msvcr110d.dll) in App1.exe: An invalid parameter was passed to a function that considers invalid parameters fatal.

    So my questions are:

    How am I supposed to let the user know that they mistyped their password?

    Why doesn't the catch mechanism work for this case?

    New info: I guess the catch mechanism fails because it ends up with fastfail:

    _CRTIMP __declspec(noreturn) void __cdecl _invoke_watson(
        const wchar_t *pszExpression,
        const wchar_t *pszFunction,
        const wchar_t *pszFile,
        unsigned int nLine,
        uintptr_t pReserved
    #if defined (_M_IX86) || defined (_M_X64)
        if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
    #endif  /* defined (_M_IX86) || defined (_M_X64) */

    • Edited by Andrew7Webb Saturday, September 15, 2012 4:59 PM
    Saturday, September 15, 2012 3:27 PM

All replies

  • The problem is that the completion doesn't run in the scope of the try / catch block. You are setting up and kicking off the task chain there, but then your enclosing function returns and the completions run later when they are ready.

    An exception thrown during the task chain will be encapsulated in a task object propagated to the end of the task chain. You can catch it by getting the result in the last completion in the chain:

    	importPfxTask.then( [this] (task<void> t)
                catch(Platform::InvalidArgumentException^ e)
                    Password->Text= "InvalidArgumentException exception";

    See Asynchronous programming in C++ for more information on how to work with asynchronous tasks. In particular, look at the section on handling errors in a task chain.


    Saturday, September 15, 2012 5:56 PM
  • Many thanks for the explanation of catching exceptions with tasks.  The code below now catches an exception:

    		importPfxTask.then( [=] ( task<void> theImportPfxTask) 
    				try {
    					Password->Text= "Made it."; // The certificate is installed in the app container MY store
    				} catch ( Platform::InvalidArgumentException^ e ) {
    					Password->Text= "InvalidArgumentException";
    				} catch ( Platform::COMException ^ e ) {
    					switch( e->HResult ) {
    					case E_INVALIDARG:	Password->Text= "Wrong password";	break;
    					case 0x80071771:	Password->Text= "Decryption failed: Wrong password";	break;	//  EXECUTES HERE
    					default:			Password->Text= "ComException exception";
    					int hResult= e->HResult;

    However, instead of catching an InvalidArgumentException, it actually produces a ComException when the password is wrong. And the hResult is  0x80071771, which I believe is a decryption failed type of error.  That makes some kind of sense because the incorrect password would be used to generate an incorrect key, which would fail to decrypt the .pfx. 

    I failed to find the symbol for 0x80071771.  Is there one?

    There should be a documented and symbolic way to catch a mistyped password for  CertificateEnrollmentManager::ImportPfxDataAsync().

    At the moment neither is true.

    Monday, September 17, 2012 1:39 PM