ASN1 - Fix memory leaks, clean code and solve crash

This commit is contained in:
Giovanni 2017-03-10 23:14:14 +01:00 committed by radare
parent 0613dc677d
commit eddf4ee678
5 changed files with 63 additions and 71 deletions

View File

@ -233,6 +233,7 @@ typedef void (*PrintfCallback)(const char *str, ...);
#define R_NEW_COPY(x,y) x=(void*)malloc(sizeof(y));memcpy(x,y,sizeof(y))
#define R_MEM_ALIGN(x) ((void *)(size_t)(((ut64)(size_t)x) & 0xfffffffffffff000LL))
#define R_ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
#define R_PTR_MOVE(d,s) d=s;s=NULL;
#define R_PTR_ALIGN(v,t) \
((char *)(((size_t)(v) ) \

View File

@ -88,7 +88,7 @@ R_API RASN1String *r_asn1_stringify_oid (const ut8* buffer, ut32 length);
R_API RASN1String *r_asn1_stringify_tag (RASN1Object *object);
R_API RASN1String *r_asn1_stringify_object (RASN1Object *object);
void r_asn1_free_object (RASN1Object **object);
void r_asn1_free_object (RASN1Object *object);
void r_asn1_free_string (RASN1String *string);

View File

@ -304,7 +304,7 @@ static RASN1Object *asn1_parse_header (const ut8 *buffer, ut32 length) {
RASN1Object *object;
ut8 head, length8, byte;
ut64 length64;
if (!buffer || !length) {
if (!buffer || length < 2) {
return NULL;
}
@ -327,9 +327,9 @@ static RASN1Object *asn1_parse_header (const ut8 *buffer, ut32 length) {
byte = buffer[2 + i8];
length64 <<= 8;
length64 |= byte;
if (length64 > 0xffffffff) {
if (length64 > length) {
free (object);
// Malformed object - overflow (128 bits instead of 32)
// Malformed object - overflow
return NULL;
}
}
@ -343,10 +343,10 @@ static RASN1Object *asn1_parse_header (const ut8 *buffer, ut32 length) {
length64 <<= 8;
length64 |= byte;
from++;
} while (from < end && length64 <= 0xffffffff && byte & 0x80);
if (length64 > 0xffffffff) {
} while (from < end && length64 <= length && byte & 0x80);
if (length64 > length) {
free (object);
// Malformed object - overflow (4GB+ is really too much)
// Malformed object - overflow
return NULL;
}
object->sector = from;
@ -399,54 +399,51 @@ RASN1Object *r_asn1_create_object (const ut8 *buffer, ut32 length) {
RASN1Object *object = asn1_parse_header (buffer, length);
if (object && (object->form == FORM_CONSTRUCTED || object->tag == TAG_BITSTRING || object->tag == TAG_OCTETSTRING)) {
ut32 i, count;
RASN1Object *inner;
RASN1Object *inner = NULL;
const ut8 *next = object->sector;
const ut8 *end = next + object->length;
if (end > buffer + length) {
free (object);
return NULL;
}
count = r_asn1_count_objects (object->sector, object->length);
inner = NULL;
object->list.length = count;
if (count == 0) {
object->list.objects = NULL;
} else {
object->list.objects = (RASN1Object**) calloc (count, sizeof (RASN1Object*));
if (count > 0) {
object->list.length = count;
object->list.objects = R_NEWS0 (RASN1Object*, count);
if (!object->list.objects) {
r_asn1_free_object (&object);
r_asn1_free_object (object);
return NULL;
}
for (i = 0; next >= buffer && next < end && i < count; ++i) {
object->list.objects[i] = NULL;
inner = r_asn1_create_object (next, end - next);
if (!inner || next == inner->sector) {
r_asn1_free_object (&inner);
r_asn1_free_object (inner);
break;
}
next = inner->sector + inner->length;
object->list.objects[i] = inner;
inner = NULL;
R_PTR_MOVE (object->list.objects[i], inner);
}
}
}
return object;
}
void r_asn1_free_object (RASN1Object **object) {
void r_asn1_free_object (RASN1Object *object) {
ut32 i;
if (!object) {
return;
}
if (*object) {
//this shall not be freed. it's a pointer into the buffer.
(*object)->sector = 0;
if ((*object)->list.objects) {
for (i = 0; i < (*object)->list.length; ++i) {
r_asn1_free_object (&(*object)->list.objects[i]);
}
R_FREE ((*object)->list.objects);
//this shall not be freed. it's a pointer into the buffer.
object->sector = 0;
if (object->list.objects) {
for (i = 0; i < object->list.length; ++i) {
r_asn1_free_object (object->list.objects[i]);
}
(*object)->list.objects = NULL;
(*object)->list.length = 0;
R_FREE ((*object));
R_FREE (object->list.objects);
}
object->list.objects = NULL;
object->list.length = 0;
R_FREE (object);
}
void r_asn1_free_string (RASN1String* str) {

View File

@ -118,8 +118,7 @@ bool r_pkcs7_parse_contentinfo (RPKCS7ContentInfo* ci, RASN1Object *object) {
ci->contentType = r_asn1_stringify_oid (object->list.objects[0]->sector, object->list.objects[0]->length);
if (object->list.length == 2 || !object->list.objects[1]) {
ci->content = object->list.objects[1];
object->list.objects[1] = NULL;
R_PTR_MOVE (ci->content, object->list.objects[1]);
}
return true;
@ -127,7 +126,7 @@ bool r_pkcs7_parse_contentinfo (RPKCS7ContentInfo* ci, RASN1Object *object) {
void r_pkcs7_free_contentinfo (RPKCS7ContentInfo* ci) {
if (ci) {
r_asn1_free_object (&ci->content);
r_asn1_free_object (ci->content);
r_asn1_free_string (ci->contentType);
// Used internally pkcs #7, so it should't free ci.
}
@ -139,8 +138,7 @@ bool r_pkcs7_parse_issuerandserialnumber (RPKCS7IssuerAndSerialNumber* iasu, RAS
}
r_x509_parse_name (&iasu->issuer, object->list.objects[0]);
iasu->serialNumber = object->list.objects[1];
object->list.objects[1] = NULL;
R_PTR_MOVE (iasu->serialNumber, object->list.objects[1]);
return true;
}
@ -148,7 +146,7 @@ bool r_pkcs7_parse_issuerandserialnumber (RPKCS7IssuerAndSerialNumber* iasu, RAS
void r_pkcs7_free_issuerandserialnumber (RPKCS7IssuerAndSerialNumber* iasu) {
if (iasu) {
r_x509_free_name (&iasu->issuer);
r_asn1_free_object (&iasu->serialNumber);
r_asn1_free_object (iasu->serialNumber);
// Used internally pkcs #7, so it should't free iasu.
}
}
@ -180,8 +178,7 @@ bool r_pkcs7_parse_signerinfo (RPKCS7SignerInfo* si, RASN1Object *object) {
shift++;
}
if (shift < object->list.length) {
si->encryptedDigest = elems[shift];
elems[shift] = NULL;
R_PTR_MOVE (si->encryptedDigest, object->list.objects[shift]);
shift++;
}
if (shift < object->list.length && elems[shift]->klass == CLASS_CONTEXT && elems[shift]->tag == 1) {
@ -196,7 +193,7 @@ void r_pkcs7_free_signerinfo (RPKCS7SignerInfo* si) {
r_x509_free_algorithmidentifier (&si->digestAlgorithm);
r_pkcs7_free_attributes (&si->authenticatedAttributes);
r_x509_free_algorithmidentifier (&si->digestEncryptionAlgorithm);
r_asn1_free_object (&si->encryptedDigest);
r_asn1_free_object (si->encryptedDigest);
r_pkcs7_free_attributes (&si->unauthenticatedAttributes);
free (si);
}
@ -288,13 +285,13 @@ RCMS *r_pkcs7_parse_cms (const ut8 *buffer, ut32 length) {
}
object = r_asn1_create_object (buffer, length);
if (!object || object->list.length != 2 || !object->list.objects[0] || object->list.objects[1]->list.length != 1) {
r_asn1_free_object (&object);
r_asn1_free_object (object);
free (container);
return NULL;
}
container->contentType = r_asn1_stringify_oid (object->list.objects[0]->sector, object->list.objects[0]->length);
r_pkcs7_parse_signeddata (&container->signedData, object->list.objects[1]->list.objects[0]);
r_asn1_free_object (&object);
r_asn1_free_object (object);
return container;
}
@ -318,8 +315,7 @@ RPKCS7Attribute* r_pkcs7_parse_attribute (RASN1Object *object) {
memset (attribute, 0, sizeof (RPKCS7Attribute));
attribute->oid = r_asn1_stringify_oid (object->list.objects[0]->sector, object->list.objects[0]->length);
if (object->list.length == 2) {
attribute->data = object->list.objects[1];
object->list.objects[1] = NULL;
R_PTR_MOVE (attribute->data, object->list.objects[1]);
}
return attribute;
@ -327,7 +323,7 @@ RPKCS7Attribute* r_pkcs7_parse_attribute (RASN1Object *object) {
void r_pkcs7_free_attribute (RPKCS7Attribute* attribute) {
if (attribute) {
r_asn1_free_object (&attribute->data);
r_asn1_free_object (attribute->data);
r_asn1_free_string (attribute->oid);
free (attribute);
}
@ -341,13 +337,11 @@ bool r_pkcs7_parse_attributes (RPKCS7Attributes* attributes, RASN1Object *object
attributes->length = object->list.length;
if (attributes->length > 0) {
attributes->elements = (RPKCS7Attribute**) calloc (attributes->length, sizeof (RPKCS7Attribute*));
attributes->elements = R_NEWS0(RPKCS7Attribute*, attributes->length);
if (!attributes->elements) {
attributes->length = 0;
return false;
}
memset (attributes->elements, 0, attributes->length * sizeof (RPKCS7Attribute*));
for (i = 0; i < object->list.length; ++i) {
attributes->elements[i] = r_pkcs7_parse_attribute (object->list.objects[i]);
}

View File

@ -7,8 +7,6 @@
#include "r_x509_internal.h"
#define MOVE_PTR(dst, src) { ((dst) = (src)); (src) = NULL; }
bool r_x509_parse_validity (RX509Validity *validity, RASN1Object *object) {
RASN1Object *o;
if (!validity || !object || object->list.length != 2) {
@ -57,7 +55,7 @@ bool r_x509_parse_subjectpublickeyinfo (RX509SubjectPublicKeyInfo * spki, RASN1O
r_x509_parse_algorithmidentifier (&spki->algorithm, object->list.objects[0]);
if (object->list.objects[1]) {
o = object->list.objects[1];
MOVE_PTR (spki->subjectPublicKey, object->list.objects[1]);
R_PTR_MOVE (spki->subjectPublicKey, object->list.objects[1]);
// spki->subjectPublicKey = object->list.objects[1];
// object->list.objects[1] = NULL;
// if (o->length > 32) {
@ -68,7 +66,7 @@ bool r_x509_parse_subjectpublickeyinfo (RX509SubjectPublicKeyInfo * spki, RASN1O
if (o->list.length == 1 && o->list.objects[0]->list.length == 2) {
o = o->list.objects[0];
if (o->list.objects[0]) {
MOVE_PTR (spki->subjectPublicKeyExponent, o->list.objects[0]);
R_PTR_MOVE (spki->subjectPublicKeyExponent, o->list.objects[0]);
// o->list.objects[0] = NULL;
// if (o->list.objects[0]->length > 32) {
// spki->subjectPublicKeyExponent = asn1_stringify_bytes (o->list.objects[0]->sector, o->list.objects[0]->length);
@ -77,7 +75,7 @@ bool r_x509_parse_subjectpublickeyinfo (RX509SubjectPublicKeyInfo * spki, RASN1O
// }
}
if (o->list.objects[1]) {
MOVE_PTR (spki->subjectPublicKeyModule, o->list.objects[1]);
R_PTR_MOVE (spki->subjectPublicKeyModule, o->list.objects[1]);
// spki->subjectPublicKeyModule = o->list.objects[1];
// o->list.objects[1] = NULL;
// spki->subjectPublicKeyModule = asn1_stringify_integer (o->list.objects[1]->sector, o->list.objects[1]->length);
@ -120,7 +118,7 @@ bool r_x509_parse_name (RX509Name *name, RASN1Object * object) {
o->list.objects[0]->tag == TAG_OID) {
name->oids[i] = r_asn1_stringify_oid (o->list.objects[0]->sector, o->list.objects[0]->length);
}
if (o->list.objects[0]->klass == CLASS_UNIVERSAL) {
if (o->list.objects[1]->klass == CLASS_UNIVERSAL) {
name->names[i] = r_asn1_stringify_string (o->list.objects[1]->sector, o->list.objects[1]->length);
}
}
@ -211,13 +209,13 @@ bool r_x509_parse_tbscertificate (RX509TBSCertificate *tbsc, RASN1Object * objec
if (elems[i]->klass != CLASS_CONTEXT) continue;
if (elems[i]->tag == 1) {
MOVE_PTR (tbsc->issuerUniqueID, object->list.objects[i]);
R_PTR_MOVE (tbsc->issuerUniqueID, object->list.objects[i]);
// tbsc->issuerUniqueID = elems[i];
// elems[i] = NULL;
}
if (elems[i]->tag == 2) {
MOVE_PTR (tbsc->subjectUniqueID, object->list.objects[i]);
R_PTR_MOVE (tbsc->subjectUniqueID, object->list.objects[i]);
// tbsc->subjectUniqueID = elems[i];
// elems[i] = NULL;
}
@ -245,28 +243,28 @@ RX509Certificate * r_x509_parse_certificate (RASN1Object *object) {
if (object->klass != CLASS_UNIVERSAL || object->form != FORM_CONSTRUCTED || object->list.length != 3) {
// Malformed certificate
// It needs to have tbsCertificate, algorithmIdentifier and a signature
r_asn1_free_object (&object);
r_asn1_free_object (object);
free (certificate);
return NULL;
}
tmp = object->list.objects[2];
if (tmp->klass != CLASS_UNIVERSAL || tmp->form != FORM_PRIMITIVE || tmp->tag != TAG_BITSTRING) {
r_asn1_free_object (&object);
r_asn1_free_object (object);
free (certificate);
return NULL;
}
MOVE_PTR (certificate->signature, object->list.objects[2]);
R_PTR_MOVE (certificate->signature, object->list.objects[2]);
// certificate->signature = object->list.objects[2];
// object->list.objects[2] = NULL;
r_x509_parse_tbscertificate (&certificate->tbsCertificate, object->list.objects[0]);
if (!r_x509_parse_algorithmidentifier (&certificate->algorithmIdentifier, object->list.objects[1])) {
r_asn1_free_object (&object);
r_asn1_free_object (object);
free (certificate);
return NULL;
}
r_asn1_free_object (&object);
r_asn1_free_object (object);
return certificate;
}
@ -365,7 +363,7 @@ void r_x509_free_name (RX509Name * name) {
void r_x509_free_extension (RX509Extension * ex) {
if (ex) {
r_asn1_free_string (ex->extnID);
r_asn1_free_object (&ex->extnValue);
r_asn1_free_object (ex->extnValue);
//this is allocated dinamically so, i'll free
free (ex);
}
@ -388,9 +386,9 @@ void r_x509_free_extensions (RX509Extensions * ex) {
void r_x509_free_subjectpublickeyinfo (RX509SubjectPublicKeyInfo * spki) {
if (spki) {
r_x509_free_algorithmidentifier (&spki->algorithm);
r_asn1_free_object (&spki->subjectPublicKey);
r_asn1_free_object (&spki->subjectPublicKeyExponent);
r_asn1_free_object (&spki->subjectPublicKeyModule);
r_asn1_free_object (spki->subjectPublicKey);
r_asn1_free_object (spki->subjectPublicKeyExponent);
r_asn1_free_object (spki->subjectPublicKeyModule);
// No need to free spki, since it's a static variable.
}
}
@ -404,8 +402,8 @@ void r_x509_free_tbscertificate (RX509TBSCertificate * tbsc) {
r_x509_free_validity (&tbsc->validity);
r_x509_free_name (&tbsc->subject);
r_x509_free_subjectpublickeyinfo (&tbsc->subjectPublicKeyInfo);
r_asn1_free_object (&tbsc->subjectUniqueID);
r_asn1_free_object (&tbsc->issuerUniqueID);
r_asn1_free_object (tbsc->subjectUniqueID);
r_asn1_free_object (tbsc->issuerUniqueID);
r_x509_free_extensions (&tbsc->extensions);
//no need to free tbsc, since this functions is used internally
}
@ -413,7 +411,7 @@ void r_x509_free_tbscertificate (RX509TBSCertificate * tbsc) {
void r_x509_free_certificate (RX509Certificate * certificate) {
if (certificate) {
r_asn1_free_object (&certificate->signature);
r_asn1_free_object (certificate->signature);
r_x509_free_algorithmidentifier (&certificate->algorithmIdentifier);
r_x509_free_tbscertificate (&certificate->tbsCertificate);
free (certificate);
@ -422,7 +420,7 @@ void r_x509_free_certificate (RX509Certificate * certificate) {
void r_x509_free_crlentry (RX509CRLEntry *entry) {
if (entry) {
r_asn1_free_object (&entry->userCertificate);
r_asn1_free_object (entry->userCertificate);
r_asn1_free_string (entry->revocationDate);
free (entry);
}
@ -617,6 +615,7 @@ char* r_x509_tbscertificate_dump (RX509TBSCertificate* tbsc, char* buffer, ut32
iid = r_asn1_stringify_integer (tbsc->issuerUniqueID->sector, tbsc->issuerUniqueID->length);
if (iid) {
if (length <= p) {
r_asn1_free_string (iid);
free (pad2);
return NULL;
}
@ -626,11 +625,13 @@ char* r_x509_tbscertificate_dump (RX509TBSCertificate* tbsc, char* buffer, ut32
free (pad2);
return NULL;
}
r_asn1_free_string (iid);
}
if (tbsc->subjectUniqueID) {
sid = r_asn1_stringify_integer (tbsc->subjectUniqueID->sector, tbsc->subjectUniqueID->length);
if (sid) {
if (length <= p) {
r_asn1_free_string (sid);
free (pad2);
return NULL;
}
@ -640,6 +641,7 @@ char* r_x509_tbscertificate_dump (RX509TBSCertificate* tbsc, char* buffer, ut32
free (pad2);
return NULL;
}
r_asn1_free_string (sid);
}
if (r < 0 || length <= p) {
free (pad2);
@ -652,8 +654,6 @@ char* r_x509_tbscertificate_dump (RX509TBSCertificate* tbsc, char* buffer, ut32
return NULL;
}
free (pad2);
r_asn1_free_string (sid);
r_asn1_free_string (iid);
return buffer + p;
}