目录

环境部署

一、openssl RSA加解密、 使用接口生成秘钥

2、使用openssl对文件进行签名认证

3、aes加解密

4、生成证书及证书合法性检查


环境部署

关于openssl的部署比较简单,在之前wifi功能移植中有过说明,或者网上大把详细步骤

一、openssl RSA加解密、 使用接口生成秘钥

命令行的方式生成证书:
参考文章:

我的具体实现

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <fstream>

using namespace std;

#define LOG_INFO(fmt,args...)   ({printf("info: %s(%d) %s:",__FILE__, __LINE__, __func__);printf(fmt"\r\n" ,##args);})
#define LOG_ERROR(fmt,args...)   ({printf("error: %s(%d) %s:",__FILE__, __LINE__, __func__);printf(fmt"\r\n" ,##args);})


#define RSA_OPENSSLKEY "./rsa_private_key.pem"
#define RSA_PUBLICKEY "./rsa_public_key.pem"

#define KEY_LENGTH  2048 

//生成秘钥
void GenerateRSAKey(std::string & out_pub_key, std::string & out_pri_key);

//传入秘钥内容进行加解密
std::string RsaPriEncrypt(const std::string &clear_text, std::string &pri_key);
std::string RsaPubDecrypt(const std::string & cipher_text, const std::string & pub_key);


//通过读秘钥文件的方式进行加解密
std::string RsaPriEncryptFile(const std::string &clear_text);
std::string RsaPubDecryptFile(const std::string & cipher_text);


int main(int argc, char* argv[])
{
		char *p_str="qaq1234567abcdef";

		std::string encrypt_text;
		std::string decrypt_text;
		
		std::string encryptFile_text;
		std::string decryptFile_text;

		std::string pub_key;
		std::string pri_key;
		GenerateRSAKey(pub_key, pri_key);
		LOG_INFO("public key:\n");
		LOG_INFO("%s\n", pub_key.c_str());
		LOG_INFO("private key:\n");
		LOG_INFO("%s\n", pri_key.c_str());


		// 直接使用秘钥信息的方式加解密
		// 私钥加密-公钥解密
		encrypt_text = RsaPriEncrypt(p_str, pri_key);
		LOG_INFO("encrypt: len=%d\n", encrypt_text.length());
		LOG_INFO("decrypt: %s\n", encrypt_text.c_str());
		decrypt_text = RsaPubDecrypt(encrypt_text, pub_key);
		LOG_INFO("decrypt: len=%d\n", decrypt_text.length());
		LOG_INFO("decrypt: %s\n", decrypt_text.c_str());

		printf("==================================\n");
		
		// 通过读秘钥文件的方式加解密
		encryptFile_text = RsaPriEncryptFile(p_str);
		LOG_INFO("encrypt: len=%d\n", encryptFile_text.length());
		LOG_INFO("encrypt: %s\n", encryptFile_text.c_str());
		decryptFile_text = RsaPubDecryptFile(encryptFile_text);
		LOG_INFO("decrypt: len=%d\n", decryptFile_text.length());
		LOG_INFO("decrypt: %s\n", decryptFile_text.c_str());



		return 0;
}

void GenerateRSAKey(std::string & out_pub_key, std::string & out_pri_key)
{
		size_t pri_len = 0; // 私钥长度
		size_t pub_len = 0; // 公钥长度
		char *pri_key = nullptr; // 私钥
		char *pub_key = nullptr; // 公钥

		// 生成密钥对
		RSA *keypair = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL);

		BIO *pri = BIO_new(BIO_s_mem());
		BIO *pub = BIO_new(BIO_s_mem());

		// 生成私钥
		PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
		// 注意------生成第1种格式的公钥
		//PEM_write_bio_RSAPublicKey(pub, keypair);
		// 注意------生成第2种格式的公钥(此处代码中使用这种)
		PEM_write_bio_RSA_PUBKEY(pub, keypair);

		// 获取长度  
		pri_len = BIO_pending(pri);
		pub_len = BIO_pending(pub);

		// 密钥对读取到字符串  
		pri_key = (char *)malloc(pri_len + 1);
		pub_key = (char *)malloc(pub_len + 1);

		BIO_read(pri, pri_key, pri_len);
		BIO_read(pub, pub_key, pub_len);

		pri_key[pri_len] = '\0';
		pub_key[pub_len] = '\0';

		out_pub_key = pub_key;
		out_pri_key = pri_key;

		// 将公钥写入文件
		std::ofstream pub_file(RSA_PUBLICKEY, std::ios::out);
		if (!pub_file.is_open())
		{
				perror("pub key file open fail:");
                goto ERROR;
				return;
		}
		pub_file << pub_key;
		pub_file.close();

		// 将私钥写入文件
		std::ofstream pri_file(RSA_OPENSSLKEY, std::ios::out);
		if (!pri_file.is_open())
		{
				perror("pri key file open fail:");
                goto ERROR;
				return;
		}
		pri_file << pri_key;
		pri_file.close();

ERROR:
		// 释放内存
		RSA_free(keypair);
		BIO_free_all(pub);
		BIO_free_all(pri);

		free(pri_key);
		free(pub_key);
}

std::string RsaPriEncrypt(const std::string &clear_text, std::string &pri_key)
{
		std::string encrypt_text;
		BIO *keybio = BIO_new_mem_buf((unsigned char *)pri_key.c_str(), -1);
		RSA* rsa = RSA_new();
		rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
		if (!rsa)
		{
				BIO_free_all(keybio);
				return std::string("");
		}

		// 获取RSA单次可以处理的数据的最大长度
		int len = RSA_size(rsa);

		// 申请内存:存贮加密后的密文数据
		char *text = new char[len + 1];
		memset(text, 0, len + 1);

		// 对数据进行私钥加密(返回值是加密后数据的长度)
		int ret = RSA_private_encrypt(clear_text.length(), (const unsigned char*)clear_text.c_str(), (unsigned char*)text, rsa, RSA_PKCS1_PADDING);
		if (ret >= 0) {
				encrypt_text = std::string(text, ret);
		}

		// 释放内存  
		delete text;
		BIO_free_all(keybio);
		RSA_free(rsa);

		return encrypt_text;
}

std::string RsaPubDecrypt(const std::string & cipher_text, const std::string & pub_key)
{
		std::string decrypt_text;
		BIO *keybio = BIO_new_mem_buf((unsigned char *)pub_key.c_str(), -1);
		RSA *rsa = RSA_new();

		// 注意--------使用第1种格式的公钥进行解密
		//rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
		// 注意--------使用第2种格式的公钥进行解密(我们使用这种格式作为示例)
		rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
		if (!rsa)
		{
				unsigned long err = ERR_get_error(); //获取错误号
				char err_msg[1024] = { 0 };
				ERR_error_string(err, err_msg); // 格式:error:errId:库:函数:原因
				printf("err msg: err:%ld, msg:%s\n", err, err_msg);
				BIO_free_all(keybio);
				return decrypt_text;
		}

		int len = RSA_size(rsa);
		char *text = new char[len + 1];
		memset(text, 0, len + 1);
		// 对密文进行解密
		int ret = RSA_public_decrypt(cipher_text.length(), (const unsigned char*)cipher_text.c_str(), (unsigned char*)text, rsa, RSA_PKCS1_PADDING);
		if (ret >= 0) {
				decrypt_text.append(std::string(text, ret));
		}

		// 释放内存  
		delete text;
		BIO_free_all(keybio);
		RSA_free(rsa);

		return decrypt_text;
}

std::string RsaPriEncryptFile(const std::string &clear_text)
{
	std::string encrypt_text;
	RSA *prikey = RSA_new();
	BIO *priio;
	
	priio = BIO_new_file(RSA_OPENSSLKEY, "rb");
    prikey = PEM_read_bio_RSAPrivateKey(priio, &prikey, NULL, NULL);
	if (!prikey)
	{
		BIO_free(priio);
		return std::string("");
	}
	int len = RSA_size(prikey);
	char *text = new char[len + 1];
	memset(text, 0, len + 1);
	
	int ret = RSA_private_encrypt(clear_text.length(), (const unsigned char*)clear_text.c_str(), (unsigned char*)text, prikey, RSA_PKCS1_PADDING);
	if (ret >= 0) {
		encrypt_text = std::string(text, ret);
	}
	delete text;
	RSA_free(prikey);
    BIO_free(priio);
	
	return encrypt_text;
}

std::string RsaPubDecryptFile(const std::string & cipher_text)
{
	std::string decrypt_text;
	RSA *pubkey = RSA_new();
	BIO *pubio;
	pubio = BIO_new_file(RSA_PUBLICKEY, "rb");
    pubkey = PEM_read_bio_RSA_PUBKEY(pubio, &pubkey, NULL, NULL);
	if (!pubkey)
	{
		unsigned long err = ERR_get_error(); //获取错误号
		char err_msg[1024] = { 0 };
		ERR_error_string(err, err_msg); // 格式:error:errId:库:函数:原因
		printf("err msg: err:%ld, msg:%s\n", err, err_msg);
		BIO_free(pubio);
		return decrypt_text;
	}
	
	int len = RSA_size(pubkey);
	char *text = new char[len + 1];
	memset(text, 0, len + 1);
	
	int ret = RSA_public_decrypt(cipher_text.length(), (const unsigned char*)cipher_text.c_str(), (unsigned char*)text, pubkey, RSA_PKCS1_PADDING);
	if (ret >= 0) {
		decrypt_text.append(std::string(text, ret));
	}
	
	delete text;
	RSA_free(pubkey);
    BIO_free(pubio);
	
	return decrypt_text;
}

记得编译时加上 -lssl -lcrypto

2、使用openssl对文件进行签名认证

命令行方式:

message.sign:签名文件

source_ile:目标文件

sha1:摘要算法 使用openssl dgst - 可以看到支持的列表

使用私钥对升级包进行签名
openssl dgst -sha1 -out message.sign -sign rsa_private_key.pem source_file

使用公钥验证签名
openssl dgst -sha1 -verify rsa_public_key.pem -signature message.sign source_file

代码实现

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/evp.h>

#define  SIGN_PATH			"./.message.sign"  //签名文件
#define  SOURCE_PATH		"./source_file"    //源文件

#define PUBLIC_KEY_PASH		"./pub_key.pem"    //公钥

static EVP_PKEY *PEM_read_PublicKey(FILE *fp)
{
	BIO *b;
	EVP_PKEY *ret;

	if ((b = BIO_new(BIO_s_file())) == NULL)
	{
		//PEMerr(PEM_F_PEM_READ_PRIVATEKEY, ERR_R_BUF_LIB);
		return(0);
	}
	BIO_set_fp(b, fp, BIO_NOCLOSE);
	ret = PEM_read_bio_PUBKEY(b, NULL, NULL, NULL);
	BIO_free(b);
	return(ret);
}

static EVP_PKEY* Read_PublicKey(char* p_KeyPath)
{
	FILE *fp = NULL;
	char szKeyPath[1024];
	EVP_PKEY *pubRsa = NULL;

	/*	打开密钥文件 */
	if (NULL == (fp = fopen(p_KeyPath, "r")))
	{
		return NULL;
	}
	/*	获取私密钥 */
	pubRsa = PEM_read_PublicKey(fp);
	if (NULL == pubRsa)
	{
		fclose(fp);
		return NULL;
	}
	fclose(fp);

	return pubRsa;
}

int VerifyUpgrade(char *sign_data, int sign_len)
{
	printf("sign_len = %d\n", sign_len);
	
	int nRet = 0;
	EVP_PKEY *pKey;
	EVP_MD_CTX* pMdCtx = NULL;
	EVP_PKEY_CTX* pKeyCtx = NULL;
	
	/*初始化验签函数*/
	pKey = Read_PublicKey(PUBLIC_KEY_PASH);
	if (!pKey)
	{
		printf("Read_PublicKey failed!\n");
		return -1;
	}
	
	pMdCtx = EVP_MD_CTX_create();
	if (NULL == pMdCtx)
	{
		printf("EVP_MD_CTX_create failed!\n");
		EVP_PKEY_free(pKey);
		pKey = NULL;
		return -1;
	}

	nRet = EVP_DigestVerifyInit(pMdCtx, &pKeyCtx, EVP_sha256(), NULL, pKey);
	if (nRet <= 0)
	{
		printf("EVP_DigestVerifyInit failed!\n");
		EVP_PKEY_free(pKey);
		pKey = NULL;
		EVP_MD_CTX_destroy(pMdCtx);
		pMdCtx = NULL;
		return -1;
	}
	
	FILE *fp = NULL;
	char p_pBuf[512];
	fp = fopen(SOURCE_PATH, "r");
	while (feof(fp) == 0)
	{
		int i = fread(p_pBuf, 1, 512, fp);
		EVP_DigestVerifyUpdate(pMdCtx, p_pBuf, i);
	}

	
	/*验签*/
	nRet = EVP_DigestVerifyFinal(pMdCtx, (unsigned char *)sign_data, sign_len);
	if (nRet <= 0)
	{
		printf("EVP_DigestVerifyFinal failed !!! nRet = %d \n", nRet);
		EVP_PKEY_free(pKey);
		pKey = NULL;
		EVP_MD_CTX_destroy(pMdCtx);
		pMdCtx = NULL;
		fclose(fp);
		printf("========================= Verify Failed ========================\n");
		return -1;
	}
	fclose(fp);

	printf("========================= Verify Success ========================\n");
	
	return 0;
}

int main()
{
	int sign_len = 0;
	char *p_sign_data = NULL;

	struct stat statbuf;
	stat(SIGN_PATH, &statbuf);
	sign_len = statbuf.st_size;
	
	p_sign_data = (char *)malloc(sign_len);
	memset(p_sign_data, 0, sign_len);
	FILE *sign_fp = fopen(SIGN_PATH, "r");
	if (sign_fp)
	{
		fread(p_sign_data, 1, sign_len, sign_fp);
	}
	
	VerifyUpgrade(p_sign_data, sign_len);
	
	free(p_sign_data);
	
	return 0;
}

3、aes加解密

命令行方式:

1、ecb

echo -n "AA:BB:CC:11:22:33" | openssl enc -aes-128-ecb -K 78346c3932774542754d32656e345273 | xxd -p -c 64

AA:BB:CC:11:22:33 要加密的字符串

xxd让加密后的内容以十六进制的方式显示,方便查看

2、cbc

echo -n "test" | openssl enc -aes-128-cbc -K 69249e45dd8f1088c6ce8ec74b027035 -iv 69249e45dd8f1088c6ce8ec74b027035 | xxd

代码实现:(这里实现的是cbc,ecb大同小异)

命令行指定的key和iv是十六进制数,为了能跟命令行的输出结果一致,这里简单赋了一下值

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <openssl/evp.h>
#include <openssl/aes.h>


static unsigned char sAesIV[] = "69249e45dd8f1088c6ce8ec74b027035";
static unsigned char sAesKey[] = "69249e45dd8f1088c6ce8ec74b027035";

int AES_ENC(char *_InData, int InLen, char *OutData, int *OutLen)
{
	unsigned char key[16] = {}, iv[16] = { 0 };
	key[0] = 0x69;
	key[1] = 0x24;
	key[2] = 0x9e;
	key[3] = 0x45;
	key[4] = 0xdd;
	key[5] = 0x8f;
	key[6] = 0x10;
	key[7] = 0x88;
	key[8] = 0xc6;
	key[9] = 0xce;
	key[10] = 0x8e;
	key[11] = 0xc7;
	key[12] = 0x4b;
	key[13] = 0x02;
	key[14] = 0x70;
	key[15] = 0x35;
	
	iv[0] = 0x69;
	iv[1] = 0x24;
	iv[2] = 0x9e;
	iv[3] = 0x45;
	iv[4] = 0xdd;
	iv[5] = 0x8f;
	iv[6] = 0x10;
	iv[7] = 0x88;
	iv[8] = 0xc6;
	iv[9] = 0xce;
	iv[10] = 0x8e;
	iv[11] = 0xc7;
	iv[12] = 0x4b;
	iv[13] = 0x02;
	iv[14] = 0x70;
	iv[15] = 0x35;
	
	
	EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
	EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1);
	
	int len = 0;
	EVP_CipherUpdate(ctx, (unsigned char*)OutData, &len, (unsigned char*)_InData, InLen);
	*OutLen = len;
	EVP_CipherFinal_ex(ctx, (unsigned char*)OutData + len, &len);
	*OutLen += len;
	EVP_CIPHER_CTX_free(ctx);
	
	return 0;
}

int AES_DEC(char *_InData, int InLen, char *OutData, int *OutLen)
{
	unsigned char key[16] = {}, iv[16] = { 0 };
	key[0] = 0x69;
	key[1] = 0x24;
	key[2] = 0x9e;
	key[3] = 0x45;
	key[4] = 0xdd;
	key[5] = 0x8f;
	key[6] = 0x10;
	key[7] = 0x88;
	key[8] = 0xc6;
	key[9] = 0xce;
	key[10] = 0x8e;
	key[11] = 0xc7;
	key[12] = 0x4b;
	key[13] = 0x02;
	key[14] = 0x70;
	key[15] = 0x35;
	
	iv[0] = 0x69;
	iv[1] = 0x24;
	iv[2] = 0x9e;
	iv[3] = 0x45;
	iv[4] = 0xdd;
	iv[5] = 0x8f;
	iv[6] = 0x10;
	iv[7] = 0x88;
	iv[8] = 0xc6;
	iv[9] = 0xce;
	iv[10] = 0x8e;
	iv[11] = 0xc7;
	iv[12] = 0x4b;
	iv[13] = 0x02;
	iv[14] = 0x70;
	iv[15] = 0x35;
	
	EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
	EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 0);
	
	int len = 0;
	EVP_CipherUpdate(ctx, (unsigned char*)OutData, &len, (unsigned char*)_InData, InLen);
	*OutLen = len;
	EVP_CipherFinal_ex(ctx, (unsigned char*)OutData + len, &len);
	*OutLen += len;
	EVP_CIPHER_CTX_free(ctx);
	
	return 0;
	
}

int main()
{
	char Source[128] = "test";
	char EncData[128] = {};
	char DecData[128] = {};
	int EncLen = 0;
	int DecLen = 0;
	
	AES_ENC(Source, (int)strlen(Source), EncData, &EncLen);
	for (int i = 0; i < EncLen; ++i)
		printf("%02x ", EncData[i]);
	printf("\n");
	
	AES_DEC(EncData, (int)strlen(EncData), DecData, &DecLen);
	for (int i = 0; i < DecLen; ++i)
		printf("%x ", DecData[i]);
	printf("\n");
	
	return 0;
}

注意:

openssl默认是PKCS7填充的数据,AES-128AES-192AES-256 的数据块长度分别为 128/8=16bytes192/8=24bytes256/8=32bytes。

当我们拿到一串PKCS7填充的数据时,取其最后一个字符paddingChar,此字符的ASCII码的十进制ord(paddingChar)即为填充的数据长度paddingSize,读取真实数据时去掉填充长度即可得到原始的数据。

命令行输出结果

go语言使用proto2_c语言

 代码输出结果

go语言使用proto2_#include_02

4、生成证书及证书合法性检查

#include <stdio.h>
#include <string.h>

#include "openssl/ssl.h"
#include "openssl/crypto.h"
#include "openssl/conf.h"
#include "openssl/x509v3.h"
#include "openssl/err.h"
#include "openssl/engine.h"
#include "openssl/rsa.h"

//#define BASE64_SIZE(x)  (((x)+2) / 3 * 4 + 1)
//#define PADDING_BUF(LEN)	 (LEN %4 == 0)?(LEN + 4):((LEN + 0x03) &(~0x03))
#define SERVER_CIPHERS		"ALL"
#define CLIENT_CIPHERS		"ALL:!EXPORT:!LOW"

#define BUF_LEN  (128)
#define BUF_BUF  (BUF_LEN + 4)

#define CUSTOM_CERT_KEY_PATH	"./custom_key.pem"
#define CUSTOM_CERT_REQ_PATH	"./certreq.pem"

#define CUSTOM_CERT_TEMP_PATH	"./custom_cert_temp.pem"

typedef struct _certificate_params_t
{
	char commonName[BUF_BUF];
	char country[BUF_BUF];
	char stateOrProvince[BUF_BUF];
	char locality[BUF_BUF];
	char organization[BUF_BUF];
	char organizationUnit[BUF_BUF];
}certificate_params_t;

//创建证书请求文件pem
static int create_cret(certificate_params_t *param);

static int check_certs_availability(const char *p_ciphers, const char *p_ca, const char *p_cert,const char *p_private_key);

int main(int argc, char *argv[])
{
	certificate_params_t param = {};
	
	memcpy(param.country,"SZ" , BUF_LEN);
	memcpy(param.stateOrProvince,"GD", BUF_LEN);
	memcpy(param.locality,"NS", BUF_LEN);
	memcpy(param.organization,"MYSELF", BUF_LEN);
	memcpy(param.organizationUnit,"MY" , BUF_LEN);
	memcpy(param.commonName,"SS", BUF_LEN);
		
	create_cret(¶m);
	
	
	
	return 0;
	
	//TODO
	//write file
	
	//检查证书是否合法
	check_certs_availability(SERVER_CIPHERS, NULL, CUSTOM_CERT_TEMP_PATH, CUSTOM_CERT_KEY_PATH);//check证书有误
	
	
	return 0;
}

static int _name_entry_create_by_txt(X509_NAME* name,X509_NAME_ENTRY *entry,const char *field,const char* pNameStr,int nameLen)
{
	if(0==nameLen || nameLen> 128 || NULL==name || NULL==pNameStr)
		return -1;
	char bytes[128]={0};
	memset(&bytes,0,sizeof(bytes));
	memcpy(bytes, pNameStr,sizeof(bytes) );
    int len = strlen(bytes);
    entry = X509_NAME_ENTRY_create_by_txt(&entry, field, V_ASN1_UTF8STRING, (unsigned char*)bytes, len);
    X509_NAME_add_entry(name, entry, 0, -1);

	return 0;
}

static int create_cret(certificate_params_t *param)
{
	if(NULL == param)
		return -1;
	
    X509_NAME_ENTRY* entry = NULL;
	const EVP_MD* md;
    BIO* b;
	unsigned long  e = RSA_3;
    char   mdout[20];
    int    mdlen;
    int    bits = 1024;//512;
	int    ret = 0;

    X509_REQ*req = X509_REQ_new();
    long version = 1;
    ret = X509_REQ_set_version(req, version);
    X509_NAME* name = X509_NAME_new();
	
	//Common Name (e.g. server FQDN or YOUR name) CN
	if( 0!=_name_entry_create_by_txt( name, entry, "commonName", param->commonName, BUF_LEN) )
	{
		printf(" [%s %d] _name_entry_create_by_txt  commonName err!!! \n",__FUNCTION__,__LINE__);
		return -2;
	}

	//Country Name (2 letter code) C
	if( 0!=_name_entry_create_by_txt( name, entry, "countryName", param->country, BUF_LEN) )
	{
		printf(" [%s %d] _name_entry_create_by_txt countryName err!!! \n",__FUNCTION__,__LINE__);
		return -3;
	}
	
	//State or Province Name (full name) ST
	if( 0!=_name_entry_create_by_txt( name, entry, "stateOrProvinceName", param->stateOrProvince, BUF_LEN) )
	{
		printf(" [%s %d] _name_entry_create_by_txt stateOrProvinceName err!!! \n",__FUNCTION__,__LINE__);
		return -4;
	}
	
	//Locality Name (eg, city) L
	if( 0!=_name_entry_create_by_txt( name, entry, "localityName", param->locality, BUF_LEN) )
	{
		printf(" [%s %d] _name_entry_create_by_txt localityName err!!! \n",__FUNCTION__,__LINE__);
		return -5;
	}
	
	//Organization Name (eg, company) O
	if( 0!=_name_entry_create_by_txt( name, entry, "organizationName", param->organization, BUF_LEN) )
	{
		printf(" [%s %d] _name_entry_create_by_txt organizationName err!!! \n",__FUNCTION__,__LINE__);
		return -6;
	}
	
	//Organizational Unit Name (eg, section) OU
	if( 0!=_name_entry_create_by_txt( name, entry, "organizationalUnitName", param->organizationUnit, BUF_LEN) )
	{
		printf(" [%s %d] _name_entry_create_by_txt organizationalUnitName err!!! \n",__FUNCTION__,__LINE__);
		return -7;
	}
	
	 /* subject name */
	//申请者信息
    ret = X509_REQ_set_subject_name(req, name);
    /* pub key */
    EVP_PKEY*pkey = EVP_PKEY_new();
    RSA*rsa = RSA_generate_key(bits, e, NULL, NULL);
    EVP_PKEY_assign_RSA(pkey, rsa);
    ret = X509_REQ_set_pubkey(req, pkey);
    /* 写入私钥PEM格式 */
    b = BIO_new_file(CUSTOM_CERT_KEY_PATH, "w");
	if(!PEM_write_bio_RSAPrivateKey( b, rsa, NULL,NULL, 0,0, NULL) )//往BIO中写入一个私钥,采用3DES加密
		printf("PEM_write_bio_RSAPrivateKey err!\n");
    BIO_free(b);
	
	/* 写入公钥PEM格式 */
	/*
    b = BIO_new_file("certpubkey.pem", "w");
	if (!PEM_write_bio_RSAPublicKey(b, rsa))
		printf("PEM_write_bio_RSAPublicKey err!\n");
    BIO_free(b);
	*/
	
    md = EVP_sha1();

    ret = X509_REQ_digest(req, md, (unsigned char *)mdout, (unsigned int *)&mdlen);// 根据指定的摘要算法,对X509_REQ结构做摘要计算
    ret = X509_REQ_sign(req, pkey, md);
    if (!ret)
    {
        printf("sign err!\n");
        X509_REQ_free(req);
        return -8;
    }
	
    /* 写入文件PEM格式 */
    b = BIO_new_file(CUSTOM_CERT_REQ_PATH, "w");
    PEM_write_bio_X509_REQ(b, req );
    BIO_free(b);
    X509_REQ_free(req);
	
	return 0;
}

static int check_certs_availability(const char *p_ciphers, const char *p_ca, const char *p_cert,const char *p_private_key)
{
	SSL_library_init();//必须加上不然有概率出现SSL_CTX_new返回NULL
	SSL_CTX *p_ssl_ctx = SSL_CTX_new((SSL_METHOD*)SSLv23_method());

	if (!p_ssl_ctx)
	{
		printf("Create SSL CTX fail!\n");
		SSL_CTX_free(p_ssl_ctx);
		p_ssl_ctx = NULL;
		return -1;
	}
	printf("new ssl ctx ok\n");

	//SSL_CTX_set_options((SSL_CTX*)p_ssl_ctx, SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
	SSL_CTX_set_options(p_ssl_ctx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1);
	SSL_CTX_set_mode(p_ssl_ctx, SSL_MODE_AUTO_RETRY |
								SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
								SSL_MODE_ENABLE_PARTIAL_WRITE |
								SSL_MODE_RELEASE_BUFFERS);

	/* 指定加密套件 */
	if (p_ciphers)//SERVER_CIPHERS
	{
		if (SSL_CTX_set_cipher_list(p_ssl_ctx, p_ciphers) != 1)
		{
			printf("Set cipher fail!\n");
			ERR_print_errors_fp(stderr);
			SSL_CTX_free(p_ssl_ctx);
			return -1;
		}
		printf("set cipher ok\n");
	}
	
	SSL_CTX_set_verify(p_ssl_ctx, SSL_VERIFY_NONE, NULL);//?
	/* 加载受信任的证书列表 */
	if (p_ca)
	{
		if (SSL_CTX_load_verify_locations(p_ssl_ctx, p_ca, NULL) == 0)
		{
			printf("Load trust CA [%s] fail!\n",p_ca);
			ERR_print_errors_fp(stderr);
			SSL_CTX_free(p_ssl_ctx);
			return -1;
		}
		printf("load [%s] ca ok\n",p_ca);
	}
	
	if ( NULL!=p_cert && !SSL_CTX_use_certificate_file(p_ssl_ctx, p_cert, X509_FILETYPE_PEM))
	{
		SSL_CTX_free(p_ssl_ctx);
		p_ssl_ctx = NULL;
		printf("Load cert  [%s] fail!\n",p_cert);
		return -1;
	}
	printf("load cert [%s] ok\n",p_cert);

	if (NULL!=p_private_key && !SSL_CTX_use_PrivateKey_file(p_ssl_ctx, p_private_key, X509_FILETYPE_PEM))
	{
		SSL_CTX_free(p_ssl_ctx);
		p_ssl_ctx = NULL;
		printf("Load private key [%s] fail!\n",p_private_key);
		return -1;
	}
	printf("use private key [%s] ok\n",p_private_key);

	if (!SSL_CTX_check_private_key(p_ssl_ctx))
	{
		SSL_CTX_free(p_ssl_ctx);
		p_ssl_ctx = NULL;
		printf("Check private key fail!\n");
		return -1;
	}
	printf("@@@@@@@@@@ [ltz] check cert and private ok!!! \n");
	
	SSL_CTX_set_quiet_shutdown(p_ssl_ctx, 1);

	SSL_CTX_free(p_ssl_ctx);
	
	return 0;
}