MbedtlsおよびOpenssl復号x 509 Certificate
52969 ワード
最近のプロジェクトでは、opensslまたはmbedtlsライブラリを使用することができるx 509 Certificate機能を復号する必要があります.この2つのライブラリの使用についてまとめます.
Openssl復号x 509 Certificate
1. 初期化
bufferをopenssl形式に変換
2. バージョン番号の取得
3. シリアル番号の取得
4. 公開鍵タイプの取得
5. 公開鍵使用タイプの取得
6. 署名アルゴリズムタイプの取得
7. パブリッシャ名の取得
8. 証明書所有者の取得
9. 証明書有効時間の開始点の取得
10. 証明書取得終了時間
11. 公開鍵の使用を取得
12. 強化された公開鍵の使用を取得
13. 基本的な制限の取得
14. SANの入手
15. カスタム関数ConvertName
16. カスタム関数ConvertTime
17. カスタム関数ConvertIp
2 Mbedtls復号x 509 Certificate
mbedtlsに関する資料は少なく、自分も長い間研究してきた.SANはHostnameのみをサポートしています
1. 初期化
bufferをmbedtlsタイプに変換
2. バージョン番号の取得
3. シリアル番号の取得
4. 公開鍵タイプの取得
5. 公開鍵使用タイプの取得
6. 署名アルゴリズムタイプの取得
7. パブリッシャ名の取得
8. 証明書所有者の取得
9. 証明書取得開始時間
10. 証明書取得終了時間
11. 証明書の使用
12. 強化された公開鍵の使用を取得
13. 基本的な制限の取得
14. SANの取得(Hostnameのみサポート)
純オリジナル、参考は出典を明記してください、ありがとうございます!!
Openssl復号x 509 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 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;
}
2 Mbedtls復号x 509 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<:string/>
san = san->next;
}
純オリジナル、参考は出典を明記してください、ありがとうございます!!