【问题标题】:Check that a file is certificate or a key检查文件是证书还是密钥
【发布时间】:2014-03-14 07:16:14
【问题描述】:

我有一个问题,我允许用于上传证书和私钥文件。现在假设我有一个文件的扩展名被弄乱(有意或无意更改)说要破坏系统。我需要进行验证,可以检查并告诉我给定文件是有效的证书文件或私钥文件或其他文件..

我当时的想法是:检查文件内容中的-- BEGIN CERTIFICATE ---- BEGIN RSA PRIVATE KEY --。请告诉我我是什么东西好,或者有其他更好的解决方案。

谢谢

【问题讨论】:

    标签: python-2.7 ssl openssl ssl-certificate private-key


    【解决方案1】:

    检查并告诉我给定的文件是有效的证书文件或私钥文件

    我将在 C 中回答这个问题,因为 OpenSSL 是一个 C 库。其他人或许可以将其翻译成pyOpenSSL,在这种情况下,他们的答案可能比我的更好。

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

    此外,调用*_check_key 例程也很重要,因为 OpenSSL 只检查密钥是否编码良好;并且它不检查它是否真的有效。例如,请参阅Private key generated by openssl does not satisfy 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 包含一个原因码。否则,您有一个正确编码的私钥(但不一定有效)。

    PasswordCallback 可以简单地提供缓冲区中的密码,也可以提示用户并返回缓冲区中的密码。有关PasswordCallback 的更多信息,请参阅Loading a PEM format certificate

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

    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 */
    

    【讨论】:

      猜你喜欢
      • 2012-09-14
      • 2016-10-07
      • 2014-11-06
      • 1970-01-01
      • 2021-09-03
      • 2011-09-21
      • 1970-01-01
      • 2012-10-05
      相关资源
      最近更新 更多