以下代码并非完全原创,有所参考借鉴。
/* 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/