即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

C++运用OpenSSL证书API

编程语言 vaintwyt 109℃ 0评论

本文主要介绍如果在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_ASC,
                               (unsigned char *)"CN", -1, -1, 0);
    // 省份
    X509_NAME_add_entry_by_txt(subject, SN_stateOrProvinceName,  MBSTRING_ASC,
                               (unsigned char *)"GuangDong", -1, -1, 0);
    // 城市
    X509_NAME_add_entry_by_txt(subject, SN_localityName,  MBSTRING_ASC,
                               (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



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















转载请注明:CodingBlog » C++运用OpenSSL证书API

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情