我对使用OpenSSL API进行编程非常陌生,只是通过阅读openssl的文档很难理解工作原理(现在,为什么我不能在帖子中放置尽可能多的链接? ??)。
我已按照OpenSSL Certificate Authority | Create the root pair和OpenSSL Certificate Authority | Sign server and client certificates创建密钥和证书,现在我希望我的应用程序使用服务器私钥和证书与客户端进行通信。这就是我到目前为止(请随意评论您认为此代码错误的每一个细节)。
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, certificate_chain_file))
{
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, private_key_file, SSL_FILETYPE_PEM) != 1)
{
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
现在,在调用SSL_CTX_use_PrivateKey_file时,它失败并显示以下错误:
139649166755520:错误:0B080074:LIB(11):函数(128):原因(116):x509_cmp.c:330:
我已经下载了相应的OpenSSL源代码,并在x509_cmp.c的第330行下载了:
X509err(X509_F_X509_CHECK_PRIVATE_KEY,X509_R_KEY_VALUES_MISMATCH);
当谷歌搜索时,我看到有人说这意味着密码不正确,但绝对不是(因为当我输入任何其他密码时,我得到另一堆错误的痕迹)。可能是造成此错误的原因是什么?
答案 0 :(得分:0)
现在,在调用SSL_CTX_use_PrivateKey_file时,它失败并显示以下错误:
<IfModule mod_auth_pam.c> AuthPAM off </IfModule>
您没有阅读问题。这似乎工作正常。
完整的错误字符串是:
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
应该是PEM编码证书的串联,包括(1)由根CA签名的中间证书,以及(2)由中间CA签名的服务器证书。 certificate_chain_file
应该是服务器证书的私钥;而不是其中一个CA.为了完整起见,客户必须信任您的根CA,而不是在链中发送。
对于“... PEM编码证书的串联......”,请参阅(例如)Adding an intermediate certificates to a pkcs12 file和Is it possible to include the private key in a .CER certificate file?
以编程方式读取私钥文件...
为了完整起见,这里是如何以ASN.1 / DER和PEM格式读取和写入它们,但我不相信它的问题:Use OpenSSL RSA key with .Net。
不要让.Net欺骗你。答案是在C / C ++中,它向您展示了如何检查二进制ASN.1 / DER编码键;以及 private_key_file
和 ----- BEGIN XXX-----
的Base64 PEM编码密钥。
----- END XXX-----
相关,这可能还有改进的余地。
请参阅OpenSSL wiki上TLS Client的设置代码以获取一些建议。
我已按照OpenSSL Certificate Authority | Create the root pair和OpenSSL Certificate Authority | Sign server and client certificates创建密钥和证书......
相关的,您可能需要查看How do you sign Certificate Signing Request with your Certification Authority和How to create a self-signed certificate with openssl?它提供了有关X.509服务器证书的大量背景信息,以及各种规则的来源。
更新 (来自评论):
“...私钥文件和与私钥对应的证书文件是完全独立的文件,当我将私钥文件提供给SSL_CTX_use_PrivateKey_file函数时,我认为它无法知道证书文件”
您必须知道与服务器证书一起使用的私钥。这是您必须加载的私钥。根证书和中间证书不需要私钥,因为您不对它们执行私钥操作。
答案 1 :(得分:0)
我觉得我有点失落 - 私钥文件和与私钥对应的证书文件是完全独立的文件,当我将私钥文件提供给SSL_CTX_use_PrivateKey_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
所以它必须是别的东西,就像我不理解的一些加密东西。
答案 2 :(得分:0)
由于我没有回答,我不确定我的问题/解释是否太久了。现在的简短问题是:
使用
时SSL_CTX_use_PrivateKey_file
功能;为什么我得到
139923876902592:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:539:
139923876902592:error:0906A065:PEM routines:PEM_do_header:bad decrypt:pem_lib.c:483:
139923876902592:error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib:ssl_rsa.c:669:
ERROR: Failed to set private key file /home/jocke/ca/intermediate/private/xxx.key.pem. ERROR:
当我输错密码时,
39814590265024:error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch:x509_cmp.c:330:
ERROR: Failed to set private key file /home/jocke/ca/intermediate/private/xxx.key.pem. ERROR:
当我提供正确的密码?
旧帖子:
对不起这里的布局,但工具说的是代码但没有格式化为代码,但我不知道它是什么,所以我会“编码”所有内容。
好吧,我以为我做到了。让我准确地说明我在做什么,并解释为什么我认为我是对的(尽管我显然不是):
目录设置
mkdir ~/ca/
cd ~/ca
mkdir certs crl newcerts private
chmod 700 private
index.txt文件是OpenSSL ca工具存储证书数据库的位置。请勿手动删除或编辑此文件。它现在应该包含一个引用中间证书的行。
touch index.txt
echo 1000 > serial
创建〜/ ca / openssl.cnf,如下面的“根CA配置文件”,并确保dir值正确
openssl genrsa -aes256 -out private/ca.key.pem 4096
chmod 400 private/ca.key.pem
警告:每当使用req工具时,必须指定要与-config选项一起使用的配置文件,否则OpenSSL将默认为/etc/pki/tls/openssl.cnf。 注意:到期时间长,使用20年(7300天)
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
ROOT CA PRIVATE KEY:〜/ ca / private / ca.key.pem ROOT CA CERTIFICATE:〜/ ca / 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
创建〜/ ca / intermediate / openssl.cnf,如下面的“中间CA配置文件”,并确保dir值正确
cd ~/ca
创建中间CA私钥:
openssl genrsa -aes256 -out intermediate/private/intermediate.key.pem 4096
chmod 400 intermediate/private/intermediate.key.pem
创建证书签名请求(CSR):(确保指定中间CA CONF文件!)
cd ~/ca
openssl req -config intermediate/openssl.cnf -new -sha256 -key intermediate/private/intermediate.key.pem -out intermediate/csr/intermediate.csr.pem
使用根证书和CSR创建中间CA证书:(确保指定 ROOT CA CONF FILE !!!) 注意:更短的到期时间,使用10年(3650天)
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
INTERMEDIATE CA PRIVATE KEY:〜/ ca / intermediate / private / intermediate.key.pem 中级CA证书:〜/ ca / intermediate / certs / intermediate.cert.pem
当应用程序(例如,Web浏览器)尝试验证由中间CA签名的证书时,它还必须根据根证书验证中间证书。 要完成信任链,请创建CA证书链以呈现给应用程序。 要创建CA证书链,请将中间证书和根证书连接在一起。 我们稍后将使用此文件来验证由中间CA签名的证书。
cat intermediate/certs/intermediate.cert.pem certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem
chmod 444 intermediate/certs/ca-chain.cert.pem
CERTIFICATE CHAIN FILE:〜/ ca / intermediate / certs / ca-chain.cert.pem
使用中间CA签署证书。 创建密钥:
cd ~/ca/
openssl genrsa -aes256 -out intermediate/private/myinternetaddr.key.pem 2048
chmod 400 intermediate/private/myinternetaddr.key.pem
创建证书签名请求(CSR):
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
对于WEBMASTERS:以下行被视为“代码” - 为什么?上面类似的行不是。 客户端私钥:〜/ ca / intermediate / private / myinternetaddr.key.pem 客户证书签名请求:〜/ ca / intermediate / csr / myinternetaddr.csr.pem 客户证书:〜/ ca / intermediate / certs / myinternetaddr.cert.pem
验证证书:
openssl x509 -noout -text -in intermediate/certs/myinternetaddr.cert.pem
使用我们之前创建的CA证书链文件(ca-chain.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
但显然不是 - 为什么?