加载PEM格式证书 [英] Loading a PEM format certificate
问题描述
如何在openssl c ++中将PEM格式证书作为x509加载?
How do I load the PEM format certificate as an x509 in openssl c++?
int SSL_use_certificate(SSL *ssl, X509 *x);
int SSL_use_certificate_ASN1(SSL *ssl, unsigned char *d, int len);
int SSL_use_certificate_file(SSL *ssl, const char *file, int type);
这些是可用于将句柄添加到证书的3个函数。我在程序中有一个证书字符串(这只是一个PEM格式的数据)。我想把它添加到句柄。
These are the 3 functions available to add a certificate to a Handle. I have a certificate string inside the program(This is just a PEM formatted data). I want to add it to the handle. How do I proceed?
SSL_CTX_set_default_passwd_cb是否可以使用我加载到ssl和ssl句柄而不是上下文的私钥?
Will SSL_CTX_set_default_passwd_cb work with private keys that I am loading into and ssl handle and not a context?
推荐答案
如何在openssl c ++中将PEM格式证书作为x509加载?
How do I load the PEM format certificate as an x509 in openssl c++?
您应该使用 SSL_CTX_use_certificate_chain_file
和 SSL_CTX_use_PrivateKey_file
。您可以使用它们并构建客户端或服务器上下文。示例代码如下所示。使用它们有一些细微差别,因此请查看OpenSSL的文档,网址为: SSL_CTX_use_certificate(3)
。
You should probably use SSL_CTX_use_certificate_chain_file
and SSL_CTX_use_PrivateKey_file
. You can use them and build a client or server context. The sample code is shown below. There are some nuances to using them, so take a look at OpenSSL's documentation at SSL_CTX_use_certificate(3)
.
我不知道x509是什么意思。证书将是x509,但私钥将是PKCS#8。有 PEM_read_bio_X509
和 PEM_read_X509
,他们返回 X509 *
I'm not sure what "as an x509" means. The certificate will be x509, but the private key will be PKCS #8. There are PEM_read_bio_X509
and PEM_read_X509
, they return an X509*
, and they may do what you want.
将SSL_CTX_set_default_passwd_cb与我要加载的私钥一起使用
Will SSL_CTX_set_default_passwd_cb work with private keys that I am loading
这取决于它,但它应该。密码回调是可选的。如果密码保护密钥,请使用它。在下面的代码中,我将其称为 PasswordCallback
,它用于读取和写入密钥(只读取如下所示)。
It depends, but it should. The password callback is optional. Use it if you password protected the key. In the code below, I call it PasswordCallback
, and its used for both reading and writing the key (only reading is shown below).
using SSL_CTX_ptr = std::unique_ptr<SSL_CTX, decltype(&::SSL_CTX_free)>;
SSL_CTX* CreateServerContext()
{
do
{
int rc;
unsigned long err;
const SSL_METHOD* method = SSLv23_server_method();
ASSERT(method != NULL);
if (method == NULL)
{
LogError("GetServerContext: SSLv23_server_method failed");
break; /* failed */
}
SSL_CTX_ptr t(SSL_CTX_new(method), ::SSL_CTX_free);
ASSERT(t.get() != NULL);
if (t.get() == NULL)
{
LogError("GetServerContext: SSL_CTX_new failed");
break; /* failed */
}
long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
flags |= SSL_OP_NO_COMPRESSION;
flags |= SSL_OP_SAFARI_ECDHE_ECDSA_BUG;
flags |= SSL_OP_CIPHER_SERVER_PREFERENCE;
/* Cannot fail */
SSL_CTX_set_options(t.get(), flags);
string ciphers = GetServerCipherSuites();
ASSERT(!ciphers.empty());
rc = SSL_CTX_set_cipher_list(t.get(), ciphers.c_str());
err = ERR_get_error();
ASSERT(rc == 1);
if (rc != 1)
{
LogError("GetServerContext: SSL_CTX_set_cipher_list failed");
break; /* failed */
}
string certFile = config.GetServerCertFile();
ASSERT(!certFile.empty());
rc = SSL_CTX_use_certificate_chain_file(t.get(), certFile.c_str());
err = ERR_get_error();
ASSERT(rc == 1);
if (rc != 1)
{
LogError("GetServerContext: SSL_CTX_use_certificate_chain_file failed");
break; /* failed */
}
/* These two do not return a value... cannot fail? */
SSL_CTX_set_default_passwd_cb(t.get(), PasswordCallback);
SSL_CTX_set_default_passwd_cb_userdata(t.get(), (void*) SERVER_KEY_LABEL);
string keyFile = config.GetServerKeyFile();
ASSERT(!keyFile.empty());
rc = SSL_CTX_use_PrivateKey_file(t.get(), keyFile.c_str(), SSL_FILETYPE_PEM);
err = ERR_get_error();
ASSERT(rc == 1);
if (rc != 1)
{
LogError("GetServerContext: SSL_CTX_use_PrivateKey_file failed");
break; /* failed */
}
rc = SSL_CTX_check_private_key(t.get());
err = ERR_get_error();
ASSERT(rc == 1);
if (rc != 1)
{
LogError("GetServerContext: SSL_CTX_check_private_key failed");
/* non-fatal, but everything will probably break */
}
/* These three do not return a value... cannot fail? */
SSL_CTX_set_tmp_dh_callback(t.get(), DhCallback);
SSL_CTX_set_tmp_ecdh_callback(t.get(), EcdhCallback);
SSL_CTX_set_tlsext_servername_callback(t.get(), ServerNameCallback);
return t.release();
} while (0);
return NULL;
}
密码回调的想法是:OpenSSL提供一个缓冲区和大小。你填充缓冲区,并返回你填充的大小。
The idea with the password callback is: OpenSSL provides you a buffer and a size. You fill the buffer, and return the size of how much you filled.
我的密码回调有点涉及。它在将原始密码传递到库之前执行原始密码的单个散列。这确保不使用纯文本密码(但不会减慢常规攻击)。您可以提示用户输入字符串,也可以返回硬编码的字符串。
My password callback is somewhat involved. It performs a single hash of the raw password before passing it on to the library. That ensures a "plain text" password is not used (but does not slow down the customary attacks). Yours can prompt the user for a string, or it can return a hard coded string.
我的密码回调使用标签。标签允许我根据用法导出不同的密钥(即使使用相同的基本密钥)。通过指定不同的用法或标签,我得到不同的关键位推导。通过 arg
在下面提供该标签,您可以使用 SSL_CTX_set_default_passwd_cb_userdata
设置该标签。
My password callback uses a label. The label allows me to derive different keys depending on usage (even though the same 'base' secret is used). By specifying a different usage or label, I get a different derivation of key bits. The label is provided through arg
below, and you can set it with SSL_CTX_set_default_passwd_cb_userdata
.
using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, decltype(&::EVP_MD_CTX_destroy)>;
int PasswordCallback(char *buffer, int size, int rwflag, void *arg)
{
UNUSED(rwflag);
int rc;
unsigned long err;
ostringstream oss;
const char* label = (char*) arg;
size_t lsize = (label ? strlen(label) : 0);
SecureVector sv = config.GetMasterKey();
AC_ASSERT(!sv.empty());
if (sv.empty())
{
...
throw runtime_error(oss.str().c_str());
}
EVP_MD_CTX_ptr ctx(EVP_MD_CTX_create(), ::EVP_MD_CTX_destroy);
AC_ASSERT(ctx.get() != NULL);
const EVP_MD* hash = EVP_sha512();
AC_ASSERT(hash != NULL);
rc = EVP_DigestInit_ex(ctx.get(), hash, NULL);
err = ERR_get_error();
AC_ASSERT(rc == 1);
if (rc != 1)
{
...
throw runtime_error(oss.str().c_str());
}
rc = EVP_DigestUpdate(ctx.get(), sv.data(), sv.size());
err = ERR_get_error();
AC_ASSERT(rc == 1);
if (rc != 1)
{
...
throw runtime_error(oss.str().c_str());
}
if (label && lsize)
{
rc = EVP_DigestUpdate(ctx.get(), label, lsize);
err = ERR_get_error();
AC_ASSERT(rc == 1);
if (rc != 1)
{
...
throw runtime_error(oss.str().c_str());
}
}
int n = std::min(size, EVP_MD_size(hash));
if (n <= 0)
return 0;
rc = EVP_DigestFinal_ex(ctx.get(), (unsigned char*) buffer, (unsigned int*) &n);
err = ERR_get_error();
AC_ASSERT(rc == 1);
if (rc != 1)
{
...
throw runtime_error(oss.str().c_str());
}
return n;
}
这篇关于加载PEM格式证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!