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