使用openssl操作P12证书

以下代码并非完全原创,有所参考借鉴。

/* vi:set tw=0 ts=4 sw=4 noet: */

/************************************************************************/
/*!          \file:  p12op.cpp
 *          \brief:  
 *
 *        \version:  1.0
 *         \author:  f7zz , f7zz@yahoo.com
 *        \Company:  ZLab
 *           \date:  2005-6-30 14:32:41 中国标准时间
 *             
 *            \bug:   
 *        \warning:  
 *
 * CVS:  $Id$ 
 ************************************************************************/

/** 从DER、PEM、P12格式中读取公钥证书.
 *  由该函数导出的X509必须释放(X509_free)
 */
X509 * BaseLoadCert (BIO * Cert, int iFormat, char *strPwd)
{
    X509 *x = NULL;

    switch (iFormat)
    {
    case DER:
        x = d2i_X509_bio (Cert, NULL);
        break;
    case PEM:
        x = PEM_read_bio_X509 (Cert, NULL, NULL, NULL);    //PEM_read_bio_X509_AUX
        break;
    case P12:
        {
            PKCS12 *p12 = d2i_PKCS12_bio (Cert, NULL);

            PKCS12_parse (p12, strPwd, NULL, &x, NULL);
            PKCS12_free (p12);
            p12 = NULL;
            break;
        }
    default:
        break;
    }
    return x;
}

/** 载入证书.
 *  尝试使用DER/PEM格式两种格式
 * 由该函数导出的X509必须释放
 */
X509 * LoadCert (char *cert, int certlen)
{
    BIO *in = NULL;
    X509 *x509 = NULL;

    assert(cert);

    if (certlen == 0)            /// 输入为磁盘文件
    {
        if ((in = BIO_new_file (cert, "r")) == NULL)
        {
            return NULL;
        }
    }
    else                  // 输入为内存中文件
    {
        if ((in = BIO_new_mem_buf (cert, certlen)) == NULL) //只读类型
        {
            return NULL;
        }
    }

    if ((x509 = BaseLoadCert (in, DER, NULL)) == NULL)    //尝试DER
    {
        BIO_reset (in);
        x509 = BaseLoadCert (in, PEM, NULL);      //尝试PEM
    }

    BIO_free (in);
    in = NULL;
    in = 0;
    return x509;
}

/** 尝试从DER/PEM/P12格式导出密钥
 *  由该函数导出的EVP_PKEY必须释放
 */
EVP_PKEY * BaseLoadKey (BIO * bio, int iFormat, char *strPwd)
{
    EVP_PKEY *pkey = NULL;

    switch (iFormat)
    {
    case DER:
        pkey = d2i_PrivateKey_bio (bio, NULL);
        break;
    case PEM:
        pkey = PEM_read_bio_PrivateKey (bio, NULL, NULL, strPwd);
        break;
    case P12:
        {
            PKCS12 *p12 = d2i_PKCS12_bio (bio, NULL);

            PKCS12_parse (p12, strPwd, &pkey, NULL, NULL);
            PKCS12_free (p12);
            p12 = NULL;
            break;
        }
    default:
        break;
    }
    return pkey;
}


/** 载入私钥.
 *  尝试DER/PEM格式
 */

EVP_PKEY * LoadKey (char *key, int keylen, char *pass)
{
    EVP_PKEY *pkey = NULL;
    BIO *in = NULL;

    if (keylen == 0)            //输入为磁盘文件
    {
        if ((in = BIO_new_file (key, "r")) == NULL)
        {
            return NULL;
        }
    }
    else               //输入为内存中文件
    {
        if ((in = BIO_new_mem_buf (key, keylen)) == NULL)  //只读类型
        {
            return NULL;
        }
    }

    if ((pkey = BaseLoadKey (in, DER, pass)) == NULL)    //尝试DER
    {
        BIO_reset (in);
        pkey = BaseLoadKey (in, PEM, pass);       //尝试PEM
    }

    if (in != NULL)
        BIO_free (in);

    return pkey;
}

/** 载入p12.
 *
 */
PKCS12 * LoadP12 (char *strP12File, char *strP12Pwd)
{
    FILE *fp = NULL;
    PKCS12 *p12 = NULL;

    assert(strP12File);
    assert(strP12Pwd);

    /// 读入P12
    if (!(fp = fopen (strP12File, "rb")))
        return NULL;
    p12 = d2i_PKCS12_fp (fp, NULL);
    fclose(fp);
    if (!p12)
        return NULL;

    return p12;
}


int p12_ChangePwd (char *strP12, char *strPwd, char *strNewPwd)
{
    FILE *fp = NULL;
    PKCS12 *p12 = NULL;
    int reval;

    assert(strP12);
    assert(strPwd);
    assert(strNewPwd);

    OpenSSL_add_all_algorithms ();

    /// 读入P12
    if (!(fp = fopen (strP12, "r+bc")))
    {
        /* deferr(ERR_P12CHGPWD_OPENFILE, "p12_ChangePwd(): Error Open p12 file.") */
        return ERR_P12CHGPWD_OPENFILE;
    }
    p12 = d2i_PKCS12_fp (fp, NULL);
    if (!p12)
    {
        fclose (fp);
        /* deferr(ERR_P12CHGPWD_READFILE, "p12_ChangePwd(): Error Read p12 file.") */
        return ERR_P12CHGPWD_READFILE;
    }

    reval = PKCS12_newpass (p12, strPwd, strNewPwd);
    if (!reval)
    {
        PKCS12_free (p12);
        p12 = NULL;
        fclose (fp);
        /* deferr(ERR_P12CHGPWD_UPDATE, "p12_ChangePwd(): Error Update Password.") */
        return ERR_P12CHGPWD_UPDATE;
    }

    /// i2d_PKCS12_fp的bug, 对于老文件,必须将文件指针移到文件头
    fseek (fp, 0, SEEK_SET);
    reval = i2d_PKCS12_fp (fp, p12);
    if (!reval)
    {
        PKCS12_free (p12);
        p12 = NULL;
        fclose (fp);
        /* deferr(ERR_P12CHGPWD_UPDATE, "p12_ChangePwd(): Error Update Password.") */
        return ERR_P12CHGPWD_UPDATE;
    }

    /// 释放
    PKCS12_free (p12);
    p12 = NULL;
    fclose (fp);
    return 1;
}

int p12_VerifyPwd (char *strP12, char *strPwd)
{
    int reval;

    assert(strP12);
    assert(strPwd);

    reval = p12_ChangePwd (strP12, strPwd, strPwd);
    if (reval != 1)
    {
        /* deferr(ERR_P12VERIFYPWD, "p12_ChangePwd(): Error Verify Password.") */
        return ERR_P12VERIFYPWD;
    }
    return 1;
}

int p12_ExpToNewP12 (char *strP12,      /*源p12文件 */
                 char *strPwd,          /*源p12密码 */
                 char *strPwd2,         /*新p12密码 */
                 char *strOutP12        /*新p12文件 */
                )
{
    int reval;

    FILE *fp = NULL;
    EVP_PKEY *key = NULL;
    X509 *cert = NULL;

    STACK_OF (X509) * ca = NULL;
    PKCS12 *p12 = NULL;
    int len = 0, wlen = 0;

    assert(strP12);
    assert(strPwd);
    assert(strPwd2);
    assert(strOutP12);

    OpenSSL_add_all_algorithms ();

    /// 读入P12,并分解
    if (!(fp = fopen (strP12, "rb")))
    {
        /* deferr(ERR_P12EXP_OPENFILE, "p12_ExpNewP12(): Error Open p12 file.") */
        return ERR_P12EXP_OPENFILE;
    }

    p12 = d2i_PKCS12_fp (fp, NULL);
    fclose (fp);
    if (!p12)
    {
        /* deferr(ERR_P12EXP_READFILE, "p12_ExpNewP12(): Error Read p12 file.") */
        return ERR_P12EXP_READFILE;
    }

    if (!PKCS12_parse (p12, strPwd, &key, &cert, &ca))
    {
        PKCS12_free(p12);
        p12 = NULL;
        /* deferr(ERR_P12EXP_PARSE, "p12_ExpNewP12(): Error Parse p12 file.") */
        return ERR_P12EXP_PARSE;
    }
    PKCS12_free (p12);
    p12 = NULL;

    /// 生成新P12
    p12 = PKCS12_create (strPwd2, "Duplicated", key, cert, ca, 0, 0, 0, 0, 0);
    if (!p12)
    {
        /* deferr(ERR_P12EXP_CREATESTRUCT, "p12_ExpNewP12(): Error Create p12 struct.") */
        reval = ERR_P12EXP_CREATESTRUCT;
        goto Cleanup;
    }

    /// 创建新p12文件,并保存
    if (!(fp = fopen (strOutP12, "wb")))
    {
        /* deferr(ERR_P12EXP_CREATEFILE, "p12_ExpNewP12(): Error Create p12 file.") */
        reval = ERR_P12EXP_CREATEFILE;
        goto Cleanup;
    }
    i2d_PKCS12_fp (fp, p12);

    reval = 1;

Cleanup:
    /// 释放
    if(p12 != NULL)
        PKCS12_free (p12);
    if (fp != NULL)
        fclose (fp);
    if (cert != NULL)
        X509_free (cert);
    if (key != NULL)
        EVP_PKEY_free (key);
    if (ca != NULL)
    {
        for(;;)
        {
            X509 *x5 = sk_X509_pop(ca);
            if (!x5)
                break;
            X509_free(x5);
        }
        sk_X509_free (ca);
    }

    return reval;
}


int p12_ExpToCertKey (char *strP12, char *strPwd, int iFormat, char *Cert, char *Key, char *Ca)
{
    int reval;
    EVP_PKEY *key = NULL;
    X509 *cert = NULL;

    STACK_OF (X509) * ca = NULL;
    BIO *bio = NULL, *bioCert = NULL, *bioKey = NULL, *bioCaCert = NULL;
    PKCS12 *p12 = NULL;
    int reval1 = 0, reval2 = 0, reval3 = 0;

    assert(strP12);
    assert(strPwd);
    assert(iFormat);
    assert(Cert);
    assert(Key);
    assert(Ca);

    OpenSSL_add_all_algorithms ();

    if (!(bio = BIO_new_file (strP12, "r")))
    {
        /* deferr(ERR_P12EXPCK_OPENFILE, "p12_ExpToCertKey(): Error Open p12 file.") */
        return ERR_P12EXPCK_OPENFILE;
    }

    p12 = d2i_PKCS12_bio (bio, NULL);
    BIO_free (bio);
    bio = NULL;
    if (!p12)
    {
        /* deferr(ERR_P12EXPCK_READFILE, "p12_ExpToCertKey(): Error Read p12 file.") */
        return ERR_P12EXPCK_READFILE;
    }

    if (!PKCS12_parse (p12, strPwd, &key, &cert, &ca))
    {
        /* deferr(ERR_P12EXPCK_PARSE, "p12_ExpToCertKey(): Error Parse p12 file.") */
        return ERR_P12EXPCK_PARSE;
    }
    PKCS12_free (p12);
    p12 = NULL;

    /// 输出文件
    if ((bioCert = BIO_new_file (Cert, "w")) == NULL)
    {
        /* deferr(ERR_P12EXPCK_CREATECERTFILE, "p12_ExpToCertKey(): Error Create Cert File.") */
        reval = ERR_P12EXPCK_CREATECERTFILE;
        goto Cleanup;
    }

    if ((bioKey = BIO_new_file (Key, "w")) == NULL)
    {
        /* deferr(ERR_P12EXPCK_CREATEKEYFILE, "p12_ExpToCertKey(): Error Create Key File.") */
        reval = ERR_P12EXPCK_CREATEKEYFILE;
        goto Cleanup;
    }
    if (iFormat == DER)
    {
        reval1 = i2d_X509_bio (bioCert, cert);
        reval2 = i2d_PrivateKey_bio (bioKey, key);
    }
    else if (iFormat == PEM)
    {
        reval1 = PEM_write_bio_X509 (bioCert, cert);
        reval2 = PEM_write_bio_PrivateKey (bioKey, key, NULL, NULL, 0, 0, NULL);
    }
    BIO_free (bioCert);
    bioCert = NULL;
    BIO_free (bioKey);
    bioKey = NULL;
    X509_free (cert);
    cert = NULL;
    EVP_PKEY_free (key);
    key = NULL;

    if (ca && sk_num (ca))
    {
        if ((bioCaCert = BIO_new_file (Ca, "w")) == NULL)
        {
            /* deferr(ERR_P12EXPCK_CREATEFILE, "p12_ExpToCertKey(): Error Create Cert or Key File.") */
            reval = ERR_P12EXPCK_CREATEFILE;
            goto Cleanup;
        }
        if (iFormat == DER)
        {
            /* deferr(ERR_P12EXPCK_NOTSURPORT, "p12_ExpToCertKey(): Not Surport _MCRT_EXPORT DER ca cert.") */
            reval = ERR_P12EXPCK_NOTSURPORT;
            goto Cleanup;
        }
        else if (iFormat == PEM)
        {
            int i;

            for (i = 0; i < sk_X509_num (ca); i++)
                reval3 = PEM_write_bio_X509_AUX (bioCaCert, sk_X509_value (ca, i));
        }
        BIO_free (bioCaCert);
        bioCaCert = NULL;
    }
    else
        reval3 = 1;


    if (reval1 == 0 || reval2 == 0 || reval3 == 0)
    {
        /* deferr(ERR_P12EXPCK_FAILED, "p12_ExpToCertKey(): Error _MCRT_EXPORT Cert or Key File.") */
        reval = ERR_P12EXPCK_FAILED;
        goto Cleanup;
    }
    reval = 1;

Cleanup:
    if (bio != NULL)
        BIO_free(bio);
    if (bioCert != NULL)
        BIO_free(bioCert);
    if (bioKey != NULL)
        BIO_free(bioKey);
    if (bioCaCert != NULL)
        BIO_free(bioCaCert);

    if (key != NULL)
        EVP_PKEY_free(key);
    if (cert != NULL)
        X509_free(cert);
    if (ca != NULL)
    {
        for(;;)
        {
            X509 *x5 = sk_X509_pop(ca);
            if (!x5)
                break;
            X509_free(x5);
        }
        sk_X509_free (ca);
    }

    return reval;
}

int p12_impfromCertKey (char *strP12, char *strPwd, int iFormat, char *strCert, char *strKey, char *strCa)
{
    int reval;

    FILE *fp = NULL;
    EVP_PKEY *key = NULL;
    X509 *cert = NULL, *ca0 = NULL;

    STACK_OF (X509) * ca = NULL;
    PKCS12 *p12 = NULL;
    int len = 0, wlen = 0;
 
 OpenSSL_add_all_algorithms ();

 // 加载cert,key,ca
 cert = LoadCert (strCert, 0);
    if (cert == NULL)
    {
  printf("p12_impfromCertKey(): LoadCert Error!\n");
        return ERR_CERTGETI_OPEN;
    }

 key = LoadKey (strKey, 0, NULL);   /// 默认密钥为明文
    if (key == NULL)
    {
  printf("p12_impfromCertKey(): LoadKey Error!\n");
        return -1;
    }

 ca0 = LoadCert (strCa, 0);
    if (ca0 == NULL)
    {
  printf("p12_impfromCertKey(): LoadCert CA Error!\n");
        return ERR_CERTGETI_OPEN;
    }
 
 ca = sk_X509_new_null();
    if (ca == NULL)
    {
  printf("p12_impfromCertKey(): sk_X509_new_null Error!\n");
        return -1;
    }

 printf("4\n");

 if (!sk_X509_push(ca, ca0))
 {
  printf("p12_impfromCertKey(): sk_X509_push Error!\n");
        return -1;
 }

 /// 生成新P12
    p12 = PKCS12_create (strPwd, "Duplicated", key, cert, ca, 0, 0, 0, 0, 0);
    if (!p12)
    {
        /* deferr(ERR_P12EXP_CREATESTRUCT, "p12_ExpNewP12(): Error Create p12 struct.") */
        reval = ERR_P12EXP_CREATESTRUCT;
        goto Cleanup;
    }

    /// 创建新p12文件,并保存
    if (!(fp = fopen (strP12, "wb")))
    {
        /* deferr(ERR_P12EXP_CREATEFILE, "p12_ExpNewP12(): Error Create p12 file.") */
        reval = ERR_P12EXP_CREATEFILE;
        goto Cleanup;
    }
    i2d_PKCS12_fp (fp, p12);

    reval = 1;

Cleanup:
    /// 释放
    if(p12 != NULL)
        PKCS12_free (p12);
    if (fp != NULL)
        fclose (fp);
    if (cert != NULL)
        X509_free (cert);
    if (key != NULL)
        EVP_PKEY_free (key);
    if (ca != NULL)
    {
        for(;;)
        {
            X509 *x5 = sk_X509_pop(ca);
            if (!x5)
                break;
            X509_free(x5);
        }
        sk_X509_free (ca);
    }

    return reval;
}

 在windows下使用vc编译的openssl的库是要分debug和release的,比如用release的程序去调debug的库,某些 函数可能会有错,比如以上用到的d2i_PKCS12_bio函数(在我用的0.9.7g,最新的版本未测试过)中,所以敬请注意。

如果你的windows下使用gcc编译程序和库,就不会由什么问题.


http://laokaddk.blog.51cto.com/368606/596124/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值