Jump to content
jaenicke

Bug: Access violation when libcrypto-1_1.dll is missing and loSslInfo is set

Recommended Posts

I had activated loSslInfo as LogOption. Then I got an access violation on another machine. The problem is:

- TCustomSslWSocket.StartSslHandshake calls FSslContext.InitContext

- An exception is raised, because libcrypto-1_1.dll is missing

- This exception is handled in TCustomSslWSocket.StartSslHandshake, but inside the except block TriggerSslHandshakeDone is called. This would be no problem, if IcsX509VerifyErrorToStr would not be called there for logging purposes. In this function X509_verify_cert_error_string is used, which is nil, because the library is missing.

 

I think this is a bug. Am I right?

 

Thank you

 

Share this post


Link to post

I'd suggest if you call StartSslHandshake without previously loading OpenSSL or initialising an SslContext, you need to revise your code when using low level components.  The newer higher level components do all the OpenSSL set-up for you, so errors like this won't happen. 

 

This will only be fixed if you can reproduce it in an ICS sample, it really is not possible to check OpenSSL has been opened before every single OpenSSL function. 

 

Angus

 

Share this post


Link to post

I only wanted to make an SSL call, so I don't think this is a very unusual call. A small example is:

uses
  OverbyteIcsHttpProt, OverbyteIcsLogger, OverbyteIcsWSocket;

procedure Test;
var
  SslHttpCli: TSslHttpCli;
begin
  SslHttpCli := TSslHttpCli.Create(nil);
  try
    SslHttpCli.SslContext := TSslContext.Create(SslHttpCli);
    SslHttpCli.URL := 'https://www.example.com';
    SslHttpCli.IcsLogger := TIcsLogger.Create(SslHttpCli);
    SslHttpCli.IcsLogger.LogOptions := [loSslInfo];
    SslHttpCli.Get;
  finally
    SslHttpCli.Free;
  end;
end;

The access violation happens, when Get is called.

 

Of course not all calls can be checked, but I would recommend to do it in IcsX509VerifyErrorToStr, because it is used inside the error handling. You could do it this way:

function IcsX509VerifyErrorToStr(ErrCode: Integer): String;
begin
{$IFNDEF OPENSSL_USE_RESOURCE_STRINGS}
  if Assigned(X509_verify_cert_error_string) then
    Result := String(AnsiString(X509_verify_cert_error_string(ErrCode)))
  else
{$ENDIF}
    case ErrCode of
        X509_V_OK :
            Result := sX509_V_OK;
        X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
            Result := sX509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
        X509_V_ERR_UNABLE_TO_GET_CRL:
            Result := sX509_V_ERR_UNABLE_TO_GET_CRL;
        X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
            Result := sX509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE;
        X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
            Result := sX509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE;
        X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
            Result := sX509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
        X509_V_ERR_CERT_SIGNATURE_FAILURE:
            Result := sX509_V_ERR_CERT_SIGNATURE_FAILURE;
        X509_V_ERR_CRL_SIGNATURE_FAILURE:
            Result := sX509_V_ERR_CRL_SIGNATURE_FAILURE;
        X509_V_ERR_CERT_NOT_YET_VALID:
            Result := sX509_V_ERR_CERT_NOT_YET_VALID;
        X509_V_ERR_CRL_NOT_YET_VALID:
            Result := sX509_V_ERR_CRL_NOT_YET_VALID;
        X509_V_ERR_CERT_HAS_EXPIRED:
            Result := sX509_V_ERR_CERT_HAS_EXPIRED;
        X509_V_ERR_CRL_HAS_EXPIRED:
            Result := sX509_V_ERR_CRL_HAS_EXPIRED;
        X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
            Result := sX509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
        X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
            Result := sX509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
        X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
            Result := sX509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
        X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
            Result := sX509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
        X509_V_ERR_OUT_OF_MEM:
            Result := sX509_V_ERR_OUT_OF_MEM;
        X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
            Result := sX509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
        X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
            Result := sX509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
        X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
            Result := sX509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
        X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
            Result := sX509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
        X509_V_ERR_CERT_CHAIN_TOO_LONG:
            Result := sX509_V_ERR_CERT_CHAIN_TOO_LONG;
        X509_V_ERR_CERT_REVOKED:
            Result := sX509_V_ERR_CERT_REVOKED;
        X509_V_ERR_INVALID_CA:
            Result := sX509_V_ERR_INVALID_CA;
        X509_V_ERR_INVALID_NON_CA:
            Result := sX509_V_ERR_INVALID_NON_CA;
        X509_V_ERR_PATH_LENGTH_EXCEEDED:
            Result := sX509_V_ERR_PATH_LENGTH_EXCEEDED;
        X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
            Result := sX509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
        X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED:
            Result := sX509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
        X509_V_ERR_INVALID_PURPOSE:
            Result := sX509_V_ERR_INVALID_PURPOSE;
        X509_V_ERR_CERT_UNTRUSTED:
            Result := sX509_V_ERR_CERT_UNTRUSTED;
        X509_V_ERR_CERT_REJECTED:
            Result := sX509_V_ERR_CERT_REJECTED;
        X509_V_ERR_APPLICATION_VERIFICATION:
            Result := sX509_V_ERR_APPLICATION_VERIFICATION;
        X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
            Result := sX509_V_ERR_SUBJECT_ISSUER_MISMATCH;
        X509_V_ERR_AKID_SKID_MISMATCH:
            Result := sX509_V_ERR_AKID_SKID_MISMATCH;
        X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
            Result := sX509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
        X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
            Result := sX509_V_ERR_KEYUSAGE_NO_CERTSIGN;
        X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
            Result := sX509_V_ERR_UNABLE_TO_GET_CRL_ISSUER;
        X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
            Result := sX509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
        X509_V_ERR_KEYUSAGE_NO_CRL_SIGN:
            Result := sX509_V_ERR_KEYUSAGE_NO_CRL_SIGN;
        X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE:
            Result := sX509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
        X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION:
            Result := sX509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
        X509_V_ERR_INVALID_EXTENSION:
            Result := sX509_V_ERR_INVALID_EXTENSION;
        X509_V_ERR_INVALID_POLICY_EXTENSION:
            Result := sX509_V_ERR_INVALID_POLICY_EXTENSION;
        X509_V_ERR_NO_EXPLICIT_POLICY:
            Result := sX509_V_ERR_NO_EXPLICIT_POLICY;
     { V8.39 lots more }
        X509_V_ERR_UNNESTED_RESOURCE:
            Result := sX509_V_ERR_UNNESTED_RESOURCE;

    else
        Result := sX509_V_ERR_NUMBER + IntToStr(ErrCode);
    end;
end;

Of course the resource strings have to be available as well. This way the error handling works correctly, if the DLL is not loaded (if it is neccessary, I don't know, whether any of those errors can occur then) and the correct error is displayed / logged.

Edited by jaenicke

Share this post


Link to post

Ultimately, if the DLLs are missing and you make an SSL request, you will get an exception sooner or later. 

 

Angus

Share this post


Link to post

Yes, but the problem ist, that I get this:

Error_wrong.png.0e8306d101be11c7f5eaf3aa2d7d2fca.png

 

But I should get:

error_correct.png.bedce92f871c3b5cc023ee5cfde206e6.png

 

I had to search for the error, because the error message from the log did not tell me anything.

Edited by jaenicke
  • Like 1

Share this post


Link to post

I'll look into improving the error handling next week. 

 

But if this happens in a real application, you should have OverbyteIcsWSocket.LoadSsl much earlier so OpenSSL only gets loaded once, and you handle error before starting requests, see any of the SSL samples. 

 

Angus

 

 

 

Share this post


Link to post

Thank you! I didn't pay attention to this call as I do not make many calls, so speed does not matter. But of course I'll use this now that I am aware of it.

 

There the error handling works correctly, though I would prefer not to get an exception, as I can configure it when calling the Get method. LibeayLoad always returns true instead. But it is not important as this is called only once.

 

Thank you for your help!

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×