2013-10-16 8 views
8

मैं पीडीएफ के लिए हस्ताक्षर सत्यापन को लागू करने की कोशिश कर रहा हूं। यह एक बड़ा विषय है इसलिए मैं इसे एक समय में एक कदम उठा रहा हूं, सबसे पहले मैं वास्तव में एक पीडीएफ के मामले में सकारात्मक प्रतिक्रिया देने की कोशिश कर रहा हूं, जिसने मैंने अपने हस्ताक्षर किए हैं, वर्तमान एक्रोबैट के साथ सभी डिफ़ॉल्ट मानों का उपयोग करके - यह SHA256 होना चाहिए पाचन के लिए, और एक पीकेसीएस 7 अलग हस्ताक्षर। इसलिए, मैं openssl को क्रैक करता हूं, और पीडीएफ में दी गई बाइट रेंज पढ़कर और SHA256_* फ़ंक्शंस को कॉल करके मेरे पास तुलना करने के लिए हैश है। तो अब मुझे प्रमाणपत्र डेटा आदि पढ़ने की जरूरत है, और PKCS7_* फ़ंक्शंस का उपयोग करें। यह एक ऐसा चाहता है जो मैं चाहता हूं:पीकेसीएस # 7 हस्ताक्षर सत्यापन

int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, BIO *indata, BIO *out, int flags); 

found in the documentation के रूप में। बयान के अलावा दस्तावेज मुझे यह नहीं बताता कि इन चीजों में से किसी एक को कैसे बनाया जाए। ठीक है, तो मुझे लगता है कि BIO *indatahere में कुछ फ़ंक्शंस और these (सटीक विवरणों को पूरा करने के बावजूद) का उपयोग करके कर्ट की सरणी के साथ बनाया जा सकता है, लेकिन PKCS7 *p7, या STACK_OF(x) के लिए क्या कहा जाता है। मुझे इन संरचनाओं को शुरू करने का कोई दस्तावेज तरीका नहीं मिल रहा है। वहाँ pkcs7.h शीर्षक में कुछ pkcs7_ctrl कार्य हैं: -

long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg); 

int PKCS7_set_type(PKCS7 *p7, int type); 
int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other); 
int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data); 
int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey, const EVP_MD *dgst); 
int PKCS7_SIGNER_INFO_sign(PKCS7_SIGNER_INFO *si); 
int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *p7i); 
int PKCS7_add_certificate(PKCS7 *p7, X509 *x509); 
int PKCS7_add_crl(PKCS7 *p7, X509_CRL *x509); 
int PKCS7_content_new(PKCS7 *p7, int nid); 
int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx, 
    BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si); 
int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si, X509 *x509); 

BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio); 
int PKCS7_dataFinal(PKCS7 *p7, BIO *bio); 
BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert); 

लेकिन कुछ दिशा निर्देश इस एक जंगल की तरह प्रतीत नहीं होता है बिना यह आँख बंद करके में चारों ओर poking शुरू करने के लिए प्रभावी होगा

मैं कुछ स्पष्ट याद किया है। ? मैं इस फ़ंक्शन को पीडीएफ से पार्स किए गए डेटा वैल्यू के साथ कैसे कॉल करूं?

उत्तर

7

ठीक है, यह सब (बहुत) कठिन तरीके से मिला। इस तरह आप इसे करते हैं, ताकि अन्य लोग आसानी से सीख सकें।

आइए कहें कि हमारे पास हस्ताक्षर char* sig लंबाई int sig_length है, और सत्यापन डेटा char* data, int data_length है। (वहाँ कुछ बारीकियों पीडीएफ हस्ताक्षर के लिए यहाँ हैं, लेकिन इन अच्छी तरह से पीडीएफ कल्पना में दर्ज कर रहे हैं।)

OpenSSL_add_all_algorithms(); 
OpenSSL_add_all_digests(); 
EVP_add_digest(EVP_md5()); 
EVP_add_digest(EVP_sha1()); 
EVP_add_digest(EVP_sha256()); 

BIO* sig_BIO = BIO_new_mem_buf(sig, sig_length) 
PKCS7* sig_pkcs7 = d2i_PKCS7_bio(sig_BIO, NULL); 

BIO* data_BIO = BIO_new_mem_buf(data, data_length) 
BIO* data_pkcs7_BIO = PKCS7_dataInit(sig_pkcs7, data_BIO); 

// Goto this place in the BIO. Why? No idea! 
char unneeded[1024*4]; 
while (BIO_read(dataPKCS7_BIO, unneeded, sizeof(buffer)) > 0); 

int result; 
X509_STORE *certificateStore = X509_STORE_new(); 
X509_STORE_CTX certificateContext; 
STACK_OF(PKCS7_SIGNER_INFO) *signerStack = PKCS7_get_signer_info(sig_pkcs7); 
int numSignerInfo = sk_PKCS7_SIGNER_INFO_num(signerStack); 
for (int i=0; i<numSignerInfo; ++i) { 
    PKCS7_SIGNER_INFO *signerInfo = sk_PKCS7_SIGNER_INFO_value(signerStack, i); 
    result = PKCS7_dataVerify(certificateStore, &certificateContext, data_pkcs7_BIO, sig_pkcs7, signerInfo); 
} 

X509_STORE_CTX_cleanup(&certificateContext); 
BIO_free(sig_BIO); 
BIO_free(data_BIO); 
BIO_free(data_pkcs7_BIO); 
PKCS7_free(sig_pkcs7); 
X509_STORE_free(certificateStore); 

समारोह है कि करता है काम वास्तव में PKCS7_dataVerify है, और आप किसी भी डाइजेस्ट खुद को चलाने के लिए जरूरत नहीं है।

लेकिन प्रतीक्षा करें, अगर आप इसे आजमाते हैं, तो यह काम नहीं करेगा! क्यूं कर? क्योंकि सत्यापन दोनों विश्वास और अखंडता करता है। इसके अलावा, आपको स्टोर में अलर्ट जोड़कर या तो विश्वास स्थापित करने की आवश्यकता होगी, जो जटिल और अनियंत्रित भी है।

X509_VERIFY_PARAM_set_flags(certificateStore->param, X509_V_FLAG_CB_ISSUER_CHECK); 
X509_STORE_set_verify_cb_func(certificateStore, verificationCallback); 

जहां

static int verificationCallback(int ok, X509_STORE_CTX *ctx) { 
    switch (ctx->error) 
    { 
     case X509_V_ERR_INVALID_PURPOSE: //... 
     case X509_V_ERR_CERT_HAS_EXPIRED: //... 
     case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: //... 
     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: //... 
     // ... etc 
     default: break; 
    } 
    return ok; 
} 

आप ठीक करने के लिए त्रुटि की स्थापना की और यह बता सकते हैं: आप ठीक अनाज परिणाम चाहते हैं तो आप इस तरह प्रमाणपत्र संग्रह के माध्यम से सत्यापन पर एक कॉलबैक सेट करना चाहेंगे के लिए सत्यापित करने के लिए, उदाहरण के लिए यदि आप कालबाह्य कॉर्ट को अनदेखा करना चाहते हैं:

static int verificationCallback(int ok, X509_STORE_CTX *ctx) { 
    switch (ctx->error) 
    { 
     case X509_V_ERR_CERT_HAS_EXPIRED: 
      X509_STORE_CTX_set_error(ctx, X509_V_OK); 
      ok = 1; 
      break; 
    } 
    return ok; 
} 
संबंधित मुद्दे