Add ASN1, X.509 and PKCS parsers (+ iC for PE)

This commit is contained in:
Giovanni 2017-02-18 00:07:01 +01:00 committed by radare
parent be78c631b0
commit 1f64c47c05
15 changed files with 4579 additions and 2 deletions

32
libr/bin/format/pe/pe.c Normal file → Executable file
View File

@ -1875,6 +1875,35 @@ out_error:
return;
}
static void bin_pe_get_certificate (struct PE_ (r_bin_pe_obj_t) * bin) {
RPKCS7Container *con;
ut64 size, vaddr;
ut8 *data = NULL;
int len;
if (!bin || !bin->nt_headers) {
return;
}
size = bin->data_directory[PE_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
vaddr = bin->data_directory[PE_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
data = calloc (1, size);
if (!data) return;
if (vaddr > bin->size || vaddr + size > bin->size) {
bprintf ("vaddr greater than the file\n");
free (data);
return;
}
//skipping useless header..
len = r_buf_read_at (bin->b, vaddr + 8, data, size - 8);
if (len < 1) {
R_FREE (data);
return;
}
con = r_pkcs7_parse_container (data, size);
bin->pkcs7 = r_pkcs7_container_dump (con);
r_pkcs7_free_container (con);
R_FREE (data);
}
static int bin_pe_init(struct PE_(r_bin_pe_obj_t)* bin) {
bin->dos_header = NULL;
bin->nt_headers = NULL;
@ -1897,6 +1926,7 @@ static int bin_pe_init(struct PE_(r_bin_pe_obj_t)* bin) {
bin_pe_init_imports (bin);
bin_pe_init_exports (bin);
bin_pe_init_resource (bin);
bin_pe_get_certificate(bin);
bin->big_endian = PE_(r_bin_pe_is_big_endian) (bin);
@ -2859,6 +2889,7 @@ int PE_(r_bin_pe_is_stripped_debug)(struct PE_(r_bin_pe_obj_t)* bin) {
return HASCHR (PE_IMAGE_FILE_DEBUG_STRIPPED);
}
void* PE_(r_bin_pe_free)(struct PE_(r_bin_pe_obj_t)* bin) {
if (!bin) {
return NULL;
@ -2870,6 +2901,7 @@ void* PE_(r_bin_pe_free)(struct PE_(r_bin_pe_obj_t)* bin) {
free (bin->import_directory);
free (bin->resource_directory);
free (bin->delay_import_directory);
free ((void*)bin->pkcs7);
r_buf_free (bin->b);
bin->b = NULL;
free (bin);

View File

@ -98,7 +98,8 @@ struct PE_(r_bin_pe_obj_t) {
RList* relocs;
const char* file;
struct r_buf_t* b;
Sdb* kv;
Sdb *kv;
const char* pkcs7;
};
#define GUIDSTR_LEN 34

View File

@ -613,6 +613,15 @@ static RBuffer* create(RBin* bin, const ut8 *code, int codelen, const ut8 *data,
return buf;
}
static char *signature (RBinFile *arch) {
struct PE_ (r_bin_pe_obj_t) * bin;
if (!arch || !arch->o || !arch->o->bin_obj) {
return NULL;
}
bin = arch->o->bin_obj;
return (char *) bin->pkcs7;
}
struct r_bin_plugin_t r_bin_plugin_pe = {
.name = "pe",
.desc = "PE bin plugin",
@ -627,6 +636,7 @@ struct r_bin_plugin_t r_bin_plugin_pe = {
.binsym = &binsym,
.entries = &entries,
.sections = &sections,
.signature = &signature,
.symbols = &symbols,
.imports = &imports,
.info = &info,

View File

@ -45,6 +45,9 @@
#include "r_util/r_uleb128.h"
#include "r_util/r_utf8.h"
#include "r_util/r_id_storage.h"
#include "r_util/r_asn1.h"
#include "r_util/r_x509.h"
#include "r_util/r_pkcs7.h"
#if __UNIX__
#include <signal.h>
#endif

View File

@ -0,0 +1,102 @@
#ifndef R_ASN1_H
#define R_ASN1_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ASN1_OID_LEN 64
/* Masks */
#define ASN1_CLASS 0xC0 /* Bits 8 and 7 */
#define ASN1_FORM 0x20 /* Bit 6 */
#define ASN1_TAG 0x1F /* Bits 5 - 1 */
#define ASN1_LENLONG 0x80 /* long form */
#define ASN1_LENSHORT 0x7F /* Bits 7 - 1 */
/* Classes */
#define CLASS_UNIVERSAL 0x00 /* 0 = Universal (defined by ITU X.680) */
#define CLASS_APPLICATION 0x40 /* 1 = Application */
#define CLASS_CONTEXT 0x80 /* 2 = Context-specific */
#define CLASS_PRIVATE 0xC0 /* 3 = Private */
/* Forms */
#define FORM_PRIMITIVE 0x00 /* 0 = primitive */
#define FORM_CONSTRUCTED 0x20 /* 1 = constructed */
/* Tags */
#define TAG_EOC 0x00 /* 0: End-of-contents octets */
#define TAG_BOOLEAN 0x01 /* 1: Boolean */
#define TAG_INTEGER 0x02 /* 2: Integer */
#define TAG_BITSTRING 0x03 /* 2: Bit string */
#define TAG_OCTETSTRING 0x04 /* 4: Byte string */
#define TAG_NULL 0x05 /* 5: NULL */
#define TAG_OID 0x06 /* 6: Object Identifier */
#define TAG_OBJDESCRIPTOR 0x07 /* 7: Object Descriptor */
#define TAG_EXTERNAL 0x08 /* 8: External */
#define TAG_REAL 0x09 /* 9: Real */
#define TAG_ENUMERATED 0x0A /* 10: Enumerated */
#define TAG_EMBEDDED_PDV 0x0B /* 11: Embedded Presentation Data Value */
#define TAG_UTF8STRING 0x0C /* 12: UTF8 string */
#define TAG_SEQUENCE 0x10 /* 16: Sequence/sequence of */
#define TAG_SET 0x11 /* 17: Set/set of */
#define TAG_NUMERICSTRING 0x12 /* 18: Numeric string */
#define TAG_PRINTABLESTRING 0x13 /* 19: Printable string (ASCII subset) */
#define TAG_T61STRING 0x14 /* 20: T61/Teletex string */
#define TAG_VIDEOTEXSTRING 0x15 /* 21: Videotex string */
#define TAG_IA5STRING 0x16 /* 22: IA5/ASCII string */
#define TAG_UTCTIME 0x17 /* 23: UTC time */
#define TAG_GENERALIZEDTIME 0x18 /* 24: Generalized time */
#define TAG_GRAPHICSTRING 0x19 /* 25: Graphic string */
#define TAG_VISIBLESTRING 0x1A /* 26: Visible string (ASCII subset) */
#define TAG_GENERALSTRING 0x1B /* 27: General string */
#define TAG_UNIVERSALSTRING 0x1C /* 28: Universal string */
#define TAG_BMPSTRING 0x1E /* 30: Basic Multilingual Plane/Unicode string */
typedef struct r_asn1_string_t {
ut32 length;
const char *string;
bool allocated;
} RASN1String;
typedef struct r_asn1_object_t RASN1Object;
typedef struct r_asn1_list_t {
ut32 length;
RASN1Object **objects;
} ASN1List;
typedef struct r_asn1_object_t {
ut8 class; /* class type */
ut8 form; /* defines if contains data or objects */
ut8 tag; /* tag type */
const ut8 *sector; /* Sector containg data */
ut32 length; /* Sector Length */
ASN1List list; /* List of objects contained in the sector */
} RASN1Object;
R_API RASN1Object *r_asn1_create_object (const ut8 *buffer, ut32 length);
R_API RASN1String *r_asn1_stringify_bits (const ut8 *buffer, ut32 length);
R_API RASN1String *r_asn1_stringify_utctime (const ut8 *buffer, ut32 length);
R_API RASN1String *r_asn1_stringify_time (const ut8 *buffer, ut32 length);
R_API RASN1String *r_asn1_stringify_integer (const ut8 *buffer, ut32 length);
R_API RASN1String *r_asn1_stringify_string (const ut8 *buffer, ut32 length);
R_API RASN1String *r_asn1_stringify_bytes (const ut8 *buffer, ut32 length);
R_API RASN1String *r_asn1_stringify_boolean (const ut8 *buffer, ut32 length);
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_string (RASN1String *string);
#ifdef __cplusplus
}
#endif
#endif /* R_ASN1_H */

View File

@ -0,0 +1,73 @@
#ifndef R_PKCS7_H
#define R_PKCS7_H
typedef struct r_pkcs7_certificaterevocationlists_t {
ut32 length;
RX509CertificateRevocationList **elements;
} RPKCS7CertificateRevocationLists;
typedef struct r_pkcs7_extendedcertificatesandcertificates_t {
ut32 length;
RX509Certificate **elements;
} RPKCS7ExtendedCertificatesAndCertificates;
typedef struct r_pkcs7_digestalgorithmidentifiers_t {
ut32 length;
RX509AlgorithmIdentifier **elements;
} RPKCS7DigestAlgorithmIdentifiers;
typedef struct r_pkcs7_contentinfo_t {
RASN1String *contentType; //OID
RASN1Object *content; // optional. oid structure definition
} RPKCS7ContentInfo;
typedef struct r_pkcs7_issuerandserialnumber_t {
RX509Name issuer;
RASN1Object *serialNumber;
} RPKCS7IssuerAndSerialNumber;
typedef struct r_pkcs7_attribute_t {
RASN1String *oid; //OID
RASN1Object *data; // optional. oid structure definition
} RPKCS7Attribute;
typedef struct r_pkcs7_attributes_t {
ut32 length;
RPKCS7Attribute **elements;
} RPKCS7Attributes;
typedef struct r_pkcs7_signerinfo_t {
ut32 version;
RPKCS7IssuerAndSerialNumber issuerAndSerialNumber;
RX509AlgorithmIdentifier digestAlgorithm;
RPKCS7Attributes authenticatedAttributes; //Optional
RX509AlgorithmIdentifier digestEncryptionAlgorithm;
RASN1Object *encryptedDigest;
RPKCS7Attributes unauthenticatedAttributes; //Optional
} RPKCS7SignerInfo;
typedef struct r_pkcs7_signerinfos_t {
ut32 length;
RPKCS7SignerInfo **elements;
} RPKCS7SignerInfos;
typedef struct r_pkcs7_signeddata_t {
ut32 version;
RPKCS7DigestAlgorithmIdentifiers digestAlgorithms;
RPKCS7ContentInfo contentInfo;
RPKCS7ExtendedCertificatesAndCertificates certificates; //Optional
RPKCS7CertificateRevocationLists crls; //Optional
RPKCS7SignerInfos signerinfos;
} RPKCS7SignedData;
typedef struct r_pkcs7_container_t {
RASN1String *contentType;
RPKCS7SignedData signedData;
} RPKCS7Container;
R_API RPKCS7Container *r_pkcs7_parse_container (const ut8 *buffer, ut32 length);
R_API void r_pkcs7_free_container (RPKCS7Container* container);
R_API char* r_pkcs7_container_dump (RPKCS7Container* container);
#endif /* R_PKCS7_H */

View File

@ -0,0 +1,122 @@
#ifndef R_X509_H
#define R_X509_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Following RFC 5280
*/
typedef struct r_x509_validity_t {
RASN1String *notBefore;
RASN1String *notAfter;
} RX509Validity;
typedef struct r_x509_name_t {
ut32 length;
RASN1String **oids;
RASN1String **names;
} RX509Name;
typedef struct r_x509_algorithmidentifier_t {
RASN1String *algorithm; // OBJECT IDENTIFIER
RASN1String *parameters; // OPTIONAL
} RX509AlgorithmIdentifier;
/*
//SubjectKeyIdentifier OCTET STRING so it should be an ASN1Object
typedef struct r_x509_keyusage_t {
ut8 digitalSignature : 1;
ut8 contentCommitment : 1;
ut8 keyEncipherment : 1;
ut8 dataEncipherment : 1;
ut8 keyAgreement : 1;
ut8 keyCertSign : 1;
ut8 cRLSign : 1;
ut8 encipherOnly : 1;
ut8 decipherOnly : 1;
} X509KeyUsage;
*/
typedef struct r_x509_authoritykeyidentifier_t {
RASN1Object *keyIdentifier;
RX509Name authorityCertIssuer;
RASN1Object *authorityCertSerialNumber;
} RX509AuthorityKeyIdentifier;
typedef struct r_x509_subjectpublickeyinfo_t {
RX509AlgorithmIdentifier algorithm;
//This is a bit string, but it encapsulate mod + pubkey
RASN1Object *subjectPublicKey; // BIT STRING
//This struct won't follow RFC,
//just because it should be seen as this.
RASN1Object *subjectPublicKeyExponent;
RASN1Object *subjectPublicKeyModule;
} RX509SubjectPublicKeyInfo;
typedef struct r_x509_extension_t {
RASN1String *extnID; // OBJECT IDENTIFIER
bool critical;
RASN1Object *extnValue; // OCTET STRING
} RX509Extension;
typedef struct r_x509_extensions_t {
ut32 length;
RX509Extension **extensions;
} RX509Extensions;
typedef struct r_x509_tbscertificate_t {
ut32 version; //INTEGER
RASN1String *serialNumber; // INTEGER
RX509AlgorithmIdentifier signature;
RX509Name issuer;
RX509Validity validity;
RX509Name subject;
RX509SubjectPublicKeyInfo subjectPublicKeyInfo;
RASN1Object *issuerUniqueID; // BIT STRING
RASN1Object *subjectUniqueID; // BIT STRING
RX509Extensions extensions;
} RX509TBSCertificate;
typedef struct r_x509_certificate_t {
RX509TBSCertificate tbsCertificate;
RX509AlgorithmIdentifier algorithmIdentifier;
RASN1Object *signature; // BIT STRING
} RX509Certificate;
// RFC 1422
typedef struct r_x509_crlentry {
RASN1Object *userCertificate; //INTEGER ?
RASN1String *revocationDate; //UTCTime
} RX509CRLEntry;
typedef struct r_x509_certificaterevocationlist {
RX509AlgorithmIdentifier signature;
RX509Name issuer;
RASN1String *lastUpdate; //UTCTime
RASN1String *nextUpdate; //UTCTime
ut32 length;
RX509CRLEntry **revokedCertificates;
} RX509CertificateRevocationList;
R_API RX509CertificateRevocationList* r_x509_parse_crl (RASN1Object *object);
R_API void r_x509_free_crl (RX509CertificateRevocationList *crl);
R_API char* r_x509_crl_dump (RX509CertificateRevocationList *crl, char* buffer, ut32 length, const char* pad);
R_API RX509Certificate *r_x509_parse_certificate (RASN1Object *object);
R_API RX509Certificate *r_x509_parse_certificate2 (const ut8 *buffer, ut32 length);
R_API void r_x509_free_certificate (RX509Certificate* certificate);
R_API char* r_x509_certificate_dump (RX509Certificate* certificate, char* buffer, ut32 length, const char* pad);
#ifdef __cplusplus
}
#endif
#endif /* R_X509_H */

View File

@ -12,7 +12,7 @@ OBJS+=strpool.o bitmap.o strht.o p_date.o p_format.o print.o
OBJS+=p_seven.o slist.o randomart.o log.o zip.o debruijn.o
OBJS+=utf8.o strbuf.o lib.o name.o spaces.o signal.o syscmd.o
OBJS+=diff.o bdiff.o stack.o queue.o tree.o des.o idpool.o
OBJS+=punycode.o
OBJS+=punycode.o r_pkcs7.o r_x509.o r_asn1.o
# DO NOT BUILD r_big api (not yet used and its buggy)
ifeq (1,0)

581
libr/util/r_asn1.c Normal file
View File

@ -0,0 +1,581 @@
#include <r_util.h>
#include "r_oids.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "r_asn1_internal.h"
const char* _hex = "0123456789abcdef";
RASN1String *r_asn1_create_string (const char *string, bool allocated, ut32 length) {
RASN1String *s;
if (!string || !length) {
return NULL;
}
s = (RASN1String*) malloc (sizeof (RASN1String));
if (!s) {
return NULL;
}
s->allocated = allocated;
s->length = length;
s->string = string;
return s;
}
RASN1String *r_asn1_create_string2 (const char *string, bool allocated) {
return r_asn1_create_string (string, allocated, strlen (string) + 1);
}
RASN1String *r_asn1_concatenate_strings (RASN1String *s0, RASN1String *s1, bool freestr) {
char* str;
ut32 len;
if (!s0 || !s1 || s0->length == 0 || s1->length == 0) {
return NULL;
}
len = s0->length + s1->length - 1;
str = (char*) malloc (len);
if (!str) {
if (freestr) {
r_asn1_free_string (s0);
r_asn1_free_string (s1);
}
return NULL;
}
memcpy (str, s0->string, s0->length);
memcpy (str + s0->length - 1, s1->string, s1->length);
if (freestr) {
r_asn1_free_string (s0);
r_asn1_free_string (s1);
}
return r_asn1_create_string (str, true, len);
}
RASN1String *r_asn1_stringify_string (const ut8 *buffer, ut32 length) {
char *str;
if (!buffer || !length) {
return NULL;
}
str = (char*) malloc (length + 1);
if (!str) {
return NULL;
}
memcpy (str, buffer, length);
str[length] = '\0';
return r_asn1_create_string (str, true, length + 1);
}
RASN1String *r_asn1_stringify_utctime (const ut8 *buffer, ut32 length) {
char* str;
if (!buffer || length != 13 || buffer[12] != 'Z') {
return NULL;
}
str = (char*) malloc (24);
if (!buffer || !length) {
return NULL;
}
str[0] = buffer[4];
str[1] = buffer[5];
str[2] = '/';
str[3] = buffer[2];
str[4] = buffer[3];
str[5] = '/';
str[6] = buffer[0] < '5' ? '2' : '1';
str[7] = buffer[0] < '5' ? '0' : '9';
str[8] = buffer[0];
str[9] = buffer[1];
str[10] = ' ';
str[11] = buffer[6];
str[12] = buffer[7];
str[13] = ':';
str[14] = buffer[8];
str[15] = buffer[9];
str[16] = ':';
str[17] = buffer[10];
str[18] = buffer[11];
str[19] = ' ';
str[20] = 'G';
str[21] = 'M';
str[22] = 'T';
str[23] = '\0';
return r_asn1_create_string (str, true, 24);
}
RASN1String *r_asn1_stringify_time (const ut8 *buffer, ut32 length) {
char* str;
if (!buffer || length != 15 || buffer[14] != 'Z') {
return NULL;
}
str = (char*) malloc (24);
if (!buffer || !length) {
return NULL;
}
str[0] = buffer[6];
str[1] = buffer[7];
str[2] = '/';
str[3] = buffer[4];
str[4] = buffer[5];
str[5] = '/';
str[6] = buffer[0];
str[7] = buffer[1];
str[8] = buffer[2];
str[9] = buffer[3];
str[10] = ' ';
str[11] = buffer[8];
str[12] = buffer[9];
str[13] = ':';
str[14] = buffer[10];
str[15] = buffer[11];
str[16] = ':';
str[17] = buffer[12];
str[18] = buffer[13];
str[19] = ' ';
str[20] = 'G';
str[21] = 'M';
str[22] = 'T';
str[23] = '\0';
return r_asn1_create_string (str, true, 24);
}
RASN1String *r_asn1_stringify_bits (const ut8 *buffer, ut32 length) {
ut32 i, j, k;
ut64 size;
ut8 c;
char *str;
if (!buffer || !length) {
return NULL;
}
size = 1 + ((length - 1)* 8) - buffer[0];
str = (char*) malloc (size);
if (!str) {
return NULL;
}
for (i = 1, j = 0; i < length && j < size; ++i) {
c = buffer[i];
for (k = 0; k < 8 && j < size; ++k, j++) {
str[size - j - 1] = c & 0x80 ? '1' : '0';
c <<= 1;
}
}
str[size - 1] = '\0';
return r_asn1_create_string (str, true, size);
}
RASN1String *r_asn1_stringify_boolean (const ut8 *buffer, ut32 length) {
if (!buffer || length != 1 || (buffer[0] != 0 && buffer[0] != 0xFF)) {
return NULL;
}
return r_asn1_create_string2 (buffer[0] != 0 ? "true" : "false", false);
}
RASN1String *r_asn1_stringify_integer (const ut8 *buffer, ut32 length) {
ut32 i, j;
ut64 size;
ut8 c;
char *str;
if (!buffer || !length) {
return NULL;
}
size = 3 * length;
str = (char*) malloc (size);
if (!str) {
return NULL;
}
memset (str, 0, size);
for (i = 0, j = 0; i < length && j < size; ++i, j += 3) {
c = buffer[i];
str[j + 0] = _hex[c >> 4];
str[j + 1] = _hex[c & 15];
str[j + 2] = ':';
}
str[size - 1] = '\0';
return r_asn1_create_string (str, true, size);
}
RASN1String* r_asn1_stringify_bytes (const ut8 *buffer, ut32 length) {
ut32 i, j, k;
ut64 size;
ut8 c;
char *str;
if (!buffer || !length) {
return NULL;
}
size = (4 * length);
size += (64 - (size % 64));
str = (char*) malloc (size);
if (!str) {
return NULL;
}
memset (str, 0x20, size);
for (i = 0, j = 0, k = 48; i < length && j < size && k < size; ++i, j += 3, k++) {
c = buffer[i];
str[j + 0] = _hex[c >> 4];
str[j + 1] = _hex[c & 15];
str[j + 2] = ' ';
str[k] = (c >= ' ' && c <= '~') ? c : '.';
if (i % 16 == 15) {
str[j + 19] = '\n';
j += 17;
k += 49;
}
}
str[size - 1] = '\0';
return r_asn1_create_string (str, true, size);
}
RASN1String *r_asn1_stringify_oid (const ut8* buffer, ut32 length) {
const ut8 *start, *end;
char *str, *t;
ut32 i, slen, bits;
ut64 oid;
if (!buffer || !length) {
return NULL;
}
str = (char*) malloc (ASN1_OID_LEN);
if (!str) {
return NULL;
}
memset (str, 0, ASN1_OID_LEN);
end = buffer + length;
t = str;
slen = 0;
bits = 0;
oid = 0;
for (start = buffer; start < end && slen < ASN1_OID_LEN; start++) {
ut8 c = *start;
oid <<= 7;
oid |= (c & 0x7F);
bits += 7;
if (!(c & 0x80)) {
if (!slen) {
ut32 m = oid / 40;
ut32 n = oid % 40;
snprintf (t, ASN1_OID_LEN, "%01u.%01u", m, n);
slen = strlen (str);
t = str + slen;
} else {
//overflow
if ((ASN1_OID_LEN - slen) > ASN1_OID_LEN) {
free (str);
return NULL;
}
snprintf (t, ASN1_OID_LEN - slen, ".%01u", (ut32) oid);
slen = strlen (str);
t = str + slen;
}
oid = 0;
bits = 0;
}
}
// incomplete oid.
// bad structure.
if (bits > 0) {
free (str);
return NULL;
}
i = 0;
do {
if (X509OIDList[i].oid[0] == str[0]) {
if (!strncmp (str, X509OIDList[i].oid, ASN1_OID_LEN)) {
free (str);
return r_asn1_create_string2 (X509OIDList[i].name, false);
}
}
++i;
} while (X509OIDList[i].oid && X509OIDList[i].name);
return r_asn1_create_string (str, true, ASN1_OID_LEN);
}
RASN1Object *asn1_parse_header (const ut8 *buffer, ut32 length) {
RASN1Object *object;
ut8 head, length8, byte;
ut64 length64;
if (!buffer || !length) {
return NULL;
}
object = (RASN1Object*) malloc (sizeof (RASN1Object));
if (!object) {
return NULL;
}
head = buffer[0];
object->class = head & ASN1_CLASS;
object->form = head & ASN1_FORM;
object->tag = head & ASN1_TAG;
object->sector = NULL;
object->length = 0;
object->list.length = 0;
object->list.objects = NULL;
length8 = buffer[1];
if (length8 & ASN1_LENLONG) {
length64 = 0;
length8 &= ASN1_LENSHORT;
if (length8) {
ut8 i8;
// can overflow.
for (i8 = 0; i8 < length8; ++i8) {
byte = buffer[2 + i8];
length64 <<= 8;
length64 |= byte;
if (length64 > 0xffffffff) {
free (object);
// Malformed object - overflow (128 bits instead of 32)
return NULL;
}
}
object->sector = buffer + 2 + length8;
} else {
//indefinite
const ut8 *from = buffer + 2;
const ut8 *end = from + (length - 2);
do {
byte = *from;
length64 <<= 8;
length64 |= byte;
from++;
} while (from < end && length64 <= 0xffffffff && byte & 0x80);
if (length64 > 0xffffffff) {
free (object);
// Malformed object - overflow (4GB+ is really too much)
return NULL;
}
object->sector = from;
}
object->length = (ut32) length64;
} else {
object->length = (ut32) length8;
object->sector = buffer + 2;
}
if (object->tag == TAG_BITSTRING && object->sector[0] == 0) {
object->sector++; //real sector starts +1
if (object->length > 0)
object->length--;
}
if (object->length > length) {
// Malformed object - overflow from data ptr
free (object);
return NULL;
}
return object;
}
ut32 r_asn1_count_objects (const ut8 *buffer, ut32 length) {
ut32 counter;
RASN1Object *object;
const ut8 *next, *end;
if (!buffer || !length) {
return 0;
}
counter = 0;
object = NULL;
next = buffer;
end = buffer + length;
while (next >= buffer && next < end) {
object = asn1_parse_header (next, end - next);
if (!object || next == object->sector) {
// if (object->tag != TAG_NULL)
break;
}
next = object->sector + object->length;
counter++;
free (object);
object = NULL;
}
if (object) {
free (object);
}
return counter;
}
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;
const ut8 *next = object->sector;
const ut8 *end = next + object->length;
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 (!object->list.objects) {
free (object);
return NULL;
}
memset (object->list.objects, 0, count * sizeof (RASN1Object*));
for (i = 0; next >= buffer && next < end && i < count; ++i) {
inner = r_asn1_create_object (next, end - next);
if (!inner || next == inner->sector) {
//if(inner->tag != TAG_NULL)
break;
}
next = inner->sector + inner->length;
object->list.objects[i] = inner;
inner = NULL;
}
if (inner) {
free (inner);
}
}
}
return object;
}
void r_asn1_free_object (RASN1Object *object) {
ut32 i;
if (object) {
//this shall not be freed. it's a pointer into the buffer.
object->sector = 0;
if (object->list.objects && object->list.length) {
for (i = 0; i < object->list.length; ++i) {
if (object->list.objects[i]) {
r_asn1_free_object (object->list.objects[i]);
}
object->list.objects[i] = NULL;
}
free (object->list.objects);
object->list.objects = NULL;
}
free (object);
}
}
void r_asn1_free_string (RASN1String* str) {
if (str) {
if (str->allocated) {
free ((char*) str->string);
}
free (str);
}
}
RASN1String *asn1_stringify_tag (RASN1Object *object) {
if (!object) {
return NULL;
}
switch (object->tag) {
case TAG_EOC:
return r_asn1_create_string2 ("EOC", false);
case TAG_BOOLEAN:
return r_asn1_create_string2 ("BOOLEAN", false);
case TAG_INTEGER:
return r_asn1_create_string2 ("INTEGER", false);
case TAG_BITSTRING:
return r_asn1_create_string2 ("BIT STRING", false);
case TAG_OCTETSTRING:
return r_asn1_create_string2 ("OCTET STRING", false);
case TAG_NULL:
return r_asn1_create_string2 ("NULL", false);
case TAG_OID:
return r_asn1_create_string2 ("OBJECT IDENTIFIER", false);
case TAG_OBJDESCRIPTOR:
return r_asn1_create_string2 ("ObjectDescriptor", false);
case TAG_EXTERNAL:
return r_asn1_create_string2 ("EXTERNAL", false);
case TAG_REAL:
return r_asn1_create_string2 ("REAL", false);
case TAG_ENUMERATED:
return r_asn1_create_string2 ("ENUMERATED", false);
case TAG_EMBEDDED_PDV:
return r_asn1_create_string2 ("EMBEDDED PDV", false);
case TAG_UTF8STRING:
return r_asn1_create_string2 ("UTF8String", false);
case TAG_SEQUENCE:
return r_asn1_create_string2 ("SEQUENCE", false);
case TAG_SET:
return r_asn1_create_string2 ("SET", false);
case TAG_NUMERICSTRING:
return r_asn1_create_string2 ("NumericString", false);
case TAG_PRINTABLESTRING:
return r_asn1_create_string2 ("PrintableString", false);
case TAG_T61STRING:
return r_asn1_create_string2 ("TeletexString", false);
case TAG_VIDEOTEXSTRING:
return r_asn1_create_string2 ("VideotexString", false);
case TAG_IA5STRING:
return r_asn1_create_string2 ("IA5String", false);
case TAG_UTCTIME:
return r_asn1_create_string2 ("UTCTime", false);
case TAG_GENERALIZEDTIME:
return r_asn1_create_string2 ("GeneralizedTime", false);
case TAG_GRAPHICSTRING:
return r_asn1_create_string2 ("GraphicString", false);
case TAG_VISIBLESTRING:
return r_asn1_create_string2 ("VisibleString", false);
case TAG_GENERALSTRING:
return r_asn1_create_string2 ("GeneralString", false);
case TAG_UNIVERSALSTRING:
return r_asn1_create_string2 ("UniversalString", false);
case TAG_BMPSTRING:
return r_asn1_create_string2 ("BMPString", false);
}
return r_asn1_create_string2 ("Unknown tag", false);
}
RASN1String *asn1_stringify_sector (RASN1Object *object) {
if (!object) {
return NULL;
}
switch (object->tag) {
case TAG_EOC:
return NULL;
case TAG_BOOLEAN:
return r_asn1_create_string2 (object->sector[0] == 0 ? "false" : "true", false);
case TAG_REAL:
case TAG_INTEGER:
if (object->length < 16) {
return r_asn1_stringify_integer (object->sector, object->length);
} else {
return r_asn1_stringify_bytes (object->sector, object->length);
}
case TAG_BITSTRING:
//if (object->length < 8) {
return r_asn1_stringify_bits (object->sector, object->length);
//} else {
// return asn1_stringify_bytes (object->sector, object->length);
//}
case TAG_OCTETSTRING:
return r_asn1_stringify_bytes (object->sector, object->length);
case TAG_NULL:
return NULL;
case TAG_OID:
return r_asn1_stringify_oid (object->sector, object->length);
// case TAG_OBJDESCRIPTOR:
// case TAG_EXTERNAL:
// case TAG_ENUMERATED:
// case TAG_EMBEDDED_PDV:
case TAG_UTF8STRING:
// case TAG_SEQUENCE:
// case TAG_SET:
case TAG_NUMERICSTRING:
case TAG_PRINTABLESTRING:
// case TAG_T61STRING:
// case TAG_VIDEOTEXSTRING:
case TAG_IA5STRING:
case TAG_VISIBLESTRING:
return r_asn1_stringify_string (object->sector, object->length);
case TAG_UTCTIME:
return r_asn1_stringify_utctime (object->sector, object->length);
case TAG_GENERALIZEDTIME:
return r_asn1_stringify_time (object->sector, object->length);
// case TAG_GRAPHICSTRING:
// case TAG_GENERALSTRING:
// case TAG_UNIVERSALSTRING:
// case TAG_BMPSTRING:
}
return NULL;
}

View File

@ -0,0 +1,10 @@
#ifndef R_ASN1_INTERNAL_H
#define R_ASN1_INTERNAL_H
R_API ut32 r_asn1_count_objects (const ut8 *buffer, ut32 length);
R_API RASN1String *r_asn1_create_string (const char *string, bool allocated, ut32 length);
R_API RASN1String *r_asn1_create_string2 (const char *string, bool allocated);
R_API RASN1String *r_asn1_concatenate_strings (RASN1String* s0, RASN1String* s1, bool freestr);
#endif /* R_ASN1_INTERNAL_H */

2249
libr/util/r_oids.h Normal file

File diff suppressed because it is too large Load Diff

596
libr/util/r_pkcs7.c Normal file
View File

@ -0,0 +1,596 @@
#include <stdlib.h>
#include <string.h>
#include <r_util.h>
#include "r_x509_internal.h"
#include "r_pkcs7_internal.h"
bool r_pkcs7_parse_certificaterevocationlists (RPKCS7CertificateRevocationLists *crls, RASN1Object *object) {
ut32 i;
if (!crls && !object) {
return false;
}
if (object->list.length > 0) {
crls->elements = (RX509CertificateRevocationList **) calloc (object->list.length, sizeof (RX509CertificateRevocationList*));
if (!crls->elements) {
return false;
}
crls->length = object->list.length;
for (i = 0; i < crls->length; ++i) {
crls->elements[i] = r_x509_parse_crl (object->list.objects[i]);
}
}
return true;
}
void r_pkcs7_free_certificaterevocationlists (RPKCS7CertificateRevocationLists *crls) {
ut32 i;
if (crls) {
for (i = 0; i < crls->length; ++i) {
r_x509_free_crl (crls->elements[i]);
crls->elements[i] = NULL;
}
free (crls->elements);
crls->elements = NULL;
// Used internally pkcs #7, so it should't free crls.
}
}
bool r_pkcs7_parse_extendedcertificatesandcertificates (RPKCS7ExtendedCertificatesAndCertificates *ecac, RASN1Object *object) {
ut32 i;
if (!ecac && !object) {
return false;
}
if (object->list.length > 0) {
ecac->elements = (RX509Certificate **) calloc (object->list.length, sizeof (RX509Certificate*));
if (!ecac->elements) {
return false;
}
ecac->length = object->list.length;
for (i = 0; i < ecac->length; ++i) {
ecac->elements[i] = r_x509_parse_certificate (object->list.objects[i]);
}
}
return true;
}
void r_pkcs7_free_extendedcertificatesandcertificates (RPKCS7ExtendedCertificatesAndCertificates *ecac) {
ut32 i;
if (ecac) {
for (i = 0; i < ecac->length; ++i) {
r_x509_free_certificate (ecac->elements[i]);
ecac->elements[i] = NULL;
}
free (ecac->elements);
ecac->elements = NULL;
// Used internally pkcs #7, so it should't free ecac.
}
}
bool r_pkcs7_parse_digestalgorithmidentifier (RPKCS7DigestAlgorithmIdentifiers *dai, RASN1Object *object) {
ut32 i;
if (!dai && !object) {
return false;
}
if (object->list.length > 0) {
dai->elements = (RX509AlgorithmIdentifier **) calloc (object->list.length, sizeof (RX509AlgorithmIdentifier*));
if (!dai->elements) {
return false;
}
dai->length = object->list.length;
for (i = 0; i < dai->length; ++i) {
// r_x509_parse_algorithmidentifier returns bool,
// so i have to allocate before calling the function
dai->elements[i] = (RX509AlgorithmIdentifier *) malloc (sizeof (RX509AlgorithmIdentifier));
//should i handle invalid memory? the function checks the pointer
//or it should return if dai->elements[i] == NULL ?
if (dai->elements[i]) {
//Memset is needed to initialize to 0 the structure and avoid garbage.
memset (dai->elements[i], 0, sizeof (RX509AlgorithmIdentifier));
r_x509_parse_algorithmidentifier (dai->elements[i], object->list.objects[i]);
}
}
}
return true;
}
void r_pkcs7_free_digestalgorithmidentifier (RPKCS7DigestAlgorithmIdentifiers *dai) {
ut32 i;
if (dai) {
for (i = 0; i < dai->length; ++i) {
if (dai->elements[i]) {
r_x509_free_algorithmidentifier (dai->elements[i]);
// r_x509_free_algorithmidentifier doesn't free the pointer
// because on x509 the original use was internal.
free (dai->elements[i]);
dai->elements[i] = NULL;
}
}
free (dai->elements);
dai->elements = NULL;
// Used internally pkcs #7, so it should't free dai.
}
}
bool r_pkcs7_parse_contentinfo (RPKCS7ContentInfo* ci, RASN1Object *object) {
if (!ci || !object || object->list.length < 1) {
return false;
}
ci->contentType = r_asn1_stringify_oid (object->list.objects[0]->sector, object->list.objects[0]->length);
if (object->list.length == 2) {
ci->content = object->list.objects[1];
object->list.objects[1] = NULL;
}
return true;
}
void r_pkcs7_free_contentinfo (RPKCS7ContentInfo* ci) {
if (ci) {
r_asn1_free_object (ci->content);
r_asn1_free_string (ci->contentType);
// Used internally pkcs #7, so it should't free ci.
}
}
bool r_pkcs7_parse_issuerandserialnumber (RPKCS7IssuerAndSerialNumber* iasu, RASN1Object *object) {
if (!iasu || !object || object->list.length != 2) {
return false;
}
r_x509_parse_name (&iasu->issuer, object->list.objects[0]);
iasu->serialNumber = object->list.objects[1];
object->list.objects[1] = NULL;
return true;
}
void r_pkcs7_free_issuerandserialnumber (RPKCS7IssuerAndSerialNumber* iasu) {
if (iasu) {
r_x509_free_name (&iasu->issuer);
r_asn1_free_object (iasu->serialNumber);
// Used internally pkcs #7, so it should't free iasu.
}
}
/*
RX509AlgorithmIdentifier digestEncryptionAlgorithm;
RASN1Object *encryptedDigest;
RASN1Object *unauthenticatedAttributes; //Optional type ??
} RPKCS7SignerInfo;
*/
bool r_pkcs7_parse_signerinfo (RPKCS7SignerInfo* si, RASN1Object *object) {
RASN1Object **elems;
ut32 shift = 3;
if (!si || !object || object->list.length < 5) {
return false;
}
elems = object->list.objects;
//Following RFC
si->version = (ut32) elems[0]->sector[0];
r_pkcs7_parse_issuerandserialnumber (&si->issuerAndSerialNumber, elems[1]);
r_x509_parse_algorithmidentifier (&si->digestAlgorithm, elems[2]);
if (shift < object->list.length && elems[shift]->class == CLASS_CONTEXT && elems[shift]->tag == 0) {
r_pkcs7_parse_attributes (&si->authenticatedAttributes, elems[shift]);
shift++;
}
if (shift < object->list.length) {
r_x509_parse_algorithmidentifier (&si->digestEncryptionAlgorithm, elems[shift]);
shift++;
}
if (shift < object->list.length) {
si->encryptedDigest = elems[shift];
elems[shift] = NULL;
shift++;
}
if (shift < object->list.length && elems[shift]->class == CLASS_CONTEXT && elems[shift]->tag == 1) {
r_pkcs7_parse_attributes (&si->unauthenticatedAttributes, elems[shift]);
}
return true;
}
void r_pkcs7_free_signerinfo (RPKCS7SignerInfo* si) {
if (si) {
r_pkcs7_free_issuerandserialnumber (&si->issuerAndSerialNumber);
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_pkcs7_free_attributes (&si->unauthenticatedAttributes);
free (si);
}
}
bool r_pkcs7_parse_signerinfos (RPKCS7SignerInfos *ss, RASN1Object *object) {
ut32 i;
if (!ss && !object) {
return false;
}
if (object->list.length > 0) {
ss->elements = (RPKCS7SignerInfo **) calloc (object->list.length, sizeof (RPKCS7SignerInfo*));
if (!ss->elements) {
return false;
}
ss->length = object->list.length;
for (i = 0; i < ss->length; ++i) {
// r_pkcs7_parse_signerinfo returns bool,
// so i have to allocate before calling the function
ss->elements[i] = (RPKCS7SignerInfo *) malloc (sizeof (RPKCS7SignerInfo));
//should i handle invalid memory? the function checks the pointer
//or it should return if si->elements[i] == NULL ?
if (ss->elements[i]) {
//Memset is needed to initialize to 0 the structure and avoid garbage.
memset (ss->elements[i], 0, sizeof (RPKCS7SignerInfo));
r_pkcs7_parse_signerinfo (ss->elements[i], object->list.objects[i]);
}
}
}
return true;
}
void r_pkcs7_free_signerinfos (RPKCS7SignerInfos *ss) {
ut32 i;
if (ss) {
for (i = 0; i < ss->length; ++i) {
r_pkcs7_free_signerinfo (ss->elements[i]);
//Free the ptr, since isn't done by the function
free (ss->elements[i]);
ss->elements[i] = NULL;
}
free (ss->elements);
ss->elements = NULL;
// Used internally pkcs #7, so it should't free si.
}
}
bool r_pkcs7_parse_signeddata (RPKCS7SignedData *sd, RASN1Object *object) {
RASN1Object **elems;
ut32 shift = 3;
if (!sd || !object || object->list.length < 4) {
return false;
}
memset (sd, 0, sizeof (RPKCS7SignedData));
elems = object->list.objects;
//Following RFC
sd->version = (ut32) elems[0]->sector[0];
r_pkcs7_parse_digestalgorithmidentifier (&sd->digestAlgorithms, elems[1]);
r_pkcs7_parse_contentinfo (&sd->contentInfo, elems[2]);
//Optional
if (shift < object->list.length && elems[shift]->class == CLASS_CONTEXT && elems[shift]->tag == 0) {
r_pkcs7_parse_extendedcertificatesandcertificates (&sd->certificates, elems[shift]);
shift++;
}
//Optional
if (shift < object->list.length && elems[shift]->class == CLASS_CONTEXT && elems[shift]->tag == 1) {
r_pkcs7_parse_certificaterevocationlists (&sd->crls, elems[shift]);
shift++;
}
if (shift < object->list.length)
r_pkcs7_parse_signerinfos (&sd->signerinfos, elems[shift]);
return true;
}
void r_pkcs7_free_signeddata (RPKCS7SignedData* sd) {
if (sd) {
r_pkcs7_free_digestalgorithmidentifier (&sd->digestAlgorithms);
r_pkcs7_free_contentinfo (&sd->contentInfo);
r_pkcs7_free_extendedcertificatesandcertificates (&sd->certificates);
r_pkcs7_free_certificaterevocationlists (&sd->crls);
// Used internally pkcs #7, so it should't free sd.
}
}
RPKCS7Container *r_pkcs7_parse_container (const ut8 *buffer, ut32 length) {
RASN1Object *object;
RPKCS7Container *container;
if (!buffer || !length) {
return NULL;
}
container = (RPKCS7Container*) malloc (sizeof (RPKCS7Container));
if (!container) {
return NULL;
}
memset (container, 0, sizeof (RPKCS7Container));
object = r_asn1_create_object (buffer, length);
if (!object || object->list.length != 2 || object->list.objects[1]->list.length != 1) {
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);
return container;
}
void r_pkcs7_free_container (RPKCS7Container* container) {
if (container) {
r_asn1_free_string (container->contentType);
r_pkcs7_free_signeddata (&container->signedData);
free (container);
}
}
RPKCS7Attribute* r_pkcs7_parse_attribute (RASN1Object *object) {
RPKCS7Attribute* attribute;
if (!object || object->list.length < 1) {
return NULL;
}
attribute = (RPKCS7Attribute*) malloc (sizeof (RPKCS7Attribute));
if (!attribute) {
return NULL;
}
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;
}
return attribute;
}
void r_pkcs7_free_attribute (RPKCS7Attribute* attribute) {
if (attribute) {
r_asn1_free_object (attribute->data);
r_asn1_free_string (attribute->oid);
free (attribute);
}
}
bool r_pkcs7_parse_attributes (RPKCS7Attributes* attributes, RASN1Object *object) {
ut32 i;
if (!attributes || !object || !object->list.length) {
return false;
}
attributes->length = object->list.length;
if (attributes->length > 0) {
attributes->elements = (RPKCS7Attribute**) calloc (attributes->length, sizeof (RPKCS7Attribute*));
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]);
}
}
return true;
}
void r_pkcs7_free_attributes (RPKCS7Attributes* attributes) {
ut32 i;
if (attributes) {
for (i = 0; i < attributes->length; ++i) {
r_pkcs7_free_attribute (attributes->elements[i]);
}
free (attributes->elements);
attributes->elements = NULL;
// Used internally pkcs #7, so it should't free attributes.
}
}
char* r_pkcs7_signerinfos_dump (RX509CertificateRevocationList *crl, char* buffer, ut32 length, const char* pad) {
RASN1String *algo, *last, *next;
ut32 i, p;
int r;
char *tmp, *pad2, *pad3;
if (!crl || !buffer || !length) {
return NULL;
}
if (!pad) {
pad = "";
}
pad3 = r_str_newf ("%s ", pad);
if (!pad3) return NULL;
pad2 = pad3 + 2;
algo = crl->signature.algorithm;
last = crl->lastUpdate;
next = crl->nextUpdate;
r = snprintf (buffer, length, "%sCRL:\n%sSignature:\n%s%s\n%sIssuer\n",
pad, pad2, pad3, algo ? algo->string : "", pad2);
p = (unsigned) r;
if (r < 0 || !(tmp = r_x509_name_dump (&crl->issuer, buffer + p, length - p, pad3))) {
free (pad3);
return NULL;
}
p = tmp - buffer;
if (length <= p) {
free (pad3);
return NULL;
}
r = snprintf (buffer + p, length - p, "%sLast Update: %s\n%sNext Update: %s\n%sRevoked Certificates:\n",
pad2, last ? last->string : "Missing",
pad2, next ? next->string : "Missing", pad2);
p += (unsigned) r;
if (r < 0) {
free (pad3);
return NULL;
}
for (i = 0; i < crl->length; ++i) {
if (length <= p || !(tmp = r_x509_crlentry_dump (crl->revokedCertificates[i], buffer + p, length - p, pad3))) {
free (pad3);
return NULL;
}
p = tmp - buffer;
}
free (pad3);
return buffer + p;
}
char* r_x509_signedinfo_dump (RPKCS7SignerInfo *si, char* buffer, ut32 length, const char* pad) {
RASN1String *s;
RASN1Object *o;
ut32 i, p;
int r;
char *tmp, *pad2, *pad3;
if (!si || !buffer || !length) {
return NULL;
}
if (!pad) {
pad = "";
}
pad3 = r_str_newf ("%s ", pad);
if (!pad3) return NULL;
pad2 = pad3 + 2;
r = snprintf (buffer, length, "%sSignerInfo:\n%sVersion: v%u\n%sIssuer\n", pad, pad2, si->version + 1, pad2);
p = (unsigned) r;
if (r < 0) {
free (pad3);
return NULL;
}
if (length <= p || !(tmp = r_x509_name_dump (&si->issuerAndSerialNumber.issuer, buffer + p, length - p, pad3))) {
free (pad3);
return NULL;
}
p = tmp - buffer;
if ((o = si->issuerAndSerialNumber.serialNumber)) {
s = r_asn1_stringify_integer (o->sector, o->length);
} else {
s = NULL;
}
r = snprintf (buffer + p, length - p, "%sSerial Number:\n%s%s\n", pad2, pad3, s ? s->string : "Missing");
p += (unsigned) r;
r_asn1_free_string (s);
if (r < 0) {
free (pad3);
return NULL;
}
s = si->digestAlgorithm.algorithm;
r = snprintf (buffer + p, length - p, "%sDigest Algorithm:\n%s%s\n%sAuthenticated Attributes:\n",
pad2, pad3, s ? s->string : "Missing", pad2);
p += (unsigned) r;
if (r < 0) {
free (pad3);
return NULL;
}
for (i = 0; i < si->authenticatedAttributes.length; ++i) {
RPKCS7Attribute* attr = si->authenticatedAttributes.elements[i];
if (!attr) continue;
r = snprintf (buffer + p, length - p, "%s%s: %u bytes\n",
pad3, attr->oid ? attr->oid->string : "Missing", attr->data ? attr->data->length : 0);
p += (unsigned) r;
if (r < 0) {
free (pad3);
return NULL;
}
}
s = si->digestEncryptionAlgorithm.algorithm;
r = snprintf (buffer + p, length - p, "%sDigest Encryption Algorithm\n%s%s\n",
pad2, pad3, s ? s->string : "Missing");
p += (unsigned) r;
if (r < 0) {
free (pad3);
return NULL;
}
if ((o = si->encryptedDigest)) s = r_asn1_stringify_bytes (o->sector, o->length);
else s = NULL;
r = snprintf (buffer + p, length - p, "%sEncrypted Digest: %u bytes\n%s\n", pad2, o ? o->length : 0, s ? s->string : "Missing");
p += (unsigned) r;
r_asn1_free_string (s);
if (r < 0) {
free (pad3);
return NULL;
}
r = snprintf (buffer + p, length - p, "%sUnauthenticated Attributes:\n", pad2);
p += (unsigned) r;
if (r < 0) {
free (pad3);
return NULL;
}
for (i = 0; i < si->unauthenticatedAttributes.length; ++i) {
RPKCS7Attribute* attr = si->unauthenticatedAttributes.elements[i];
if (!attr) continue;
o = attr->data;
r = snprintf (buffer + p, length - p, "%s%s: %u bytes\n",
pad3, attr->oid ? attr->oid->string : "Missing", o ? o->length : 0);
p += (unsigned) r;
if (r < 0) {
free (pad3);
return NULL;
}
}
return buffer + p;
}
char *r_pkcs7_container_dump (RPKCS7Container* container) {
RPKCS7SignedData *sd;
ut32 i, length, p;
int r;
char *buffer, *tmp = NULL;
if (!container) {
return NULL;
}
sd = &container->signedData;
p = 0;
length = 1024 + (container->signedData.certificates.length * 4096);
buffer = (char*) malloc (length);
if (!buffer) return NULL;
memset (buffer, 0, length);
r = snprintf (buffer, length, "signedData\n Version: %u\n Digest Algorithms:\n", sd->version);
p += (unsigned) r;
if (r < 0) {
free (buffer);
return NULL;
}
if (container->signedData.digestAlgorithms.elements) {
for (i = 0; i < container->signedData.digestAlgorithms.length; ++i) {
if (container->signedData.digestAlgorithms.elements[i]) {
r = snprintf (buffer + p, length - p, " %s\n", container->signedData.digestAlgorithms.elements[i]->algorithm->string);
p += (unsigned) r;
if (r < 0 || length <= p) {
free (buffer);
return NULL;
}
}
}
}
r = snprintf (buffer + p, length - p, " Certificates: %u\n", container->signedData.certificates.length);
p += (unsigned) r;
if (r < 0 || length <= p) {
free (buffer);
return NULL;
}
for (i = 0; i < container->signedData.certificates.length; ++i) {
if (length <= p || !(tmp = r_x509_certificate_dump (container->signedData.certificates.elements[i], buffer + p, length - p, " "))) {
free (buffer);
return NULL;
}
p = tmp - buffer;
}
for (i = 0; i < container->signedData.crls.length; ++i) {
if (length <= p || !(tmp = r_x509_crl_dump (container->signedData.crls.elements[i], buffer + p, length - p, " "))) {
free (buffer);
return NULL;
}
p = tmp - buffer;
}
p = tmp - buffer;
r = snprintf (buffer + p, length - p, " SignerInfos:\n");
p += (unsigned) r;
if (r < 0 || length <= p) {
free (buffer);
return NULL;
}
if (container->signedData.signerinfos.elements) {
for (i = 0; i < container->signedData.signerinfos.length; ++i) {
if (length <= p || !(tmp = r_x509_signedinfo_dump (container->signedData.signerinfos.elements[i], buffer + p, length - p, " "))) {
free (buffer);
return NULL;
}
p = tmp - buffer;
}
}
return buffer;
}

View File

@ -0,0 +1,38 @@
#ifndef R_PKCS7_INTERNAL_H
#define R_PKCS7_INTERNAL_H
R_API bool r_pkcs7_parse_certificaterevocationlists (RPKCS7CertificateRevocationLists *crls, RASN1Object *object);
R_API void r_pkcs7_free_certificaterevocationlists (RPKCS7CertificateRevocationLists *crls);
R_API bool r_pkcs7_parse_extendedcertificatesandcertificates (RPKCS7ExtendedCertificatesAndCertificates *ecac, RASN1Object *object);
R_API void r_pkcs7_free_extendedcertificatesandcertificates (RPKCS7ExtendedCertificatesAndCertificates *ecac);
R_API bool r_pkcs7_parse_digestalgorithmidentifier (RPKCS7DigestAlgorithmIdentifiers *dai, RASN1Object *object);
R_API void r_pkcs7_free_digestalgorithmidentifier (RPKCS7DigestAlgorithmIdentifiers *dai);
R_API bool r_pkcs7_parse_contentinfo (RPKCS7ContentInfo* ci, RASN1Object *object);
R_API void r_pkcs7_free_contentinfo (RPKCS7ContentInfo* ci);
R_API bool r_pkcs7_parse_issuerandserialnumber (RPKCS7IssuerAndSerialNumber* iasu, RASN1Object *object);
R_API void r_pkcs7_free_issuerandserialnumber (RPKCS7IssuerAndSerialNumber* iasu);
R_API RPKCS7Attribute* r_pkcs7_parse_attribute (RASN1Object *object);
R_API void r_pkcs7_free_attribute (RPKCS7Attribute* attribute);
R_API bool r_pkcs7_parse_attributes (RPKCS7Attributes* attribute, RASN1Object *object);
R_API void r_pkcs7_free_attributes (RPKCS7Attributes* attribute);
R_API bool r_pkcs7_parse_signerinfo (RPKCS7SignerInfo* si, RASN1Object *object);
R_API void r_pkcs7_free_signerinfo (RPKCS7SignerInfo* si);
R_API bool r_pkcs7_parse_signerinfos (RPKCS7SignerInfos* ss, RASN1Object *object);
R_API void r_pkcs7_free_signerinfos (RPKCS7SignerInfos* ss);
R_API bool r_pkcs7_parse_signeddata (RPKCS7SignedData *sd, RASN1Object *object);
R_API void r_pkcs7_free_signeddata (RPKCS7SignedData* sd);
R_API char* r_x509_signedinfo_dump (RPKCS7SignerInfo *si, char* buffer, ut32 length, const char* pad);
#endif /* R_PKCS7_INTERNAL_H */

722
libr/util/r_x509.c Normal file
View File

@ -0,0 +1,722 @@
#include <r_util.h>
#include <stdlib.h>
#include <string.h>
#include "r_x509_internal.h"
bool r_x509_parse_validity (RX509Validity *validity, RASN1Object *object) {
RASN1Object *o;
if (!validity || !object || object->list.length != 2) {
return false;
}
if (object->class == CLASS_UNIVERSAL &&
object->tag == TAG_SEQUENCE &&
object->form == FORM_CONSTRUCTED) {
o = object->list.objects[0];
if (o->class == CLASS_UNIVERSAL && o->form == FORM_PRIMITIVE) {
if (o->tag == TAG_UTCTIME) {
validity->notBefore = r_asn1_stringify_utctime (o->sector, o->length);
} else if (o->tag == TAG_GENERALIZEDTIME) {
validity->notBefore = r_asn1_stringify_time (o->sector, o->length);
}
}
o = object->list.objects[1];
if (o->class == CLASS_UNIVERSAL && o->form == FORM_PRIMITIVE) {
if (o->tag == TAG_UTCTIME) {
validity->notAfter = r_asn1_stringify_utctime (o->sector, o->length);
} else if (o->tag == TAG_GENERALIZEDTIME) {
validity->notAfter = r_asn1_stringify_time (o->sector, o->length);
}
}
}
return true;
}
bool r_x509_parse_algorithmidentifier (RX509AlgorithmIdentifier *ai, RASN1Object * object) {
if (!ai || !object || object->list.length < 1) {
return false;
}
if (object->list.objects[0]->class == CLASS_UNIVERSAL && object->list.objects[0]->tag == TAG_OID) {
ai->algorithm = r_asn1_stringify_oid (object->list.objects[0]->sector, object->list.objects[0]->length);
}
ai->parameters = NULL; // TODO
//ai->parameters = asn1_stringify_sector (object->list.objects[1]);
return true;
}
bool r_x509_parse_subjectpublickeyinfo (RX509SubjectPublicKeyInfo * spki, RASN1Object *object) {
RASN1Object *o;
if (!spki || !object || object->list.length != 2) {
return false;
}
r_x509_parse_algorithmidentifier (&spki->algorithm, object->list.objects[0]);
if (object->list.objects[1]) {
o = object->list.objects[1];
spki->subjectPublicKey = o;
object->list.objects[1] = NULL;
// if (o->length > 32) {
// spki->subjectPublicKey = asn1_stringify_bytes (o->sector, o->length);
// } else {
// spki->subjectPublicKey = asn1_stringify_bits (o->sector, o->length);
// }
if (o->list.length == 1 && o->list.objects[0]->list.length == 2) {
o = o->list.objects[0];
if (o->list.objects[0]) {
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);
// } else {
// spki->subjectPublicKeyExponent = asn1_stringify_integer (o->list.objects[0]->sector, o->list.objects[0]->length);
// }
}
if (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);
}
}
}
return true;
}
bool r_x509_parse_name (RX509Name *name, RASN1Object * object) {
ut32 i;
if (!name || !object || !object->list.length) {
return false;
}
if (object->class == CLASS_UNIVERSAL && object->tag == TAG_SEQUENCE) {
name->length = object->list.length;
name->names = (RASN1String**) calloc (name->length, sizeof (RASN1String*));
if (!name->names) {
name->length = 0;
return false;
}
name->oids = (RASN1String**) calloc (name->length, sizeof (RASN1String*));
if (!name->oids) {
name->length = 0;
free (name->names);
name->names = NULL;
return false;
}
for (i = 0; i < object->list.length; ++i) {
RASN1Object *o = object->list.objects[i];
if (o->class == CLASS_UNIVERSAL &&
o->tag == TAG_SET &&
o->form == FORM_CONSTRUCTED &&
o->list.length == 1) {
o = o->list.objects[0];
if (o->class == CLASS_UNIVERSAL &&
o->tag == TAG_SEQUENCE) {
if (o->list.objects[0]->class == CLASS_UNIVERSAL &&
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]->class == CLASS_UNIVERSAL) {
name->names[i] = r_asn1_stringify_string (o->list.objects[1]->sector, o->list.objects[1]->length);
}
}
}
}
}
return true;
}
bool r_x509_parse_extension (RX509Extension *ext, RASN1Object * object) {
RASN1Object *o;
if (!ext || !object || object->list.length < 2) {
return false;
}
memset (ext, 0, sizeof (RX509Extension));
o = object->list.objects[0];
if (o && o->tag == TAG_OID) {
ext->extnID = r_asn1_stringify_oid (object->list.objects[0]->sector, object->list.objects[0]->length);
o = object->list.objects[1];
if (o->tag == TAG_BOOLEAN) {
//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) {
ext->extnValue = o;
if (o == object->list.objects[1]) {
object->list.objects[1] = NULL;
} else if (object->list.length > 2 && o == object->list.objects[2]) {
object->list.objects[2] = NULL;
}
}
}
return true;
}
bool r_x509_parse_extensions (RX509Extensions *ext, RASN1Object * object) {
ut32 i;
if (!ext || !object || object->list.length != 1 || !object->list.objects[0]->length) {
return false;
}
object = object->list.objects[0];
ext->extensions = (RX509Extension**) calloc (object->list.length, sizeof (RX509Extension*));
if (!ext->extensions) {
return false;
}
ext->length = object->list.length;
for (i = 0; i < object->list.length; ++i) {
ext->extensions[i] = (RX509Extension*) malloc (sizeof (RX509Extension));
if (!r_x509_parse_extension (ext->extensions[i], object->list.objects[i])) {
free (ext->extensions[i]);
ext->extensions[i] = NULL;
}
}
return true;
}
bool r_x509_parse_tbscertificate (RX509TBSCertificate *tbsc, RASN1Object * object) {
RASN1Object **elems;
ut32 i;
ut32 shift = 0;
if (!tbsc || !object || object->list.length < 6) {
return false;
}
elems = object->list.objects;
//Following RFC
if (elems[0]->list.length == 1 &&
elems[0]->class == CLASS_CONTEXT &&
elems[0]->form == FORM_CONSTRUCTED &&
elems[0]->list.objects[0]->tag == TAG_INTEGER &&
elems[0]->list.objects[0]->length == 1) {
//Integer inside a CLASS_CONTEXT
tbsc->version = (ut32) elems[0]->list.objects[0]->sector[0];
shift = 1;
} else {
tbsc->version = 0;
}
if (shift < object->list.length && elems[shift]->class == CLASS_UNIVERSAL && elems[shift]->tag == TAG_INTEGER) {
tbsc->serialNumber = r_asn1_stringify_integer (elems[shift]->sector, elems[shift]->length);
}
r_x509_parse_algorithmidentifier (&tbsc->signature, elems[shift + 1]);
r_x509_parse_name (&tbsc->issuer, elems[shift + 2]);
r_x509_parse_validity (&tbsc->validity, elems[shift + 3]);
r_x509_parse_name (&tbsc->subject, elems[shift + 4]);
r_x509_parse_subjectpublickeyinfo (&tbsc->subjectPublicKeyInfo, elems[shift + 5]);
if (tbsc->version > 0) {
for (i = shift + 6; i < object->list.length; ++i) {
if (elems[i]->class != CLASS_CONTEXT) continue;
if (elems[i]->tag == 1) {
tbsc->issuerUniqueID = elems[i];
elems[i] = NULL;
}
if (elems[i]->tag == 2) {
tbsc->subjectUniqueID = elems[i];
elems[i] = NULL;
}
if (tbsc->version == 2 && elems[i]->tag == 3 && elems[i]->form == FORM_CONSTRUCTED) {
r_x509_parse_extensions (&tbsc->extensions, elems[i]);
elems[i] = NULL;
}
}
}
return true;
}
RX509Certificate * r_x509_parse_certificate (RASN1Object *object) {
RX509Certificate *certificate;
RASN1Object *tmp;
if (!object) {
return NULL;
}
certificate = (RX509Certificate*) malloc (sizeof (RX509Certificate));
if (!certificate) {
return NULL;
}
memset (certificate, 0, sizeof (RX509Certificate));
if (object->class != 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);
free (certificate);
return NULL;
}
tmp = object->list.objects[2];
if (tmp->class != CLASS_UNIVERSAL || tmp->form != FORM_PRIMITIVE || tmp->tag != TAG_BITSTRING) {
r_asn1_free_object (object);
free (certificate);
return NULL;
}
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);
free (certificate);
return NULL;
}
return certificate;
}
RX509Certificate * r_x509_parse_certificate2 (const ut8 *buffer, ut32 length) {
RX509Certificate *certificate;
RASN1Object *object;
if (!buffer || !length) {
return NULL;
}
object = r_asn1_create_object (buffer, length);
certificate = r_x509_parse_certificate (object);
r_asn1_free_object (object);
return certificate;
}
RX509CRLEntry *r_x509_parse_crlentry (RASN1Object *object) {
RX509CRLEntry *entry;
if (!object || object->list.length != 2) {
return NULL;
}
entry = (RX509CRLEntry *) malloc (sizeof (RX509CRLEntry));
if (!entry) {
return NULL;
}
entry->userCertificate = object->list.objects[0];
object->list.objects[0] = NULL;
entry->revocationDate = r_asn1_stringify_utctime (object->list.objects[1]->sector, object->list.objects[1]->length);
return entry;
}
RX509CertificateRevocationList* r_x509_parse_crl (RASN1Object *object) {
RX509CertificateRevocationList *crl;
RASN1Object **elems;
if (!object && object->list.length < 4) {
return NULL;
}
crl = (RX509CertificateRevocationList *) malloc (sizeof (RX509CertificateRevocationList));
if (!crl) {
return NULL;
}
memset (crl, 0, sizeof (RX509CertificateRevocationList));
elems = object->list.objects;
r_x509_parse_algorithmidentifier (&crl->signature, elems[0]);
r_x509_parse_name (&crl->issuer, elems[1]);
crl->lastUpdate = r_asn1_stringify_utctime (elems[2]->sector, elems[2]->length);
crl->nextUpdate = r_asn1_stringify_utctime (elems[3]->sector, elems[3]->length);
if (object->list.length > 4) {
ut32 i;
crl->revokedCertificates = calloc (object->list.objects[4]->list.length, sizeof (RX509CRLEntry*));
if (!crl->revokedCertificates) {
free (crl);
return NULL;
}
crl->length = object->list.objects[4]->list.length;
for (i = 0; i < object->list.objects[4]->list.length; ++i) {
crl->revokedCertificates[i] = r_x509_parse_crlentry (object->list.objects[4]->list.objects[i]);
}
}
return crl;
}
void r_x509_free_algorithmidentifier (RX509AlgorithmIdentifier * ai) {
if (!ai) {
return;
}
r_asn1_free_string (ai->algorithm);
r_asn1_free_string (ai->parameters);
//no need to free ai, since this functions is used internally
}
void r_x509_free_validity (RX509Validity * validity) {
if (!validity) {
return;
}
r_asn1_free_string (validity->notAfter);
r_asn1_free_string (validity->notBefore);
// not freeing validity since it's not allocated dinamically
}
void r_x509_free_name (RX509Name * name) {
ut32 i;
if (!name) {
return;
}
if (name->names) {
for (i = 0; i < name->length; ++i) {
r_asn1_free_string (name->oids[i]);
r_asn1_free_string (name->names[i]);
}
free (name->names);
}
// not freeing name since it's not allocated dinamically
}
void r_x509_free_extension (RX509Extension * ex) {
if (ex) {
r_asn1_free_string (ex->extnID);
r_asn1_free_object (ex->extnValue);
//this is allocated dinamically so, i'll free
free (ex);
}
}
void r_x509_free_extensions (RX509Extensions * ex) {
ut32 i;
if (!ex) {
return;
}
if (ex->extensions) {
for (i = 0; i < ex->length; ++i) {
r_x509_free_extension (ex->extensions[i]);
}
free (ex->extensions);
}
//no need to free ex, since this functions is used internally
}
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);
// No need to free spki, since it's a static variable.
}
}
void r_x509_free_tbscertificate (RX509TBSCertificate * tbsc) {
if (tbsc) {
// version is ut32
r_asn1_free_string (tbsc->serialNumber);
r_x509_free_algorithmidentifier (&tbsc->signature);
r_x509_free_name (&tbsc->issuer);
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_x509_free_extensions (&tbsc->extensions);
//no need to free tbsc, since this functions is used internally
}
}
void r_x509_free_certificate (RX509Certificate * certificate) {
if (certificate) {
r_asn1_free_object (certificate->signature);
r_x509_free_algorithmidentifier (&certificate->algorithmIdentifier);
r_x509_free_tbscertificate (&certificate->tbsCertificate);
free (certificate);
}
}
void r_x509_free_crlentry (RX509CRLEntry *entry) {
if (entry) {
r_asn1_free_object (entry->userCertificate);
r_asn1_free_string (entry->revocationDate);
free (entry);
}
}
void r_x509_free_crl (RX509CertificateRevocationList *crl) {
ut32 i;
if (crl) {
r_x509_free_algorithmidentifier (&crl->signature);
r_x509_free_name (&crl->issuer);
r_asn1_free_string (crl->nextUpdate);
r_asn1_free_string (crl->lastUpdate);
if (crl->revokedCertificates) {
for (i = 0; i < crl->length; ++i) {
r_x509_free_crlentry (crl->revokedCertificates[i]);
crl->revokedCertificates[i] = NULL;
}
free (crl->revokedCertificates);
crl->revokedCertificates = NULL;
}
free (crl);
}
}
char* r_x509_validity_dump (RX509Validity* validity, char* buffer, ut32 length, const char* pad) {
int p;
if (!validity || !buffer || !length) {
return NULL;
}
if (!pad)
pad = "";
const char* b = validity->notBefore ? validity->notBefore->string : "Missing";
const char* a = validity->notAfter ? validity->notAfter->string : "Missing";
p = snprintf (buffer, length, "%sNot Before: %s\n%sNot After: %s\n", pad, b, pad, a);
return p < 0 ? NULL : buffer + (unsigned) p;
}
char* r_x509_name_dump (RX509Name* name, char* buffer, ut32 length, const char* pad) {
ut32 i, p, len;
int r;
char* c;
if (!name || !buffer || !length) {
return NULL;
}
if (!pad) {
pad = "";
}
len = length;
c = buffer;
if (!c) {
return NULL;
}
for (i = 0, p = 0; i < name->length; ++i) {
if (!name->oids[i] || !name->names[i]) continue;
r = snprintf (c + p, len - p, "%s%s: %s\n", pad, name->oids[i]->string, name->names[i]->string);
p += r;
if (r < 0 || len < p) {
return NULL;
}
}
return c + p;
}
char* r_x509_subjectpublickeyinfo_dump (RX509SubjectPublicKeyInfo* spki, char* buffer, ut32 length, const char* pad) {
int r;
const char *a;
if (!spki || !buffer || !length) {
return NULL;
}
if (!pad)
pad = "";
a = spki->algorithm.algorithm->string;
RASN1String* m = r_asn1_stringify_integer (spki->subjectPublicKeyModule->sector, spki->subjectPublicKeyModule->length);
RASN1String* e = r_asn1_stringify_bytes (spki->subjectPublicKeyExponent->sector, spki->subjectPublicKeyExponent->length);
r = snprintf (buffer, length, "%sAlgorithm: %s\n%sModule: %s\n%sExponent: %u bytes\n%s\n", pad, a, pad, m->string,
pad, spki->subjectPublicKeyExponent->length - 1, e->string);
r_asn1_free_string (m);
r_asn1_free_string (e);
return r < 0 ? NULL : buffer + (unsigned) r;
}
char* r_x509_extensions_dump (RX509Extensions* exts, char* buffer, ut32 length, const char* pad) {
ut32 i, p, len;
int r;
char* c;
if (!exts || !buffer || !length) {
return NULL;
}
if (!pad) {
pad = "";
}
len = length;
c = buffer;
if (!c) {
return NULL;
}
for (i = 0, p = 0, r = 0; i < exts->length; ++i) {
//RASN1String *s;
RX509Extension *e = exts->extensions[i];
if (!e) continue;
//TODO handle extensions..
//s = r_asn1_stringify_bytes (e->extnValue->sector, e->extnValue->length);
r = snprintf (c + p, len - p, "%s%s: %s\n%s%u bytes\n", pad, e->extnID->string, e->critical ? "critical" : "", pad, e->extnValue->length);
p += r;
//r_asn1_free_string (s);
if (r < 0 || len <= p) {
return NULL;
}
}
return c + p;
}
char* r_x509_tbscertificate_dump (RX509TBSCertificate* tbsc, char* buffer, ut32 length, const char* pad) {
RASN1String *sid = NULL, *iid = NULL;
char *pad2, *tmp;
ut32 p;
int r;
if (!tbsc || !buffer || !length) {
return NULL;
}
if (!pad) {
pad = "";
}
pad2 = r_str_newf ("%s ", pad);
if (!pad2) return NULL;
r = snprintf (buffer, length, "%sVersion: v%u\n"
"%sSerial Number:\n%s %s\n"
"%sSignature Algorithm:\n%s %s\n"
"%sIssuer:\n",
pad, tbsc->version + 1,
pad, pad, tbsc->serialNumber->string,
pad, pad, tbsc->signature.algorithm->string,
pad);
p = (unsigned) r;
if (r < 0 || length <= p || !(tmp = r_x509_name_dump (&tbsc->issuer, buffer + p, length - p, pad2))) {
free (pad2);
return NULL;
}
p = tmp - buffer;
if (length <= p) {
free (pad2);
return NULL;
}
r = snprintf (buffer + p, length - p, "%sValidity:\n", pad);
p += r;
if (r < 0 || length <= p || !(tmp = r_x509_validity_dump (&tbsc->validity, buffer + p, length - p, pad2))) {
free (pad2);
return NULL;
}
p = tmp - buffer;
if (r < 0 || length <= p) return NULL;
r = snprintf (buffer + p, length - p, "%sSubject:\n", pad);
p += r;
if (r < 0 || length <= p || !(tmp = r_x509_name_dump (&tbsc->subject, buffer + p, length - p, pad2))) {
free (pad2);
return NULL;
}
p = tmp - buffer;
if (r < 0 || length <= p) return NULL;
r = snprintf (buffer + p, length - p, "%sSubject Public Key Info:\n", pad);
p += r;
if (r < 0 || length <= p ||
!(tmp = r_x509_subjectpublickeyinfo_dump (&tbsc->subjectPublicKeyInfo, buffer + p, length - p, pad2))) {
free (pad2);
return NULL;
}
p = tmp - buffer;
if (tbsc->issuerUniqueID) {
iid = r_asn1_stringify_integer (tbsc->issuerUniqueID->sector, tbsc->issuerUniqueID->length);
if (iid) {
if (length <= p) return NULL;
r = snprintf (buffer + p, length - p, "%sIssuer Unique ID:\n%s %s", pad, pad, iid->string);
p += r;
} else {
free (pad2);
return NULL;
}
}
if (tbsc->subjectUniqueID) {
sid = r_asn1_stringify_integer (tbsc->subjectUniqueID->sector, tbsc->subjectUniqueID->length);
if (sid) {
if (length <= p) return NULL;
r = snprintf (buffer + p, length - p, "%sSubject Unique ID:\n%s %s", pad, pad, sid->string);
p += r;
} else {
free (pad2);
return NULL;
}
}
if (r < 0 || length <= p) return NULL;
r = snprintf (buffer + p, length - p, "%sExtensions:\n", pad);
p += r;
if (r < 0 || length <= p || !(tmp = r_x509_extensions_dump (&tbsc->extensions, buffer + p, length - p, pad2))) {
free (pad2);
return NULL;
}
free (pad2);
r_asn1_free_string (sid);
r_asn1_free_string (iid);
return buffer + p;
}
char* r_x509_certificate_dump (RX509Certificate* certificate, char* buffer, ut32 length, const char* pad) {
RASN1String *signature, *algo;
ut32 p;
int r;
char *tbsc, *pad2;
if (!certificate || !buffer || !length) {
return NULL;
}
if (!pad) {
pad = "";
}
pad2 = r_str_newf ("%s ", pad);
if (!pad2) return NULL;
if ((r = snprintf (buffer, length, "%sTBSCertificate:\n", pad)) < 0) return NULL;
p = (unsigned) r;
tbsc = r_x509_tbscertificate_dump (&certificate->tbsCertificate, buffer + p, length - p, pad2);
p = tbsc - buffer;
if (length <= p) {
free (pad2);
return NULL;
}
algo = certificate->algorithmIdentifier.algorithm;
signature = r_asn1_stringify_bytes (certificate->signature->sector, certificate->signature->length);
r = snprintf (buffer + p, length - p, "%sAlgorithm:\n%s%s\n%sSignature: %u bytes\n%s\n",
pad, pad2, algo ? algo->string : "",
pad, certificate->signature->length, signature ? signature->string : "");
if (r < 0) {
free (pad2);
return NULL;
}
p += (unsigned) r;
free (pad2);
r_asn1_free_string (signature);
return buffer + p;
}
char* r_x509_crlentry_dump (RX509CRLEntry *crle, char* buffer, ut32 length, const char* pad) {
RASN1String *id = NULL, *utc;
int r;
if (!crle || !buffer || !length) {
return NULL;
}
if (!pad) {
pad = "";
}
utc = crle->revocationDate;
if (crle->userCertificate) {
id = r_asn1_stringify_integer (crle->userCertificate->sector, crle->userCertificate->length);
}
r = snprintf (buffer, length, "%sUser Certificate:\n%s %s\n"
"%sRevocation Date:\n%s %s\n",
pad, pad, id ? id->string : "Missing",
pad, pad, utc ? utc->string : "Missing");
return r < 0 ? NULL : buffer + (unsigned) r;
}
char* r_x509_crl_dump (RX509CertificateRevocationList *crl, char* buffer, ut32 length, const char* pad) {
RASN1String *algo, *last, *next;
ut32 i, p;
int r;
char *tmp, *pad2, *pad3;
if (!crl || !buffer || !length) {
return NULL;
}
if (!pad) {
pad = "";
}
pad3 = r_str_newf ("%s ", pad);
if (!pad3) return NULL;
pad2 = pad3 + 2;
algo = crl->signature.algorithm;
last = crl->lastUpdate;
next = crl->nextUpdate;
r = snprintf (buffer, length, "%sCRL:\n%sSignature:\n%s%s\n%sIssuer\n",
pad, pad2, pad3, algo ? algo->string : "", pad2);
p = (unsigned) r;
if (r < 0 || !(tmp = r_x509_name_dump (&crl->issuer, buffer + p, length - p, pad3))) {
free (pad3);
return NULL;
}
p = tmp - buffer;
if (length <= p) {
free (pad3);
return NULL;
}
r = snprintf (buffer + p, length - p, "%sLast Update: %s\n%sNext Update: %s\n%sRevoked Certificates:\n",
pad2, last ? last->string : "Missing",
pad2, next ? next->string : "Missing", pad2);
p += (unsigned) r;
if (r < 0) {
free (pad3);
return NULL;
}
for (i = 0; i < crl->length; ++i) {
if (length <= p || !(tmp = r_x509_crlentry_dump (crl->revokedCertificates[i], buffer + p, length - p, pad3))) {
free (pad3);
return NULL;
}
p = tmp - buffer;
}
free (pad3);
return buffer + p;
}

View File

@ -0,0 +1,38 @@
#ifndef R_X509_INTERNAL_H
#define R_X509_INTERNAL_H
#include "r_asn1_internal.h"
R_API bool r_x509_parse_validity (RX509Validity *validity, RASN1Object *object);
R_API void r_x509_free_validity (RX509Validity* validity);
R_API bool r_x509_parse_algorithmidentifier (RX509AlgorithmIdentifier *ai, RASN1Object * object);
R_API void r_x509_free_algorithmidentifier (RX509AlgorithmIdentifier * ai);
R_API bool r_x509_parse_subjectpublickeyinfo (RX509SubjectPublicKeyInfo * spki, RASN1Object *object);
R_API void r_x509_free_subjectpublickeyinfo (RX509SubjectPublicKeyInfo * spki);
R_API bool r_x509_parse_name (RX509Name *name, RASN1Object * object);
R_API void r_x509_free_name (RX509Name * name);
R_API bool r_x509_parse_extension (RX509Extension *ext, RASN1Object * object);
R_API void r_x509_free_extension (RX509Extension * ex);
R_API bool r_x509_parse_extensions (RX509Extensions *ext, RASN1Object * object);
R_API void r_x509_free_extensions (RX509Extensions* ex);
R_API bool r_x509_parse_tbscertificate (RX509TBSCertificate *tbsc, RASN1Object * object);
R_API void r_x509_free_tbscertificate (RX509TBSCertificate * tbsc);
R_API RX509CRLEntry *r_x509_parse_crlentry (RASN1Object *object);
R_API void r_x509_free_crlentry (RX509CRLEntry *entry);
R_API char* r_x509_validity_dump (RX509Validity* validity, char* buffer, ut32 length, const char* pad);
R_API char* r_x509_name_dump (RX509Name* name, char* buffer, ut32 length, const char* pad);
R_API char* r_x509_subjectpublickeyinfo_dump (RX509SubjectPublicKeyInfo* spki, char* buffer, ut32 length, const char* pad);
R_API char* r_x509_extensions_dump (RX509Extensions* exts, char* buffer, ut32 length, const char* pad);
R_API char* r_x509_tbscertificate_dump (RX509TBSCertificate* tbsc, char* buffer, ut32 length, const char* pad);
R_API char* r_x509_crlentry_dump (RX509CRLEntry *crle, char* buffer, ut32 length, const char* pad);
#endif /* R_X509_INTERNAL_H */