diff --git a/librz/bin/format/pe/pe_security.c b/librz/bin/format/pe/pe_security.c index b2befe20949..4f6ad444db8 100644 --- a/librz/bin/format/pe/pe_security.c +++ b/librz/bin/format/pe/pe_security.c @@ -11,6 +11,9 @@ static const char *PE_(bin_pe_get_claimed_authentihash)(RzBinPEObj *bin) { return NULL; } RASN1Binary *digest = bin->spcinfo->messageDigest.digest; + if (!digest) { + return NULL; + } return rz_hex_bin2strdup(digest->binary, digest->length); } @@ -19,7 +22,7 @@ static ut64 buf_fwd_hash(const ut8 *buf, ut64 size, void *user) { } char *PE_(bin_pe_compute_authentihash)(RzBinPEObj *bin) { - if (!bin->spcinfo) { + if (!bin->spcinfo || !bin->spcinfo->messageDigest.digestAlgorithm.algorithm) { return NULL; } @@ -131,7 +134,12 @@ int PE_(bin_pe_init_security)(RzBinPEObj *bin) { if (!bin->cms && cert->wCertificateType == PE_WIN_CERT_TYPE_PKCS_SIGNED_DATA) { bin->cms = rz_pkcs7_parse_cms(cert->bCertificate, cert->dwLength - 6); - bin->spcinfo = rz_pkcs7_parse_spcinfo(bin->cms); + bin->spcinfo = bin->cms ? rz_pkcs7_parse_spcinfo(bin->cms) : NULL; + } + if (!bin->cms || !bin->spcinfo) { + RZ_FREE(cert->bCertificate); + RZ_FREE(cert); + return false; } security_directory->certificates[security_directory->length] = cert; diff --git a/librz/core/cmd/cmd_print.c b/librz/core/cmd/cmd_print.c index 6ffa48e7105..b5273522627 100644 --- a/librz/core/cmd/cmd_print.c +++ b/librz/core/cmd/cmd_print.c @@ -1074,7 +1074,7 @@ static void cmd_print_fromage(RzCore *core, const char *input, const ut8 *data, switch (*input) { case 'a': { asn1_setformat(input[1] != 'q'); - RASN1Object *asn1 = rz_asn1_create_object(data, size, data); + RASN1Object *asn1 = rz_asn1_create_object(data, size); if (asn1) { char *res = rz_asn1_to_string(asn1, 0, NULL); rz_asn1_free_object(asn1); @@ -1088,7 +1088,8 @@ static void cmd_print_fromage(RzCore *core, const char *input, const ut8 *data, } break; case 'x': // "pFx" x509 { - RX509Certificate *x509 = rz_x509_parse_certificate(rz_asn1_create_object(data, size, data)); + RASN1Object *object = rz_asn1_create_object(data, size); + RX509Certificate *x509 = rz_x509_parse_certificate(object); if (x509) { RzStrBuf *sb = rz_strbuf_new(""); rz_x509_certificate_dump(x509, NULL, sb); diff --git a/librz/include/rz_util/rz_asn1.h b/librz/include/rz_util/rz_asn1.h index 0e05921389e..4943f630dca 100644 --- a/librz/include/rz_util/rz_asn1.h +++ b/librz/include/rz_util/rz_asn1.h @@ -86,7 +86,7 @@ typedef struct rz_asn1_object_t { ASN1List list; /* List of objects contained in the sector */ } RASN1Object; -RZ_API RASN1Object *rz_asn1_create_object(const ut8 *buffer, ut32 length, const ut8 *start_pointer); +RZ_API RASN1Object *rz_asn1_create_object(RZ_NONNULL const ut8 *buffer, ut32 length); RZ_API RASN1Binary *rz_asn1_create_binary(const ut8 *buffer, ut32 length); RZ_API RASN1String *rz_asn1_create_string(const char *string, bool allocated, ut32 length); RZ_API RASN1String *rz_asn1_stringify_bits(const ut8 *buffer, ut32 length); diff --git a/librz/util/asn1.c b/librz/util/asn1.c index 843a286b79d..e9a3c5ee6b2 100644 --- a/librz/util/asn1.c +++ b/librz/util/asn1.c @@ -13,7 +13,7 @@ RZ_API void asn1_setformat(int fmt) { ASN1_STD_FORMAT = fmt; } -static ut32 asn1_ber_indefinite(const ut8 *buffer, ut32 length) { +static ut64 asn1_ber_indefinite(const ut8 *buffer, ut64 length) { if (!buffer || length < 3) { return 0; } @@ -25,8 +25,8 @@ static ut32 asn1_ber_indefinite(const ut8 *buffer, ut32 length) { } if (next[0] == 0x80 && (next[-1] & ASN1_FORM) == FORM_CONSTRUCTED) { next--; - int sz = asn1_ber_indefinite(next, end - next); - if (sz < 1) { + st64 sz = (st64)asn1_ber_indefinite(next, end - next); + if (sz < (st64)1) { break; } next += sz; @@ -36,9 +36,9 @@ static ut32 asn1_ber_indefinite(const ut8 *buffer, ut32 length) { return (next - buffer) + 2; } -static RASN1Object *asn1_parse_header(const ut8 *buffer, ut32 length, const ut8 *start_pointer) { +static RASN1Object *asn1_parse_header(const ut8 *buffer, ut64 length, const ut8 *start_pointer) { ut8 head, length8, byte; - ut64 length64; + ut64 length64, remaining; if (!buffer || length < 2) { return NULL; } @@ -48,45 +48,49 @@ static RASN1Object *asn1_parse_header(const ut8 *buffer, ut32 length, const ut8 return NULL; } head = buffer[0]; - object->offset = start_pointer ? (buffer - start_pointer) : 0; + object->offset = buffer - start_pointer; object->klass = head & ASN1_CLASS; object->form = head & ASN1_FORM; object->tag = head & ASN1_TAG; length8 = buffer[1]; + remaining = length - 2; if (length8 & ASN1_LENLONG) { length64 = 0; length8 &= ASN1_LENSHORT; object->sector = buffer + 2; - if (length8 && length8 < length - 2) { - ut8 i8; + if (length8 && length8 < remaining) { + remaining -= length8; // can overflow. - for (i8 = 0; i8 < length8; i8++) { + for (ut8 i8 = 0; i8 < length8; i8++) { byte = buffer[2 + i8]; length64 <<= 8; length64 |= byte; - if (length64 > length) { + if (length64 > remaining) { + // Malformed object - overflow from data ptr goto out_error; } } object->sector += length8; } else { - length64 = asn1_ber_indefinite(object->sector, length - 2); + length64 = asn1_ber_indefinite(object->sector, remaining); + if (length64 > remaining) { + // Malformed object - overflow from data ptr + goto out_error; + } } object->length = (ut32)length64; } else { + if (length8 > remaining) { + // Malformed object - overflow from data ptr + goto out_error; + } object->length = (ut32)length8; object->sector = buffer + 2; } - if (object->tag == TAG_BITSTRING && object->sector[0] == 0) { - if (object->length > 0) { - object->sector++; // real sector starts + 1 - object->length--; - } - } - if (object->length > length) { - // Malformed object - overflow from data ptr - goto out_error; + if (object->tag == TAG_BITSTRING && !object->sector[0] && object->length > 0) { + object->sector++; // real sector starts + 1 + object->length--; } return object; out_error: @@ -94,30 +98,32 @@ static RASN1Object *asn1_parse_header(const ut8 *buffer, ut32 length, const ut8 return NULL; } -static ut32 rz_asn1_count_objects(const ut8 *buffer, ut32 length) { - if (!buffer || !length) { +static ut32 asn1_count_objects(RASN1Object *object) { + if (!object) { return 0; } + const ut8 *buffer = object->sector; + ut64 length = object->length; ut32 counter = 0; - RASN1Object *object = NULL; + RASN1Object *tmp = NULL; const ut8 *next = buffer; const ut8 *end = buffer + length; while (next >= buffer && next < end) { // i do not care about the offset now. - object = asn1_parse_header(next, end - next, 0); - if (!object || next == object->sector) { - RZ_FREE(object); + tmp = asn1_parse_header(next, end - next, buffer); + if (!tmp || next == tmp->sector) { + RZ_FREE(tmp); break; } - next = object->sector + object->length; + next = tmp->sector + tmp->length; counter++; - RZ_FREE(object); + RZ_FREE(tmp); } - RZ_FREE(object); + RZ_FREE(tmp); return counter; } -RZ_API RASN1Object *rz_asn1_create_object(const ut8 *buffer, ut32 length, const ut8 *start_pointer) { +static RASN1Object *asn1_create_object(const ut8 *buffer, ut64 length, const ut8 *start_pointer) { RASN1Object *object = asn1_parse_header(buffer, length, start_pointer); if (object && (object->form == FORM_CONSTRUCTED || object->tag == TAG_BITSTRING || object->tag == TAG_OCTETSTRING)) { const ut8 *next = object->sector; @@ -126,7 +132,7 @@ RZ_API RASN1Object *rz_asn1_create_object(const ut8 *buffer, ut32 length, const free(object); return NULL; } - ut32 count = rz_asn1_count_objects(object->sector, object->length); + ut64 count = asn1_count_objects(object); if (count > 0) { object->list.length = count; object->list.objects = RZ_NEWS0(RASN1Object *, count); @@ -134,9 +140,8 @@ RZ_API RASN1Object *rz_asn1_create_object(const ut8 *buffer, ut32 length, const rz_asn1_free_object(object); return NULL; } - ut32 i; - for (i = 0; next >= buffer && next < end && i < count; i++) { - RASN1Object *inner = rz_asn1_create_object(next, end - next, start_pointer); + for (ut32 i = 0; next >= buffer && next < end && i < count; i++) { + RASN1Object *inner = asn1_create_object(next, end - next, start_pointer); if (!inner || next == inner->sector) { rz_asn1_free_object(inner); break; @@ -149,6 +154,11 @@ RZ_API RASN1Object *rz_asn1_create_object(const ut8 *buffer, ut32 length, const return object; } +RZ_API RASN1Object *rz_asn1_create_object(RZ_NONNULL const ut8 *buffer, ut32 length) { + rz_return_val_if_fail(buffer && length > 0, NULL); + return asn1_create_object(buffer, length, buffer); +} + RZ_API RASN1Binary *rz_asn1_create_binary(const ut8 *buffer, ut32 length) { if (!buffer || !length) { return NULL; diff --git a/librz/util/pkcs7.c b/librz/util/pkcs7.c index bfcc5f41289..244bfa7c667 100644 --- a/librz/util/pkcs7.c +++ b/librz/util/pkcs7.c @@ -315,7 +315,7 @@ RZ_API RCMS *rz_pkcs7_parse_cms(const ut8 *buffer, ut32 length) { if (!container) { return NULL; } - object = rz_asn1_create_object(buffer, length, buffer); + object = rz_asn1_create_object(buffer, length); if (!object || object->list.length < 2 || !object->list.objects || !object->list.objects[0] || !object->list.objects[1] || object->list.objects[1]->list.length < 1) { @@ -689,7 +689,7 @@ RZ_API SpcIndirectDataContent *rz_pkcs7_parse_spcinfo(RCMS *cms) { free(spcinfo); return NULL; } - RASN1Object *object = rz_asn1_create_object(content->binary, content->length, content->binary); + RASN1Object *object = rz_asn1_create_object(content->binary, content->length); if (!object || object->list.length < 2 || !object->list.objects || !object->list.objects[0] || !object->list.objects[1]) { RZ_FREE_CUSTOM(spcinfo, rz_pkcs7_free_spcinfo); diff --git a/librz/util/x509.c b/librz/util/x509.c index dae17f91847..726318a09c6 100644 --- a/librz/util/x509.c +++ b/librz/util/x509.c @@ -16,7 +16,7 @@ static bool rz_x509_parse_validity(RX509Validity *validity, RASN1Object *object) object->tag == TAG_SEQUENCE && object->form == FORM_CONSTRUCTED) { o = object->list.objects[0]; - if (o->klass == CLASS_UNIVERSAL && o->form == FORM_PRIMITIVE) { + if (o && o->klass == CLASS_UNIVERSAL && o->form == FORM_PRIMITIVE) { if (o->tag == TAG_UTCTIME) { validity->notBefore = rz_asn1_stringify_utctime(o->sector, o->length); } else if (o->tag == TAG_GENERALIZEDTIME) { @@ -24,7 +24,7 @@ static bool rz_x509_parse_validity(RX509Validity *validity, RASN1Object *object) } } o = object->list.objects[1]; - if (o->klass == CLASS_UNIVERSAL && o->form == FORM_PRIMITIVE) { + if (o && o->klass == CLASS_UNIVERSAL && o->form == FORM_PRIMITIVE) { if (o->tag == TAG_UTCTIME) { validity->notAfter = rz_asn1_stringify_utctime(o->sector, o->length); } else if (o->tag == TAG_GENERALIZEDTIME) { @@ -128,12 +128,12 @@ RZ_API bool rz_x509_parse_extension(RX509Extension *ext, RASN1Object *object) { if (o && o->tag == TAG_OID) { ext->extnID = rz_asn1_stringify_oid(o->sector, o->length); o = object->list.objects[1]; - if (o->tag == TAG_BOOLEAN && object->list.length > 2) { + if (o && o->tag == TAG_BOOLEAN && object->list.length > 2) { // This field is optional (so len must be 3) ext->critical = o->sector[0] != 0; o = object->list.objects[2]; } - if (o->tag == TAG_OCTETSTRING) { + if (o && o->tag == TAG_OCTETSTRING) { ext->extnValue = rz_asn1_create_binary(o->sector, o->length); } } @@ -170,9 +170,11 @@ RZ_API bool rz_x509_parse_tbscertificate(RX509TBSCertificate *tbsc, RASN1Object } elems = object->list.objects; // Following RFC - if (elems[0]->list.length == 1 && + if (elems[0] && + elems[0]->list.length == 1 && elems[0]->klass == CLASS_CONTEXT && elems[0]->form == FORM_CONSTRUCTED && + elems[0]->list.objects[0] && elems[0]->list.objects[0]->tag == TAG_INTEGER && elems[0]->list.objects[0]->length == 1) { if (object->list.length < 7) { @@ -185,7 +187,7 @@ RZ_API bool rz_x509_parse_tbscertificate(RX509TBSCertificate *tbsc, RASN1Object } else { tbsc->version = 0; } - if (shift < object->list.length && elems[shift]->klass == CLASS_UNIVERSAL && elems[shift]->tag == TAG_INTEGER) { + if (elems[shift] && elems[shift]->klass == CLASS_UNIVERSAL && elems[shift]->tag == TAG_INTEGER) { tbsc->serialNumber = rz_asn1_stringify_integer(elems[shift]->sector, elems[shift]->length); } rz_x509_parse_algorithmidentifier(&tbsc->signature, elems[shift + 1]); @@ -199,16 +201,10 @@ RZ_API bool rz_x509_parse_tbscertificate(RX509TBSCertificate *tbsc, RASN1Object continue; } if (elems[i]->tag == 1) { - tbsc->issuerUniqueID = rz_asn1_create_binary(object->list.objects[i]->sector, object->list.objects[i]->length); - } - if (!elems[i]) { - continue; + tbsc->issuerUniqueID = rz_asn1_create_binary(elems[i]->sector, elems[i]->length); } if (elems[i]->tag == 2) { - tbsc->subjectUniqueID = rz_asn1_create_binary(object->list.objects[i]->sector, object->list.objects[i]->length); - } - if (!elems[i]) { - continue; + tbsc->subjectUniqueID = rz_asn1_create_binary(elems[i]->sector, elems[i]->length); } if (tbsc->version == 2 && elems[i]->tag == 3 && elems[i]->form == FORM_CONSTRUCTED) { rz_x509_parse_extensions(&tbsc->extensions, elems[i]); @@ -226,7 +222,12 @@ RZ_API RX509Certificate *rz_x509_parse_certificate(RASN1Object *object) { if (!cert) { goto fail; } - if (object->klass != CLASS_UNIVERSAL || object->form != FORM_CONSTRUCTED || object->list.length != 3) { + if (object->klass != CLASS_UNIVERSAL || + object->form != FORM_CONSTRUCTED || + object->list.length != 3 || + !object->list.objects[0] || + !object->list.objects[1] || + !object->list.objects[2]) { RZ_FREE(cert); goto fail; } @@ -256,7 +257,7 @@ RZ_API RX509Certificate *rz_x509_parse_certificate2(const ut8 *buffer, ut32 leng if (!buffer || !length) { return NULL; } - object = rz_asn1_create_object(buffer, length, buffer); + object = rz_asn1_create_object(buffer, length); certificate = rz_x509_parse_certificate(object); // object freed by rz_x509_parse_certificate return certificate; @@ -264,10 +265,13 @@ RZ_API RX509Certificate *rz_x509_parse_certificate2(const ut8 *buffer, ut32 leng RZ_API RX509CRLEntry *rz_x509_parse_crlentry(RASN1Object *object) { RX509CRLEntry *entry; - if (!object || object->list.length != 2) { + if (!object || + object->list.length != 2 || + !object->list.objects[1] || + !object->list.objects[0]) { return NULL; } - entry = (RX509CRLEntry *)malloc(sizeof(RX509CRLEntry)); + entry = RZ_NEW0(RX509CRLEntry); if (!entry) { return NULL; } @@ -282,12 +286,15 @@ RZ_API RX509CertificateRevocationList *rz_x509_parse_crl(RASN1Object *object) { if (!object || object->list.length < 4) { return NULL; } - crl = (RX509CertificateRevocationList *)malloc(sizeof(RX509CertificateRevocationList)); + crl = RZ_NEW0(RX509CertificateRevocationList); if (!crl) { return NULL; } - memset(crl, 0, sizeof(RX509CertificateRevocationList)); elems = object->list.objects; + if (!elems || !elems[0] || !elems[1] || !elems[2] || !elems[3]) { + free(crl); + return NULL; + } rz_x509_parse_algorithmidentifier(&crl->signature, elems[0]); rz_x509_parse_name(&crl->issuer, elems[1]); crl->lastUpdate = rz_asn1_stringify_utctime(elems[2]->sector, elems[2]->length);