/* Copyright 2021 - 2025 R. Thomas * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "LIEF/BinaryStream/ASN1Reader.hpp" #include "LIEF/BinaryStream/BinaryStream.hpp" #include "logging.hpp" #include #include #include #include #include #include #include extern "C" { int mbedtls_x509_get_name(unsigned char **p, const unsigned char *end, mbedtls_x509_name *cur); int mbedtls_x509_get_time(unsigned char **p, const unsigned char *end, mbedtls_x509_time *t); int mbedtls_x509_get_serial(unsigned char **p, const unsigned char *end, mbedtls_x509_buf *serial); } namespace LIEF { inline void free_names(mbedtls_x509_name& names) { mbedtls_x509_name *name_cur; name_cur = names.next; while (name_cur != nullptr) { mbedtls_x509_name *name_prv = name_cur; name_cur = name_cur->next; mbedtls_free(name_prv); } } result ASN1Reader::is_tag(int tag) { size_t out = 0; uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_asn1_get_tag(&p, end, &out, tag); if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) { return make_error_code(lief_errors::read_out_of_bound); } if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { return false; } if (ret != 0) { return make_error_code(lief_errors::read_error); } return true; } result ASN1Reader::read_tag(int tag) { size_t out = 0; const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_asn1_get_tag(&p, end, &out, tag); if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) { return make_error_code(lief_errors::read_out_of_bound); } if (ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { return make_error_code(lief_errors::asn1_bad_tag); } if (ret != 0) { std::string strerr(1024, 0); mbedtls_strerror(ret, const_cast(strerr.data()), strerr.size()); LIEF_DEBUG("mbedtls_asn1_get_tag: {}", strerr.c_str()); return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return out; } result ASN1Reader::read_len() { size_t len = 0; const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_asn1_get_len(&p, end, &len); if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) { return make_error_code(lief_errors::read_out_of_bound); } if (ret != 0) { return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return len; } result ASN1Reader::read_alg() { mbedtls_asn1_buf alg_oid; std::array oid_str = {0}; const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_asn1_get_alg_null(&p, end, &alg_oid); if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) { return make_error_code(lief_errors::read_out_of_bound); } if (ret != 0) { return make_error_code(lief_errors::read_error); } ret = mbedtls_oid_get_numeric_string(oid_str.data(), oid_str.size(), &alg_oid); if (ret <= 0) { return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return std::string(oid_str.data()); } result ASN1Reader::read_oid() { mbedtls_asn1_buf buf; std::array oid_str = {0}; auto len = read_tag(MBEDTLS_ASN1_OID); if (!len) { return make_error_code(len.error()); } buf.len = len.value(); buf.p = stream_.p(); buf.tag = MBEDTLS_ASN1_OID; int ret = mbedtls_oid_get_numeric_string(oid_str.data(), oid_str.size(), &buf); if (ret == MBEDTLS_ERR_OID_BUF_TOO_SMALL) { LIEF_DEBUG("asn1_read_oid: mbedtls_oid_get_numeric_string return MBEDTLS_ERR_OID_BUF_TOO_SMALL"); return make_error_code(lief_errors::read_error); } stream_.increment_pos(buf.len); return std::string(oid_str.data()); } result ASN1Reader::read_bool() { int value; const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_asn1_get_bool(&p, end, &value); if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) { return make_error_code(lief_errors::read_out_of_bound); } if (ret != 0) { std::string strerr(1024, 0); mbedtls_strerror(ret, const_cast(strerr.data()), strerr.size()); LIEF_DEBUG("mbedtls_asn1_get_bool: {}", strerr.c_str()); return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return static_cast(value); } result> ASN1Reader::read_large_int() { std::vector value; mbedtls_mpi mpi; mbedtls_mpi_init(&mpi); const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_asn1_get_mpi(&p, end, &mpi); if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) { return make_error_code(lief_errors::read_out_of_bound); } if (ret != 0) { std::string strerr(1024, 0); mbedtls_strerror(ret, const_cast(strerr.data()), strerr.size()); LIEF_DEBUG("mbedtls_asn1_get_mpi: {}", strerr.c_str()); return make_error_code(lief_errors::read_error); } value.resize(mbedtls_mpi_size(&mpi)); ret = mbedtls_mpi_write_binary_le(&mpi, value.data(), value.size()); mbedtls_mpi_free(&mpi); if (ret != 0) { std::string strerr(1024, 0); mbedtls_strerror(ret, const_cast(strerr.data()), strerr.size()); LIEF_DEBUG("mbedtls_asn1_get_mpi: {}", strerr.c_str()); return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return value; } result ASN1Reader::read_int64() { int64_t value = 0; mbedtls_mpi mpi; mbedtls_mpi_init(&mpi); const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_asn1_get_mpi(&p, end, &mpi); if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) { return make_error_code(lief_errors::read_out_of_bound); } if (ret != 0) { std::string strerr(1024, 0); mbedtls_strerror(ret, const_cast(strerr.data()), strerr.size()); LIEF_DEBUG("mbedtls_asn1_get_mpi: {}", strerr.c_str()); return make_error_code(lief_errors::read_error); } if (mbedtls_mpi_size(&mpi) > sizeof(uint64_t)) { mbedtls_mpi_free(&mpi); LIEF_INFO("MPI value can be stored on a 64-bit integer"); return make_error_code(lief_errors::read_error); } ret = mbedtls_mpi_write_binary_le(&mpi, reinterpret_cast(&value), sizeof(value)); mbedtls_mpi_free(&mpi); if (ret != 0) { std::string strerr(1024, 0); mbedtls_strerror(ret, const_cast(strerr.data()), strerr.size()); LIEF_DEBUG("mbedtls_asn1_get_mpi: {}", strerr.c_str()); return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return value; } result ASN1Reader::read_int() { int32_t value = 0; const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_asn1_get_int(&p, end, &value); if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) { return make_error_code(lief_errors::read_out_of_bound); } if (ret != 0) { std::string strerr(1024, 0); mbedtls_strerror(ret, const_cast(strerr.data()), strerr.size()); LIEF_DEBUG("mbedtls_asn1_get_int: {}", strerr.c_str()); return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return value; } result> ASN1Reader::read_bitstring() { mbedtls_asn1_bitstring bs = {0, 0, nullptr}; const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_asn1_get_bitstring(&p, end, &bs); if (ret == MBEDTLS_ERR_ASN1_OUT_OF_DATA) { return make_error_code(lief_errors::read_out_of_bound); } if (ret == MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) { stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return std::vector{bs.p, bs.p + bs.len}; } if (ret != 0) { return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return std::vector{bs.p, bs.p + bs.len}; } result> ASN1Reader::read_octet_string() { auto tag = read_tag(MBEDTLS_ASN1_OCTET_STRING); if (!tag) { return make_error_code(tag.error()); } std::vector raw = {stream_.p(), stream_.p() + tag.value()}; stream_.increment_pos(tag.value()); return raw; } result> ASN1Reader::read_cert() { std::unique_ptr ca{new mbedtls_x509_crt{}}; mbedtls_x509_crt_init(ca.get()); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); const uintptr_t buff_len = reinterpret_cast(end) - reinterpret_cast(p); int ret = mbedtls_x509_crt_parse_der(ca.get(), p, /* buff len */ buff_len); if (ret != 0) { std::string strerr(1024, 0); mbedtls_strerror(ret, const_cast(strerr.data()), strerr.size()); LIEF_DEBUG("asn1_read_cert(): {} (pos={})", strerr.c_str(), stream_.pos()); return make_error_code(lief_errors::read_error); } if (ca->raw.len <= 0) { return make_error_code(lief_errors::read_error); } stream_.increment_pos(ca->raw.len); return ca; } result ASN1Reader::x509_read_names() { mbedtls_x509_name name; std::memset(&name, 0, sizeof(name)); auto tag = read_tag(/* Name */ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (!tag) { LIEF_INFO("Wrong tag: 0x{:x} for x509_read_names (pos: {:d})", *stream_.peek(), stream_.pos()); return make_error_code(tag.error()); } const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = p + tag.value(); int ret = mbedtls_x509_get_name(&p, end, &name); if (ret != 0) { free_names(name); LIEF_DEBUG("mbedtls_x509_get_name failed with {:d}", ret); return make_error_code(lief_errors::read_error); } std::array buffer = {0}; ret = mbedtls_x509_dn_gets(buffer.data(), buffer.size(), &name); free_names(name); if (ret < 0) { return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return std::string(buffer.data()); } result> ASN1Reader::x509_read_serial() { mbedtls_x509_buf serial; const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_x509_get_serial(&p, end, &serial); if (ret != 0) { return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return std::vector{serial.p, serial.p + serial.len}; } result> ASN1Reader::x509_read_time() { std::unique_ptr tm{new mbedtls_x509_time{}}; const uint8_t* cur_p = stream_.p(); uint8_t* p = stream_.p(); const uint8_t* end = stream_.end(); int ret = mbedtls_x509_get_time(&p, end, tm.get()); if (ret != 0) { std::string strerr(1024, 0); mbedtls_strerror(ret, const_cast(strerr.data()), strerr.size()); LIEF_INFO("mbedtls_x509_get_time: {}", strerr.c_str()); return make_error_code(lief_errors::read_error); } stream_.increment_pos(reinterpret_cast(p) - reinterpret_cast(cur_p)); return tm; } result ASN1Reader::read_utf8_string() { auto tag = read_tag(MBEDTLS_ASN1_UTF8_STRING); if (!tag) { return make_error_code(tag.error()); } std::string raw = {stream_.p(), stream_.p() + tag.value()}; stream_.increment_pos(tag.value()); return raw; } std::string ASN1Reader::get_str_tag() { if (auto tag = stream_.peek()) { return tag2str(*tag); } return "MBEDTLS_ASN1_UNKNOWN"; } std::string ASN1Reader::tag2str(int tag) { #define HANDLE(X) do { \ if (tag & MBEDTLS_##X) { \ tag_str += " | " #X; \ } \ } while(0) std::string tag_str; HANDLE(ASN1_BOOLEAN); HANDLE(ASN1_INTEGER); HANDLE(ASN1_BIT_STRING); HANDLE(ASN1_OCTET_STRING); HANDLE(ASN1_NULL); HANDLE(ASN1_OID); HANDLE(ASN1_ENUMERATED); HANDLE(ASN1_UTF8_STRING); HANDLE(ASN1_SEQUENCE); HANDLE(ASN1_SET); HANDLE(ASN1_PRINTABLE_STRING); HANDLE(ASN1_T61_STRING); HANDLE(ASN1_IA5_STRING); HANDLE(ASN1_UTC_TIME); HANDLE(ASN1_GENERALIZED_TIME); HANDLE(ASN1_UNIVERSAL_STRING); HANDLE(ASN1_BMP_STRING); HANDLE(ASN1_PRIMITIVE); HANDLE(ASN1_CONSTRUCTED); HANDLE(ASN1_CONTEXT_SPECIFIC); if (tag_str.size() < 3) { return "MBEDTLS_ASN1_UNKNOWN"; } return tag_str.substr(3); #undef HANDLE } }