我正在尝试根据UTN_USERFirst_硬件CA验证IRC服务器的证书。
我遇到了来自SSL_get_verify_result的错误代码20(如果我是正确的,这意味着它无法获得对等证书?).
另外,我也不太确定“步骤”的优先顺序是什么。
以下是我拼凑的:

int tallis_ssl_verify(tallis_t *tallis, X509 *cert)
{
    int rv;

    X509_VERIFY_PARAM_set_hostflags(
            tallis->param,
            X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);

    SSL_CTX_set_default_verify_paths(tallis->ssl_context);

    ERR_clear_error();
    rv = SSL_CTX_load_verify_locations(
            tallis->ssl_context,
            "/etc/ssl/certs/AddTrust_External_Root.pem",
            "/etc/ssl/certs");

    if (!rv)
    {
        fprintf(stderr, ERR_error_string(ERR_get_error(), NULL));
        return 1;
    }

    X509_VERIFY_PARAM_set1_host(tallis->param, tallis->host, 0);
    SSL_CTX_set_verify(tallis->ssl_context, SSL_VERIFY_PEER, NULL);
    SSL_set_verify(tallis->ssl_connection, SSL_VERIFY_PEER, NULL);

    ERR_clear_error();
    rv = SSL_get_verify_result(tallis->ssl_connection);

    if (rv != X509_V_OK)
    {
        printf("%d\n", rv);
        fprintf(stderr, ERR_error_string(ERR_get_error(), NULL));
        return 1;
    }

    ERR_clear_error();
    X509_STORE_CTX *ctx = X509_STORE_CTX_new();

    if (!ctx)
    {
        fprintf(stderr, ERR_error_string(ERR_get_error(), NULL));
        return 1;
    }

    ERR_clear_error();
    X509_STORE *store = X509_STORE_new();

    if (!store)
    {
        X509_STORE_free(store);
        fprintf(stderr, ERR_error_string(ERR_get_error(), NULL));
        return 1;
    }

    ERR_clear_error();
    rv = X509_STORE_CTX_init(ctx, store, cert, NULL);

    if (!rv)
    {
        X509_STORE_free(store);
        fprintf(stderr, ERR_error_string(ERR_get_error(), NULL));
        return 1;
    }

    X509_STORE_set_flags(store, X509_V_FLAG_CB_ISSUER_CHECK);
    X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());

    X509_STORE_load_locations(
            store,
            "/etc/ssl/certs/AddTrust_External_Root.pem",
            NULL);

    X509_STORE_set_default_paths(store);

    X509_LOOKUP_load_file(
            lookup,
            "/etc/ssl/certs/AddTrust_External_Root.pem",
            X509_FILETYPE_PEM);

    X509_STORE_add_cert(store, cert);

    ERR_clear_error();
    rv = X509_verify_cert(ctx);

    if (rv != 1)
    {
        X509_STORE_free(store);
        fprintf(
                stderr,
                "%s\n%s\n",
                ERR_error_string(ERR_get_error(), NULL),
                X509_verify_cert_error_string(ctx->error));

        return 1;
    }

    return 0;
}

以及上下文的调用例程:
int main(int argc, char *argv[])
{
    tallis_t *tallis = malloc(sizeof(tallis_t));
    tallis->host = "irc.freenode.net";
    tallis->port = "6697";
    tallis->bio = NULL;
    tallis->ssl_connection = NULL;
    ssl_init(tallis->ssl_connection);
    tallis->ssl_context = SSL_CTX_new(TLSv1_2_client_method());
    tallis->ssl_connection = SSL_new(tallis->ssl_context);
    tallis->param = SSL_get0_param(tallis->ssl_connection);

    int rv;

    rv = tallis_connect(tallis);

    if (rv)
        DIE("%s\n", "connection failed");

    ERR_clear_error();
    X509 *cert = SSL_get_peer_certificate(tallis->ssl_connection);

    if (!cert)
        DIE("%s\n", ERR_error_string(ERR_get_error(), NULL));

    rv = tallis_ssl_verify(tallis, cert);

    X509_free(cert);

    if (rv)
        DIE("%s\n", "certificate verificiation failed");
    else
        printf("%s\n", "certificate verification succeeded");

    rv = tallis_loop(tallis);

    if (rv)
        DIE("%s\n", "socket connection terminated");

    rv = ssl_shutdown(tallis);

    if (rv)
        DIE("%s\n", "ssl shutdown failed");
}

所以,我的流程是:在socket(BIO)级别建立连接->调用SSL_get_peer_certificate->进行证书验证,这是正确的吗?
SSL_get_verify_resultX509_verify_cert之间有什么区别?应该先使用哪个?
抱歉,如果这太笼统了,我需要一点指导,文档只是一个没有太多相关信息的手动页面,我发现很难获得一个有组织的OpenSSL视图。
“如何在OpenSSL中尽可能简单地验证对等证书?”

最佳答案

我正在尝试根据UTN_USERFirst_硬件CA验证IRC服务器的证书
我认为那是错误的根CA。
“如何在OpenSSL中尽可能简单地验证对等证书?”
我想你就在你需要的地方你只需要稍微调整一下。
当我检查链中最上面的颁发者时(s:表示主题,而i:表示颁发者):

$ openssl s_client -connect irc.freenode.net:6697 -servername irc.freenode.net -tls1_2
CONNECTED(00000005)
depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
verify error:num=20:unable to get local issuer certificate
Server did acknowledge servername extension.
---
Certificate chain
 0 s:/OU=Domain Control Validated/OU=Gandi Standard Wildcard SSL/CN=*.freenode.net
   i:/C=FR/ST=Paris/L=Paris/O=Gandi/CN=Gandi Standard SSL CA 2
 1 s:/C=FR/ST=Paris/L=Paris/O=Gandi/CN=Gandi Standard SSL CA 2
   i:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority
 2 s:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority
   i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
...

<skip certificate and lots of other stuff>

...
Start Time: 1475924259
Timeout   : 7200 (sec)
Verify return code: 20 (unable to get local issuer certificate)

看起来你希望你的信任根在CN=AddTrust External CA Root;而不是UTN_USERFirst_Hardware_Root_CA你可以在科摩多的网站[Root] AddTrust External CA Root找到它。
文件addtrustexternalcaroot.crt采用PEM格式您只需指定-CAfile选项即可成功完成命令(X509_V_OK):
$ openssl s_client -connect irc.freenode.net:6697 -servername irc.freenode.net -tls1_2 -CAfile addtrustexternalcaroot.crt
CONNECTED(00000005)
depth=3 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
verify return:1
depth=2 C = US, ST = New Jersey, L = Jersey City, O = The USERTRUST Network, CN = USERTrust RSA Certification Authority
verify return:1
depth=1 C = FR, ST = Paris, L = Paris, O = Gandi, CN = Gandi Standard SSL CA 2
verify return:1
depth=0 OU = Domain Control Validated, OU = Gandi Standard Wildcard SSL, CN = *.freenode.net
verify return:1
Server did acknowledge servername extension.
---
Certificate chain
 0 s:/OU=Domain Control Validated/OU=Gandi Standard Wildcard SSL/CN=*.freenode.net
   i:/C=FR/ST=Paris/L=Paris/O=Gandi/CN=Gandi Standard SSL CA 2
 1 s:/C=FR/ST=Paris/L=Paris/O=Gandi/CN=Gandi Standard SSL CA 2
   i:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority
 2 s:/C=US/ST=New Jersey/L=Jersey City/O=The USERTRUST Network/CN=USERTrust RSA Certification Authority
   i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
...

<skip certificate and lots of other stuff>

...
Start Time: 1475924761
Timeout   : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: no

既然您知道如何测试它,以及好的测试用例是什么样子的,下面介绍如何在代码中修复它:
rv = SSL_CTX_load_verify_locations(
        ssl_context,
        ".../addtrustexternalcaroot.crt",
        NULL;

下面是CA根的外观:
$ cat addtrustexternalcaroot.crt | openssl x509 -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 1 (0x1)
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
        Validity
            Not Before: May 30 10:48:38 2000 GMT
            Not After : May 30 10:48:38 2020 GMT
        Subject: C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:b7:f7:1a:33:e6:f2:00:04:2d:39:e0:4e:5b:ed:
                    1f:bc:6c:0f:cd:b5:fa:23:b6:ce:de:9b:11:33:97:
                    a4:29:4c:7d:93:9f:bd:4a:bc:93:ed:03:1a:e3:8f:
                    cf:e5:6d:50:5a:d6:97:29:94:5a:80:b0:49:7a:db:
                    2e:95:fd:b8:ca:bf:37:38:2d:1e:3e:91:41:ad:70:
                    56:c7:f0:4f:3f:e8:32:9e:74:ca:c8:90:54:e9:c6:
                    5f:0f:78:9d:9a:40:3c:0e:ac:61:aa:5e:14:8f:9e:
                    87:a1:6a:50:dc:d7:9a:4e:af:05:b3:a6:71:94:9c:
                    71:b3:50:60:0a:c7:13:9d:38:07:86:02:a8:e9:a8:
                    69:26:18:90:ab:4c:b0:4f:23:ab:3a:4f:84:d8:df:
                    ce:9f:e1:69:6f:bb:d7:42:d7:6b:44:e4:c7:ad:ee:
                    6d:41:5f:72:5a:71:08:37:b3:79:65:a4:59:a0:94:
                    37:f7:00:2f:0d:c2:92:72:da:d0:38:72:db:14:a8:
                    45:c4:5d:2a:7d:b7:b4:d6:c4:ee:ac:cd:13:44:b7:
                    c9:2b:dd:43:00:25:fa:61:b9:69:6a:58:23:11:b7:
                    a7:33:8f:56:75:59:f5:cd:29:d7:46:b7:0a:2b:65:
                    b6:d3:42:6f:15:b2:b8:7b:fb:ef:e9:5d:53:d5:34:
                    5a:27
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A
            X509v3 Key Usage:
                Certificate Sign, CRL Sign
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Authority Key Identifier:
                keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A
                DirName:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
                serial:01

    Signature Algorithm: sha1WithRSAEncryption
         b0:9b:e0:85:25:c2:d6:23:e2:0f:96:06:92:9d:41:98:9c:d9:
         84:79:81:d9:1e:5b:14:07:23:36:65:8f:b0:d8:77:bb:ac:41:
         6c:47:60:83:51:b0:f9:32:3d:e7:fc:f6:26:13:c7:80:16:a5:
         bf:5a:fc:87:cf:78:79:89:21:9a:e2:4c:07:0a:86:35:bc:f2:
         de:51:c4:d2:96:b7:dc:7e:4e:ee:70:fd:1c:39:eb:0c:02:51:
         14:2d:8e:bd:16:e0:c1:df:46:75:e7:24:ad:ec:f4:42:b4:85:
         93:70:10:67:ba:9d:06:35:4a:18:d3:2b:7a:cc:51:42:a1:7a:
         63:d1:e6:bb:a1:c5:2b:c2:36:be:13:0d:e6:bd:63:7e:79:7b:
         a7:09:0d:40:ab:6a:dd:8f:8a:c3:f6:f6:8c:1a:42:05:51:d4:
         45:f5:9f:a7:62:21:68:15:20:43:3c:99:e7:7c:bd:24:d8:a9:
         91:17:73:88:3f:56:1b:31:38:18:b4:71:0f:9a:cd:c8:0e:9e:
         8e:2e:1b:e1:8c:98:83:cb:1f:31:f1:44:4c:c6:04:73:49:76:
         60:0f:c7:f8:bd:17:80:6b:2e:e9:cc:4c:0e:5a:9a:79:0f:20:
         0a:2e:d5:9e:63:26:1e:55:92:94:d8:82:17:5a:7b:d0:bc:c7:
         8f:4e:86:04

关于c - SSL_get_verify_result为irc.freenode.net返回错误20,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39930636/

10-15 13:12