使用OpenSSL以编程方式读取私钥文件

使用OpenSSL以编程方式读取私钥文件,openssl,x509,pki,ca,Openssl,X509,Pki,Ca,我对使用OpenSSL API编程非常陌生,仅仅通过阅读OpenSSL的文档就很难理解事情是如何工作的(现在,为什么我不能在帖子中放尽可能多的链接??) 我已经按照和创建了密钥和证书,现在我希望我的应用程序在与客户端通信时使用服务器私钥和证书。这就是我到目前为止所做的(请随意评论您认为此代码错误的每一个小细节) 现在,在调用SSL_CTX_use_PrivateKey_文件时,它失败,并打印出以下错误: 139649166755520:error:0B080074:lib(11):func(12

我对使用OpenSSL API编程非常陌生,仅仅通过阅读OpenSSL的文档就很难理解事情是如何工作的(现在,为什么我不能在帖子中放尽可能多的链接??)

我已经按照和创建了密钥和证书,现在我希望我的应用程序在与客户端通信时使用服务器私钥和证书。这就是我到目前为止所做的(请随意评论您认为此代码错误的每一个小细节)

现在,在调用SSL_CTX_use_PrivateKey_文件时,它失败,并打印出以下错误:

139649166755520:error:0B080074:lib(11):func(128):reason(116):x509_cmp.c:330:
139649166755520:错误:0B080074:lib(11):func(128):原因(116):x509\u cmp.c:330:

我已经下载了相应的OpenSSL源代码,在x509_cmp.c的第330行,上面写着:

在谷歌上搜索时,我看到有人说这意味着密码不正确,但肯定不是(因为当我输入任何其他密码时,我会得到另一个错误堆栈跟踪)。这一错误的原因可能是什么

现在,在调用SSL_CTX_use_PrivateKey_文件时,它失败,并打印出以下错误:

139649166755520:error:0B080074:lib(11):func(128):reason(116):x509_cmp.c:330:
你在阅读上没有问题。这似乎很有效

完整的错误字符串为:

$ openssl errstr 0x0B080074
error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch
您提供的私钥与服务器的证书中的公钥不匹配

touch index.txt
echo 1000 > serial
SSL_library_init();
SSL_METHOD const * method = SSLv3_server_method();
if (!method)
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}

SSL_CTX * ctx = SSL_CTX_new(method);
if (!ctx)
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}
if (!SSL_CTX_use_certificate_chain_file(ctx, "~/ca/intermediate/certs/ca-chain.cert.pem"))
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) private_key_file_password);
SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);

if (SSL_CTX_use_PrivateKey_file(ctx, "~/ca/intermediate/private/myinternetaddr.key.pem", SSL_FILETYPE_PEM) != 1)
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}
certificate\u chain\u file
应该是PEM编码证书的串联,包括(1)由根CA签名的中间证书,以及(2)由中间CA签名的服务器证书。
private\u key\u file
应该是服务器证书的私钥;而不是一个CAs。为了完整性,客户端必须信任您的根CA,并且它不在链中发送

有关“…PEM编码证书的连接…”,请参阅(例如)和


以编程方式读取私钥文件

为了完整起见,这里介绍了如何以ASN.1/DER和PEM格式读写它们,但我不认为这是您的问题:

不要让.Net欺骗你。答案是C/C++,它向您展示了如何检查二进制ASN.1/DER编码密钥;以及带有
----开始XXX---
----结束XXX---
的Base64 PEM编码密钥


与此相关,这可能还有改进的余地

有关一些建议,请参阅OpenSSL wiki上的设置代码


我已经遵循并创建了密钥和证书

与此相关,您可能希望了解一下,它提供了很多关于X.509服务器证书的背景信息,以及各种规则的来源


更新(来自评论):

“…私钥文件和与私钥相对应的证书文件是完全独立的文件,当我将私钥文件提供给SSL_CTX_use_PrivateKey_file函数时,我认为它无法了解证书文件”

您必须知道与服务器证书一起使用的私钥。这是您必须加载的私钥。根证书和中间证书不需要私钥,因为您不使用它们执行私钥操作

现在,在调用SSL_CTX_use_PrivateKey_文件时,它失败,并打印出以下错误:

139649166755520:error:0B080074:lib(11):func(128):reason(116):x509_cmp.c:330:
你在阅读上没有问题。这似乎很有效

完整的错误字符串为:

$ openssl errstr 0x0B080074
error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch
您提供的私钥与服务器的证书中的公钥不匹配

touch index.txt
echo 1000 > serial
SSL_library_init();
SSL_METHOD const * method = SSLv3_server_method();
if (!method)
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}

SSL_CTX * ctx = SSL_CTX_new(method);
if (!ctx)
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}
if (!SSL_CTX_use_certificate_chain_file(ctx, "~/ca/intermediate/certs/ca-chain.cert.pem"))
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) private_key_file_password);
SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);

if (SSL_CTX_use_PrivateKey_file(ctx, "~/ca/intermediate/private/myinternetaddr.key.pem", SSL_FILETYPE_PEM) != 1)
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}
certificate\u chain\u file
应该是PEM编码证书的串联,包括(1)由根CA签名的中间证书,以及(2)由中间CA签名的服务器证书。
private\u key\u file
应该是服务器证书的私钥;而不是一个CAs。为了完整性,客户端必须信任您的根CA,并且它不在链中发送

有关“…PEM编码证书的连接…”,请参阅(例如)和


以编程方式读取私钥文件

为了完整起见,这里介绍了如何以ASN.1/DER和PEM格式读写它们,但我不认为这是您的问题:

不要让.Net欺骗你。答案是C/C++,它向您展示了如何检查二进制ASN.1/DER编码密钥;以及带有
----开始XXX---
----结束XXX---
的Base64 PEM编码密钥


与此相关,这可能还有改进的余地

有关一些建议,请参阅OpenSSL wiki上的设置代码


我已经遵循并创建了密钥和证书

与此相关,您可能希望了解一下,它提供了很多关于X.509服务器证书的背景信息,以及各种规则的来源


更新(来自评论):

“…私钥文件和与私钥相对应的证书文件是完全独立的文件,当我将私钥文件提供给SSL_CTX_use_PrivateKey_file函数时,我认为它无法了解证书文件”


您必须知道与服务器证书一起使用的私钥。这是您必须加载的私钥。根证书和中间证书不需要私钥,因为您不使用它们执行私钥操作。

我想我在这里有点迷路了-私钥文件和对应于私钥的证书文件是完全独立的文件,当我将私钥文件交给
SSL\u CTX\u use\u PrivateKey\u file
函数我想它不知道证书文件。我知道私钥文件的密钥是正确的。当我输入错误的密码时,会出现以下情况

139818423899840:error:06065064:lib(6):func(101):reason(100):evp_enc.c:539:
139818423899840:error:0906A065:lib(9):func(106):reason(101):pem_lib.c:483:
139818423899840:error:140B0009:lib(20):func(176):reason(9):ssl_rsa.c:669:
这意味着

$ openssl errstr 140B0009
error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib
$ openssl errstr 0906A065
error:0906A065:PEM routines:PEM_do_header:bad decrypt
$ openssl errstr 06065064
error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
所以它必须是别的东西,比如
openssl genrsa -aes256 -out private/ca.key.pem 4096
chmod 400 private/ca.key.pem
openssl req -config openssl.cnf -key private/ca.key.pem -new -x509 -days 7300 -sha256 -extensions v3_ca -out certs/ca.cert.pem
chmod 444 certs/ca.cert.pem
openssl x509 -noout -text -in certs/ca.cert.pem
mkdir ~/ca/indermediate
cd ~/ca/indermediate
mkdir certs crl csr newcerts private
chmod 700 private
touch index.txt
echo 1000 > serial
echo 1000 > ~/ca/intermediate/crlnumber
cd ~/ca
openssl genrsa -aes256 -out intermediate/private/intermediate.key.pem 4096
chmod 400 intermediate/private/intermediate.key.pem
cd ~/ca
openssl req -config intermediate/openssl.cnf -new -sha256 -key intermediate/private/intermediate.key.pem -out intermediate/csr/intermediate.csr.pem
openssl ca -config openssl.cnf -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -in intermediate/csr/intermediate.csr.pem -out intermediate/certs/intermediate.cert.pem
chmod 444 intermediate/certs/intermediate.cert.pem
openssl x509 -noout -text -in intermediate/certs/intermediate.cert.pem
cat intermediate/certs/intermediate.cert.pem certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem
chmod 444 intermediate/certs/ca-chain.cert.pem
cd ~/ca/
openssl genrsa -aes256 -out intermediate/private/myinternetaddr.key.pem 2048
chmod 400 intermediate/private/myinternetaddr.key.pem
openssl req -config intermediate/openssl.cnf -key intermediate/private/myinternetaddr.key.pem -keyform PEM -new -sha256 -out intermediate/csr/myinternetaddr.csr.pem
openssl ca -config intermediate/openssl.cnf -extensions server_cert -days 375 -notext -md sha256 -in intermediate/csr/myinternetaddr.csr.pem -out intermediate/certs/myinternetaddr.cert.pem
chmod 444 intermediate/certs/myinternetaddr.cert.pem
cat index.txt
openssl x509 -noout -text -in intermediate/certs/myinternetaddr.cert.pem
$ openssl verify -CAfile intermediate/certs/ca-chain.cert.pem intermediate/certs/myinternetaddr.cert.pem
intermediate/certs/myinternetaddr.cert.pem: OK
SSL_library_init();
SSL_METHOD const * method = SSLv3_server_method();
if (!method)
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}

SSL_CTX * ctx = SSL_CTX_new(method);
if (!ctx)
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}
if (!SSL_CTX_use_certificate_chain_file(ctx, "~/ca/intermediate/certs/ca-chain.cert.pem"))
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) private_key_file_password);
SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);

if (SSL_CTX_use_PrivateKey_file(ctx, "~/ca/intermediate/private/myinternetaddr.key.pem", SSL_FILETYPE_PEM) != 1)
{
    ERR_print_errors_fp(stderr);
    exit(EXIT_FAILURE);
}
static int pem_passwd_cb(char * buf, int size, int rwflag, void * userdata)
{
    char const * const password = (char const * const) userdata;
    Logger & logger = Logger::get_instance();
    logger << "Setting password to [" << password << "]";
    logger.log_info();
    strncpy(buf, (char *) password, size);
    buf[size - 1] = '\0';
    fprintf(stdout, "BUFLEN: %d\nBUF: [%s]\n", (int) strlen(buf), buf);
    return strlen(buf);
}
$ openssl req -config intermediate/openssl.cnf -key intermediate/private/myinternetaddr.key.pem -new -sha256 -out intermediate/csr/myinternetaddr.csr.pem
Enter pass phrase for intermediate/private/myinternetaddr.key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:SE
State or Province Name [England]:Sweden
Locality Name []:NA
Organization Name [Alice Ltd]:NA
Organizational Unit Name []:NA
Common Name []:Jocke
Email Address []:yyy@hotmail.com
$ openssl ca -config intermediate/openssl.cnf -extensions server_cert -days 375 -notext -md sha256 -in intermediate/csr/myinternetaddr.csr.pem -out intermediate/certs/myinternetaddr.cert.pem
Using configuration from intermediate/openssl.cnf
Enter pass phrase for ~/ca/intermediate/private/intermediate.key.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 4098 (0x1002)
        Validity
            Not Before: Aug 13 20:58:46 2016 GMT
            Not After : Aug 23 20:58:46 2017 GMT
        Subject:
            countryName               = SE
            stateOrProvinceName       = Sweden
            localityName              = NA
            organizationName          = NA
            organizationalUnitName    = NA
            commonName                = Jocke
            emailAddress              = yyy@hotmail.com
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            Netscape Cert Type: 
                SSL Server
            Netscape Comment: 
                OpenSSL Generated Server Certificate
            X509v3 Subject Key Identifier: 
                    D5:D6:F4:38:24:18:41:F7:F0:29:9F:99:6C:D3:08:38:CE:35:B8:43
                X509v3 Authority Key Identifier: 
                    keyid:2C:EB:99:69:BE:00:EE:C2:FD:86:B7:CF:6C:AD:47:4E:65:AA:90:5A
                    DirName:/C=SE/ST=Sweden/L=/O=Joachim Person/CN=Joachim Person/emailAddress=xxx@gmail.com
                    serial:10:00

                X509v3 Key Usage: critical
                    Digital Signature, Key Encipherment
                X509v3 Extended Key Usage: 
                    TLS Web Server Authentication
    Certificate is to be certified until Aug 23 20:58:46 2017 GMT (375 days)
    Sign the certificate? [y/n]:y


    1 out of 1 certificate requests certified, commit? [y/n]y
    Write out database with 1 new entries
    Data Base Updated