以编程方式验证X509证书和私钥匹配

光彩柠檬

我使用EVP_aes_256_cbc()密码创建了RSA密钥对私钥是PEM编码的,具有密码短语。这要求用户输入密码。

这是创建私钥调用:

//Save private key
    bio_priv = BIO_new_file(full_asymKeyFilePath.c_str(), "a+");
    if (PEM_write_bio_RSAPrivateKey(
        bio_priv,   //BIO handle
        rsa,        //Key handle
        EVP_aes_256_cbc(),      //Cipher encoding format
        pwd,        //Password
        pwd_len,            //Password length
        NULL,       //Callback
        NULL        //Not sure
        ) != 1) {
            //report err
    } 

然后,我生成了一个证书,并用私钥对其进行了签名。

//Sign the certificate with the generated key
    if (!X509_sign(cert, evpKey, EVP_sha1())){
        //report err
    }

稍后,我要验证此证书是否与此RSA密钥对匹配。当我SSL_CTX_check_private_key()输入,系统会提示我从控制台输入密码。

有没有办法自动输入密码,以便不会从控制台得到提示?

//Load server certificate, must be called before ever calling use private key
    if (SSL_CTX_use_certificate_file(context, full_certFilePath.c_str(), SSL_FILETYPE_PEM) == 0){   //load all certs from PEM file into SSL_CTX 
        //err
    }

    //Load private key corresponding to the certificate
    if (SSL_CTX_use_PrivateKey_file(context, full_asymKeyFilePath.c_str(), SSL_FILETYPE_PEM) == 0){ //load all certs from PEM file into SSL_CTX 
        //file type is not pem or private key was loaded before calling this function. Private key does not match the public key in the certificate
        //err
    }

    //Verify that certificate and private key match
    if (!SSL_CTX_check_private_key(context)){  //<====== Prompts me to enter pass :(
        //err
    }
w

以编程方式验证X509证书和私钥匹配。私钥具有PEM密码

这里有两个答案。一个用于证书,第二个用于私钥。首先显示私钥,因为它用于验证证书(因此首先访问它很有意义)。

另外,调用*_check_key例程也很重要,因为OpenSSL仅检查密钥是否编码正确;并且不会检查其实际有效。例如,请参见openssl生成的私钥不满足n = p * q


在OpenSSL中,您将使用以下内容来验证私钥是否编码正确:

FILE* file = fopen(...);
EVP_PKEY* pkey = PEM_read_PrivateKey(file, NULL, PasswordCallback, NULL);
unsigned long err = ERR_get_error();

if(pkey)
    EVP_PKEY_free(pkey);

如果pkeyNULL,则存在问题并err保存原因码。否则,您将拥有正确编码的私钥(但不一定有效)。

如果密钥编码正确,则可以检查私钥的类型并使用以下方法对其进行验证。

int type = EVP_PKEY_get_type(pkey);
switch (type)
{
case EVP_PKEY_RSA:
case EVP_PKEY_RSA2:
    RSA* rsa = EVP_PKEY_get1_RSA(pkey);
    rc = RSA_check_key(rsa);
    ASSERT(rc);
    RSA_free(rsa);

    break;

case EVP_PKEY_DSA:
case EVP_PKEY_DSA1:
case EVP_PKEY_DSA2:
case EVP_PKEY_DSA3:
case EVP_PKEY_DSA4:
    DSA* dsa = EVP_PKEY_get1_DSA(pkey);
    rc = DSA_check_key(dsa);
    ASSERT(rc);
    DSA_free(dsa);

    break;

case EVP_PKEY_DH:
    DH* dh = EVP_PKEY_get1_DH(pkey);
    rc = DH_check_key(dh);
    ASSERT(rc);
    DH_free(dh);

    break;

case EVP_PKEY_EC:
    EC_KEY* ec = EVP_PKEY_get1_EC_KEY(pkey);
    rc = EC_KEY_check_key(ec);
    ASSERT(rc);
    EC_KEY_free(ec);

    break;

default:
    ASSERT(0);
}

EVP_PKEY_get_type不属于OpenSSL。这是我的实现方式:

int EVP_PKEY_get_type(EVP_PKEY *pkey)
{
    ASSERT(pkey);
    if (!pkey)
        return NID_undef;

    return EVP_PKEY_type(pkey->type);
}

在OpenSSL中,您将使用以下方法来验证证书的编码是否正确:

FILE* file = fopen(...);
X509* x509 = PEM_read_X509(file, NULL, NULL, NULL);
unsigned long err = ERR_get_error();

如果x509NULL,则存在问题并err保存原因码。否则,您将拥有正确编码的证书(但不一定有效)。

然后,您可以使用以下方法验证证书:

/* See above on validating the private key */
EVP_PKEY* pkey = ReadPrivateKey(...);

int rc = X509_verify(x509, pkey);
err = ERR_get_error();

如果为rc != 1,则存在问题并err保存原因码。否则,您将具有有效的证书和私钥对。如果证书有效,则不能使用,err因为err只有在有问题时才有效。

如果您的证书是由颁发者(例如,CA或中间机构)X509_STORE签名的,则您需要使用来验证证书上颁发者的签名(省略了很多错误检查):

const char* serverCertFilename = ...;
const char* issuerCertFilename = ...;    

X509_STORE* store = X509_STORE_new();
ASSERT(store);

static const long flags = X509_V_FLAG_X509_STRICT | X509_V_FLAG_CHECK_SS_SIGNATURE
        | X509_V_FLAG_POLICY_CHECK;
rc = X509_STORE_set_flags(store, flags);
err = ERR_get_error();
ASSERT(rc);

/* Some other object/functions owns 'lookup', but I'm not sure which (perhaps the store) */
X509_LOOKUP* lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
/* err = ERR_get_error(); // Does not set error codes. */
ASSERT(lookup);    

/* Cannot load this from memory. No API!!! */
rc = X509_LOOKUP_load_file(lookup, issuerCertFilename, X509_FILETYPE_PEM);
/* err = ERR_get_error(); // Does not set error codes. */
ASSERT(rc);

X509_STORE_CTX* ctx = X509_STORE_CTX_new();
ASSERT(ctx);

X509* serverCert = ReadCertifcate(serverCertFilename);
ASSERT(serverCert);

rc = X509_STORE_CTX_init(ctx, store, serverCert, NULL);
ret = err = ERR_get_error();
ASSERT(rc);

/* Error codes at https://www.openssl.org/docs/crypto/X509_STORE_CTX_get_error.html */
rc = X509_verify_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);

/* Do cleanup, return success/failure */

有没有办法自动输入密码,以便不会从控制台得到提示?

是的。在中使用密码回调PEM_read_PrivateKeyPasswordCallback可以简单地在缓冲器提供口令,或者可以提示用户并在缓冲器中返回的密码。

我的密码回调有点涉及。在将原始密码传递给库之前,它将对原始密码执行一次哈希处理。这样可以确保不使用“纯文本”密码(但不会减慢常规攻击的速度)。您可以提示用户输入字符串,也可以返回硬编码的字符串。

我的密码回调使用标签。标签使我可以根据用法派生出不同的密钥(即使使用了相同的“基本”机密)。通过指定不同的用法或标签,我得到密钥位的不同派生。该标签通过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();
    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);
    ASSERT(ctx.get() != NULL);

    const EVP_MD* hash = EVP_sha512();
    ASSERT(hash != NULL);

    rc = EVP_DigestInit_ex(ctx.get(), hash, NULL);
    err = ERR_get_error();

    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();

    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();

        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();

    ASSERT(rc == 1);
    if (rc != 1)
    {
        ...
        throw runtime_error(oss.str().c_str());
    }

    return n;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何以编程方式获取X509证书的完整证书链?

来自分类Dev

如何完全验证X509证书?

来自分类Dev

如何验证 x509 证书的签名?

来自分类Dev

以编程方式从钥匙串中删除私钥(与证书匹配)

来自分类Dev

使用TrustLevel = Medium验证X509证书

来自分类Dev

iOS:如何通过程序中的私钥和x509证书创建PKCS12(P12)密钥库?

来自分类Dev

在将C#导出到p12之前,将私钥添加到X509证书

来自分类Dev

X509证书公用密钥填充

来自分类Dev

加载X509证书时出错

来自分类Dev

X509证书公用密钥填充

来自分类Dev

加载X509证书时出错

来自分类Dev

阅读X509证书以进行处理

来自分类Dev

X509证书的Ruby SOAP响应未通过XML SignatureValue验证

来自分类Dev

Java安全性-具有公钥的X509证书验证

来自分类Dev

Meteor.js使用X509证书身份验证连接到Mongo

来自分类Dev

使用openssl验证x509证书是否有效并由受信任的CA签名

来自分类Dev

Grails中基于RESTful证书的(X509)登录身份验证

来自分类Dev

X509证书的Ruby SOAP响应未通过XML SignatureValue验证

来自分类Dev

Apache X509证书身份验证模式设置HTTP标头

来自分类Dev

带有嵌入式 x509 证书的 xades4j 验证问题

来自分类Dev

使用 X509 证书指纹进行用户身份验证

来自分类Dev

如何验证私钥是否与证书匹配?

来自分类Dev

如何以编程方式创建X509存储密钥以用于加密?

来自分类Dev

在Android(Java / Kotlin)上获取X.509证书ECDH私钥和公钥

来自分类Dev

如何创建防止“服务器模式 SSL 必须使用具有关联私钥的证书”异常的 X509 证书?

来自分类Dev

Spring Webflux + Spring Security的X509证书验证问题:x509.X509CertImpl无法转换为类java.lang.String

来自分类Dev

使用OpenSSL和PHP设置过去的x509证书的notBefore

来自分类Dev

Skaffold和Microk8s-入门-x509:未知授权机构签署的证书

来自分类Dev

使用clickonce应用程序在客户端上打包和安装x509证书

Related 相关文章

  1. 1

    如何以编程方式获取X509证书的完整证书链?

  2. 2

    如何完全验证X509证书?

  3. 3

    如何验证 x509 证书的签名?

  4. 4

    以编程方式从钥匙串中删除私钥(与证书匹配)

  5. 5

    使用TrustLevel = Medium验证X509证书

  6. 6

    iOS:如何通过程序中的私钥和x509证书创建PKCS12(P12)密钥库?

  7. 7

    在将C#导出到p12之前,将私钥添加到X509证书

  8. 8

    X509证书公用密钥填充

  9. 9

    加载X509证书时出错

  10. 10

    X509证书公用密钥填充

  11. 11

    加载X509证书时出错

  12. 12

    阅读X509证书以进行处理

  13. 13

    X509证书的Ruby SOAP响应未通过XML SignatureValue验证

  14. 14

    Java安全性-具有公钥的X509证书验证

  15. 15

    Meteor.js使用X509证书身份验证连接到Mongo

  16. 16

    使用openssl验证x509证书是否有效并由受信任的CA签名

  17. 17

    Grails中基于RESTful证书的(X509)登录身份验证

  18. 18

    X509证书的Ruby SOAP响应未通过XML SignatureValue验证

  19. 19

    Apache X509证书身份验证模式设置HTTP标头

  20. 20

    带有嵌入式 x509 证书的 xades4j 验证问题

  21. 21

    使用 X509 证书指纹进行用户身份验证

  22. 22

    如何验证私钥是否与证书匹配?

  23. 23

    如何以编程方式创建X509存储密钥以用于加密?

  24. 24

    在Android(Java / Kotlin)上获取X.509证书ECDH私钥和公钥

  25. 25

    如何创建防止“服务器模式 SSL 必须使用具有关联私钥的证书”异常的 X509 证书?

  26. 26

    Spring Webflux + Spring Security的X509证书验证问题:x509.X509CertImpl无法转换为类java.lang.String

  27. 27

    使用OpenSSL和PHP设置过去的x509证书的notBefore

  28. 28

    Skaffold和Microk8s-入门-x509:未知授权机构签署的证书

  29. 29

    使用clickonce应用程序在客户端上打包和安装x509证书

热门标签

归档