/**
 * @file cert_openssl.c
 * @brief 利用openssl api处理证书
 * @author zy
 * @date 2014-10-11 modify
 */
#include <stdio.h>
#include <unistd.h>

#include <openssl/pem.h>
#include <openssl/pkcs12.h>

#define CONTEXT_MAX_NUM 7
#define SERIAL_RAND_BITS 64

/**
* 描  述: 获取X509对象
* 参  数: @param[IN] cert_file  证书
* 返回值: X509对象
*/
X509* read_public_cert(const char* cert_file)
{
    X509 *x509 = NULL;
   
    FILE *fp = fopen (cert_file, "r");  
    if(!fp)
    {
        printf("read_public_cert, open cert failed!");
        return NULL;
    }

x509 = PEM_read_X509(fp, NULL, 0, NULL);

if(x509 == NULL)
    { 
        printf("read_public_cert, get x509 failed!");
        return NULL;  
    }

return x509;
}

/**
* 描  述: 获取公钥
* 参  数: @param[IN] cert_file  证书
* 返回值: 公钥
*/
EVP_PKEY * read_public_key(const char* cert_file)
{
    X509 *x509 = NULL;
    EVP_PKEY *pkey = NULL;

FILE *fp = fopen (cert_file, "r");  
    if(!fp)
    {
        printf("read_public_key, open cert failed!");
        return NULL;
    }

x509 = PEM_read_X509(fp, NULL, 0, NULL);

if(x509 == NULL)
    { 
        printf("read_public_key, get x509 failed!");
        return NULL;  
    }

fclose(fp);

pkey = X509_extract_key(x509);
    X509_free(x509);

if(pkey == NULL)
    {
        printf("read_public_key, get key failed!");
    }

return pkey;
}

/**
* 描  述: 获取私钥
* 参  数: @param[IN] key_file  证书
* 返回值: 私钥
*/
EVP_PKEY *read_private_key(const char* key_file)
{
    EVP_PKEY *pkey = NULL;
   
    FILE *fp = fopen(key_file, "r");
    if(!fp)
    {
        printf("read_private_key, open key failed!");
        return NULL;
    }

pkey = PEM_read_PrivateKey(fp, NULL, 0, NULL);

fclose(fp);

if (pkey == NULL)
    {
        printf("read_private_key, get key failed!");
    }

return pkey;
}

/**
* 描  述: 添加证书内容
* 参  数: @param[IN] name  X509_NAME
          @param[IN] ctx   使用者信息
          @param[IN] num   ctx数组长度
* 返回值: 1: 成功 0: 失败
*/
int add_cert_ctx(X509_NAME* name, char* ctx[], int num)
{
    int i = 0;
    int max = 0;

int item[] = {NID_commonName, NID_countryName,
        NID_stateOrProvinceName, NID_localityName,
        NID_organizationName, NID_organizationalUnitName,
        NID_pkcs9_emailAddress};

max = sizeof(item)/sizeof(item[0]);
    max = max > num ? num : max;

for(i=0; i<max; ++i)
    {
        if(!X509_NAME_add_entry_by_NID(name, item[i], MBSTRING_UTF8, ctx[i], -1, -1, 0))
        {
            printf("add_cert_ctx, add entry:%d to %s failed!", item[i], ctx[i]);
            return 0;
        }
    }

return 1;
}
 
/**
* 描  述: 创建证书密钥
* 参  数: @param[OUT] pkey  EVP_PKEY
          @param[IN] bits   密钥长度
* 返回值: 1: 成功 0: 失败
*/
int create_client_key(EVP_PKEY** pkey, int bits)
{
    RSA *rsa = NULL;
    EVP_PKEY *pk = NULL;

if((pk = EVP_PKEY_new()) == NULL)
    {
        printf("create_client_key, gen new key failed!");
        goto err;
    }

rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
    if(!EVP_PKEY_assign_RSA(pk, rsa))
    {
        printf("create_client_key, assign key failed!");
        EVP_PKEY_free(pk);
        goto err;
    }
    rsa = NULL;

*pkey = pk;
    return 1;
 
err:
    return 0;
}

/**
* 描  述: CA签发证书
* 参  数: @param[OUT] x509p      EVP_PKEY
    @param[OUT] pkey       X509
    @param[IN] ca_file      CA
    @param[IN] ca_key_file   CA密钥
    @param[IN] serial      序列号
          @param[IN] days        过期时长
* 返回值: 1: 成功 0: 失败
*/
int create_ca_signed_crt(X509** x509p, EVP_PKEY** pkey,
            const char* ca_file, const char* ca_key_file, const char* user, const int serial, const int days)
{
    X509* x = NULL;
    EVP_PKEY* pk = NULL;
    X509* xca = NULL;
    EVP_PKEY* xca_key = NULL;
    X509_NAME* name = NULL;
    //X509_NAME *tname = NULL;
    //char buf[256] = {0};
    char* ctx[] = {(char*)user, "bb", "cc", "dd", "ee", "ff", "ff@sf.com"};

if(!create_client_key(&pk, 2048))
    {
        printf("create_ca_signed_crt, gen key failed!");
        goto err;
    }

if((x = X509_new()) == NULL)
    {
        printf("create_ca_signed_crt, gen x509 failed!");
        goto err;
    }

xca = read_public_cert(ca_file);
    xca_key = read_private_key(ca_key_file);
    if(!X509_check_private_key(xca, xca_key))
    {
        printf("create_ca_signed_crt, check ca %s and key %s failed!", ca_file, ca_key_file);
        goto err;
    }

if(!X509_set_issuer_name(x, X509_get_subject_name(xca)))
    {
        printf("create_ca_signed_crt, set issuer failed!");
        goto err;
    }

ASN1_INTEGER_set(X509_get_serialNumber(x), serial);

if(X509_gmtime_adj(X509_get_notBefore(x), 0L) == NULL)
    {
        printf("create_ca_signed_crt, set cert begin time failed!");
        goto err;
    }

if(X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days) == NULL)
    {
        printf("create_ca_signed_crt, set cert expired time failed!");
        goto err;
    }

if(!X509_set_pubkey(x, pk))
    {
        printf("create_ca_signed_crt, set pubkey failed!");
        goto err;
    }

//tname = X509_get_subject_name(xca);
    //X509_NAME_get_text_by_NID(tname, NID_localityName, buf, 256);
    //printf("city: %s\n", buf);

name = X509_get_subject_name(x);
    if(!add_cert_ctx(name, ctx, CONTEXT_MAX_NUM))
    {
        printf("create_ca_signed_crt, add entry failed!");
        goto err;
    }

if(!X509_sign(x, xca_key, EVP_sha1()))
    {
        printf("create_ca_signed_crt, sign cert failed!");
        goto err;
    }

*pkey = pk;
    *x509p = x;
    return 1;
err:
    if(x)
        X509_free(x);
    if(pk)
        EVP_PKEY_free(pk);
   
    return 0;
}

/**
* 描  述: 创建P12证书
* 参  数: @param[IN] p12_file     p12
    @param[IN] p12_passwd   p12密码
    @param[IN] ca_file      CA
    @param[IN] ca_key_file   CA密钥
    @param[IN] serial      序列号
          @param[IN] days        过期时长
* 返回值: 1: 成功 0: 失败
*/
int create_p12_cert(char* p12_file, char* p12_passwd,
            const char* ca_file, const char* ca_key_file, const char* user, const int serial, const int days)
{
    int ret = 0;
    PKCS12* p12 = NULL;
    X509* cert = NULL;
    EVP_PKEY* pkey = NULL;
 FILE *fp = NULL;
 BIO *mem = NULL;
 char *mem_out = NULL;
 long len = 0;

SSLeay_add_all_algorithms();

if(!create_ca_signed_crt(&cert, &pkey, ca_file, ca_key_file, user, serial, days))
    {
        printf("create_p12_cert, create signed cert failed!");
        goto err;
    }

p12 = PKCS12_create(p12_passwd, NULL, pkey, cert, NULL, 0,0,0,0,0);
    if(!p12)
    {
        printf("create_p12_cert, create p12 object failed!");
        goto err;
    }

/*
    fp = fopen(p12_file, "wb");
    if(!fp)
    {
        printf("create_p12_cert, open/create p12 file failed!");
        goto err;
    }
    if(!i2d_PKCS12_fp(fp, p12))
    {
        printf("create_p12_cert, put p12 file failed!");
        goto err;
    }
 */
 
 fp = fopen(p12_file, "wb");
    if(!fp)
    {
        printf("create_p12_cert, open/create p12 file failed!");
        goto err;
    }
 
 mem = BIO_new(BIO_s_mem());
 if(!mem)
 {
  printf("create_p12_cert, BIO_new failed!");
        goto err;
 }
 
 i2d_PKCS12_bio(mem, p12);
 len = BIO_get_mem_data(mem, &mem_out);
 fwrite(mem_out, sizeof(char), len, fp);

ret = 1;
err:
    if(cert)
        X509_free(cert);
    if(pkey)
        EVP_PKEY_free(pkey);
    if (p12)
        PKCS12_free(p12);
 if (mem)
  BIO_free(mem);
    if(fp)
        fclose(fp);
   
    EVP_cleanup();
    return ret;
}

//openssl smime -sign -in unsign.mc -out signed.mc -signer ssl.crt -inkey ssl.key -certfile server.crt -outform der -nodetach
int sign_mobile_config(const char *inmc, int inlen, char **outmc, int *outlen,
 char *certfile, char *signerfile, char *keyfile)
{
    X509 *signer = NULL;
    EVP_PKEY *key = NULL;
    PKCS7 *p7 = NULL;
    X509 *cert = NULL;

BIO *in = NULL;
    BIO *out = NULL;
    STACK_OF(X509) * other = NULL;
   
    int mclen = 0;
    char *mc = NULL;
    char *tmp = NULL;

SSLeay_add_all_algorithms();
   
    // in
    in = BIO_new_mem_buf((char*)inmc, inlen); // BIO_write
    if (!in)
    {
        return -1;
    }

cert = read_public_cert(certfile);
  
   other = sk_X509_new_null();
   sk_X509_push(other, cert);

signer = read_public_cert(signerfile);
    key = read_private_key(keyfile);

if (!X509_check_private_key(signer, key))
    {
        printf("x509 check failed!\n");
        return -1;
    }
   
    p7 = PKCS7_sign(signer, key, other, in, 0);
    if (!p7)
     goto end;

// out
    out = BIO_new(BIO_s_mem());
    i2d_PKCS7_bio(out, p7);
    mclen = BIO_get_mem_data(out, &tmp);// BIO_read
    mc = (char*)malloc(mclen);
    memcpy(mc, tmp, mclen);
    *outmc = mc;
    *outlen = mclen;
       
end:
    sk_X509_pop_free(other, X509_free);
    X509_free(signer);
    EVP_PKEY_free(key);
    PKCS7_free(p7);
    BIO_free(in);
    BIO_free_all(out);

return 0;
}

int main()
{
 create_p12_cert("/root/out.p12", "1234", "/root/server_mdm.crt", "/root/server_mdm.key", "test", 0, 3650);
 return 0;
}

gcc -o test cert_openssl.c -L. -lcrypto

OpenSSL API 签发证书相关推荐

  1. 使用OpenSSL生成/签发证书的原理、流程与示例

    文章目录 1 生成证书的步骤与原理 2 标准的CA签发流程 2.1 创建私钥(.key) 2.2 基于私钥创建证书签名请求(.csr) 2.3 (可选)直接同时生成私钥和证书签名请求 2.4 将证书申 ...

  2. Linux 使用openssl ca方式签发证书

    前言 Linux 使用openssl x509方式签发证书(推荐用这种方式):https://blog.csdn.net/QianLiStudent/article/details/109818208 ...

  3. OpenSSL API

    /*** @file cert_openssl.c* @brief 利用openssl api处理证书* @author zy* @date 2014-10-11 modify*/ #include ...

  4. OpenSSL生成root CA及签发证书

    一.openssl 简介 openssl 是目前最流行的 SSL 密码库工具,其提供了一个通用.健壮.功能完备的工具套件,用以支持SSL/TLS 协议的实现.官网:https://www.openss ...

  5. openssl 自建CA签发证书 网站https的ssl通信

    <<COMMENT X509 文件扩展名 首先我们要理解文件的扩展名代表什么.DER.PEM.CRT和CER这些扩展名经常令人困惑. 很多人错误地认为这些扩展名可以互相代替.尽管的确有时候 ...

  6. OpenSSL签发证书时编码UTF8STRING PRINTABLESTRING不匹配

    问题如下: Check that the request matches the signature Signature ok The countryName field is different b ...

  7. openssl创建CA并签发证书

    一.创建私有CA根证书 1.创建CA目录 root@DESKTOP-JP3S3AN:/home/wsl/openssl_pro# mkdir -pv /etc/pki/CA/{private,cert ...

  8. 加密解密概述及openssl应用及其创建CA和签发证书的实现

    数据非常重要,这是大家的共识,为了保证数据的安全,就会涉及到加密及其解密,本文主要介绍加密 解密相关概念及其在Linux平台下加密解密的具体实现openssl基础,及openssl创建CA和签发证书: ...

  9. 使用 openssl 创建自签发证书,含 IP证书 及 泛域名证书

    web里面需要使用ssl才能使用,所以需要使用域名证书: 1. 创建根证书 创建秘钥 openssl genrsa -out LocalRootCA.key 2048 生成证书并自签名,nodes是不 ...

最新文章

  1. 操作系统常用词典(一)
  2. linux awk 教程,AWK简单使用方法
  3. airpods2使用_如何使用AirPods和AirPods Pro:完整指南
  4. JAVA进阶教学之(Object类中的hashCode方法)
  5. 数据分析告诉你为什么Apple Watch会大卖?
  6. 惠普打印机只打印一半_惠普打印机如何安装 惠普打印机加墨方法【介绍】
  7. nacos启动_nacos微服务注册中心
  8. android app启动过程
  9. C++ 将数据转为字符串的几种方法
  10. MFC开发IM-第二十八篇、acl 的编译与使用
  11. android sdk 环境签名,gradle打包APK,并使用jarsigner签名
  12. Java 图片处理解决方案:ImageMagick 快速入门教程
  13. data spring 指定时区_今天的工作内容:Spring Boot 2.X整合Spring-cache
  14. Atitit 网盘使用法 艾提拉著 目录 1. 需要解决几个问题 2 1.1. 多关键词搜索的问题 使用every索引解决 2 1.2. 重要文具类索引使用分类索引 日志 crm类增加000前缀
  15. 【知识图谱系列】PairNorm、DropEdge、DAGNN、Grand和GCNII五篇2020 Over-Smoothing论文综述
  16. 微信小程序 —— 成员管理及开发管理
  17. 2021年美容师(中级)考试题及美容师(中级)模拟考试
  18. 百鸡问题用计算机思维,大力出奇迹:当古代数学难题遇到现代计算机
  19. 你的年龄体重身高,最好别对这款 app 撒谎
  20. 医院门诊透视的生活万花筒

热门文章

  1. 微型计算机系统原理及应用实验,微型计算机系统原理及应用实验报告 .doc
  2. 网站备案和公安备案区别
  3. SSRF测试(Server Side Request Forgery)(owasp)
  4. 南京邮电大学计算机非全调剂,南京邮电大学2018年拟接收(非全日制)考研调剂公告...
  5. ATI显卡配置aticonfig和amdcccle全解
  6. [C语言]描述算法的工具——流程图
  7. 彻底卸载SQL Server2017
  8. 大数据精准营销(五)
  9. 高精密库仑计DS2740驱动程序
  10. 诺基亚智能手机的sis和jar格式游戏文件安装方法图解