加载PEM格式证书

如何在openssl c ++中加载PEM格式证书作为x509?

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个function。 我在程序中有一个证书string(这只是一个PEM格式的数据)。 我想把它添加到句柄。 我如何继续?

SSL_CTX_set_default_passwd_cb是否可以使用我正在加载的私钥和ssl句柄而不是上下文?

如何在openssl c ++中加载PEM格式证书作为x509?

你应该使用SSL_CTX_use_certificate_chain_fileSSL_CTX_use_PrivateKey_file 。 您可以使用它们并构建客户端或服务器上下文。 示例代码如下所示。 使用它们有一些细微差别,所以在SSL_CTX_use_certificate(3)看看OpenSSL的文档。

我不确定“x509”是什么意思。 证书将是x509,但私钥将是PKCS#8。 有PEM_read_bio_X509PEM_read_X509 ,他们返回一个X509* ,他们可以做你想做的。

SSL_CTX_set_default_passwd_cb将与我正在加载的私钥协同工作

这取决于,但它应该。 密码回调是可选的。 如果您使用密码保护密钥,请使用它。 在下面的代码中,我称之为PasswordCallback ,它用于读写密钥(只读如下所示)。


 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为您提供了一个缓冲区和一个大小。 你填充缓冲区,并返回你填充的大小。

我的密码回调有些涉及。 在将其传递给库之前,它会对原始密码执行一次散列。 这可以确保不使用“纯文本”密码(但不会减慢习惯性攻击)。 你可以提示用户输入一个字符串,也可以返回一个硬编码的字符串。

我的密码回调使用一个标签。 该标签允许我根据使用情况派生不同的密钥(即使使用相同的“基本密码”)。 通过指定不同的用法或标签,我可以得到不同的密钥位的派生。 标签通过下面的arg提供,您可以使用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; }