用于创建X 509证书并验证它的c ++代码

时间:2014-10-30 16:52:21

标签: ssl

我正在为服务器客户端执行代码,服务器是CA,客户端向服务器发送签名请求,服务器创建签名证书,然后客户端向服务器发送其证书。服务器首先验证证书。客户端也提取证书的序列号 我在这里遇到一些问题 1-验证过程失败 验证失败 证书签名失败 2-序列号总是返回一个常数3我不知道为什么

分享给我帮助

certificate.cpp

#include <iostream>
#include "server.h"
#include "client.h"
using namespace std;
int main()
{
Client clientest;
Server servertest;
X509 *cert;
cert = servertest.CreateCertificate(clientest.MakeSignedCertReq());
clientest.SetCert(cert);
clientest.CertConverter();
X509 *test;
test = clientest.GetCert();
servertest.CheckCert(cert);
int serial = 0;
serial = clientest.ExtractCertSerial();
cout<<"client serial is "<<serial<<endl;
return 0;
}

server.h

#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <openssl/asn1.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/conf.h>
#include  "client.h"
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
using namespace std;
class Server
{
 public:
 Server();
 ~Server();
 X509 *CreateCertificate (X509_REQ *req);
 void CreateMyCertificate();
 void GenerateMyKeyPairs ( );
 void SetPublicKey ();
 int CheckCert (X509 *clientcert);
 private:
 X509       *m_myCert;
 RSA        *m_caKeyPairs;
 EVP_PKEY   *m_pukey;
 X509_NAME  *m_issuerName;
 };
 #endif /* SERVER_H_ */

server.cc

#include "server.h"
Server::Server()
{
  m_myCert = X509_new();
  m_caKeyPairs = RSA_new();
  m_pukey  = EVP_PKEY_new();
  m_issuerName = X509_NAME_new();
  GenerateMyKeyPairs();
  CreateMyCertificate();
  //SetPublicKey();
 }
 Server::~Server()
 {
  X509_free(m_myCert);
  RSA_free(m_caKeyPairs);
  X509_NAME_free(m_issuerName);
  }
  X509*
  Server::CreateCertificate(X509_REQ* req)
  {
     cout<<"hello i began"<<endl;
    X509 *m_req_reply;
    m_req_reply = X509_new();
    X509_NAME *subject = NULL;
    EVP_PKEY *pkey = NULL;
     ASN1_INTEGER_set(X509_get_serialNumber(m_req_reply), 2);
     X509_gmtime_adj(X509_get_notBefore(m_req_reply), 0);
    X509_gmtime_adj(X509_get_notAfter(m_req_reply), 31536000L);
     pkey = X509_REQ_get_pubkey(req);
   X509_set_pubkey(m_req_reply, pkey); 
     X509_NAME *issuerSubject = X509_get_subject_name(m_myCert);
     X509_set_issuer_name(m_req_reply, issuerSubject);
     //extract the subject of the request
    subject = X509_REQ_get_subject_name(req);
    X509_set_subject_name(m_req_reply, subject);
     cout << "cert subject name:" << X509_get_subject_name(m_req_reply) << endl;
     if(1 == X509_sign(m_req_reply, m_pukey, EVP_sha1()))
     cout << "client cert ok\n";
     else
     cout << "client cert error\n";
     return m_req_reply;
     }
  void
  Server::CreateMyCertificate()
  {
 // we use rsa pairs and assign it into evp_key
 SetPublicKey();
 // properties of the certificate
 //set the serial number
 ASN1_INTEGER_set(X509_get_serialNumber(m_myCert), 1);
 //set the time validity
 X509_gmtime_adj(X509_get_notBefore(m_myCert), 0);
 X509_gmtime_adj(X509_get_notAfter(m_myCert), 31536000L);
 //set the public key of the cert to be signed
 X509_set_pubkey(m_myCert, m_pukey);
 //this is a self-signed certificate, we set the name of the issuer to the name of the subject
 m_issuerName = X509_get_subject_name(m_myCert);
 X509_NAME_add_entry_by_txt(m_issuerName, "C",  MBSTRING_ASC,
                            (unsigned char *)"CA", -1, -1, 0);
 X509_NAME_add_entry_by_txt(m_issuerName, "O",  MBSTRING_ASC,
                            (unsigned char *)"MyCompany Inc.", -1, -1, 0);
 X509_NAME_add_entry_by_txt(m_issuerName, "CN", MBSTRING_ASC,
                            (unsigned char *)"localhost", -1, -1, 0);
 //set the issuer name
 X509_set_issuer_name(m_myCert, m_issuerName);
 //sign the cert
 if(1 == X509_sign(m_myCert, m_pukey, EVP_sha1()))
     cout << "self cert signed ok\n";
 else
     cout << "self cert sign error\n";
 FILE * fcert;
 fcert = fopen("cert.pem", "wb");
 PEM_write_X509(
     fcert,   /* write the certificate to the file we've opened */
     m_myCert /* our certificate */
 );
 }
 void
 Server::GenerateMyKeyPairs()
 {
 m_caKeyPairs = RSA_generate_key(2048,RSA_F4 , NULL , NULL);
 }
 void
 Server::SetPublicKey()
 {
 if(1 == EVP_PKEY_assign_RSA(m_pukey,m_caKeyPairs))
     cout << "key assigned OK\n";
 else
     cout << "key assign error\n";
 BIO *out = NULL;
 const char szPath[10] = "key2.pem";
 out = BIO_new_file(szPath,"wb");
 EVP_PKEY_print_private(out, m_pukey,
                                0, NULL);
 BIO_free(out);
 out = BIO_new_file("key.pem","wb");
 //print the self signed certificate
 //FILE * fkey;
 //fkey = fopen("key.pem", "wb");
 PEM_write_bio_PrivateKey(
     out,                  /* write the key to the file we've opened */
     m_pukey,               /* our key from earlier */
     EVP_des_ede3_cbc(), /* default cipher for encrypting the key on disk */
     (unsigned char *)"replace_me",       /* passphrase required for decrypting the key on disk */
     10,                 /* length of the passphrase string */
     NULL,               /* callback for requesting a password */
     NULL                /* data to pass to the callback */
 );
 }
 int
 Server::CheckCert(X509* clientcert)
 {
 int status = 0;
 X509_STORE_CTX *ctx = X509_STORE_CTX_new();
 //void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
 //void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
 //store the trusted cert into ctx
 X509_STORE *store = X509_STORE_new();
 X509_STORE_add_cert(store, m_myCert);
 //put the trusted cert and cert then verify it
 X509_STORE_CTX_init(ctx,store, clientcert, NULL);
 status  = X509_verify_cert(ctx);
 //status = X509_verify(clientcert, m_pukey);
 if (status == 1)
 {
     cout<<"verified succesfully"<<endl;
 }
 else
 {
     cout<<"verifiy fail"<<endl;
     cout << X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx));
 }
 return status;
 }

client.h

#ifndef CLIENT_H_
#define CLIENT_H_
#include <stdlib.h>
#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/conf.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include "server.h"
class Client
{
 public:
Client();
~Client();
void GenerateRSAKeyPair ();
void SetPublicKey ();
X509_REQ *MakeSignedCertReq();
void SetCert (X509 *cert);
X509 *GetCert();
int CertConverter ();
int ExtractCertSerial ();
private:
X509_REQ   *m_myCertReq;
X509       *m_myCert;
X509_NAME  *m_name;
RSA        *m_rsa_keyPair;
EVP_PKEY   *m_puk;
};
#endif /* CLIENT_H_ */

client.cc

#include "client.h"
Client :: Client()
{
  m_myCertReq = X509_REQ_new();
  m_myCert = X509_new();
  m_name = X509_NAME_new();
  m_rsa_keyPair = RSA_new();
  m_puk  = EVP_PKEY_new();
  GenerateRSAKeyPair();
 // SetPublicKey();
 }
Client :: ~Client()
{
  X509_REQ_free(m_myCertReq);
  X509_free(m_myCert);
  //X509_NAME_free(m_name);
  RSA_free(m_rsa_keyPair);
  //EVP_PKEY_free(m_puk);
 }
void
Client :: GenerateRSAKeyPair ( )
{
 m_rsa_keyPair = RSA_generate_key(2048,RSA_F4,NULL,NULL);
 BIO *pubout = NULL;
 const char szPath[10] = "clrsa.pem";
 pubout = BIO_new_file(szPath,"wb");
 PEM_write_bio_RSAPublicKey (pubout , m_rsa_keyPair);
}
void
Client::SetPublicKey()
{
 EVP_PKEY_assign_RSA(m_puk,m_rsa_keyPair);
 BIO *out = NULL;
 const char szPath[10] = "cpuky.pem";
 out = BIO_new_file(szPath,"wb");
 PEM_write_bio_PUBKEY(out,m_puk);
}
X509_REQ*
Client::MakeSignedCertReq()
{
 SetPublicKey();
 //include the public key in the req
 X509_REQ_set_pubkey(m_myCertReq,m_puk);
 //set the subject name of the request
 m_name=X509_REQ_get_subject_name(m_myCertReq);
 //set the request
 X509_NAME_add_entry_by_txt(m_name,"C",MBSTRING_ASC, (const unsigned char *)"UK", -1, -1, 0);
 X509_NAME_add_entry_by_txt(m_name,"CN",MBSTRING_ASC, (const unsigned char *)"OpenSSL Group", -1, -1, 0);
 //sign the req
 X509_REQ_sign(m_myCertReq,m_puk,EVP_sha1());
 BIO *out = NULL;
 const char szPath[10] = "req.pem";
 out = BIO_new_file(szPath,"wb");
 PEM_write_bio_X509_REQ(out,m_myCertReq);
 return m_myCertReq;
 }
 void
 Client::SetCert(X509 *cert)
 {
 cout << "writing certificate\n";
 BIO *out = NULL;
 const char szPath[10] = "x509.pem";
 out = BIO_new_file(szPath,"wb");
 m_myCert =  cert;
 int len;
 unsigned char *buf, *p;
 len = i2d_X509(cert, NULL);
 cout << "cert length =" << len << endl;
 buf = (unsigned char *)OPENSSL_malloc(len);
 p = buf;
 i2d_X509(cert, &p);
 cout << "cert= "<<endl;
 for(int i=0; i<len; i++)
     cout << buf[i];
 cout << endl;
 if(!PEM_write_bio_X509 (out , cert))
     cout << "error writing certificate\n";
  }
 int
 Client::CertConverter()
 {
 int len = i2d_X509(m_myCert, NULL);
 unsigned char *buf, *p;
 buf = (unsigned char *)OPENSSL_malloc(len);
 p = buf;
 i2d_X509(m_myCert, &p);
 unsigned char certarray[len];
 for (int i = 0 ; i<len ; i++)
 {
     certarray[i] = *(p-len+i);
 }
 cout << "converted client cert is"<<endl;
 for (int j = 0 ; j<len ; j++)
 {
     cout << certarray[j];
 }
 cout<<endl;
 /*
 X509 *certtest = NULL;
 certtest = d2i_X509(NULL, certarray , len);
 cout<<"write the array to file"<<endl;
 FILE * fcert;
 fcert = fopen("certarray.pem", "wb");
 PEM_write_X509(
     fcert,    //write the certificate to the file we've opened
     certtest  //our certificate
 );
*/
 return 0;
 }
 X509*
 Client::GetCert()
 {
 return m_myCert;
 }
 int
 Client::ExtractCertSerial()
 {
 int serial = 0;
 unsigned char **out = NULL;
 ASN1_INTEGER *asn1_serial = NULL;
 asn1_serial = X509_get_serialNumber(m_myCert);
 serial = i2d_ASN1_INTEGER(asn1_serial, out);
 return (serial);
 }

希望任何人都能尽快帮助我解决我的问题

注意我在cert.pem文件中创建了自签名证书,x509.pem(对于客户端)也创建得很好但是当我验证它时,由于证书签名失败,我一直都没有验证错误当我得到错误处理程序X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx))时,序列号也始终是常量3

2 个答案:

答案 0 :(得分:1)

我发现在请求中应该添加

     //adds all digest algorithms to the table
     OpenSSL_add_all_digests();

没有此行,证书永远无法正确验证

答案 1 :(得分:0)

  1. CreateCertificate(X509_REQ* req){...}中,您有 ASN1_INTEGER_set(X509_get_serialNumber(m_req_reply), 2);所以你 将始终将序列号设置为2(3)。
  2. CreateCertificate(X509_REQ* req){...}中,您也有if(1 == X509_sign(m_req_reply, m_pukey, EVP_sha1())),但是X509_sign(...)将返回签名的大小,如果成功则返回1。