MbedtlsおよびOpenssl復号x 509 Certificate

52969 ワード

最近のプロジェクトでは、opensslまたはmbedtlsライブラリを使用することができるx 509 Certificate機能を復号する必要があります.この2つのライブラリの使用についてまとめます.
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;
}

純オリジナル、参考は出典を明記してください、ありがとうございます!!