CertCreateCertificateContext 返回 CRYPT_E_ASN1_BADTAG/8009310b [英] CertCreateCertificateContext returns CRYPT_E_ASN1_BADTAG / 8009310b

查看:56
本文介绍了CertCreateCertificateContext 返回 CRYPT_E_ASN1_BADTAG/8009310b的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我意识到这是一个与其他人非常相似的帖子(例如 这个),但帖子中缺少可能对我的案例很重要的细节.

I realize this is a very similar post to others (e.g. this one), but there are details missing from the posts which might be significant for my case.

首先,这是我的简化程序:

To start with, here's my simplified program:

#include "stdafx.h"
#include <windows.h>
#include <wincrypt.h>

int _tmain(int argc, _TCHAR* argv[])
{
    // usage: CertExtract certpath

    char keyFile[] = "C:\\Certificates\\public.crt";
    BYTE lp[65536];

    SECURITY_ATTRIBUTES sa;
    HANDLE hKeyFile;
    DWORD bytes;

    PCCERT_CONTEXT  certContext;

    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = FALSE;

    hKeyFile = CreateFile(keyFile, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hKeyFile) {

        if (ReadFile(hKeyFile, lp, GetFileSize(hKeyFile, NULL), &bytes, NULL) && bytes > 0) {

            certContext = CertCreateCertificateContext(X509_ASN_ENCODING, lp, bytes);

            if (certContext) {

                printf("yay!");

                CertFreeCertificateContext(certContext);
            }
            else {
                printf("Could not convert certificate to internal form\n");
            }
        }
        else {
            printf("Failed to read key file: %s\n", keyFile);
        }
    }
    else {
        printf("Failed to open key file: %s\n", keyFile);
    }

    CloseHandle(hKeyFile);


    return 0;
}

为了创建证书,我对 OpenSSL 使用了以下步骤:

In order to create the certificate, I used the following steps with OpenSSL:

C:\Certificates>openssl genrsa -out private.key 1024
Loading 'screen' into random state - done
Generating RSA private key, 1024 bit long modulus
......................................++++++
................++++++
e is 65537 (0x10001)

C:\Certificates>openssl req -new -key private.key -out public.csr
Loading 'screen' into random state - done

C:\Certificates>copy private.key private.key.org
        1 file(s) copied.

C:\Certificates>openssl rsa -in private.key.org -out private.key
writing RSA key

C:\Certificates>openssl x509 -req -days 365 -in public.csr -signkey private.key -ou
t public.crt
Loading 'screen' into random state - done
Signature ok
subject=/CN=My Signing Cert
Getting Private key

使用以下配置文件:

RANDFILE        = .rnd

[ req ]
distinguished_name     = req_distinguished_name
prompt                 = no

[ req_distinguished_name ]
commonName             = My Signing Cert

证书文件如下:

-----BEGIN CERTIFICATE-----
MIIBqzCCARQCCQDUJyWk0OxlRTANBgkqhkiG9w0BAQUFADAaMRgwFgYDVQQDDA9N
eSBTaWduaW5nIENlcnQwHhcNMTYwMTA1MjIzODU5WhcNMTcwMTA0MjIzODU5WjAa
MRgwFgYDVQQDDA9NeSBTaWduaW5nIENlcnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
MIGJAoGBAJobIhfSSMLEPeG9SOBelWHo4hjKXe8dT6cllPr6QXdXe2VNLh9fxVlx
spVGFQwjlF3OHYnmSQnY3m2b5wlFNYVuHvy8rUsZWOF4drSbiqWKh0TuJ+4MBeGq
EormTJ+kiGqNm5IVRrTu9OV8f0XQTGV1pxHircQxsGhxY5w0QTjjAgMBAAEwDQYJ
KoZIhvcNAQEFBQADgYEAedqjKfMyIFC8nUbJ6t/Y8D+fJFwCcdwojUFizr78FEwA
IZSas1b1bXSkA+QEooW7pYdBAfzNuD3WfZAIZpqFlr4rPNIqHzYa0OIdDPwzQQLa
3zPKqjj6QeTWEi5/ArzO+sTVv4m3Og3GQjMChb8H/GxsWdbComPVP82DTUet+ZU=
-----END CERTIFICATE-----

将 PEM 编码转换为十六进制允许我识别证书的部分:

Converting the PEM-encoding to hex allows me to identify the parts of the certificate:

30 SEQUENCE             //Certificate
(82 01 AB) 

   30 SEQUENCE          //tbsCertificate
   (82   01   14) 

      02 INTEGER        //serialNumber  
      (09)  
         00   D4   27   25   A4   D0   EC   65   45 

      30 SEQUENCE       //signature
      (0D) 

         06 OBJECT IDENTIFIER
         (09)  
         2A   86   48   86   F7   0D   01   01   05

         05 NULL 
         (00)

      30 SEQUENCE       //issuer
      (1A) 

         31 SET
         (18) 

            30 SEQUENCE
            (16) 

               06 OBJECT IDENTIFIER
               (03)  
               55   04   03

               0C UTF8String
               (0F)  
                  4D  79   20   53   69   67   6E   69   6E   67   20   43   65   72   74

      30 SEQUENCE       //validity
      (1E) 
         17 UTCTime
         (0D)  
            31   36   30   31   30   35   32   32   33   38   35   39   5A

         17 UTCTime
         (0D)  
            31   37   30   31   30   34   32   32   33   38   35   39   5A

      30 SEQUENCE       //subjectName
      (1A) 

         31 SET
         (18) 

            30 SEQUENCE
            (16) 
               06 OBJECT IDENTIFIER
               (03)  
                  55   04   03

               0C UTF8String
               (0F)  
                  4D   79   20   53   69  67   6E   69   6E   67   20   43   65   72   74

      30 SEQUENCE       //subjectPublicKeyInfo
      (81   9F) 
         30 SEQUENCE    //algorithmId
         (0D) 
            06 OBJECT IDENTIFIER    //algorithm
            (09)  
               2A   86   48   86   F7   0D   01   01   01

            05 NULL
            (00)

         03 BIT STRING   //subjectPublicKey
         (81   8D)  
            [00] //padding bits
            30 SEQUENCE  //RSAPublicKey
            (81   89)   

               02 INTEGER  //modulus
               (81   81)   
                  00   9A   1B   22   17   D2   48   C2   C4   3D  E1   BD   48   E0   5E   95   61   E8   E2   18   CA   5D   EF   1D   4F   A7  25   94   FA   FA   41   77   57   7B   65   4D   2E   1F   5F   C5   59   71  B2   95   46   15   0C   23   94   5D   CE   1D   89   E6   49   09   D8   DE  6D   9B   E7   09   45   35   85   6E   1E   FC   BC   AD   4B   19   58   E1  78   76   B4   9B   8A   A5   8A   87   44   EE   27   EE   0C   05   E1   AA  12   8A   E6   4C   9F   A4   88   6A   8D   9B   92   15   46   B4   EE   F4  E5   7C   7F   45   D0   4C   65   75   A7   11   E2   AD   C4   31   B0   68  71   63   9C   34   41   38   E3   02   03   01   00   01

   30 SEQUENCE             //signatureAlgorithm
   (0D) 
      06 OBJECT IDENTIFIER
      (09) 
         2A   86   48   86   F7   0D   01   01   05

      05 NULL
      (00)

   03 BIT STRING           //signatureValue
   (81   81)  
      [00] //padding bits
      79  DA   A3   29   F3   32   20   50   BC   9D   46   C9   EA   DF   D8   F0   3F   9F   24   5C   02   71   DC   28   8D   41   62   CE   BE   FC   14   4C   00   21   94   9A   B3   56   F5   6D   74   A4   03   E4   04   A2   85   BB   A5   87   41   01   FC   CD   B8   3D   D6   7D   90   08   66   9A   85   96   BE   2B   3C   D2   2A   1F   36   1A   D0   E2   1D   0C   FC   33   41   02   DA   DF   33   CA   AA   38   FA   41   E4   D6   12   2E   7F   02   BC   CE   FA   C4   D5   BF   89   B7   3A   0D   C6   42   33   02   85   BF   07   FC   6C   6C   59   D6   C2   A2   63   D5   3F   CD   83   4D   47   AD   F9   95

似乎符合 X.509 规范(因为我希望它):

which appears to conform to the X.509 specs (as I would expect it to):

Certificate ::= {
   tbsCertificate TBSCertificate,
   signatureAlgorithm AlgorithmIdentifier,
   signatureValue BIT STRING
}

TBSCertificate ::= SEQUENCE {   
   version [0] Version DEFAULT v1,  <-- what does this mean?
   serialNumber INTEGER,
   signature AlgorithmIdentifier,
   issuer Name,
   validity Validity,
   subjectName Name,
   subjectPublicKeyInfo SubjectPublicKeyInfo
   ...
}

唯一的例外是版本部分,我不清楚它是否是可选的(尽管它似乎从未与我使用 OpenSSL 创建的证书一起添加).

with the lone exception of the version part, which isn't clear to me whether it is optional or not (though it never seems to be added with certificates I create with OpenSSL).

我可以打开证书导入到证书存储中(并且可以成功导入到存储中),所以我不认为文件/编码有什么特别的问题.

I can open the certificate to import into a certificate store (and can successfully import to a store), so I don't think anything is specifically wrong with the file/encoding.

当我调用 CertCreateCertificateContext 时,我的 lp 缓冲区看起来像:

When I reach the call to CertCreateCertificateContext, my lp buffer looks like:

<代码> ----- BEGIN CERTIFICATE ----- \ nMIIBqzCCARQCCQDUJyWk0OxlRTANBgkqhkiG9w0BAQUFADAaMRgwFgYDVQQDDA9N \ neSBTaWduaW5nIENlcnQwHhcNMTYwMTA1MjIzODU5WhcNMTcwMTA0MjIzODU5WjAa \ nMRgwFgYDVQQDDA9NeSBTaWduaW5nIENlcnQwgZ8wDQ ...

and bytes = 639 -- 这是文件大小.

and bytes = 639 -- which is the file size.

我尝试添加逻辑来去除证书注释,但是 以这种方式导入证书的示例并不表明这是必要的.

I've tried adding logic to strip out the certificate comments, but examples of importing a certificate in this manner don't indicate that should be necessary.

我已经尝试将 dwCertEncodingType 设置为 X509_ASN_ENCODING |PKCS_7_ASN_ENCODING 和 PKCS_7_ASN_ENCODING 出于绝望(虽然我不相信我在这里使用 PKCS#7 编码......对此有点模糊).

I've tried setting the dwCertEncodingType to X509_ASN_ENCODING | PKCS_7_ASN_ENCODING and PKCS_7_ASN_ENCODING out of desperation (though I don't believe I am using PKCS#7 encoding here...a little fuzzy on that).

有人对我在这里可能做错的事情有什么建议吗?我很感激.

Does anyone have any suggestions on what I might be doing incorrectly here? I appreciate it.

推荐答案

我想出了我的问题.CertCreateCertificateContext 需要二进制 ASN.1 数据,而不是我使用 openssl 创建的 PEM 编码证书.我通过使用 Microsoft 证书生成工具并测试该证书来解决这个问题:

I figured out my issue. CertCreateCertificateContext is expecting the binary ASN.1 data, not the PEM-encoded certificate I created with openssl. I figured this out by using a Microsoft certificate generation tool and testing that certificate out:

C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin>makecert.exe -n "CN=Test Signing Cert" -b 0
1/06/2016 -e 01/06/2017 -len 1024 -r C:\Certificates\public_v2.crt
Succeeded

在十六进制编辑器中查看该文件,它看起来与 ASN.1 二进制数据完全一样.接下来,我使用了证书查看器中的复制到文件"功能,当您双击证书将我的原始 public.crt 文件复制到 DER 编码的二进制 X.509 (.CER) 文件时,该功能会启动,并验证我的程序开始工作(即 CertCreateCertificateContext 现在很高兴).

looking at the file in a hex editor, it looked precisely like the ASN.1 binary data. next, I used the Copy to File feature from the certificate viewer that launches when you double-click a certificate to copy my original public.crt file to a DER encoded binary X.509 (.CER) file and verified that my program began to work (that is, the CertCreateCertificateContext was now happy).

因此,如果其他人遇到我遇到的相同问题,这里有一个完整的解决方案,用于将 PEM 编码的证书从文件导入内存以与 Crypto API 一起使用:

so, in case someone else is bumping up against the same issue I was having, here is a complete solution to importing a PEM-encoded certificate from a file into memory for use with the Crypto API:

#include "stdafx.h"
#include <windows.h>
#include <wincrypt.h>

#define LF 0x0A

int _tmain(int argc, _TCHAR* argv[])
{
    char keyFile[] = "C:\\Certificates\\public.crt";
    BYTE lp[65536];

    SECURITY_ATTRIBUTES sa;
    HANDLE hKeyFile;
    DWORD bytes;

    PCCERT_CONTEXT  certContext;
    BYTE *p;
    DWORD flags;

    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = FALSE;

    hKeyFile = CreateFile(keyFile, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hKeyFile) {

        if (ReadFile(hKeyFile, lp, GetFileSize(hKeyFile, NULL), &bytes, NULL) && bytes > 0) {

            p = lp + bytes;
            if (CryptStringToBinary((char *)lp, p - lp, CRYPT_STRING_BASE64_ANY, p, &bytes, NULL, &flags) && bytes > 0) {

                certContext = CertCreateCertificateContext(X509_ASN_ENCODING, p, bytes);

                if (certContext) {

                    printf("yay!");

                    CertFreeCertificateContext(certContext);
                }
                else {
                    printf("Could not convert certificate to internal form\n");
                }
            }
            else {
                printf("Failed to convert from PEM");
            }
        }
        else {
            printf("Failed to read key file: %s\n", keyFile);
        }
    }
    else {
        printf("Failed to open key file: %s\n", keyFile);
    }

    CloseHandle(hKeyFile);


    return 0;
}

注意:

因为我很懒,所以我在我用来加载文件的同一个 BYTE 数组中将 PEM 编码解码为二进制——对于这个简单的测试,这是权宜之计,但如果你想实现这种真的,我不推荐它

because I'm lazy, I decode the PEM encoding to binary in the same BYTE array I used to load the file into -- for this simple test, it was expedient, but if you're looking to implement this sort of thing for real, I wouldn't recommend it

这篇关于CertCreateCertificateContext 返回 CRYPT_E_ASN1_BADTAG/8009310b的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆