2014-03-14 69 views
1

我有個問題,我允許用來上傳證書和私鑰文件。現在假設我有一個文件的擴展名被搞亂了(有意或無意地改變了)來打破這個系統..我需要進行驗證,可以檢查並且可以告訴我給定的文件是一個有效的證書文件,或者私鑰文件或者其他一些文件..檢查文件是證書還是密鑰

我是什麼事情是:檢查-- BEGIN CERTIFICATE ---- BEGIN RSA PRIVATE KEY --在文件的內容。請告訴我是什麼東西好,還是有一些其他更好的辦法解決這個問題..

感謝

回答

2

檢查,並告訴我,給定文件是一個有效的證書文件或私鑰FIL e

我打算在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 */