欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++使用OpenSSL证书API

程序员文章站 2022-07-12 22:56:29
...

本文主要介绍如果在C++中使用OpenSSL的证书相关API。(基于OpenSSL 1.0.2k版本,不同版本可能API会有一些差异,但大体应该类似)


使用下面方法前,需要全局调用一次(无需多次调用)

OpenSSL_add_all_algorithms();



1、生成公私钥对

    BIGNUM *bne = NULL;
    int bits = RSAKeyBits;
    unsigned long   e = RSA_F4;
    int ret = 0;

    bne = BN_new();
    int r = BN_set_word(bne,e);
    if(r != 1){
        goto free_all;
    }

    if(m_rsa)
    {
        RSA_free(m_rsa);
        m_rsa = NULL;
    }
    // m_rsa是成员变量,用于存储公私钥对
    m_rsa = RSA_new();
    
    r = RSA_generate_key_ex(m_rsa, bits, bne, NULL);
    if(r != 1){
        goto free_all;
    }

free_all:
    BN_free(bne);


2、生成CSR

    X509 *x509 = NULL;
    X509_NAME *subject = NULL;
    BIO *bio = NULL;
    X509_REQ *x509Req = NULL;
    char *szCSR = NULL;
    // 提取私钥
    EVP_PKEY_assign_RSA(m_pKey, m_rsa);

    x509 = X509_new();
    X509_set_pubkey(x509, m_pKey);

    // 设置属性
    subject = X509_get_subject_name(x509);
    // 国家
    X509_NAME_add_entry_by_txt(subject, SN_countryName, MBSTRING_UTF8,
                               (unsigned char *)"CN", -1, -1, 0);
    // 省份
    X509_NAME_add_entry_by_txt(subject, SN_stateOrProvinceName,  MBSTRING_UTF8,
                               (unsigned char *)"GuangDong", -1, -1, 0);
    // 城市
    X509_NAME_add_entry_by_txt(subject, SN_localityName,  MBSTRING_UTF8,
                               (unsigned char *)"ShenZhen", -1, -1, 0);

    X509_set_subject_name(x509, subject);


    x509Req = X509_to_X509_REQ(x509, m_pKey, ShaFunc);
    if(!x509Req)
    {
        goto free_all;
    }

    // 可视化输出
    bio = BIO_new(BIO_s_mem());
    PEM_write_bio_X509_REQ(bio, x509Req);
    if(bio->num_write == 0)
    {
        goto free_all;
    }

    szCSR = (char*)malloc(bio->num_write+1);
    if(!szCSR)
    {
        goto free_all;
    }

    memset(szCSR, 0, bio->num_write+1);
    BIO_read(bio, szCSR, bio->num_write);


free_all:
    if(x509)
        X509_free(x509);
    if(x509Req)
        X509_REQ_free(x509Req);
    if(bio)
        BIO_free(bio);
    if(szCSR)
        free(szCSR);

3、生成证书

void x509FromCertString(string cert, X509 **pX509)
{
    if(cert.length() == 0)
        return;
    
    handleCertLineBreak(cert);
    
    BIO *bio = NULL;
    X509 *x509 = NULL;
    
    const char *certData = cert.c_str();
    
    bio = BIO_new(BIO_s_mem());
    BIO_puts(bio, certData);
    x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
    
    *pX509 = x509;
    
    BIO_free(bio);
}

bool checkX509Data(X509 *x509)
{
    // 校验**和证书是否匹配
    if(!X509_check_private_key(x509, m_pKey))
    {
        return false;
    }
    
    // 根证书校验
    if(m_rootCert == NULL)
    {
        BIO *bio = BIO_new_file("cert/RootCA.cer","r");
        if(!bio)
        {
            return false;
        }
        
        PEM_read_bio_X509(bio, &m_rootCert, NULL, NULL);
        
        BIO_free(bio);
        
        if(m_rootCert == NULL)
        {
            return false;
        }
    }
    
    EVP_PKEY *pubKey = X509_get_pubkey(m_rootCert);
    if(X509_verify(x509, pubKey) != 1)
    {
        return false;
    }
    
    return true;
}

// p12
void importCert(string cert, string pass, string path)
{
    if(cert.length() == 0 || path.length() == 0)
        return;
    
    int ret = 0;
    BIO *bio = NULL;
    X509 *x509 = NULL;
    PKCS12 *p12 = NULL;
    BIO *bioW = NULL;
    
    const char *certData = cert.c_str();
    
    bio = BIO_new(BIO_s_mem());
    BIO_puts(bio, certData);
    x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
    
    // 校验数据
    ret = checkX509Data(x509);
    if(ret)
    {
        goto free_all;
    }
    
    p12 = PKCS12_create((char*)pass.c_str(), CertAlias, m_pKey, x509, NULL, 0, 0, 0, 0, 0);
    
    if(!p12)
    {
        goto free_all;
    }
    
    bioW = BIO_new_file(path.c_str(),"wb");
    if(!bioW)
    {
        goto free_all;
    }
    
    // 写入文件
    if ( i2d_PKCS12_bio(bioW,p12) != 1)
    {
        goto free_all;
    }
    
    
free_all:
    if(x509)
        X509_free(x509);
    if(p12)
        PKCS12_free(p12);
    if(bioW)
        BIO_free(bioW);
}

// crt
void importCert(string cert, string path)
{
    if(cert.length() == 0 || path.length() == 0)
        return;
    
    int ret = 0;
    X509 *x509 = NULL;
    BIO *bioW = NULL;
    
    ret = x509FromCertString(cert, &x509);
    if(ret)
    {
        goto free_all;
    }
    
    ret = checkX509Data(x509, false);
    if(ret)
    {
        goto free_all;
    }
    
    bioW = BIO_new_file(path.c_str(),"wb");
    if(!bioW)
    {
        goto free_all;
    }
    
    // 写入文件
    if ( i2d_X509_bio(bioW,x509) != 1)
    {
        goto free_all;
    }
    
    
free_all:
    if(x509)
        X509_free(x509);
    if(bioW)
        BIO_free(bioW);
    
}

4、展示证书信息

// p12
void getCertInfo(string path, string pass, string &info)
{
    BIO *bio = NULL;
    PKCS12 *p12 = NULL;
    EVP_PKEY *pKey = NULL;
    X509 *x509 = NULL;
    BIO *x509Bio = NULL;
    char *szCertInfo = NULL;

    bio = BIO_new_file(path.c_str(),"r");
    if(!bio)
    {
        goto free_all;
    }

    p12 = d2i_PKCS12_bio(bio, NULL);
    if(!p12)
    {
        goto free_all;
    }

    if(PKCS12_parse(p12, pass.c_str(), &pKey, &x509, NULL) != 1)
    {
        goto free_all;
    }

    x509Bio = BIO_new(BIO_s_mem());
    X509_print(x509Bio, x509);
    if(x509Bio->num_write == 0)
    {
        goto free_all;
    }

    szCertInfo = (char*)malloc(x509Bio->num_write+1);
    if(!szCertInfo)
    {
        goto free_all;
    }

    memset(szCertInfo, 0, x509Bio->num_write+1);
    BIO_read(x509Bio, szCertInfo, x509Bio->num_write);

    info = szCertInfo;


free_all:
    if(bio)
        BIO_free(bio);
    if(p12)
        PKCS12_free(p12);
    if(x509Bio)
        BIO_free(x509Bio);
    if(szCertInfo)
        free(szCertInfo);

}

// crt
int getCertInfo(string path, string &info)
{
    BIO *bio = NULL;
    X509 *x509 = NULL;
    BIO *x509Bio = NULL;
    char *szCertInfo = NULL;

    bio = BIO_new_file(path.c_str(),"r");
    if(!bio)
    {
        goto free_all;
    }

    x509 = d2i_X509_bio(bio, NULL);
    if(!x509)
    {
        goto free_all;
    }

    x509Bio = BIO_new(BIO_s_mem());
    X509_print(x509Bio, x509);
    if(x509Bio->num_write == 0)
    {
        goto free_all;
    }

    szCertInfo = (char*)malloc(x509Bio->num_write+1);
    if(!szCertInfo)
    {
        goto free_all;
    }

    memset(szCertInfo, 0, x509Bio->num_write+1);
    BIO_read(x509Bio, szCertInfo, x509Bio->num_write);

    info = szCertInfo;


free_all:
    if(bio)
        BIO_free(bio);
    if(x509)
        X509_free(x509);
    if(x509Bio)
        BIO_free(x509Bio);
    if(szCertInfo)
        free(szCertInfo);

}

5、读取证书和**

// p12
void p_getP12FromCertFile(const string filePath, PKCS12 **p12)
{
    BIO *bio = NULL;
    
    bio = BIO_new_file(filePath.c_str(),"r");
    if(!bio)
    {
        goto free_all;
    }
    
    *p12 = d2i_PKCS12_bio(bio, NULL);
    if(!*p12)
    {
        goto free_all;
    }
    
free_all:
    if(bio)
        BIO_free(bio);
}

void p_getRSAKeyFromP12(PKCS12 *p12, const string pass, RSA **rsa)
{
    EVP_PKEY *pKey = NULL;
    X509 *x509 = NULL;
    
    if(PKCS12_parse(p12, pass.c_str(), &pKey, &x509, NULL) != 1)
    {
        return;
    }
    
    *rsa = EVP_PKEY_get1_RSA(pKey);
}

// crt
void p_getX509FromCertFile(const string filePath, X509 **x509)
{
    BIO *bio = NULL;
    
    bio = BIO_new_file(filePath.c_str(),"r");
    if(!bio)
    {
        goto free_all;
    }
    
    *x509 = d2i_X509_bio(bio, NULL);
    if(!*x509)
    {
        goto free_all;
    }
    
free_all:
    if(bio)
        BIO_free(bio);
    
}

void p_getRSAKeyFromX509(X509 *x509, RSA **rsa)
{
    EVP_PKEY *pKey = X509_get_pubkey(x509);
    if(!pKey)
    {
        return;
    }
    *rsa = EVP_PKEY_get1_RSA(pKey);
}

6、加解密

#define RSA_Data_Len 256

int p_rsaCrypt(bool bPubKey, bool bEncrypt, RSA *rsa, unsigned char inData[RSA_Data_Len], unsigned char outData[RSA_Data_Len])
{
    memset(outData, 0, RSA_Data_Len);
    
    int (*rsa_func)(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding);
    if(bPubKey && bEncrypt)
    {
        rsa_func = &RSA_public_encrypt;
    }
    else if(bPubKey && !bEncrypt)
    {
        rsa_func = &RSA_public_decrypt;
    }
    else if(!bPubKey && bEncrypt)
    {
        rsa_func = &RSA_private_encrypt;
    }
    else
    {
        rsa_func = &RSA_private_decrypt;
    }
    
    int retLen = rsa_func(RSA_Data_Len, inData, outData, rsa, RSA_NO_PADDING);
    if(retLen < RSA_Data_Len)
    {
        return 1;
    }
    
    return 0;
}

void rsaCrypt(bool bPubKey, bool bEncrypt, const string input, string &output)
{
    int inLen;
    char *szIn;
    if(bEncrypt)
    {
        inLen = input.length();
        szIn = (char*)input.c_str();
    }
    else
    {
        szIn = (char*)alloca(input.length());
        if(!szIn)
        {
            return;
        }
        
        int ret = Base64_Decode(input.c_str(), input.length(), (unsigned char*)szIn, input.length(), &inLen);
        if(ret)
        {
            return;
        }
    }
    
    int round = (inLen+TP_RSA_Data_Len-1)/RSA_Data_Len;// 1024
    int outLen = round*TP_RSA_Data_Len;
    char *szOut = (char *)alloca(outLen);
    if(!szOut)
    {
        return;
    }
    
    for(int i=0; i<round; i++)
    {
        int cryptLen = RSA_Data_Len;
        if(i == round-1)
        {
            cryptLen = inLen-(round-1)*RSA_Data_Len;
        }
        
        char inBuf[RSA_Data_Len];
        memset(inBuf, 0, RSA_Data_Len);
        memcpy(inBuf, szIn+(i*RSA_Data_Len), cryptLen);
        
        int ret = p_rsaCrypt(bPubKey, bEncrypt, m_rsa, (unsigned char*)inBuf, (unsigned char*)szOut+(i*TP_RSA_Data_Len));
        if(ret)
        {
            return;
        }
    }
    
    if(bEncrypt)
    {
        // base64
        int base64Len = outLen*2;
        char *szBase64 = (char*)alloca(base64Len);
        int retLen;
        int ret = Base64_Encode((unsigned char*)szOut, outLen, szBase64, base64Len, &retLen);
        if(ret)
        {
            return;
        }
        
        output = szBase64;
    }
    else
    {
        output = szOut;
    }
}

7、签名/验签

// 签名
int p_signWithSha256(RSA *rsa, unsigned char *inData, int inLen, unsigned char outData[RSA_Data_Len])
{
    unsigned char sha256[SHA256_DIGEST_LENGTH];
    
    memset(sha256, 0, sizeof(sha256));
    
    // sha256
    SHA256_CTX c;
    SHA256_Init(&c);
    SHA256_Update(&c, inData, inLen);
    SHA256_Final(sha256, &c);
    
    // rsa pri key encrypt
    memset(outData, 0, TP_RSA_Data_Len);
    // OPENSSL_PKCS1_OAEP_PADDING support is only for: PublicKey::encrypt() -> PrivateKey::decrypt()
    int len = RSA_private_encrypt(sizeof(sha256), sha256, outData, rsa, RSA_PKCS1_PADDING);
    if(len != RSA_Data_Len)
    {
        return 1;
    }
    
    return 0;
}

void signWithSha256(string src, string &sign)
{
    unsigned char *bSrc = (unsigned char*)src.c_str();
    int srcLen = src.length();
    unsigned char bSign[TP_RSA_Data_Len];

    memset(bSign, 0, sizeof(bSign));

    int ret = p_signWithSha256(m_rsa, bSrc, srcLen, bSign);
    if(ret)
    {
        return ret;
    }

    // base64
    int base64Len = sizeof(bSign)*2;
    char *szBase64 = (char*)alloca(base64Len);
    int retLen;
    ret = Base64_Encode(bSign, sizeof(bSign), szBase64, base64Len, &retLen);
    if(ret)
    {
        return;
    }

    sign = szBase64;
}

// 验签
int p_verifySignWithSha256(RSA *rsa, unsigned char sign[RSA_Data_Len], unsigned char *src, int srcLen, bool *verify)
{
    *verify = false;
    
    // rsa pub key decrypt
    unsigned char decSha256[SHA256_DIGEST_LENGTH];
    memset(decSha256, 0, sizeof(decSha256));
    
    int len = RSA_public_decrypt(RSA_Data_Len, sign, decSha256, rsa, RSA_PKCS1_PADDING);
    if(len != sizeof(decSha256))
    {
        return 1;
    }
    
    
    // src sha256
    unsigned char srcSha256[SHA256_DIGEST_LENGTH];
    memset(srcSha256, 0, sizeof(srcSha256));
    
    SHA256_CTX c;
    SHA256_Init(&c);
    SHA256_Update(&c, src, srcLen);
    SHA256_Final(srcSha256, &c);
    
    if(memcmp(decSha256, srcSha256, SHA256_DIGEST_LENGTH) == 0)
    {
        *verify = true;
    }
    
    return 0;
}

void verifySignWithSha256(string sign, string src, bool *verify)
{
    unsigned char bSign[RSA_Data_Len];

    memset(bSign, 0, sizeof(bSign));

    int retLen;

    int ret = Base64_Decode(sign.c_str(), sign.length(), bSign, sizeof(bSign), &retLen);
    if(ret)
    {
        return;
    }

    p_verifySignWithSha256(m_rsa, bSign, (unsigned char *)src.c_str(), src.length(), verify);
}