• Mbedtls和Opesnssl 解码x509Certificate


     最近项目需要添加解码x509Certificate功能,可以使用openssl或者mbedtls库。对这两个库的使用总结一下。

    一 Openssl解码x509 Certificate

      1. 初始化

          将一段buffer转化成openssl格式

    const unsigned char* certificateValue = (unsigned char*)certificate->Value().data(); //这里的certificate是接收到的一段buffer
    X509* m_certificate = d2i_X509(nullptr, &certificateValue, certificate->Value().size());

      2. 获得版本号

    int32_t certVersion = X509_get_version(m_certificate);

        3. 获得序列号

    const ASN1_INTEGER* ans1SerialNum = X509_get_serialNumber(m_certificate);
    BIGNUM* bigSerialNUm = ASN1_INTEGER_to_BN(ans1SerialNum, nullptr);
    char* serialNum = BN_bn2hex(bigSerialNUm);
    serialNumber = std::string(serialNum, strlen(serialNum));
    BN_free(bigSerialNUm);
    OPENSSL_free(serialNum);

      4. 获得公钥类型

    const EVP_PKEY* pubKey = X509_get_pubkey(m_certificate);
    switch (pubKey->type) {
    case EVP_PKEY_RSA:
        type = X509CertPubKeyType::PUB_KEY_TYPE_RSA;
        break;
    case EVP_PKEY_EC:
        type = X509CertKeyAlgType::PUB_KEY_TYPE_ECKEY;
        break;
    case EVP_PKEY_DSA:
        type = X509CertKeyAlgType::PUB_KEY_TYPE_ECDSA;
        break;
    case EVP_PKEY_DH:
        type = X509CertKeyAlgType::PUB_KEY_TYPE_ECKEY_DH;
        break;
    default:
        type = X509CertKeyAlgType::PUB_KEY_TYPE_UNKNOWN;
        break;
    }

      5. 获得公钥使用类型

    X509_check_ca(m_certificate);
    if ((m_certificate->ex_kusage & KU_DATA_ENCIPHERMENT) == KU_DATA_ENCIPHERMENT) {
        type = X509CertKeyUseType::KEY_USE_TYPE_EXCH;
    }
    else if ((m_certificate->ex_kusage & KU_DIGITAL_SIGNATURE) == KU_DIGITAL_SIGNATURE) {
        type = X509CertKeyUseType::KEY_USE_TYPE_SIGN;
    }
    else {
        type = X509CertKeyUseType::KEY_USE_TYPE_UNKNOWN;
    }

      6. 获得签名算法类型

    const ASN1_OBJECT* signAlg = m_certificate->sig_alg.algorithm;
    const int32_t oidMaxLen = 128;
    char oid[oidMaxLen] = { 0 };
    OBJ_obj2txt(oid, oidMaxLen, signAlg, 1);
    std::string strOid(oid, strlen(oid));
    
    const std::string CERT_SIG_ALG_RSA_RSA = "1.2.840.113549.1.1.1";
    const std::string CERT_SIG_ALG_MD2RSA = "1.2.840.113549.1.1.2";
    const std::string CERT_SIG_ALG_MD4RSA = "1.2.840.113549.1.1.3";
    const std::string CERT_SIG_ALG_MD5RSA = "1.2.840.113549.1.1.4";
    const std::string CERT_SIG_ALG_SHA1RSA = "1.2.840.113549.1.1.5";
    const std::string CERT_SIG_ALG_SM3SM2 = "1.2.156.10197.1.501";
    
    if (strOid == CERT_SIG_ALG_RSA_RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_RSA_RSA;
    }
    else if (strOid == CERT_SIG_ALG_MD2RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_MD2RSA;
    }
    else if (strOid == CERT_SIG_ALG_MD4RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_MD4RSA;
    }
    else if (strOid == CERT_SIG_ALG_MD5RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_MD5RSA;
    }
    else if (strOid == CERT_SIG_ALG_SHA1RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_SHA1RSA;
    }
    else if (strOid == CERT_SIG_ALG_SM3SM2) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_SM3SM2;
    }
    else {
        type = X509CertSigAlgType::SIG_ALG_TYPE_UNKNOWN;
    }

      7. 获得发布者名字

    X509_NAME* issuerName = X509_get_issuer_name(m_certificate);
    name = ConvertName(issuerName); //自定义函数

      8. 获得证书持有者

    X509_NAME* subjectName = X509_get_subject_name(m_certificate);
    name = ConvertName(subjectName);

      9. 获得证书有效时间起点

    const ASN1_TIME* start = X509_get_notBefore(m_certificate);
    time = ConvertTime(start);//自定义函数

      10. 获得证书结束时间

    const ASN1_TIME* end = X509_get_notAfter(m_certificate);
    time = ConvertTime(end);

      11. 获得公钥使用

    const ASN1_BIT_STRING* keyUsage = (ASN1_BIT_STRING*)X509_get_ext_d2i(m_certificate, NID_key_usage, nullptr, nullptr);
    uint16_t val = keyUsage->data[0];
    if (keyUsage->length > 1) {
        val |= keyUsage->data[1] << 8;
    }
    if (val & MBEDTLS_X509_KU_DIGITAL_SIGNATURE) {
        usage += "Digital Signature, ";
    }
    if (val & MBEDTLS_X509_KU_NON_REPUDIATION) {
         usage += "Non-Repudiation, ";
    }
    if (val & MBEDTLS_X509_KU_KEY_ENCIPHERMENT) {
        usage += "Key Encipherment, ";
    }
    if (val & MBEDTLS_X509_KU_DATA_ENCIPHERMENT) {
        usage += "Data  Encipherment, ";
    }
    if (val & MBEDTLS_X509_KU_KEY_AGREEMENT) {
        usage += "Key  Agreement, ";
    }
    if (val & MBEDTLS_X509_KU_KEY_CERT_SIGN) {
        usage += "Certificate Signature, ";
    }
    if (val & MBEDTLS_X509_KU_CRL_SIGN) {
        usage += "CRL Signature, ";
    }
    const int32_t valMaxLen = 32;
    char value[valMaxLen] = { 0 };
    sprintf_s(value, valMaxLen, "(%x)", val);
    usage += std::string(value, strlen(value));

      12. 获得强化公钥使用

    EXTENDED_KEY_USAGE* enUsage = (EXTENDED_KEY_USAGE*)X509_get_ext_d2i(m_certificate, NID_ext_key_usage, nullptr, nullptr);
    for (int i = 0; i < sk_ASN1_OBJECT_num(enUsage); i++) {
        const int32_t objMaxLen = 128;
        char objId[objMaxLen] = { 0 };
        char objName[objMaxLen] = { 0 };
        const ASN1_OBJECT* obj = sk_ASN1_OBJECT_value(enUsage, i);
        OBJ_obj2txt(objId, sizeof(objId), obj, 1);
        OBJ_obj2txt(objName, sizeof(objName), obj, 0);
        if (!usage.empty()) {
            usage += "; ";
        }
        usage += objName + std::string(" (") + objId + ")";
    }
    sk_ASN1_OBJECT_pop_free(enUsage, ASN1_OBJECT_free);

      13. 获得基础限制

    BASIC_CONSTRAINTS* bcons = (BASIC_CONSTRAINTS*)X509_get_ext_d2i(m_certificate, NID_basic_constraints, nullptr, nullptr);
    if (bcons->ca == 0) {
        constraints += "Subject Type=End Entity; Path Length Constraint=None";
    }
    else {
        std::string pathLenConstraint = nullptr == bcons->pathlen ? "None" : std::string((char*)bcons->pathlen->data);
        constraints += "Subject Type=CA; " + std::string("Path Length Constraint=") + pathLenConstraint;
    }
    BASIC_CONSTRAINTS_free(bcons);

      14. 获得SAN

    STACK_OF(GENERAL_NAME)* extensions = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(m_certificate, NID_subject_alt_name, nullptr, nullptr);
    for (int i = 0; i < sk_GENERAL_NAME_num(extensions); i++) {
        const GENERAL_NAME* nval = sk_GENERAL_NAME_value(extensions, i);
        if (nval->type == GEN_DNS) {
            const unsigned char* dnsName = ASN1_STRING_get0_data(nval->d.dNSName);
            dnsNames.push_back("DNS Name=" + std::string((const char*)dnsName));
        }
        else if (nval->type == GEN_IPADD) {
            const unsigned char* ipAddr = ASN1_STRING_get0_data(nval->d.iPAddress);
            ipAddrs.push_back("IP Address=" + ConvertIpAddr(ipAddr));//ConvertIpAddr是自定义函数
        }
        else if (nval->type == GEN_URI) {
            const unsigned char* uri = ASN1_STRING_get0_data(nval->d.uniformResourceIdentifier);
            uris.push_back("URL=" + std::string((const char*)uri));
        }
        else if (nval->type == GEN_DIRNAME) {
            X509_NAME* dirName = nval->d.directoryName;
            dirNames.push_back("Directory Name=" + ConvertName(dirName));
        }
        else if (nval->type == GEN_EMAIL) {
            const unsigned char* email = ASN1_STRING_get0_data(nval->d.rfc822Name);
            emails.push_back("RFC822 Name=" + std::string((const char*)email));
        }
    }
    sk_GENERAL_NAME_pop_free(extensions, GENERAL_NAME_free)

      15. 自定义函数ConvertName

    std::string ConvertName(X509_NAME * name)
    {
        if (nullptr == name) {
          return "";
        }
        const int32_t partNameMaxLen = 256;
        char partName[partNameMaxLen] = { 0 };
        std::string strName;
        int returnLen = X509_NAME_get_text_by_NID(name, NID_countryName, partName, partNameMaxLen);
        if (returnLen > 0) {
            strName += "C=" + std::string(partName, strlen(partName)) + ", ";
        }
        memset(partName, 0, partNameMaxLen);
        returnLen = X509_NAME_get_text_by_NID(name, NID_organizationalUnitName, partName, partNameMaxLen);
        if (returnLen > 0) {
            strName += "OU=" + std::string(partName, strlen(partName)) + ", ";
        }
        memset(partName, 0, partNameMaxLen);
            returnLen = X509_NAME_get_text_by_NID(name, NID_commonName, partName, partNameMaxLen);
        if (returnLen > 0) {
            strName += "CN=" + std::string(partName, strlen(partName));
        }
    
        return strName;
    }

      16. 自定义函数ConvertTime

    std::string ConvertTime(const ASN1_TIME * time)
    {
        if (nullptr == time) {
            return "";
        }
        std::shared_ptr<tm> tmTime(new tm());
        int res = ASN1_TIME_to_tm(time, tmTime.get());
        if (res == 0) {
            return "";
        }
        const int32_t bufMaxLen = 256;
        char buf[bufMaxLen] = { 0 };
        int32_t basicYear = 1900;
        int32_t basicMon = 1;
        int32_t basicDay = 0;
        int32_t basicHour = 8;
        int32_t basicMin = 0;
        int32_t basicSec = 0;
        #ifdef _WIN32
        sprintf_s(buf, "%d-%d-%d %d:%d:%d", tmTime->tm_year + basicYear, tmTime->tm_mon + basicMon, tmTime->tm_mday + basicDay,
        tmTime->tm_hour + basicHour, tmTime->tm_min + basicMin, tmTime->tm_sec + basicSec);
        #else
        sprintf(buf, "%d-%d-%d %d:%d:%d", tmTime->tm_year + basicYear, tmTime->tm_mon + basicMon, tmTime->tm_mday + basicDay,
        tmTime->tm_hour + basicHour, tmTime->tm_min + basicMin, tmTime->tm_sec + basicSec);
        #endif
        return std::string(buf, strlen(buf));
    }

      17. 自定义函数ConvertIp

    std::string ConvertIpAddr(const unsigned char* ipv4octet)
    {
        if (nullptr == ipv4octet) {
            return "";
        }
        std::string ipAddr;
        for (auto i = 0; i < 4; i++)
        {
            if (!ipAddr.empty())
            {
                ipAddr += '.';
            }
    
            char bits[4] = { 0 };
        #ifdef _WIN32
            sprintf_s(bits, sizeof(bits), "%d", ipv4octet[i]);
        #else
            snprintf(bits, sizeof(bits), "%d", ipv4octet[i]);
        #endif // _WIN32
            ipAddr.append(bits);
        }
        return ipAddr;
    }

    二 Mbedtls解码x509 Certificate

    mbedtls的相关资料很少,自己也是研究了很长时间。并且SAN只支持Hostname

      1. 初始化

          将一段buffer转化成mbedtls类型

    mbedtls_x509_crt_init(m_certificate);
    uint32_t status = mbedtls_x509_crt_parse(m_certificate, (const unsigned char*)certificate->Value().data(), certificate->Value().size());

      2. 获得版本号

    int32_t certVersion = m_certificate->version;

      3. 获得序列号

    mbedtls_mpi mpi;
    mbedtls_mpi_init(&mpi);
    uint32_t status = mbedtls_mpi_read_binary(&mpi, m_certificate->serial.p, m_certificate->serial.len);
    const int32_t strMaxLen = 128;
    char str[strMaxLen] = { 0 };
    size_t returnLen;
    uint32_t radix = 16;
    status = mbedtls_mpi_write_string(&mpi, radix, str, strMaxLen, &returnLen);
    serialNumber = std::string(str, strlen(str));
    mbedtls_mpi_free(&mpi);

      4. 获得公钥类型

    mbedtls_pk_type_t pubKeyType = mbedtls_pk_get_type(&m_certificate->pk);
    switch (pubKeyType) {
    case mbedtls_pk_type_t::MBEDTLS_PK_RSA:
        type = X509CertPubKeyType::PUB_KEY_TYPE_RSA;
        break;
    case mbedtls_pk_type_t::MBEDTLS_PK_ECKEY:
        type = X509CertPubKeyType::PUB_KEY_TYPE_ECKEY;
        break;
    case mbedtls_pk_type_t::MBEDTLS_PK_ECKEY_DH:
        type = X509CertPubKeyType::PUB_KEY_TYPE_ECKEY_DH;
        break;
    case mbedtls_pk_type_t::MBEDTLS_PK_ECDSA:
        type = X509CertPubKeyType::PUB_KEY_TYPE_ECDSA;
        break;
    case mbedtls_pk_type_t::MBEDTLS_PK_RSA_ALT:
        type = X509CertPubKeyType::PUB_KEY_TYPE_RSA_ALT;
        break;
    case mbedtls_pk_type_t::MBEDTLS_PK_RSASSA_PSS:
        type = X509CertPubKeyType::PUB_KEY_TYPE_RSASSA_PSS;
        break;
    default:
        type = X509CertPubKeyType::PUB_KEY_TYPE_UNKNOWN;
        break;
    }

      5. 获得公钥使用类型

    if ((m_certificate->key_usage & MBEDTLS_X509_KU_DATA_ENCIPHERMENT) == MBEDTLS_X509_KU_DATA_ENCIPHERMENT) {
        type = X509CertKeyUseType::KEY_USE_TYPE_EXCH;
    }
    else if ((m_certificate->key_usage & MBEDTLS_X509_KU_DIGITAL_SIGNATURE) == MBEDTLS_X509_KU_DIGITAL_SIGNATURE) {
        type = X509CertKeyUseType::KEY_USE_TYPE_SIGN;
    }
    else {
        type = X509CertKeyUseType::KEY_USE_TYPE_UNKNOWN;
    }

      6. 获得签名算法类型

    mbedtls_md_type_t mdType;
    mbedtls_pk_type_t pkType;
    uint32_t status = mbedtls_oid_get_sig_alg(&m_certificate->sig_oid, &mdType, &pkType);
    if (mdType == MBEDTLS_MD_MD2 && pkType == MBEDTLS_PK_RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_MD2RSA;
    }
    else if (mdType == MBEDTLS_MD_MD4 && pkType == MBEDTLS_PK_RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_MD4RSA;
    }
    else if (mdType == MBEDTLS_MD_MD5 && pkType == MBEDTLS_PK_RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_MD5RSA;
    }
    else if (mdType == MBEDTLS_MD_SHA1 && pkType == MBEDTLS_PK_RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_SHA1RSA;
    }
    else if (mdType == MBEDTLS_MD_SHA224 && pkType == MBEDTLS_PK_RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_SHA224RSA;
    }
    else if (mdType == MBEDTLS_MD_SHA256 && pkType == MBEDTLS_PK_RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_SHA256RSA;
    }
    else if (mdType == MBEDTLS_MD_SHA384 && pkType == MBEDTLS_PK_RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_SHA384RSA;
    }
    else if (mdType == MBEDTLS_MD_SHA512 && pkType == MBEDTLS_PK_RSA) {
        type = X509CertSigAlgType::SIG_ALG_TYPE_SHA512RSA;
    }
    else {
        type = X509CertSigAlgType::SIG_ALG_TYPE_UNKNOWN;
    }

      7. 获得发布者名字

    const char* shortName = nullptr;
    uint32_t status = OpcUa_Good;
    do{
         if (MBEDTLS_ASN1_UTF8_STRING != m_certificate->issuer.val.tag) {
            continue;
         }
        status = mbedtls_oid_get_attr_short_name(&m_certificate->issuer.oid, &shortName);
        name += shortName + std::string("=") + std::string((char*)m_certificate->issuer.val.p, m_certificate->issuer.val.len);
    }while (nullptr != m_certificate->issuer.next);

      8. 获得证书持有者

    const char* shortName = nullptr;
    uint32_t status = OpcUa_Good;
    do {
       if (MBEDTLS_ASN1_UTF8_STRING != m_certificate->subject.val.tag)         
       {
           continue;
       }
       status = mbedtls_oid_get_attr_short_name(&m_certificate->subject.oid, &shortName);    
       name += shortName + std::string("=") + std::string((char*)m_certificate->subject.val.p, m_certificate->subject.val.len);
    } while (nullptr != m_certificate->subject.next);  

      9. 获得证书起始时间

    const int32_t bufMaxLen = 256;
    char buf[bufMaxLen] = { 0 };
    uint32_t basicHour = 8;
    sprintf_s(buf, "%d-%d-%d %d:%d:%d", m_certificate->valid_from.year, m_certificate->valid_from.mon, m_certificate->valid_from.day,
            m_certificate->valid_from.hour + basicHour, m_certificate->valid_from.min, m_certificate->valid_from.sec);
    time = std::string(buf, strlen(buf));

      10. 获得证书结束时间

    const int32_t bufMaxLen = 256;
    char buf[bufMaxLen] = { 0 };
    uint32_t basicHour = 8;
    sprintf_s(buf, "%d-%d-%d %d:%d:%d", m_certificate->valid_to.year, m_certificate->valid_to.mon, m_certificate->valid_to.day,
            m_certificate->valid_to.hour + basicHour, m_certificate->valid_to.min, m_certificate->valid_to.sec);
    time = std::string(buf, strlen(buf));

      11. 获得证书使用

    uint32_t val = m_certificate->key_usage;
    if (val & MBEDTLS_X509_KU_DIGITAL_SIGNATURE) {
        usage += "Digital Signature, ";
    }
    if (val & MBEDTLS_X509_KU_NON_REPUDIATION) {
        usage += "Non-Repudiation, ";
    }
    if (val & MBEDTLS_X509_KU_KEY_ENCIPHERMENT) {
        usage += "Key Encipherment, ";
    }
    if (val & MBEDTLS_X509_KU_DATA_ENCIPHERMENT) {
        usage += "Data  Encipherment, ";
    }
    if (val & MBEDTLS_X509_KU_KEY_AGREEMENT) {
        usage += "Key  Agreement, ";
    }
    if (val & MBEDTLS_X509_KU_KEY_CERT_SIGN) {
        usage += "Certificate Signature, ";
    }
    if (val & MBEDTLS_X509_KU_CRL_SIGN) {
        usage += "CRL Signature, ";
    }
    const int32_t valMaxLen = 32;
    char value[valMaxLen] = { 0 };
    sprintf_s(value, valMaxLen, "(%x)", val);
    usage += std::string(value, strlen(value));

      12. 获得强化公钥使用

    mbedtls_x509_sequence* enKeyUsage = &m_certificate->ext_key_usage;
    while( nullptr != enKeyUsage) {             
        const char* des = nullptr;
        uint32_t status = mbedtls_oid_get_extended_key_usage(&enKeyUsage->buf, &des);
        const int valMaxLen = 128;
        char val[valMaxLen] = { 0 };
        status = mbedtls_oid_get_numeric_string(val, valMaxLen, &enKeyUsage->buf);
        if (!usage.empty()) {
            usage += ";";
        }
        usage += des + std::string(" (") + std::string(val, strlen(val)) + ")";
        enKeyUsage = enKeyUsage->next;
    } 

      13. 获得基础限制

    if (m_certificate->ca_istrue == 0) {
        constraints = "Subject Type=End Entity; Path Length Constraint=None";
    }
    else {
        std::string pathLenConstraint = 0 == m_certificate->max_pathlen ? "None" : std::to_string(m_certificate->max_pathlen);
        constraints += "Subject Type=CA; " + std::string("Path Length Constraint=") + pathLenConstraint;
    }

      14. 获得SAN(仅支持Hostname)

    mbedtls_asn1_sequence* san = &m_certificate->subject_alt_names;
    while (nullptr != san) {
        dnsNames.push_back(std::string((char*)san->buf.p, san->buf.len));//dsnNames类型是std::vector<std::string>
        san = san->next;
    }

    纯原创,参考请标明出处,谢谢!!

    愿有志之人,成就非凡之事。
  • 相关阅读:
    最简单方式理解为什么MongoDB索引选择B-树,而 Mysql 选择B+树
    单点登录基本原理
    我是这样理解HTTP和HTTPS区别的
    数据库mvvc的简单理解
    mysql数据库一些知识点
    一条SQL完成跨数据库实例Join查询
    api接口安全性设计
    Redis-Scan命令
    分布式缓存的基本原理
    记录主从延迟造成数据查询不准确的问题
  • 原文地址:https://www.cnblogs.com/damon-song/p/13762917.html
Copyright © 2020-2023  润新知