基于visual c++之windows核心编程代码分析(46)遍历数字证书
数字证书就是互联网通讯中标志通讯各方身份信息的一系列数据,提供了一种在Internet上验证您身份的方式,其作用类似于司机的驾驶执照或日常生活中的身份证。它是由一个由权威机构-----CA机构,又称为证书授权(Certificate Authority)中心发行的,人们可以在网上用它来识别对方的身份。数字证书是一个经证书授权中心数字签名的包含公开密钥拥有者信息以及公开密钥的文件。最简单的证书包含一个公开密钥、名称以及证书授权中心的数字签名。
数字证书是一种权威性的电子文档,由权威公正的第三方机构,即CA中心签发的证书。
它以数字证书为核心的加密技术可以对网络上传输的信息进行加密和解密、数字签名和签名验证,确保网上传递信息的机密性、完整性。使用了数字证书,即使您发送的信息在网上被他人截获,甚至您丢失了个人的账户、密码等信息,仍可以保证您的账户、资金安全。
它能提供在Internet上进行身份验证的一种权威性电子文档,人们可以在互联网交往中用它来证明自己的身份和识别对方的身份。
当然在数字证书认证的过程中证书认证中心(CA)作为权威的、公正的、可信赖的第三方,其作用是至关重要的.如何判断数字认证中心公正第三方的地位是权威可信的,国家工业和信息化部以资质合规的方式,陆续向天威诚信数字认证中心等30家相关机构颁发了从业资质。
由于Internet网电子商务系统技术使在网上购物的顾客能够极其方便轻松地获得商家和企业的信息,但同时也增加了对某些敏感或有价值的数据被滥用的风险. 为了保证互联网上电子交易及支付的安全性,保密性等,防范交易及支付过程中的欺诈行为,必须在网上建立一种信任机制。这就要求参加电子商务的买方和卖方都必须拥有合法的身份,并且在网上能够有效无误的被进行验证。
数字证书可用于:发送安全电子邮件、访问安全站点、网上证券交易、网上招标采购、网上办公、网上保险、网上税务、网上签约和网上银行等安全电子事务处理和安全电子交易活动。
下面我们来编程实践之
#include "stdafx.h" #include "证书解析.h" #include "证书解析Dlg.h" #include <stdio.h> #include <string.h> #include <windows.h> #include <openssl/evp.h> #include <openssl/x509.h> #include <openssl/pem.h> #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMyDlg dialog CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/) : CDialog(CMyDlg::IDD, pParent) { //{{AFX_DATA_INIT(CMyDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMyDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CMyDlg) DDX_Control(pDX, IDC_LIST1, m_list); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CMyDlg, CDialog) //{{AFX_MSG_MAP(CMyDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, OnButton1) ON_BN_CLICKED(IDC_BUTTON2, OnButton2) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMyDlg message handlers BOOL CMyDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here return TRUE; // return TRUE unless you set the focus to a control } void CMyDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CMyDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CMyDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; } void CMyDlg::OnButton1() { // TODO: Add your control notification handler code here CString filename; unsigned char Cert[4099]; unsigned long Certlen; unsigned char *pTmp = NULL; X509 *usrCert = NULL; //X509证书结构体,保存用户证书 FILE *fp; CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY| OFN_OVERWRITEPROMPT,0,this); if (IDOK == dlg.DoModal()) { filename = dlg.GetPathName() ; GetDlgItem(IDC_EDIT1)->SetWindowText(filename); } fp=fopen(filename.GetBuffer(0),"rb"); if(fp==NULL) { MessageBox("读取证书错误"); return ; } Certlen=fread(Cert,1,4096,fp); fclose(fp); //判断是否为DER编码的用户证书,并转化为X509结构体 pTmp=Cert; usrCert = d2i_X509(NULL,(const unsigned char ** )&pTmp,Certlen); if(usrCert==NULL) { BIO *b; /* 判断是否为PEM格式的数字证书 */ b=BIO_new_file(filename.GetBuffer(0),"r"); usrCert=PEM_read_bio_X509(b,NULL,NULL,NULL); BIO_free(b); if(usrCert==NULL) { MessageBox("转化格式错误!"); return; } } //解析证书 X509_NAME *issuer = NULL; //X509_NAME结构体,保存证书颁发者信息 X509_NAME *subject = NULL; //X509_NAME结构体,保存证书拥有者信息 int i; int entriesNum; X509_NAME_ENTRY *name_entry; // ASN1_INTEGER *Serial = NULL; //保存证书序列号 long Nid; ASN1_TIME *time; //保存证书有效期时间 EVP_PKEY *pubKey; //保存证书公钥 long Version; //保存证书版本 unsigned char derpubkey[1024]; int derpubkeyLen; unsigned char msginfo[1024]; int msginfoLen; unsigned short *pUtf8 = NULL; int nUtf8; int rv; CString tmp; //获取证书版本 Version = X509_get_version(usrCert); tmp.Format("X509 Version:%ld\n",Version); m_list.InsertString(-1,tmp); tmp.Empty(); //获取证书颁发者信息,X509_NAME结构体保存了多项信息,包括国家、组织、部门、通用名、mail等。 issuer = X509_get_issuer_name(usrCert); //获取X509_NAME条目个数 entriesNum = sk_X509_NAME_ENTRY_num(issuer->entries); //循环读取各条目信息 for(i=0;i<entriesNum;i++) { //获取第I个条目值 name_entry = sk_X509_NAME_ENTRY_value(issuer->entries,i); //获取对象ID Nid = OBJ_obj2nid(name_entry->object); //判断条目编码的类型 if(name_entry->value->type==V_ASN1_UTF8STRING)//把UTF8编码数据转化成可见字符 { nUtf8 = 2*name_entry->value->length; pUtf8 = (unsigned short *)malloc(nUtf8); memset(pUtf8,0,nUtf8); rv = MultiByteToWideChar( CP_UTF8, 0, (char*)name_entry->value->data, name_entry->value->length, pUtf8, nUtf8); rv = WideCharToMultiByte( CP_ACP, 0, pUtf8, rv, (char*)msginfo, nUtf8, NULL, NULL); free(pUtf8); pUtf8 = NULL; msginfoLen = rv; msginfo[msginfoLen]='\0'; } else { msginfoLen=name_entry->value->length; memcpy(msginfo,name_entry->value->data,msginfoLen); msginfo[msginfoLen]='\0'; } //根据NID打印出信息 switch(Nid) { case NID_countryName://国家 tmp.Format("issuer 's countryName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_stateOrProvinceName://省 tmp.Format("issuer 's ProvinceName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_localityName://地区 tmp.Format("issuer 's localityName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_organizationName://组织 tmp.Format("issuer 's organizationName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_organizationalUnitName://单位 tmp.Format("issuer 's organizationalUnitName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_commonName://通用名 tmp.Format("issuer 's commonName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_pkcs9_emailAddress://Mail tmp.Format("issuer 's emailAddress:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; }//end switch } //获取证书主题信息 subject = X509_get_subject_name(usrCert); //获得证书主题信息条目个数 entriesNum = sk_X509_NAME_ENTRY_num(subject->entries); //循环读取个条目信息 for(i=0;i<entriesNum;i++) { //获取第I个条目值 name_entry = sk_X509_NAME_ENTRY_value(subject->entries,i); Nid = OBJ_obj2nid(name_entry->object); //判断条目编码的类型 if(name_entry->value->type==V_ASN1_UTF8STRING)//把UTF8编码数据转化成可见字符 { nUtf8 = 2*name_entry->value->length; pUtf8 = (unsigned short *)malloc(nUtf8); memset(pUtf8,0,nUtf8); rv = MultiByteToWideChar( CP_UTF8, 0, (char*)name_entry->value->data, name_entry->value->length, pUtf8, nUtf8); rv = WideCharToMultiByte( CP_ACP, 0, pUtf8, rv, (char*)msginfo, nUtf8, NULL, NULL); free(pUtf8); pUtf8 = NULL; msginfoLen = rv; msginfo[msginfoLen]='\0'; } else { msginfoLen=name_entry->value->length; memcpy(msginfo,name_entry->value->data,msginfoLen); msginfo[msginfoLen]='\0'; } switch(Nid) { case NID_countryName://国家 tmp.Format("subject 's countryName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_stateOrProvinceName://省 tmp.Format("subject 's ProvinceName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_localityName://地区 tmp.Format("subject 's localityName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_organizationName://组织 tmp.Format("subject 's organizationName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_organizationalUnitName://单位 tmp.Format("subject 's organizationalUnitName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_commonName://通用名 tmp.Format("subject 's commonName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_pkcs9_emailAddress://Mail tmp.Format("subject 's emailAddress:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; }//end switch } //获取证书生效日期 time = X509_get_notBefore(usrCert); tmp.Format("Cert notBefore:%s\n",time->data); m_list.InsertString(-1,tmp); tmp.Empty(); //获取证书过期日期 time = X509_get_notAfter(usrCert); tmp.Format("Cert notAfter:%s\n",time->data); m_list.InsertString(-1,tmp); tmp.Empty(); //获取证书公钥 pubKey = X509_get_pubkey(usrCert); pTmp=derpubkey; //把证书公钥转为DER编码的数据 derpubkeyLen=i2d_PublicKey(pubKey,&pTmp); printf("PublicKey is: \n"); tmp.Format("PublicKey is: \n"); for(i = 0; i < derpubkeyLen; i++) { CString tmpp; tmpp.Format("%02x", derpubkey[i]); tmp=tmp+tmpp; } m_list.InsertString(-1,tmp); X509_free(usrCert); } void CMyDlg::OnButton2() { // TODO: Add your control notification handler code here m_list.ResetContent(); }