/* * Basic implementation of ITU-T X.690 (07/2002) for parsing BER encoded * X.509 certificates */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #ifdef HAVE_UNISTD_H # include <unistd.h> #endif #ifdef HAVE_STDLIB_H # include <stdlib.h> #endif #ifdef HAVE_STDARG_H # include <stdarg.h> #endif #include "asn1-x509.h" struct asn1_object { unsigned long tag; unsigned long size; void *contents; unsigned long asn1rep_len; void *asn1rep; }; struct x509_object { struct asn1_object wholething; struct asn1_object certificate; struct asn1_object version; struct asn1_object serial_number; struct asn1_object signature_algo; struct asn1_object issuer; struct asn1_object validity; struct asn1_object subject; struct asn1_object signature; }; static int _asn1_x509_read_asn1_object(unsigned char *buf, size_t buflen, va_list *args) { unsigned char small_object_size; unsigned char *buf_p; struct asn1_object *outbuf; outbuf = va_arg(*args, struct asn1_object *); if (outbuf == NULL) { return(0); } if (buflen == 0) { return(-1); } buf_p = buf; outbuf->tag = *buf_p; buf_p++; buflen--; if (buflen == 0) { return(-1); } small_object_size = *buf_p; buf_p++; buflen--; if (buflen == 0) { return(-1); } if ((small_object_size & 0x80) == 0x80) { outbuf->size = 0; for (small_object_size ^= 0x80; small_object_size; small_object_size--) { outbuf->size <<= 8; outbuf->size += *buf_p; buf_p++; buflen--; if (buflen == 0) { break; } } } else { outbuf->size = small_object_size; } if (outbuf->size > buflen) { return(-1); } outbuf->contents = buf_p; outbuf->asn1rep_len = outbuf->size + (buf_p - buf); outbuf->asn1rep = buf; buf_p += outbuf->size; buflen -= outbuf->size; return(_asn1_x509_read_asn1_object(buf_p, buflen, args)); } static int asn1_x509_read_asn1_object(unsigned char *buf, size_t buflen, ...) { va_list args; int retval; va_start(args, buflen); retval = _asn1_x509_read_asn1_object(buf, buflen, &args); va_end(args); return(retval); } static int asn1_x509_read_object(unsigned char *buf, size_t buflen, struct x509_object *outbuf) { int read_ret; read_ret = asn1_x509_read_asn1_object(buf, buflen, &outbuf->wholething, NULL); if (read_ret != 0) { return(-1); } read_ret = asn1_x509_read_asn1_object(outbuf->wholething.contents, outbuf->wholething.size, &outbuf->certificate, NULL); if (read_ret != 0) { return(-1); } read_ret = asn1_x509_read_asn1_object(outbuf->certificate.contents, outbuf->certificate.size, &outbuf->version, &outbuf->serial_number, &outbuf->signature_algo, &outbuf->issuer, &outbuf->validity, &outbuf->subject, NULL); if (read_ret != 0) { return(-1); } return(0); } ssize_t x509_to_issuer(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf) { struct x509_object x509; int read_ret; read_ret = asn1_x509_read_object(x509_der_buf, x509_der_buf_len, &x509); if (read_ret != 0) { return(-1); } if (outbuf) { *outbuf = x509.issuer.asn1rep; } return(x509.issuer.asn1rep_len); } ssize_t x509_to_subject(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf) { struct x509_object x509; int read_ret; read_ret = asn1_x509_read_object(x509_der_buf, x509_der_buf_len, &x509); if (read_ret != 0) { return(-1); } if (outbuf) { *outbuf = x509.subject.asn1rep; } return(x509.subject.asn1rep_len); } ssize_t x509_to_serial(void *x509_der_buf, size_t x509_der_buf_len, void **outbuf) { struct x509_object x509; int read_ret; read_ret = asn1_x509_read_object(x509_der_buf, x509_der_buf_len, &x509); if (read_ret != 0) { return(-1); } if (outbuf) { *outbuf = x509.serial_number.asn1rep; } return(x509.serial_number.asn1rep_len); }