OpenSSL學習之使用個人資訊數字證書(PFX)進行簽名和驗證
from http://blog.csdn.net/michelsn/article/details/2311140
最近需要用到數字簽名的相關技術,但是網路上對這方面的文章說的含糊,所以自己把這段時間在學習OpenSSL過程中得到心得發表出來,供大家討論,歡迎大家聯絡我,互相交流。
以下是實現PFX證書的讀取和應用證書進行數字簽名與簽名驗證:
環境:VC6 + WIN2003 + OPENSSL
程式碼:
#include "stdafx.h"
#include <windows.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/pkcs12.h>
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")
bool DoSignData(const char* szPKCS12FileName, const char* szPKCS12Password,
const char* szUnSignData, char* szSignData)
{
if (szPKCS12FileName == NULL || szUnSignData == NULL || szSignData == NULL) {
return false;
}
/*變數*/
int err;
unsigned int sig_len;
unsigned char sig_buf[4096];
EVP_MD_CTX md_ctx;
EVP_PKEY * pkey = NULL;
FILE * fp = NULL;
X509 * x509 = NULL;
PKCS12* p12 = NULL;
STACK_OF(X509) *ca = NULL;
/*初始化*/
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
/*讀取個人資訊證書並分解出金鑰和證書*/
if (!(fp = fopen(szPKCS12FileName, "rb"))) {
return false;
}
p12 = d2i_PKCS12_fp(fp, NULL);
fclose (fp);
if (!p12) {
fprintf(stderr, "Error reading PKCS#12 file/n");
ERR_print_errors_fp(stderr);
return false;
}
if (!PKCS12_parse(p12, szPKCS12Password, &pkey, &x509, &ca)) {
fprintf(stderr, "Error parsing PKCS#12 file/n");
ERR_print_errors_fp(stderr);
PKCS12_free(p12);
return false;
}
PKCS12_free(p12);
if (pkey == NULL) {
ERR_print_errors_fp (stderr);
return false;
}
/*簽名資料*/
EVP_SignInit (&md_ctx, EVP_sha1());
EVP_SignUpdate (&md_ctx, szUnSignData, strlen(szUnSignData));
sig_len = sizeof(sig_buf);
err = EVP_SignFinal (&md_ctx, sig_buf, &sig_len, pkey);
if (err != 1) {
ERR_print_errors_fp(stderr);
/*釋放相關變數*/
if (pkey) {
EVP_PKEY_free (pkey);
}
if (x509) {
X509_free(x509);
}
return false;
}
sig_buf[sig_len] = 0;
memcpy(szSignData, sig_buf, sig_len);
/*釋放相關變數*/
if (pkey) {
EVP_PKEY_free (pkey);
}
if (x509) {
X509_free(x509);
}
return true;
}
bool DoVerifyData(const char* szPKCS12FileName, const char* szPKCS12Password,
const char* szUnSignData, const char* szSignData)
{
if (szPKCS12FileName == NULL || szSignData == NULL) {
return false;
}
/*變數*/
int err;
unsigned int sig_len;
EVP_MD_CTX md_ctx;
EVP_PKEY * pkey = NULL;
FILE * fp = NULL;
X509 * x509 = NULL;
PKCS12* p12 = NULL;
STACK_OF(X509) *ca = NULL;
/*初始化*/
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
/*讀取個人資訊證書並分解出金鑰和證書*/
if (!(fp = fopen(szPKCS12FileName, "rb"))) {
return false;
}
p12 = d2i_PKCS12_fp(fp, NULL);
fclose (fp);
if (!p12) {
fprintf(stderr, "Error reading PKCS#12 file/n");
ERR_print_errors_fp(stderr);
return false;
}
if (!PKCS12_parse(p12, szPKCS12Password, &pkey, &x509, &ca)) {
fprintf(stderr, "Error parsing PKCS#12 file/n");
ERR_print_errors_fp(stderr);
PKCS12_free(p12);
return false;
}
PKCS12_free(p12);
if (x509 == NULL) {
ERR_print_errors_fp (stderr);
return false;
}
/*驗證簽名*/
pkey=X509_get_pubkey(x509);
if (pkey == NULL) {
ERR_print_errors_fp (stderr);
if (x509) {
X509_free(x509);
}
return false;
}
/* Verify the signature */
sig_len = 0;
sig_len = strlen(szSignData);
EVP_VerifyInit(&md_ctx, EVP_sha1());
EVP_VerifyUpdate(&md_ctx, szUnSignData, strlen(szUnSignData));
err = EVP_VerifyFinal (&md_ctx, (const BYTE*)szSignData, sig_len, pkey);
EVP_PKEY_free (pkey);
if (err != 1) {
ERR_print_errors_fp (stderr);
/*釋放相關變數*/
if (pkey) {
EVP_PKEY_free(pkey);
}
return false;
}
/*釋放相關變數*/
if (pkey) {
EVP_PKEY_free(pkey);
}
return true;
}
int main(int argc, char* argv[])
{
char sig_buf [4096];
memset(sig_buf, 0, sizeof(sig_buf));
if (!DoSignData("F://專案檔案//10002-password=123456.pfx", "123456", "i love china.", sig_buf)) {
printf("Signature Data Failed.");
}else{
printf("Signature Data Success.");
printf(">------------after sign data--------------begin/n");
printf((char*)sig_buf);
printf("/n>------------after sign data--------------end/n");
if (!DoVerifyData("F://專案檔案//10002-password=123456.pfx", "123456", "i love china.", sig_buf)) {
printf ("Signature Verified Failed./n");
}else{
printf ("Signature Verified Ok./n");
}
}
Sleep(10000);
return 0;
}