Search code examples
c++opensslgsoap

gSoap SSL/TLS certificate host name mismatch in tcp_connect


My soap client is not accepting the certificate on the service I have to connect to. It gives the error: SSL/TLS certificate host name mismatch in tcp_connect. However chrome does accept the certificate. I inspected the certificate in chrome and I noticed it is a wildcard certificate in the form *.domain.nl. Are there additional configurations steps required to get gSoap/openssl to accept this?

ssl init:

soap_ssl_client_context(&proxy,
    SOAP_SSL_DEFAULT,   /* use SOAP_SSL_DEFAULT in production code */
    NULL,       /* keyfile (cert+key) */
    NULL,       /* password to read the keyfile */
    "c:\\test\\cacert.pem", 
    NULL,       /* optional capath to directory with trusted certificates */
    NULL    
)

The cacert.pem I'm testing with is http://curl.haxx.se/ca/cacert.pem

When I add SOAP_SSL_SKIP_HOST_CHECK to the options everything works fine.


Solution

  • I had the same issue using gSOAP 2.8.22. Searching for a solution I found your question... but no answer. So I download, built and debugged "OpenSSL 1.0.2d 9 Jul 2015" (current last version).

    I tried to access https://outlook.office365.com/ews/exchange.asmx. The certificate contains in the "Certificate Subject Alt Name" wildcard names like "*.office365.com". I found the code handling this field in stdsoap2.cpp but it doesn't check wildcard names:

    names = (GENERAL_NAMES*)X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL);
    if (names)
    { val = i2v_GENERAL_NAMES(NULL, names, val);
        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
    }
    if (val)
    { int j;
        for (j = 0; j < sk_CONF_VALUE_num(val); j++)
        { CONF_VALUE *nval = sk_CONF_VALUE_value(val, j);
        if (nval && !strcmp(nval->name, "DNS") && !strcmp(nval->value, host))
        { ok = 1;
            break;
        }
        }
        sk_CONF_VALUE_pop_free(val, X509V3_conf_free);
    }
    

    Then I changed the code to

    names = (GENERAL_NAMES*)X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL);
    if (names)
    { val = i2v_GENERAL_NAMES(NULL, names, val);
        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
    }
    if (val)
    { int j;
        for (j = 0; j < sk_CONF_VALUE_num(val); j++)
        { CONF_VALUE *nval = sk_CONF_VALUE_value(val, j);
        if (nval && !strcmp(nval->name, "DNS"))
        {
            if ( !strcmp( nval->value, host))
            { 
                ok = 1;
                break;
            }
            else if ( *nval->value == '*')
            {
                const char* const t = nval->value + 1;
                if ( *t == '.')
                {
                    const char* const h = strchr( host, '.');
                    if ( h && !strcmp( t, h))
                    {
                        ok = 1;
                        break;
                    }
                }
            }
        }
        }
        sk_CONF_VALUE_pop_free(val, X509V3_conf_free);
    }
    

    This fix doesn't deal with UTF-8 names. For that you can have a look in the code for handling common name (search for NID_commonName).