最近项目需要添加解码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; }
纯原创,参考请标明出处,谢谢!!
愿有志之人,成就非凡之事。