【问题标题】:Verify errorcode = 20 : unable to get local issuer certificate验证错误代码 = 20:无法获取本地颁发者证书
【发布时间】:2015-02-20 09:25:31
【问题描述】:

我在服务器中有一个证书链:

Certificate chain
 0 s:/******/O=Foobar International BV/OU****
   i:/C=US/O=Symantec Corporation/OU=Symantec Trust Network/****

 1 s:/C=US/O=Symantec Corporation/OU=Symantec Trust Network/****
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=**** - G5

 2 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=**** - G5
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority

而我的本地根 CA 证书是:

   s:/C=US/O=Symantec Corporation/OU=Symantec Trust Network/****
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=**** - G5

我正在使用这个 sn-p 来验证证书:

//gcc -lssl -lcrypto -o certverify certverify.c 

#include <openssl/ssl.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <string.h>

int main() {

  const char ca_bundlestr[] = "./ca-bundle.pem";
  const char cert_filestr[] = "./cert-file.pem";

  BIO              *certbio = NULL;
  BIO               *outbio = NULL;
  X509          *error_cert = NULL;
  X509                *cert = NULL;
  X509_NAME    *certsubject = NULL;
  X509_STORE         *store = NULL;
  X509_STORE_CTX  *vrfy_ctx = NULL;
  int ret;

  /* ---------------------------------------------------------- *
   * These function calls initialize openssl for correct work.  *
   * ---------------------------------------------------------- */
  OpenSSL_add_all_algorithms();
  ERR_load_BIO_strings();
  ERR_load_crypto_strings();

  /* ---------------------------------------------------------- *
   * Create the Input/Output BIO's.                             *
   * ---------------------------------------------------------- */
  certbio = BIO_new(BIO_s_file());
  outbio  = BIO_new_fp(stdout, BIO_NOCLOSE);

  /* ---------------------------------------------------------- *
   * Initialize the global certificate validation store object. *
   * ---------------------------------------------------------- */
  if (!(store=X509_STORE_new()))
     BIO_printf(outbio, "Error creating X509_STORE_CTX object\n");

  /* ---------------------------------------------------------- *
   * Create the context structure for the validation operation. *
   * ---------------------------------------------------------- */
  vrfy_ctx = X509_STORE_CTX_new();

  /* ---------------------------------------------------------- *
   * Load the certificate and cacert chain from file (PEM).     *
   * ---------------------------------------------------------- */
  ret = BIO_read_filename(certbio, cert_filestr);
  if (! (cert = PEM_read_bio_X509(certbio, NULL, 0, NULL))) {
    BIO_printf(outbio, "Error loading cert into memory\n");
    exit(-1);
  }

  ret = X509_STORE_load_locations(store, ca_bundlestr, NULL);
  if (ret != 1)
    BIO_printf(outbio, "Error loading CA cert or chain file\n");

  /* ---------------------------------------------------------- *
   * Initialize the ctx structure for a verification operation: *
   * Set the trusted cert store, the unvalidated cert, and any  *
   * potential certs that could be needed (here we set it NULL) *
   * ---------------------------------------------------------- */
  X509_STORE_CTX_init(vrfy_ctx, store, cert, NULL);

  /* ---------------------------------------------------------- *
   * Check the complete cert chain can be build and validated.  *
   * Returns 1 on success, 0 on verification failures, and -1   *
   * for trouble with the ctx object (i.e. missing certificate) *
   * ---------------------------------------------------------- */
  ret = X509_verify_cert(vrfy_ctx);
  BIO_printf(outbio, "Verification return code: %d\n", ret);

  if(ret == 0 || ret == 1)
  BIO_printf(outbio, "Verification result text: %s\n",
             X509_verify_cert_error_string(vrfy_ctx->error));

  /* ---------------------------------------------------------- *
   * The error handling below shows how to get failure details  *
   * from the offending certificate.                            *
   * ---------------------------------------------------------- */
  if(ret == 0) {
    /*  get the offending certificate causing the failure */
    error_cert  = X509_STORE_CTX_get_current_cert(vrfy_ctx);
    certsubject = X509_NAME_new();
    certsubject = X509_get_subject_name(error_cert);
    BIO_printf(outbio, "Verification failed cert:\n");
    X509_NAME_print_ex(outbio, certsubject, 0, XN_FLAG_MULTILINE);
    BIO_printf(outbio, "\n");
  }

  /* ---------------------------------------------------------- *
   * Free up all structures                                     *
   * ---------------------------------------------------------- */
  X509_STORE_CTX_free(vrfy_ctx);
  X509_STORE_free(store);
  X509_free(cert);
  BIO_free_all(certbio);
  BIO_free_all(outbio);
  exit(0);
}

但此代码返回以下输出:

Verification return code: 0
Verification result text: unable to get issuer certificate
Verification failed cert:
countryName               = US
organizationName          = Symantec Corporation
organizationalUnitName    = Symantec Trust Network
commonName                = Symantec Class 3 Secure Server CA - G4

这里有什么问题?

【问题讨论】:

    标签: ssl openssl ssl-certificate x509 ca


    【解决方案1】:

    您的根 CA 使用的公钥可能与链中的第一个中间 CA(在主机证书下方)相同,并且您可能没有可用于信任最后一个链证书的根 CA。这样的设置不是很常见,但确实会发生。不幸的是,OpenSSL 在此设置方面存在问题,并且只会尝试验证最长的链,即使较短的链已经提供了必要的信任。

    a bug entry 解决了这个 OpenSSL 问题,但 OpenSSL 开发人员没有人处理过它。如果您正在寻找X509_V_FLAG_TRUSTED_FIRST,也可以找到补丁。看起来 OpenSSL 1.0.2(尚未发布)也会有这个选项。

    据我了解,只有 OpenSSL 存在这种问题,即既不是 NSS(Firefox,桌面上的 Chrome)也不是 SChannel(微软)。

    【讨论】:

    • 感谢您提供的重要信息!我在这个错误的有序链上浪费了很多天。至少我现在知道我的方法是正确的。证书链和 openssl 都是有罪的;)
    • 我可以检查到期日期、热名称验证以及是否由 CA 证书签名。但是如何获取 CRL 列表并检查我的服务器证书是否已被吊销。你能给我一些工作代码吗?
    • 要获取 CRL 列表,您必须从证书中提取 CRL 分发点,然后通过 HTTP 请求加载这些 CRL。完成此操作后,您可以加载它们并将其添加到 CTX 以进行验证。不,我没有这方面的工作代码。除此之外,这是一个不同的问题,因此最好作为一个新问题提出。
    【解决方案2】:

    我认为 Steffen 可能会帮助您解决问题。但这里有一个小问题,可能会绕过您遇到的错误并改善您的安全状况。

    const char ca_bundlestr[] = "./ca-bundle.pem";

    您不需要 CA 捆绑包。您只需要 Verisign 的 3 类公共主要证书颁发机构 (G5)。您可以通过 Use of Root Certificates 从 Verisign 获得所需的一份 CA 证书。

    这是对您的安全状况的一种改进,因为您允许任何 CA 来验证服务器的证书(甚至是错误的),而不是使用已知的来验证服务器的证书 (Verisign)。


    我正在使用这个 sn-p 来验证证书...

    如果您想查看简单 TLS 客户端的示例,请查看 OpenSSL wiki 上的 SSL/TLS Client。它提供了一个从random.org 获取随机数的示例。将其更改为example.com 不需要太多工作。

    注意:OpenSSL在验证期间执行主机名匹配。如果您使用的是 OpenSSL 1.0.2、1.0.1、1.0.0 和更低版本,您仍然需要自己进行操作。 OpenSSL 在 1.1.0 中提供了主机名匹配,但目前尚不可用。

    SSL/TLS Client 中提供了从 X.509 证书中的通用名称 (CN) 和主题替代名称 (SAN) 中提取主机名的示例代码,但您必须提供实际的匹配代码。


    根据 cmets 中的信息,您需要证书:“Symantec Class 3 Secure Server CA - G5”。下面是提供正确锚点时的样子 - 它以 Verify return code: 0 (ok) 结尾(而不是错误 20)。

    “Symantec Class 3 Secure Server CA - G5”是指纹4e b6 d5 78 49 9b 1c cf 5f 58 1e ad 56 be 3d 9b 67 44 a5 e5。您可以从 Verisign 的 Use of Root Certificates 获取它。

    s_client(下)使用的CAfile 选项设置在s_client.c 内部,并调用SSL_CTX_load_verify_locations。其设置为验证服务器证书所需的一个 CA,而不是 CA Zoo(即cacerts.pem)。


    您可以使用$ openssl s_client -connect www.smartbabymonitor.ugrow.example.com:443 | openssl x509 -text -noout 检查证书中的主题备用名称 (SAN)。你会没事的,因为主机www.smartbabymonitor.ugrow.example.com 列在 SAN 中。您甚至可以在命令中添加 -servername 选项以使用服务器名称指示 (SNI)。


    $ openssl s_client -showcerts -connect www.smartbabymonitor.ugrow.example.com:443 -CAfile VeriSign-Class\ 3-Public-Primary-Certification-Authority-G5.pem 
    CONNECTED(00000003)
    depth=3 C = US, O = "VeriSign, Inc.", OU = Class 3 Public Primary Certification Authority
    verify return:1
    depth=2 C = US, O = "VeriSign, Inc.", OU = VeriSign Trust Network, OU = "(c) 2006 VeriSign, Inc. - For authorized use only", CN = VeriSign Class 3 Public Primary Certification Authority - G5
    verify return:1
    depth=1 C = US, O = Symantec Corporation, OU = Symantec Trust Network, CN = Symantec Class 3 Secure Server CA - G4
    verify return:1
    depth=0 C = NL, ST = Netherlands, L = Eindhoven, O = Example International BV, OU = Consumer Lifestyle, CN = smartbabymonitor.ugrow.example.com
    verify return:1
    ---
    Certificate chain
     0 s:/C=NL/ST=Netherlands/L=Eindhoven/O=Example International BV/OU=Consumer Lifestyle/CN=smartbabymonitor.ugrow.example.com
       i:/C=US/O=Symantec Corporation/OU=Symantec Trust Network/CN=Symantec Class 3 Secure Server CA - G4
    -----BEGIN CERTIFICATE-----
    MIIF+DCCBOCgAwIBAgIQa0fyuH2bp1ucngiNHVoV4jANBgkqhkiG9w0BAQsFADB+
    MQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAd
    ...
    +eGxGqm8e1jgxB/fQePrh1vG4V40nr0cBKh6t52HmksBCfM0wOlMMJyUYiO0p44W
    s4nxNrvMJS6e4bwdECI0UNhJznWr0tAu+ilFoTsfOlQpngCBDJEkZYr3mRjpIjX8
    Sz4+hGzIhZVyjDvbcVCrsvCpM67cU2rQpJ2nkYM4ol/z6VDRs/G5aPiXe7o=
    -----END CERTIFICATE-----
     1 s:/C=US/O=Symantec Corporation/OU=Symantec Trust Network/CN=Symantec Class 3 Secure Server CA - G4
       i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
    -----BEGIN CERTIFICATE-----
    MIIFODCCBCCgAwIBAgIQUT+5dDhwtzRAQY0wkwaZ/zANBgkqhkiG9w0BAQsFADCB
    yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
    ...
    QGX0InLNmfiIEfXzf+YzguaoxX7+0AjiJVgIcWjmzaLmFN5OUiQt/eV5E1PnXi8t
    TRttQBVSK/eHiXgSgW7ZTaoteNTCLD0IX4eRnh8OsN4wUmSGiaqdZpwOdgyA8nTY
    Kvi4Os7X1g8RvmurFPW9QaAiY4nxug9vKWNmLT+sjHLF+8fk1A/yO0+MKcc=
    -----END CERTIFICATE-----
     2 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
       i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
    -----BEGIN CERTIFICATE-----
    MIIE0DCCBDmgAwIBAgIQJQzo4DBhLp8rifcFTXz4/TANBgkqhkiG9w0BAQUFADBf
    MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsT
    ...
    A4GBABMC3fjohgDyWvj4IAxZiGIHzs73Tvm7WaGY5eE43U68ZhjTresY8g3JbT5K
    lCDDPLq9ZVTGr0SzEK0saz6r1we2uIFjxfleLuUqZ87NMwwq14lWAyMfs77oOghZ
    tOxFNfeKW/9mz1Cvxm1XjRl4t7mi0VfqH5pLr7rJjhJ+xr3/
    -----END CERTIFICATE-----
    ---
    Server certificate
    subject=/C=NL/ST=Netherlands/L=Eindhoven/O=Example International BV/OU=Consumer Lifestyle/CN=smartbabymonitor.ugrow.example.com
    issuer=/C=US/O=Symantec Corporation/OU=Symantec Trust Network/CN=Symantec Class 3 Secure Server CA - G4
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 4805 bytes and written 434 bytes
    ---
    New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
    Server public key is 2048 bit
    Secure Renegotiation IS supported
    Compression: NONE
    Expansion: NONE
    SSL-Session:
        Protocol  : TLSv1.2
        Cipher    : ECDHE-RSA-AES256-GCM-SHA384
        Session-ID: F1B9C9DFA3CFC6CB3F958FAD4ECBBAFA0E72EA8A86F6AC9601CF8204819DB0F0
        Session-ID-ctx: 
        Master-Key: EC4C5B32E60B5A0458BC85CC02529EA18DE61AFB8583D85D275C2822AC84E0E5E0C5B5E2C3C2D90F8B6E0EBB518EAA99
        Key-Arg   : None
        PSK identity: None
        PSK identity hint: None
        SRP username: None
        TLS session ticket lifetime hint: 300 (seconds)
        TLS session ticket:
        0000 - 27 e0 fb b8 dd c9 9f 29-31 85 2b 6c d1 5a b3 d1   '......)1.+l.Z..
        0010 - 55 d6 e4 8a 4d f5 ef 2e-51 95 21 90 47 9d b6 0a   U...M...Q.!.G...
        0020 - df a5 d2 10 3d 03 e5 07-41 81 92 09 30 0e 08 3d   ....=...A...0..=
        0030 - fc ea 24 93 29 ed 60 9a-d0 d9 57 88 e4 4d 18 e3   ..$.).`...W..M..
        0040 - ba aa 97 ee bf 39 9e 5b-76 5b 76 f7 81 c4 03 08   .....9.[v[v.....
        0050 - fb b9 a3 4f 11 b0 99 4c-8c f2 a6 8a 9a e4 fe c6   ...O...L........
        0060 - 0d 7b 6d a7 5b 53 b5 33-15 4f c4 ab 6b 29 7b 8f   .{m.[S.3.O..k){.
        0070 - ec 00 7f b2 6f 91 e4 ca-63 45 58 73 3a 78 8b 29   ....o...cEXs:x.)
        0080 - 44 fc d5 e8 ad 4d dd 9c-22 df 50 eb d5 bf b9 90   D....M..".P.....
        0090 - d8 6a 7d 6d bd 61 f2 63-07 75 8b d0 fc 40 64 76   .j}m.a.c.u...@dv
        00a0 - 2b 97 53 aa 47 bc 3d d1-76 aa 8a 07 e1 60 14 d1   +.S.G.=.v....`..
        00b0 - f7 88 8f f6 d9 b9 6b 0c-64 96 b5 f0 46 73 27 d6   ......k.d...Fs'.
    
        Start Time: 1419835334
        Timeout   : 300 (sec)
        Verify return code: 0 (ok)
    ---
    

    【讨论】:

    • 感谢您的建议。那么我的cert-file.pem 会包含什么? 0 s:/******/O=Foobar International BV/OU**** i:/C=US/O=Symantec Corporation/OU=Symantec Trust Network/**** ?
    • 通过将第 0 个证书设置为 const char cert_filestr[] = "./cert-file.pem" 并将 Verisign 的 3 类公共主要证书颁发机构 (G5) 设置为 const char ca_bundlestr[] = "./ca-bundle.pem",代码仍然返回 unable to get local issuer certificate
    • @Kaidul - 查看更新的答案。使用 Verisign CA (G5) 时无法复制。您应该使用SSL_CTX_load_verify_locations 将 Verisgn CA 设置为客户端中的信任锚。
    • 我忘了提到我已经使用这个 sn-p - etutorials.org/Programming/secure+programming/… 进行主机名验证。所以我认为那部分没问题:) 你能给我一些正确的./ca-bundle.pem./cert-file.pem 文件来处理我上面的代码并给出一些解释吗?
    • 我将威瑞信的证书保存在我的桌面并从桌面openssl s_client -showcerts -connect www.smartbabymonitor.ugrow.mysite.com:443 -CAfile VeriSign-Class3-Public-Primary-Certification-Authority-G5.pem 执行此命令,但它仍然返回errorcode = 20 : unable to get local issuer certificate。你能告诉我发生了什么吗?同样通过SSL_CTX_load_verify_locations 加载verisgn 的证书应该可以使用上面的代码吗?
    猜你喜欢
    • 2012-07-18
    • 2012-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 2015-03-18
    • 2011-12-26
    相关资源
    最近更新 更多