Split up X509 files into smaller modules
diff --git a/library/x509_crl.c b/library/x509_crl.c
new file mode 100644
index 0000000..3f1e175
--- /dev/null
+++ b/library/x509_crl.c
@@ -0,0 +1,740 @@
+/*
+ * X.509 certificate and private key decoding
+ *
+ * Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ * This file is part of PolarSSL (http://www.polarssl.org)
+ * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ * The ITU-T X.509 standard defines a certificate format for PKI.
+ *
+ * http://www.ietf.org/rfc/rfc3279.txt
+ * http://www.ietf.org/rfc/rfc3280.txt
+ *
+ * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
+ *
+ * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
+ * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_X509_CRL_PARSE_C)
+
+#include "polarssl/x509_crl.h"
+#include "polarssl/oid.h"
+#if defined(POLARSSL_PEM_PARSE_C)
+#include "polarssl/pem.h"
+#endif
+
+#if defined(POLARSSL_MEMORY_C)
+#include "polarssl/memory.h"
+#else
+#define polarssl_malloc malloc
+#define polarssl_free free
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#if defined(_WIN32)
+#include <windows.h>
+#else
+#include <time.h>
+#endif
+
+#if defined(POLARSSL_FS_IO)
+#include <stdio.h>
+#endif
+
+/*
+ * Version ::= INTEGER { v1(0), v2(1) }
+ */
+static int x509_crl_get_version( unsigned char **p,
+ const unsigned char *end,
+ int *ver )
+{
+ int ret;
+
+ if( ( ret = asn1_get_int( p, end, ver ) ) != 0 )
+ {
+ if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+ {
+ *ver = 0;
+ return( 0 );
+ }
+
+ return( POLARSSL_ERR_X509_CERT_INVALID_VERSION + ret );
+ }
+
+ return( 0 );
+}
+
+/*
+ * X.509 CRL v2 extensions (no extensions parsed yet.)
+ */
+static int x509_get_crl_ext( unsigned char **p,
+ const unsigned char *end,
+ x509_buf *ext )
+{
+ int ret;
+ size_t len = 0;
+
+ /* Get explicit tag */
+ if( ( ret = x509_get_ext( p, end, ext, 0) ) != 0 )
+ {
+ if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+ return( 0 );
+
+ return( ret );
+ }
+
+ while( *p < end )
+ {
+ if( ( ret = asn1_get_tag( p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ *p += len;
+ }
+
+ if( *p != end )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+/*
+ * X.509 CRL v2 entry extensions (no extensions parsed yet.)
+ */
+static int x509_get_crl_entry_ext( unsigned char **p,
+ const unsigned char *end,
+ x509_buf *ext )
+{
+ int ret;
+ size_t len = 0;
+
+ /* OPTIONAL */
+ if (end <= *p)
+ return( 0 );
+
+ ext->tag = **p;
+ ext->p = *p;
+
+ /*
+ * Get CRL-entry extension sequence header
+ * crlEntryExtensions Extensions OPTIONAL -- if present, MUST be v2
+ */
+ if( ( ret = asn1_get_tag( p, end, &ext->len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+ {
+ ext->p = NULL;
+ return( 0 );
+ }
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+ }
+
+ end = *p + ext->len;
+
+ if( end != *p + ext->len )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ while( *p < end )
+ {
+ if( ( ret = asn1_get_tag( p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ *p += len;
+ }
+
+ if( *p != end )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+/*
+ * X.509 CRL Entries
+ */
+static int x509_get_entries( unsigned char **p,
+ const unsigned char *end,
+ x509_crl_entry *entry )
+{
+ int ret;
+ size_t entry_len;
+ x509_crl_entry *cur_entry = entry;
+
+ if( *p == end )
+ return( 0 );
+
+ if( ( ret = asn1_get_tag( p, end, &entry_len,
+ ASN1_SEQUENCE | ASN1_CONSTRUCTED ) ) != 0 )
+ {
+ if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+ return( 0 );
+
+ return( ret );
+ }
+
+ end = *p + entry_len;
+
+ while( *p < end )
+ {
+ size_t len2;
+ const unsigned char *end2;
+
+ if( ( ret = asn1_get_tag( p, end, &len2,
+ ASN1_SEQUENCE | ASN1_CONSTRUCTED ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ cur_entry->raw.tag = **p;
+ cur_entry->raw.p = *p;
+ cur_entry->raw.len = len2;
+ end2 = *p + len2;
+
+ if( ( ret = x509_get_serial( p, end2, &cur_entry->serial ) ) != 0 )
+ return( ret );
+
+ if( ( ret = x509_get_time( p, end2, &cur_entry->revocation_date ) ) != 0 )
+ return( ret );
+
+ if( ( ret = x509_get_crl_entry_ext( p, end2, &cur_entry->entry_ext ) ) != 0 )
+ return( ret );
+
+ if ( *p < end )
+ {
+ cur_entry->next = polarssl_malloc( sizeof( x509_crl_entry ) );
+
+ if( cur_entry->next == NULL )
+ return( POLARSSL_ERR_X509_MALLOC_FAILED );
+
+ cur_entry = cur_entry->next;
+ memset( cur_entry, 0, sizeof( x509_crl_entry ) );
+ }
+ }
+
+ return( 0 );
+}
+
+/*
+ * Parse one or more CRLs and add them to the chained list
+ */
+int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen )
+{
+ int ret;
+ size_t len;
+ unsigned char *p, *end;
+ x509_crl *crl;
+#if defined(POLARSSL_PEM_PARSE_C)
+ size_t use_len;
+ pem_context pem;
+#endif
+
+ crl = chain;
+
+ /*
+ * Check for valid input
+ */
+ if( crl == NULL || buf == NULL )
+ return( POLARSSL_ERR_X509_INVALID_INPUT );
+
+ while( crl->version != 0 && crl->next != NULL )
+ crl = crl->next;
+
+ /*
+ * Add new CRL on the end of the chain if needed.
+ */
+ if ( crl->version != 0 && crl->next == NULL)
+ {
+ crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) );
+
+ if( crl->next == NULL )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_MALLOC_FAILED );
+ }
+
+ crl = crl->next;
+ memset( crl, 0, sizeof( x509_crl ) );
+ }
+
+#if defined(POLARSSL_PEM_PARSE_C)
+ pem_init( &pem );
+ ret = pem_read_buffer( &pem,
+ "-----BEGIN X509 CRL-----",
+ "-----END X509 CRL-----",
+ buf, NULL, 0, &use_len );
+
+ if( ret == 0 )
+ {
+ /*
+ * Was PEM encoded
+ */
+ buflen -= use_len;
+ buf += use_len;
+
+ /*
+ * Steal PEM buffer
+ */
+ p = pem.buf;
+ pem.buf = NULL;
+ len = pem.buflen;
+ pem_free( &pem );
+ }
+ else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+ {
+ pem_free( &pem );
+ return( ret );
+ }
+ else
+#endif
+ {
+ /*
+ * nope, copy the raw DER data
+ */
+ p = (unsigned char *) polarssl_malloc( len = buflen );
+
+ if( p == NULL )
+ return( POLARSSL_ERR_X509_MALLOC_FAILED );
+
+ memcpy( p, buf, buflen );
+
+ buflen = 0;
+ }
+
+ crl->raw.p = p;
+ crl->raw.len = len;
+ end = p + len;
+
+ /*
+ * CertificateList ::= SEQUENCE {
+ * tbsCertList TBSCertList,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING }
+ */
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT );
+ }
+
+ if( len != (size_t) ( end - p ) )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+ }
+
+ /*
+ * TBSCertList ::= SEQUENCE {
+ */
+ crl->tbs.p = p;
+
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+ }
+
+ end = p + len;
+ crl->tbs.len = end - crl->tbs.p;
+
+ /*
+ * Version ::= INTEGER OPTIONAL { v1(0), v2(1) }
+ * -- if present, MUST be v2
+ *
+ * signature AlgorithmIdentifier
+ */
+ if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 ||
+ ( ret = x509_get_alg_null( &p, end, &crl->sig_oid1 ) ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( ret );
+ }
+
+ crl->version++;
+
+ if( crl->version > 2 )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION );
+ }
+
+ if( ( ret = x509_get_sig_alg( &crl->sig_oid1, &crl->sig_md,
+ &crl->sig_pk ) ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG );
+ }
+
+ /*
+ * issuer Name
+ */
+ crl->issuer_raw.p = p;
+
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+ }
+
+ if( ( ret = x509_get_name( &p, p + len, &crl->issuer ) ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( ret );
+ }
+
+ crl->issuer_raw.len = p - crl->issuer_raw.p;
+
+ /*
+ * thisUpdate Time
+ * nextUpdate Time OPTIONAL
+ */
+ if( ( ret = x509_get_time( &p, end, &crl->this_update ) ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( ret );
+ }
+
+ if( ( ret = x509_get_time( &p, end, &crl->next_update ) ) != 0 )
+ {
+ if ( ret != ( POLARSSL_ERR_X509_CERT_INVALID_DATE +
+ POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) &&
+ ret != ( POLARSSL_ERR_X509_CERT_INVALID_DATE +
+ POLARSSL_ERR_ASN1_OUT_OF_DATA ) )
+ {
+ x509_crl_free( crl );
+ return( ret );
+ }
+ }
+
+ /*
+ * revokedCertificates SEQUENCE OF SEQUENCE {
+ * userCertificate CertificateSerialNumber,
+ * revocationDate Time,
+ * crlEntryExtensions Extensions OPTIONAL
+ * -- if present, MUST be v2
+ * } OPTIONAL
+ */
+ if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( ret );
+ }
+
+ /*
+ * crlExtensions EXPLICIT Extensions OPTIONAL
+ * -- if present, MUST be v2
+ */
+ if( crl->version == 2 )
+ {
+ ret = x509_get_crl_ext( &p, end, &crl->crl_ext );
+
+ if( ret != 0 )
+ {
+ x509_crl_free( crl );
+ return( ret );
+ }
+ }
+
+ if( p != end )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+ }
+
+ end = crl->raw.p + crl->raw.len;
+
+ /*
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING
+ */
+ if( ( ret = x509_get_alg_null( &p, end, &crl->sig_oid2 ) ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( ret );
+ }
+
+ if( crl->sig_oid1.len != crl->sig_oid2.len ||
+ memcmp( crl->sig_oid1.p, crl->sig_oid2.p, crl->sig_oid1.len ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_CERT_SIG_MISMATCH );
+ }
+
+ if( ( ret = x509_get_sig( &p, end, &crl->sig ) ) != 0 )
+ {
+ x509_crl_free( crl );
+ return( ret );
+ }
+
+ if( p != end )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+ }
+
+ if( buflen > 0 )
+ {
+ crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) );
+
+ if( crl->next == NULL )
+ {
+ x509_crl_free( crl );
+ return( POLARSSL_ERR_X509_MALLOC_FAILED );
+ }
+
+ crl = crl->next;
+ memset( crl, 0, sizeof( x509_crl ) );
+
+ return( x509parse_crl( crl, buf, buflen ) );
+ }
+
+ return( 0 );
+}
+
+#if defined(POLARSSL_FS_IO)
+/*
+ * Load one or more CRLs and add them to the chained list
+ */
+int x509parse_crlfile( x509_crl *chain, const char *path )
+{
+ int ret;
+ size_t n;
+ unsigned char *buf;
+
+ if ( ( ret = x509_load_file( path, &buf, &n ) ) != 0 )
+ return( ret );
+
+ ret = x509parse_crl( chain, buf, n );
+
+ memset( buf, 0, n + 1 );
+ polarssl_free( buf );
+
+ return( ret );
+}
+#endif /* POLARSSL_FS_IO */
+
+#if defined _MSC_VER && !defined snprintf
+#include <stdarg.h>
+
+#if !defined vsnprintf
+#define vsnprintf _vsnprintf
+#endif // vsnprintf
+
+/*
+ * Windows _snprintf and _vsnprintf are not compatible to linux versions.
+ * Result value is not size of buffer needed, but -1 if no fit is possible.
+ *
+ * This fuction tries to 'fix' this by at least suggesting enlarging the
+ * size by 20.
+ */
+static int compat_snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+ int res = -1;
+
+ va_start( ap, format );
+
+ res = vsnprintf( str, size, format, ap );
+
+ va_end( ap );
+
+ // No quick fix possible
+ if ( res < 0 )
+ return( (int) size + 20 );
+
+ return res;
+}
+
+#define snprintf compat_snprintf
+#endif
+
+#define POLARSSL_ERR_DEBUG_BUF_TOO_SMALL -2
+
+#define SAFE_SNPRINTF() \
+{ \
+ if( ret == -1 ) \
+ return( -1 ); \
+ \
+ if ( (unsigned int) ret > n ) { \
+ p[n - 1] = '\0'; \
+ return POLARSSL_ERR_DEBUG_BUF_TOO_SMALL;\
+ } \
+ \
+ n -= (unsigned int) ret; \
+ p += (unsigned int) ret; \
+}
+
+/*
+ * Return an informational string about the certificate.
+ */
+#define BEFORE_COLON 14
+#define BC "14"
+/*
+ * Return an informational string about the CRL.
+ */
+int x509parse_crl_info( char *buf, size_t size, const char *prefix,
+ const x509_crl *crl )
+{
+ int ret;
+ size_t n;
+ char *p;
+ const char *desc;
+ const x509_crl_entry *entry;
+
+ p = buf;
+ n = size;
+
+ ret = snprintf( p, n, "%sCRL version : %d",
+ prefix, crl->version );
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n%sissuer name : ", prefix );
+ SAFE_SNPRINTF();
+ ret = x509parse_dn_gets( p, n, &crl->issuer );
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n%sthis update : " \
+ "%04d-%02d-%02d %02d:%02d:%02d", prefix,
+ crl->this_update.year, crl->this_update.mon,
+ crl->this_update.day, crl->this_update.hour,
+ crl->this_update.min, crl->this_update.sec );
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n%snext update : " \
+ "%04d-%02d-%02d %02d:%02d:%02d", prefix,
+ crl->next_update.year, crl->next_update.mon,
+ crl->next_update.day, crl->next_update.hour,
+ crl->next_update.min, crl->next_update.sec );
+ SAFE_SNPRINTF();
+
+ entry = &crl->entry;
+
+ ret = snprintf( p, n, "\n%sRevoked certificates:",
+ prefix );
+ SAFE_SNPRINTF();
+
+ while( entry != NULL && entry->raw.len != 0 )
+ {
+ ret = snprintf( p, n, "\n%sserial number: ",
+ prefix );
+ SAFE_SNPRINTF();
+
+ ret = x509parse_serial_gets( p, n, &entry->serial);
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, " revocation date: " \
+ "%04d-%02d-%02d %02d:%02d:%02d",
+ entry->revocation_date.year, entry->revocation_date.mon,
+ entry->revocation_date.day, entry->revocation_date.hour,
+ entry->revocation_date.min, entry->revocation_date.sec );
+ SAFE_SNPRINTF();
+
+ entry = entry->next;
+ }
+
+ ret = snprintf( p, n, "\n%ssigned using : ", prefix );
+ SAFE_SNPRINTF();
+
+ ret = oid_get_sig_alg_desc( &crl->sig_oid1, &desc );
+ if( ret != 0 )
+ ret = snprintf( p, n, "???" );
+ else
+ ret = snprintf( p, n, "%s", desc );
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n" );
+ SAFE_SNPRINTF();
+
+ return( (int) ( size - n ) );
+}
+
+/*
+ * Unallocate all CRL data
+ */
+void x509_crl_free( x509_crl *crl )
+{
+ x509_crl *crl_cur = crl;
+ x509_crl *crl_prv;
+ x509_name *name_cur;
+ x509_name *name_prv;
+ x509_crl_entry *entry_cur;
+ x509_crl_entry *entry_prv;
+
+ if( crl == NULL )
+ return;
+
+ do
+ {
+ name_cur = crl_cur->issuer.next;
+ while( name_cur != NULL )
+ {
+ name_prv = name_cur;
+ name_cur = name_cur->next;
+ memset( name_prv, 0, sizeof( x509_name ) );
+ polarssl_free( name_prv );
+ }
+
+ entry_cur = crl_cur->entry.next;
+ while( entry_cur != NULL )
+ {
+ entry_prv = entry_cur;
+ entry_cur = entry_cur->next;
+ memset( entry_prv, 0, sizeof( x509_crl_entry ) );
+ polarssl_free( entry_prv );
+ }
+
+ if( crl_cur->raw.p != NULL )
+ {
+ memset( crl_cur->raw.p, 0, crl_cur->raw.len );
+ polarssl_free( crl_cur->raw.p );
+ }
+
+ crl_cur = crl_cur->next;
+ }
+ while( crl_cur != NULL );
+
+ crl_cur = crl;
+ do
+ {
+ crl_prv = crl_cur;
+ crl_cur = crl_cur->next;
+
+ memset( crl_prv, 0, sizeof( x509_crl ) );
+ if( crl_prv != crl )
+ polarssl_free( crl_prv );
+ }
+ while( crl_cur != NULL );
+}
+
+#endif