mirror of
https://github.com/radareorg/radare2.git
synced 2025-01-22 05:37:06 +00:00
Add ASN1, X.509 and PKCS parsers (+ iC for PE)
This commit is contained in:
parent
be78c631b0
commit
1f64c47c05
32
libr/bin/format/pe/pe.c
Normal file → Executable file
32
libr/bin/format/pe/pe.c
Normal file → Executable 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);
|
||||
|
@ -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
|
||||
|
@ -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 = §ions,
|
||||
.signature = &signature,
|
||||
.symbols = &symbols,
|
||||
.imports = &imports,
|
||||
.info = &info,
|
||||
|
@ -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
|
||||
|
102
libr/include/r_util/r_asn1.h
Normal file
102
libr/include/r_util/r_asn1.h
Normal 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 */
|
||||
|
73
libr/include/r_util/r_pkcs7.h
Normal file
73
libr/include/r_util/r_pkcs7.h
Normal 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 */
|
||||
|
122
libr/include/r_util/r_x509.h
Normal file
122
libr/include/r_util/r_x509.h
Normal 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 */
|
||||
|
@ -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
581
libr/util/r_asn1.c
Normal 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;
|
||||
}
|
10
libr/util/r_asn1_internal.h
Normal file
10
libr/util/r_asn1_internal.h
Normal 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
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
596
libr/util/r_pkcs7.c
Normal 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;
|
||||
}
|
||||
|
38
libr/util/r_pkcs7_internal.h
Normal file
38
libr/util/r_pkcs7_internal.h
Normal 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
722
libr/util/r_x509.c
Normal 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;
|
||||
}
|
38
libr/util/r_x509_internal.h
Normal file
38
libr/util/r_x509_internal.h
Normal 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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user