1. 程式人生 > >OpenSSL學習之使用個人資訊數字證書(PFX)進行簽名和驗證

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;
}