Split up X509 files into smaller modules
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index e839bea..b601e44 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -49,13 +49,18 @@
sha512.c
ssl_cache.c
ssl_ciphersuites.c
- ssl_cli.c
- ssl_srv.c
+ ssl_cli.c
+ ssl_srv.c
ssl_tls.c
timing.c
version.c
- x509parse.c
- x509write.c
+ x509.c
+ x509_crt.c
+ x509_crl.c
+ x509_csr.c
+ x509_create.c
+ x509_crt_write.c
+ x509_csr_write.c
xtea.c
)
diff --git a/library/debug.c b/library/debug.c
index 5522fb6..1c7eeb6 100644
--- a/library/debug.c
+++ b/library/debug.c
@@ -224,7 +224,7 @@
}
#endif /* POLARSSL_BIGNUM_C */
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
static void debug_print_pk( const ssl_context *ssl, int level,
const char *file, int line,
const char *text, const pk_context *pk )
@@ -288,6 +288,6 @@
crt = crt->next;
}
}
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
#endif
diff --git a/library/oid.c b/library/oid.c
index 0386ba1..485fd4c 100644
--- a/library/oid.c
+++ b/library/oid.c
@@ -32,7 +32,7 @@
#include "polarssl/oid.h"
#include "polarssl/rsa.h"
-#if defined(POLARSSL_X509_PARSE_C) || defined(POLARSSL_X509_WRITE_C)
+#if defined(POLARSSL_X509_USE_C) || defined(POLARSSL_X509_CREATE_C)
#include "polarssl/x509.h"
#endif
@@ -207,7 +207,7 @@
FN_OID_TYPED_FROM_ASN1(oid_x520_attr_t, x520_attr, oid_x520_attr_type);
FN_OID_GET_ATTR1(oid_get_attr_short_name, oid_x520_attr_t, x520_attr, const char *, short_name);
-#if defined(POLARSSL_X509_PARSE_C) || defined(POLARSSL_X509_WRITE_C)
+#if defined(POLARSSL_X509_USE_C) || defined(POLARSSL_X509_CREATE_C)
/*
* For X509 extensions
*/
@@ -260,7 +260,7 @@
FN_OID_TYPED_FROM_ASN1(oid_descriptor_t, ext_key_usage, oid_ext_key_usage);
FN_OID_GET_ATTR1(oid_get_extended_key_usage, oid_descriptor_t, ext_key_usage, const char *, description);
-#endif /* POLARSSL_X509_PARSE_C || POLARSSL_X509_WRITE_C */
+#endif /* POLARSSL_X509_USE_C || POLARSSL_X509_CREATE_C */
#if defined(POLARSSL_MD_C)
/*
diff --git a/library/ssl_cache.c b/library/ssl_cache.c
index 7c7da4b..3090dc0 100644
--- a/library/ssl_cache.c
+++ b/library/ssl_cache.c
@@ -85,7 +85,7 @@
session->verify_result = entry->session.verify_result;
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
/*
* Restore peer certificate (without rest of the original chain)
*/
@@ -104,7 +104,7 @@
return( 1 );
}
}
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
return( 0 );
}
@@ -163,13 +163,13 @@
{
cur = old;
memset( &cur->session, 0, sizeof(ssl_session) );
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
if( cur->peer_cert.p != NULL )
{
polarssl_free( cur->peer_cert.p );
memset( &cur->peer_cert, 0, sizeof(x509_buf) );
}
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
}
#else /* POLARSSL_HAVE_TIME */
/*
@@ -184,13 +184,13 @@
cur = cache->chain;
cache->chain = cur->next;
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
if( cur->peer_cert.p != NULL )
{
polarssl_free( cur->peer_cert.p );
memset( &cur->peer_cert, 0, sizeof(x509_buf) );
}
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
memset( cur, 0, sizeof(ssl_cache_entry) );
prv->next = cur;
@@ -217,7 +217,7 @@
memcpy( &cur->session, session, sizeof( ssl_session ) );
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
/*
* Store peer certificate
*/
@@ -233,7 +233,7 @@
cur->session.peer_cert = NULL;
}
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
return( 0 );
}
@@ -267,10 +267,10 @@
ssl_session_free( &prv->session );
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
if( prv->peer_cert.p != NULL )
polarssl_free( prv->peer_cert.p );
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
polarssl_free( prv );
}
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 0ffe886..28d3a6c 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -62,9 +62,9 @@
{
unsigned char *p = buf;
size_t left = buf_len;
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
size_t cert_len;
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
if( left < sizeof( ssl_session ) )
return( -1 );
@@ -73,7 +73,7 @@
p += sizeof( ssl_session );
left -= sizeof( ssl_session );
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
((ssl_session *) buf)->peer_cert = NULL;
if( session->peer_cert == NULL )
@@ -92,7 +92,7 @@
memcpy( p, session->peer_cert->raw.p, cert_len );
p += cert_len;
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
*olen = p - buf;
@@ -107,9 +107,9 @@
{
const unsigned char *p = buf;
const unsigned char * const end = buf + len;
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
size_t cert_len;
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
if( p + sizeof( ssl_session ) > end )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
@@ -117,7 +117,7 @@
memcpy( session, p, sizeof( ssl_session ) );
p += sizeof( ssl_session );
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
if( p + 3 > end )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
@@ -144,7 +144,7 @@
if( ( ret = x509parse_crt( session->peer_cert, p, cert_len ) ) != 0 )
{
- x509_free( session->peer_cert );
+ x509_crt_free( session->peer_cert );
polarssl_free( session->peer_cert );
session->peer_cert = NULL;
return( ret );
@@ -152,7 +152,7 @@
p += cert_len;
}
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
if( p != end )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 24cee1c..d0534af 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -75,7 +75,7 @@
ssl_session_free( dst );
memcpy( dst, src, sizeof( ssl_session ) );
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
if( src->peer_cert != NULL )
{
int ret;
@@ -93,7 +93,7 @@
return( ret );
}
}
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
#if defined(POLARSSL_SSL_SESSION_TICKETS)
if( src->ticket != NULL )
@@ -2482,7 +2482,7 @@
/* In case we tried to reuse a session but it failed */
if( ssl->session_negotiate->peer_cert != NULL )
{
- x509_free( ssl->session_negotiate->peer_cert );
+ x509_crt_free( ssl->session_negotiate->peer_cert );
polarssl_free( ssl->session_negotiate->peer_cert );
}
@@ -3377,7 +3377,7 @@
ssl->authmode = authmode;
}
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
void ssl_set_verify( ssl_context *ssl,
int (*f_vrfy)(void *, x509_cert *, int, int *),
void *p_vrfy )
@@ -3385,7 +3385,7 @@
ssl->f_vrfy = f_vrfy;
ssl->p_vrfy = p_vrfy;
}
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
void ssl_set_rng( ssl_context *ssl,
int (*f_rng)(void *, unsigned char *, size_t),
@@ -3463,7 +3463,7 @@
ssl->ciphersuite_list[minor] = ciphersuites;
}
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain,
x509_crl *ca_crl, const char *peer_cn )
{
@@ -3523,7 +3523,7 @@
return( pk_init_ctx_rsa_alt( ssl->pk_key, rsa_key,
rsa_decrypt, rsa_sign, rsa_key_len ) );
}
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
#if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED)
void ssl_set_psk( ssl_context *ssl, const unsigned char *psk, size_t psk_len,
@@ -3730,7 +3730,7 @@
return( "unknown" );
}
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
const x509_cert *ssl_get_peer_cert( const ssl_context *ssl )
{
if( ssl == NULL || ssl->session == NULL )
@@ -3738,7 +3738,7 @@
return ssl->session->peer_cert;
}
-#endif /* POLARSSL_X509_PARSE_C */
+#endif /* POLARSSL_X509_CRT_PARSE_C */
int ssl_get_session( const ssl_context *ssl, ssl_session *dst )
{
@@ -4076,10 +4076,10 @@
void ssl_session_free( ssl_session *session )
{
-#if defined(POLARSSL_X509_PARSE_C)
+#if defined(POLARSSL_X509_CRT_PARSE_C)
if( session->peer_cert != NULL )
{
- x509_free( session->peer_cert );
+ x509_crt_free( session->peer_cert );
polarssl_free( session->peer_cert );
}
#endif
diff --git a/library/x509.c b/library/x509.c
new file mode 100644
index 0000000..40ee180
--- /dev/null
+++ b/library/x509.c
@@ -0,0 +1,798 @@
+/*
+ * 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_USE_C)
+
+#include "polarssl/x509.h"
+#include "polarssl/asn1.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>
+#if !defined(_WIN32)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#endif
+#endif
+
+/*
+ * CertificateSerialNumber ::= INTEGER
+ */
+int x509_get_serial( unsigned char **p, const unsigned char *end,
+ x509_buf *serial )
+{
+ int ret;
+
+ if( ( end - *p ) < 1 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL +
+ POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+ if( **p != ( ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2 ) &&
+ **p != ASN1_INTEGER )
+ return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL +
+ POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
+
+ serial->tag = *(*p)++;
+
+ if( ( ret = asn1_get_len( p, end, &serial->len ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + ret );
+
+ serial->p = *p;
+ *p += serial->len;
+
+ return( 0 );
+}
+
+/* Get an algorithm identifier without parameters (eg for signatures)
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ */
+int x509_get_alg_null( unsigned char **p, const unsigned char *end,
+ x509_buf *alg )
+{
+ int ret;
+
+ if( ( ret = asn1_get_alg_null( p, end, alg ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret );
+
+ return( 0 );
+}
+
+/*
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ */
+static int x509_get_attr_type_value( unsigned char **p,
+ const unsigned char *end,
+ x509_name *cur )
+{
+ int ret;
+ size_t len;
+ x509_buf *oid;
+ x509_buf *val;
+
+ if( ( ret = asn1_get_tag( p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret );
+
+ if( ( end - *p ) < 1 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_NAME +
+ POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+ oid = &cur->oid;
+ oid->tag = **p;
+
+ if( ( ret = asn1_get_tag( p, end, &oid->len, ASN1_OID ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret );
+
+ oid->p = *p;
+ *p += oid->len;
+
+ if( ( end - *p ) < 1 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_NAME +
+ POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+ if( **p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING &&
+ **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING &&
+ **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING )
+ return( POLARSSL_ERR_X509_CERT_INVALID_NAME +
+ POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
+
+ val = &cur->val;
+ val->tag = *(*p)++;
+
+ if( ( ret = asn1_get_len( p, end, &val->len ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret );
+
+ val->p = *p;
+ *p += val->len;
+
+ cur->next = NULL;
+
+ return( 0 );
+}
+
+/*
+ * RelativeDistinguishedName ::=
+ * SET OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ */
+int x509_get_name( unsigned char **p, const unsigned char *end,
+ x509_name *cur )
+{
+ int ret;
+ size_t len;
+ const unsigned char *end2;
+ x509_name *use;
+
+ if( ( ret = asn1_get_tag( p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SET ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret );
+
+ end2 = end;
+ end = *p + len;
+ use = cur;
+
+ do
+ {
+ if( ( ret = x509_get_attr_type_value( p, end, use ) ) != 0 )
+ return( ret );
+
+ if( *p != end )
+ {
+ use->next = (x509_name *) polarssl_malloc(
+ sizeof( x509_name ) );
+
+ if( use->next == NULL )
+ return( POLARSSL_ERR_X509_MALLOC_FAILED );
+
+ memset( use->next, 0, sizeof( x509_name ) );
+
+ use = use->next;
+ }
+ }
+ while( *p != end );
+
+ /*
+ * recurse until end of SEQUENCE is reached
+ */
+ if( *p == end2 )
+ return( 0 );
+
+ cur->next = (x509_name *) polarssl_malloc(
+ sizeof( x509_name ) );
+
+ if( cur->next == NULL )
+ return( POLARSSL_ERR_X509_MALLOC_FAILED );
+
+ memset( cur->next, 0, sizeof( x509_name ) );
+
+ return( x509_get_name( p, end2, cur->next ) );
+}
+
+/*
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime }
+ */
+int x509_get_time( unsigned char **p, const unsigned char *end,
+ x509_time *time )
+{
+ int ret;
+ size_t len;
+ char date[64];
+ unsigned char tag;
+
+ if( ( end - *p ) < 1 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_DATE +
+ POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+ tag = **p;
+
+ if ( tag == ASN1_UTC_TIME )
+ {
+ (*p)++;
+ ret = asn1_get_len( p, end, &len );
+
+ if( ret != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret );
+
+ memset( date, 0, sizeof( date ) );
+ memcpy( date, *p, ( len < sizeof( date ) - 1 ) ?
+ len : sizeof( date ) - 1 );
+
+ if( sscanf( date, "%2d%2d%2d%2d%2d%2d",
+ &time->year, &time->mon, &time->day,
+ &time->hour, &time->min, &time->sec ) < 5 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_DATE );
+
+ time->year += 100 * ( time->year < 50 );
+ time->year += 1900;
+
+ *p += len;
+
+ return( 0 );
+ }
+ else if ( tag == ASN1_GENERALIZED_TIME )
+ {
+ (*p)++;
+ ret = asn1_get_len( p, end, &len );
+
+ if( ret != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret );
+
+ memset( date, 0, sizeof( date ) );
+ memcpy( date, *p, ( len < sizeof( date ) - 1 ) ?
+ len : sizeof( date ) - 1 );
+
+ if( sscanf( date, "%4d%2d%2d%2d%2d%2d",
+ &time->year, &time->mon, &time->day,
+ &time->hour, &time->min, &time->sec ) < 5 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_DATE );
+
+ *p += len;
+
+ return( 0 );
+ }
+ else
+ return( POLARSSL_ERR_X509_CERT_INVALID_DATE + POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
+}
+
+int x509_get_sig( unsigned char **p, const unsigned char *end, x509_buf *sig )
+{
+ int ret;
+ size_t len;
+
+ if( ( end - *p ) < 1 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE +
+ POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+ sig->tag = **p;
+
+ if( ( ret = asn1_get_bitstring_null( p, end, &len ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE + ret );
+
+ sig->len = len;
+ sig->p = *p;
+
+ *p += len;
+
+ return( 0 );
+}
+
+int x509_get_sig_alg( const x509_buf *sig_oid, md_type_t *md_alg,
+ pk_type_t *pk_alg )
+{
+ int ret = oid_get_sig_alg( sig_oid, md_alg, pk_alg );
+
+ if( ret != 0 )
+ return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG + ret );
+
+ return( 0 );
+}
+
+/*
+ * X.509 Extensions (No parsing of extensions, pointer should
+ * be either manually updated or extensions should be parsed!
+ */
+int x509_get_ext( unsigned char **p, const unsigned char *end,
+ x509_buf *ext, int tag )
+{
+ int ret;
+ size_t len;
+
+ if( *p == end )
+ return( 0 );
+
+ ext->tag = **p;
+
+ if( ( ret = asn1_get_tag( p, end, &ext->len,
+ ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | tag ) ) != 0 )
+ return( ret );
+
+ ext->p = *p;
+ end = *p + ext->len;
+
+ /*
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ * Extension ::= SEQUENCE {
+ * extnID OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING }
+ */
+ if( ( ret = asn1_get_tag( p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ if( end != *p + len )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+#if defined(POLARSSL_FS_IO)
+/*
+ * Load all data from a file into a given buffer.
+ */
+int x509_load_file( const char *path, unsigned char **buf, size_t *n )
+{
+ FILE *f;
+ long size;
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( POLARSSL_ERR_X509_FILE_IO_ERROR );
+
+ fseek( f, 0, SEEK_END );
+ if( ( size = ftell( f ) ) == -1 )
+ {
+ fclose( f );
+ return( POLARSSL_ERR_X509_FILE_IO_ERROR );
+ }
+ fseek( f, 0, SEEK_SET );
+
+ *n = (size_t) size;
+
+ if( *n + 1 == 0 ||
+ ( *buf = (unsigned char *) polarssl_malloc( *n + 1 ) ) == NULL )
+ {
+ fclose( f );
+ return( POLARSSL_ERR_X509_MALLOC_FAILED );
+ }
+
+ if( fread( *buf, 1, *n, f ) != *n )
+ {
+ fclose( f );
+ polarssl_free( *buf );
+ return( POLARSSL_ERR_X509_FILE_IO_ERROR );
+ }
+
+ fclose( f );
+
+ (*buf)[*n] = '\0';
+
+ return( 0 );
+}
+
+#if defined(POLARSSL_RSA_C)
+/*
+ * Load and parse a private RSA key
+ */
+int x509parse_keyfile_rsa( rsa_context *rsa, const char *path, const char *pwd )
+{
+ int ret;
+ pk_context pk;
+
+ pk_init( &pk );
+
+ ret = pk_parse_keyfile( &pk, path, pwd );
+
+ if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) )
+ ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
+
+ if( ret == 0 )
+ rsa_copy( rsa, pk_rsa( pk ) );
+ else
+ rsa_free( rsa );
+
+ pk_free( &pk );
+
+ return( ret );
+}
+
+/*
+ * Load and parse a public RSA key
+ */
+int x509parse_public_keyfile_rsa( rsa_context *rsa, const char *path )
+{
+ int ret;
+ pk_context pk;
+
+ pk_init( &pk );
+
+ ret = pk_parse_public_keyfile( &pk, path );
+
+ if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) )
+ ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
+
+ if( ret == 0 )
+ rsa_copy( rsa, pk_rsa( pk ) );
+ else
+ rsa_free( rsa );
+
+ pk_free( &pk );
+
+ return( ret );
+}
+#endif /* POLARSSL_RSA_C */
+#endif /* POLARSSL_FS_IO */
+
+#if defined(POLARSSL_RSA_C)
+/*
+ * Parse a private RSA key
+ */
+int x509parse_key_rsa( rsa_context *rsa,
+ const unsigned char *key, size_t keylen,
+ const unsigned char *pwd, size_t pwdlen )
+{
+ int ret;
+ pk_context pk;
+
+ pk_init( &pk );
+
+ ret = pk_parse_key( &pk, key, keylen, pwd, pwdlen );
+
+ if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) )
+ ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
+
+ if( ret == 0 )
+ rsa_copy( rsa, pk_rsa( pk ) );
+ else
+ rsa_free( rsa );
+
+ pk_free( &pk );
+
+ return( ret );
+}
+
+/*
+ * Parse a public RSA key
+ */
+int x509parse_public_key_rsa( rsa_context *rsa,
+ const unsigned char *key, size_t keylen )
+{
+ int ret;
+ pk_context pk;
+
+ pk_init( &pk );
+
+ ret = pk_parse_public_key( &pk, key, keylen );
+
+ if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) )
+ ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
+
+ if( ret == 0 )
+ rsa_copy( rsa, pk_rsa( pk ) );
+ else
+ rsa_free( rsa );
+
+ pk_free( &pk );
+
+ return( ret );
+}
+#endif /* POLARSSL_RSA_C */
+
+#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; \
+}
+
+/*
+ * Store the name in printable form into buf; no more
+ * than size characters will be written
+ */
+int x509parse_dn_gets( char *buf, size_t size, const x509_name *dn )
+{
+ int ret;
+ size_t i, n;
+ unsigned char c;
+ const x509_name *name;
+ const char *short_name = NULL;
+ char s[128], *p;
+
+ memset( s, 0, sizeof( s ) );
+
+ name = dn;
+ p = buf;
+ n = size;
+
+ while( name != NULL )
+ {
+ if( !name->oid.p )
+ {
+ name = name->next;
+ continue;
+ }
+
+ if( name != dn )
+ {
+ ret = snprintf( p, n, ", " );
+ SAFE_SNPRINTF();
+ }
+
+ ret = oid_get_attr_short_name( &name->oid, &short_name );
+
+ if( ret == 0 )
+ ret = snprintf( p, n, "%s=", short_name );
+ else
+ ret = snprintf( p, n, "\?\?=" );
+ SAFE_SNPRINTF();
+
+ for( i = 0; i < name->val.len; i++ )
+ {
+ if( i >= sizeof( s ) - 1 )
+ break;
+
+ c = name->val.p[i];
+ if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
+ s[i] = '?';
+ else s[i] = c;
+ }
+ s[i] = '\0';
+ ret = snprintf( p, n, "%s", s );
+ SAFE_SNPRINTF();
+ name = name->next;
+ }
+
+ return( (int) ( size - n ) );
+}
+
+/*
+ * Store the serial in printable form into buf; no more
+ * than size characters will be written
+ */
+int x509parse_serial_gets( char *buf, size_t size, const x509_buf *serial )
+{
+ int ret;
+ size_t i, n, nr;
+ char *p;
+
+ p = buf;
+ n = size;
+
+ nr = ( serial->len <= 32 )
+ ? serial->len : 28;
+
+ for( i = 0; i < nr; i++ )
+ {
+ if( i == 0 && nr > 1 && serial->p[i] == 0x0 )
+ continue;
+
+ ret = snprintf( p, n, "%02X%s",
+ serial->p[i], ( i < nr - 1 ) ? ":" : "" );
+ SAFE_SNPRINTF();
+ }
+
+ if( nr != serial->len )
+ {
+ ret = snprintf( p, n, "...." );
+ SAFE_SNPRINTF();
+ }
+
+ return( (int) ( size - n ) );
+}
+
+/*
+ * Helper for writing "RSA key size", "EC key size", etc
+ */
+int x509_key_size_helper( char *buf, size_t size, const char *name )
+{
+ char *p = buf;
+ size_t n = size;
+ int ret;
+
+ if( strlen( name ) + sizeof( " key size" ) > size )
+ return POLARSSL_ERR_DEBUG_BUF_TOO_SMALL;
+
+ ret = snprintf( p, n, "%s key size", name );
+ SAFE_SNPRINTF();
+
+ return( 0 );
+}
+
+/*
+ * Return an informational string describing the given OID
+ */
+const char *x509_oid_get_description( x509_buf *oid )
+{
+ const char *desc = NULL;
+ int ret;
+
+ ret = oid_get_extended_key_usage( oid, &desc );
+
+ if( ret != 0 )
+ return( NULL );
+
+ return( desc );
+}
+
+/* Return the x.y.z.... style numeric string for the given OID */
+int x509_oid_get_numeric_string( char *buf, size_t size, x509_buf *oid )
+{
+ return oid_get_numeric_string( buf, size, oid );
+}
+
+/*
+ * Return 0 if the x509_time is still valid, or 1 otherwise.
+ */
+#if defined(POLARSSL_HAVE_TIME)
+int x509parse_time_expired( const x509_time *to )
+{
+ int year, mon, day;
+ int hour, min, sec;
+
+#if defined(_WIN32)
+ SYSTEMTIME st;
+
+ GetLocalTime(&st);
+
+ year = st.wYear;
+ mon = st.wMonth;
+ day = st.wDay;
+ hour = st.wHour;
+ min = st.wMinute;
+ sec = st.wSecond;
+#else
+ struct tm *lt;
+ time_t tt;
+
+ tt = time( NULL );
+ lt = localtime( &tt );
+
+ year = lt->tm_year + 1900;
+ mon = lt->tm_mon + 1;
+ day = lt->tm_mday;
+ hour = lt->tm_hour;
+ min = lt->tm_min;
+ sec = lt->tm_sec;
+#endif
+
+ if( year > to->year )
+ return( 1 );
+
+ if( year == to->year &&
+ mon > to->mon )
+ return( 1 );
+
+ if( year == to->year &&
+ mon == to->mon &&
+ day > to->day )
+ return( 1 );
+
+ if( year == to->year &&
+ mon == to->mon &&
+ day == to->day &&
+ hour > to->hour )
+ return( 1 );
+
+ if( year == to->year &&
+ mon == to->mon &&
+ day == to->day &&
+ hour == to->hour &&
+ min > to->min )
+ return( 1 );
+
+ if( year == to->year &&
+ mon == to->mon &&
+ day == to->day &&
+ hour == to->hour &&
+ min == to->min &&
+ sec > to->sec )
+ return( 1 );
+
+ return( 0 );
+}
+#else /* POLARSSL_HAVE_TIME */
+int x509parse_time_expired( const x509_time *to )
+{
+ ((void) to);
+ return( 0 );
+}
+#endif /* POLARSSL_HAVE_TIME */
+
+#endif /* POLARSSL_X509_USE_C */
diff --git a/library/x509_create.c b/library/x509_create.c
new file mode 100644
index 0000000..6991161
--- /dev/null
+++ b/library/x509_create.c
@@ -0,0 +1,267 @@
+/*
+ * X.509 base functions for creating certificates / CSRs
+ *
+ * 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.
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_X509_CREATE_C)
+
+#include "polarssl/x509.h"
+#include "polarssl/asn1write.h"
+#include "polarssl/oid.h"
+
+int x509write_string_to_names( asn1_named_data **head, char *name )
+{
+ int ret = 0;
+ char *s = name, *c = s;
+ char *end = s + strlen( s );
+ char *oid = NULL;
+ int in_tag = 1;
+ asn1_named_data *cur;
+
+ /* Clear existing chain if present */
+ asn1_free_named_data_list( head );
+
+ while( c <= end )
+ {
+ if( in_tag && *c == '=' )
+ {
+ if( memcmp( s, "CN", 2 ) == 0 && c - s == 2 )
+ oid = OID_AT_CN;
+ else if( memcmp( s, "C", 1 ) == 0 && c - s == 1 )
+ oid = OID_AT_COUNTRY;
+ else if( memcmp( s, "O", 1 ) == 0 && c - s == 1 )
+ oid = OID_AT_ORGANIZATION;
+ else if( memcmp( s, "L", 1 ) == 0 && c - s == 1 )
+ oid = OID_AT_LOCALITY;
+ else if( memcmp( s, "R", 1 ) == 0 && c - s == 1 )
+ oid = OID_PKCS9_EMAIL;
+ else if( memcmp( s, "OU", 2 ) == 0 && c - s == 2 )
+ oid = OID_AT_ORG_UNIT;
+ else if( memcmp( s, "ST", 2 ) == 0 && c - s == 2 )
+ oid = OID_AT_STATE;
+ else
+ {
+ ret = POLARSSL_ERR_X509WRITE_UNKNOWN_OID;
+ goto exit;
+ }
+
+ s = c + 1;
+ in_tag = 0;
+ }
+
+ if( !in_tag && ( *c == ',' || c == end ) )
+ {
+ if( ( cur = asn1_store_named_data( head, oid, strlen( oid ),
+ (unsigned char *) s,
+ c - s ) ) == NULL )
+ {
+ return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
+ }
+
+ while( c < end && *(c + 1) == ' ' )
+ c++;
+
+ s = c + 1;
+ in_tag = 1;
+ }
+ c++;
+ }
+
+exit:
+
+ return( ret );
+}
+
+/* The first byte of the value in the asn1_named_data structure is reserved
+ * to store the critical boolean for us
+ */
+int x509_set_extension( asn1_named_data **head, const char *oid, size_t oid_len,
+ int critical, const unsigned char *val, size_t val_len )
+{
+ asn1_named_data *cur;
+
+ if( ( cur = asn1_store_named_data( head, oid, oid_len,
+ NULL, val_len + 1 ) ) == NULL )
+ {
+ return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
+ }
+
+ cur->val.p[0] = critical;
+ memcpy( cur->val.p + 1, val, val_len );
+
+ return( 0 );
+}
+
+/*
+ * RelativeDistinguishedName ::=
+ * SET OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ *
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ */
+static int x509_write_name( unsigned char **p, unsigned char *start,
+ const char *oid, size_t oid_len,
+ const unsigned char *name, size_t name_len )
+{
+ int ret;
+ size_t len = 0;
+
+ // Write PrintableString for all except OID_PKCS9_EMAIL
+ //
+ if( OID_SIZE( OID_PKCS9_EMAIL ) == oid_len &&
+ memcmp( oid, OID_PKCS9_EMAIL, oid_len ) == 0 )
+ {
+ ASN1_CHK_ADD( len, asn1_write_ia5_string( p, start,
+ (const char *) name,
+ name_len ) );
+ }
+ else
+ {
+ ASN1_CHK_ADD( len, asn1_write_printable_string( p, start,
+ (const char *) name,
+ name_len ) );
+ }
+
+ // Write OID
+ //
+ ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_len ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SET ) );
+
+ return( len );
+}
+
+int x509_write_names( unsigned char **p, unsigned char *start,
+ asn1_named_data *first )
+{
+ int ret;
+ size_t len = 0;
+ asn1_named_data *cur = first;
+
+ while( cur != NULL )
+ {
+ ASN1_CHK_ADD( len, x509_write_name( p, start, (char *) cur->oid.p,
+ cur->oid.len,
+ cur->val.p, cur->val.len ) );
+ cur = cur->next;
+ }
+
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ return( len );
+}
+
+int x509_write_sig( unsigned char **p, unsigned char *start,
+ const char *oid, size_t oid_len,
+ unsigned char *sig, size_t size )
+{
+ int ret;
+ size_t len = 0;
+
+ if( *p - start < (int) size + 1 )
+ return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+
+ len = size;
+ (*p) -= len;
+ memcpy( *p, sig, len );
+
+ *--(*p) = 0;
+ len += 1;
+
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_BIT_STRING ) );
+
+ // Write OID
+ //
+ ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( p, start, oid,
+ oid_len, 0 ) );
+
+ return( len );
+}
+
+static int x509_write_extension( unsigned char **p, unsigned char *start,
+ asn1_named_data *ext )
+{
+ int ret;
+ size_t len = 0;
+
+ ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, ext->val.p + 1,
+ ext->val.len - 1 ) );
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, ext->val.len - 1 ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_OCTET_STRING ) );
+
+ if( ext->val.p[0] != 0 )
+ {
+ ASN1_CHK_ADD( len, asn1_write_bool( p, start, 1 ) );
+ }
+
+ ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, ext->oid.p,
+ ext->oid.len ) );
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, ext->oid.len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_OID ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ return( len );
+}
+
+/*
+ * Extension ::= SEQUENCE {
+ * extnID OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING
+ * -- contains the DER encoding of an ASN.1 value
+ * -- corresponding to the extension type identified
+ * -- by extnID
+ * }
+ */
+int x509_write_extensions( unsigned char **p, unsigned char *start,
+ asn1_named_data *first )
+{
+ int ret;
+ size_t len = 0;
+ asn1_named_data *cur_ext = first;
+
+ while( cur_ext != NULL )
+ {
+ ASN1_CHK_ADD( len, x509_write_extension( p, start, cur_ext ) );
+ cur_ext = cur_ext->next;
+ }
+
+ return( len );
+}
+
+#endif /* POLARSSL_X509_CREATE_C */
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
diff --git a/library/x509_crt.c b/library/x509_crt.c
new file mode 100644
index 0000000..3c88b5e
--- /dev/null
+++ b/library/x509_crt.c
@@ -0,0 +1,1756 @@
+/*
+ * 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_CRT_PARSE_C)
+
+#include "polarssl/x509_crt.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>
+#if !defined(_WIN32)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#endif
+#endif
+
+/*
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ */
+static int x509_get_version( unsigned char **p,
+ const unsigned char *end,
+ int *ver )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = asn1_get_tag( p, end, &len,
+ ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ) != 0 )
+ {
+ if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+ {
+ *ver = 0;
+ return( 0 );
+ }
+
+ return( ret );
+ }
+
+ end = *p + len;
+
+ if( ( ret = asn1_get_int( p, end, ver ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_VERSION + ret );
+
+ if( *p != end )
+ return( POLARSSL_ERR_X509_CERT_INVALID_VERSION +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+/*
+ * Validity ::= SEQUENCE {
+ * notBefore Time,
+ * notAfter Time }
+ */
+static int x509_get_dates( unsigned char **p,
+ const unsigned char *end,
+ x509_time *from,
+ x509_time *to )
+{
+ int ret;
+ size_t len;
+
+ if( ( ret = asn1_get_tag( p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret );
+
+ end = *p + len;
+
+ if( ( ret = x509_get_time( p, end, from ) ) != 0 )
+ return( ret );
+
+ if( ( ret = x509_get_time( p, end, to ) ) != 0 )
+ return( ret );
+
+ if( *p != end )
+ return( POLARSSL_ERR_X509_CERT_INVALID_DATE +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+/*
+ * X.509 v2/v3 unique identifier (not parsed)
+ */
+static int x509_get_uid( unsigned char **p,
+ const unsigned char *end,
+ x509_buf *uid, int n )
+{
+ int ret;
+
+ if( *p == end )
+ return( 0 );
+
+ uid->tag = **p;
+
+ if( ( ret = asn1_get_tag( p, end, &uid->len,
+ ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n ) ) != 0 )
+ {
+ if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+ return( 0 );
+
+ return( ret );
+ }
+
+ uid->p = *p;
+ *p += uid->len;
+
+ return( 0 );
+}
+
+static int x509_get_basic_constraints( unsigned char **p,
+ const unsigned char *end,
+ int *ca_istrue,
+ int *max_pathlen )
+{
+ int ret;
+ size_t len;
+
+ /*
+ * BasicConstraints ::= SEQUENCE {
+ * cA BOOLEAN DEFAULT FALSE,
+ * pathLenConstraint INTEGER (0..MAX) OPTIONAL }
+ */
+ *ca_istrue = 0; /* DEFAULT FALSE */
+ *max_pathlen = 0; /* endless */
+
+ if( ( ret = asn1_get_tag( p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ if( *p == end )
+ return 0;
+
+ if( ( ret = asn1_get_bool( p, end, ca_istrue ) ) != 0 )
+ {
+ if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+ ret = asn1_get_int( p, end, ca_istrue );
+
+ if( ret != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ if( *ca_istrue != 0 )
+ *ca_istrue = 1;
+ }
+
+ if( *p == end )
+ return 0;
+
+ if( ( ret = asn1_get_int( p, end, max_pathlen ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ if( *p != end )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ (*max_pathlen)++;
+
+ return 0;
+}
+
+static int x509_get_ns_cert_type( unsigned char **p,
+ const unsigned char *end,
+ unsigned char *ns_cert_type)
+{
+ int ret;
+ x509_bitstring bs = { 0, 0, NULL };
+
+ if( ( ret = asn1_get_bitstring( p, end, &bs ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ if( bs.len != 1 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_INVALID_LENGTH );
+
+ /* Get actual bitstring */
+ *ns_cert_type = *bs.p;
+ return 0;
+}
+
+static int x509_get_key_usage( unsigned char **p,
+ const unsigned char *end,
+ unsigned char *key_usage)
+{
+ int ret;
+ x509_bitstring bs = { 0, 0, NULL };
+
+ if( ( ret = asn1_get_bitstring( p, end, &bs ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ if( bs.len < 1 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_INVALID_LENGTH );
+
+ /* Get actual bitstring */
+ *key_usage = *bs.p;
+ return 0;
+}
+
+/*
+ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+ *
+ * KeyPurposeId ::= OBJECT IDENTIFIER
+ */
+static int x509_get_ext_key_usage( unsigned char **p,
+ const unsigned char *end,
+ x509_sequence *ext_key_usage)
+{
+ int ret;
+
+ if( ( ret = asn1_get_sequence_of( p, end, ext_key_usage, ASN1_OID ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ /* Sequence length must be >= 1 */
+ if( ext_key_usage->buf.p == NULL )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_INVALID_LENGTH );
+
+ return 0;
+}
+
+/*
+ * SubjectAltName ::= GeneralNames
+ *
+ * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+ *
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER }
+ *
+ * OtherName ::= SEQUENCE {
+ * type-id OBJECT IDENTIFIER,
+ * value [0] EXPLICIT ANY DEFINED BY type-id }
+ *
+ * EDIPartyName ::= SEQUENCE {
+ * nameAssigner [0] DirectoryString OPTIONAL,
+ * partyName [1] DirectoryString }
+ *
+ * NOTE: PolarSSL only parses and uses dNSName at this point.
+ */
+static int x509_get_subject_alt_name( unsigned char **p,
+ const unsigned char *end,
+ x509_sequence *subject_alt_name )
+{
+ int ret;
+ size_t len, tag_len;
+ asn1_buf *buf;
+ unsigned char tag;
+ asn1_sequence *cur = subject_alt_name;
+
+ /* Get main sequence tag */
+ if( ( ret = asn1_get_tag( p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ if( *p + len != end )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ while( *p < end )
+ {
+ if( ( end - *p ) < 1 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+ tag = **p;
+ (*p)++;
+ if( ( ret = asn1_get_len( p, end, &tag_len ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ if( ( tag & ASN1_CONTEXT_SPECIFIC ) != ASN1_CONTEXT_SPECIFIC )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
+
+ if( tag != ( ASN1_CONTEXT_SPECIFIC | 2 ) )
+ {
+ *p += tag_len;
+ continue;
+ }
+
+ buf = &(cur->buf);
+ buf->tag = tag;
+ buf->p = *p;
+ buf->len = tag_len;
+ *p += buf->len;
+
+ /* Allocate and assign next pointer */
+ if (*p < end)
+ {
+ cur->next = (asn1_sequence *) polarssl_malloc(
+ sizeof( asn1_sequence ) );
+
+ if( cur->next == NULL )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_MALLOC_FAILED );
+
+ memset( cur->next, 0, sizeof( asn1_sequence ) );
+ cur = cur->next;
+ }
+ }
+
+ /* Set final sequence entry's next pointer to NULL */
+ cur->next = NULL;
+
+ if( *p != end )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+/*
+ * X.509 v3 extensions
+ *
+ * TODO: Perform all of the basic constraints tests required by the RFC
+ * TODO: Set values for undetected extensions to a sane default?
+ *
+ */
+static int x509_get_crt_ext( unsigned char **p,
+ const unsigned char *end,
+ x509_cert *crt )
+{
+ int ret;
+ size_t len;
+ unsigned char *end_ext_data, *end_ext_octet;
+
+ if( ( ret = x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 )
+ {
+ if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+ return( 0 );
+
+ return( ret );
+ }
+
+ while( *p < end )
+ {
+ /*
+ * Extension ::= SEQUENCE {
+ * extnID OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING }
+ */
+ x509_buf extn_oid = {0, 0, NULL};
+ int is_critical = 0; /* DEFAULT FALSE */
+ int ext_type = 0;
+
+ if( ( ret = asn1_get_tag( p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ end_ext_data = *p + len;
+
+ /* Get extension ID */
+ extn_oid.tag = **p;
+
+ if( ( ret = asn1_get_tag( p, end, &extn_oid.len, ASN1_OID ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ extn_oid.p = *p;
+ *p += extn_oid.len;
+
+ if( ( end - *p ) < 1 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_OUT_OF_DATA );
+
+ /* Get optional critical */
+ if( ( ret = asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 &&
+ ( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ /* Data should be octet string type */
+ if( ( ret = asn1_get_tag( p, end_ext_data, &len,
+ ASN1_OCTET_STRING ) ) != 0 )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
+
+ end_ext_octet = *p + len;
+
+ if( end_ext_octet != end_ext_data )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ /*
+ * Detect supported extensions
+ */
+ ret = oid_get_x509_ext_type( &extn_oid, &ext_type );
+
+ if( ret != 0 )
+ {
+ /* No parser found, skip extension */
+ *p = end_ext_octet;
+
+#if !defined(POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
+ if( is_critical )
+ {
+ /* Data is marked as critical: fail */
+ return ( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
+ }
+#endif
+ continue;
+ }
+
+ crt->ext_types |= ext_type;
+
+ switch( ext_type )
+ {
+ case EXT_BASIC_CONSTRAINTS:
+ /* Parse basic constraints */
+ if( ( ret = x509_get_basic_constraints( p, end_ext_octet,
+ &crt->ca_istrue, &crt->max_pathlen ) ) != 0 )
+ return ( ret );
+ break;
+
+ case EXT_KEY_USAGE:
+ /* Parse key usage */
+ if( ( ret = x509_get_key_usage( p, end_ext_octet,
+ &crt->key_usage ) ) != 0 )
+ return ( ret );
+ break;
+
+ case EXT_EXTENDED_KEY_USAGE:
+ /* Parse extended key usage */
+ if( ( ret = x509_get_ext_key_usage( p, end_ext_octet,
+ &crt->ext_key_usage ) ) != 0 )
+ return ( ret );
+ break;
+
+ case EXT_SUBJECT_ALT_NAME:
+ /* Parse subject alt name */
+ if( ( ret = x509_get_subject_alt_name( p, end_ext_octet,
+ &crt->subject_alt_names ) ) != 0 )
+ return ( ret );
+ break;
+
+ case EXT_NS_CERT_TYPE:
+ /* Parse netscape certificate type */
+ if( ( ret = x509_get_ns_cert_type( p, end_ext_octet,
+ &crt->ns_cert_type ) ) != 0 )
+ return ( ret );
+ break;
+
+ default:
+ return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
+ }
+ }
+
+ if( *p != end )
+ return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+ return( 0 );
+}
+
+/*
+ * Parse and fill a single X.509 certificate in DER format
+ */
+static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf,
+ size_t buflen )
+{
+ int ret;
+ size_t len;
+ unsigned char *p, *end, *crt_end;
+
+ /*
+ * Check for valid input
+ */
+ if( crt == NULL || buf == NULL )
+ return( POLARSSL_ERR_X509_INVALID_INPUT );
+
+ p = (unsigned char *) polarssl_malloc( len = buflen );
+
+ if( p == NULL )
+ return( POLARSSL_ERR_X509_MALLOC_FAILED );
+
+ memcpy( p, buf, buflen );
+
+ buflen = 0;
+
+ crt->raw.p = p;
+ crt->raw.len = len;
+ end = p + len;
+
+ /*
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING }
+ */
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT );
+ }
+
+ if( len > (size_t) ( end - p ) )
+ {
+ x509_crt_free( crt );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+ }
+ crt_end = p + len;
+
+ /*
+ * TBSCertificate ::= SEQUENCE {
+ */
+ crt->tbs.p = p;
+
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+ }
+
+ end = p + len;
+ crt->tbs.len = end - crt->tbs.p;
+
+ /*
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ *
+ * CertificateSerialNumber ::= INTEGER
+ *
+ * signature AlgorithmIdentifier
+ */
+ if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 ||
+ ( ret = x509_get_serial( &p, end, &crt->serial ) ) != 0 ||
+ ( ret = x509_get_alg_null( &p, end, &crt->sig_oid1 ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+
+ crt->version++;
+
+ if( crt->version > 3 )
+ {
+ x509_crt_free( crt );
+ return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION );
+ }
+
+ if( ( ret = x509_get_sig_alg( &crt->sig_oid1, &crt->sig_md,
+ &crt->sig_pk ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+
+ /*
+ * issuer Name
+ */
+ crt->issuer_raw.p = p;
+
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+ }
+
+ if( ( ret = x509_get_name( &p, p + len, &crt->issuer ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+
+ crt->issuer_raw.len = p - crt->issuer_raw.p;
+
+ /*
+ * Validity ::= SEQUENCE {
+ * notBefore Time,
+ * notAfter Time }
+ *
+ */
+ if( ( ret = x509_get_dates( &p, end, &crt->valid_from,
+ &crt->valid_to ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+
+ /*
+ * subject Name
+ */
+ crt->subject_raw.p = p;
+
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+ }
+
+ if( len && ( ret = x509_get_name( &p, p + len, &crt->subject ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+
+ crt->subject_raw.len = p - crt->subject_raw.p;
+
+ /*
+ * SubjectPublicKeyInfo
+ */
+ if( ( ret = pk_parse_get_pubkey( &p, end, &crt->pk ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+
+ /*
+ * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
+ * -- If present, version shall be v2 or v3
+ * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
+ * -- If present, version shall be v2 or v3
+ * extensions [3] EXPLICIT Extensions OPTIONAL
+ * -- If present, version shall be v3
+ */
+ if( crt->version == 2 || crt->version == 3 )
+ {
+ ret = x509_get_uid( &p, end, &crt->issuer_id, 1 );
+ if( ret != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+ }
+
+ if( crt->version == 2 || crt->version == 3 )
+ {
+ ret = x509_get_uid( &p, end, &crt->subject_id, 2 );
+ if( ret != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+ }
+
+ if( crt->version == 3 )
+ {
+ ret = x509_get_crt_ext( &p, end, crt);
+ if( ret != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+ }
+
+ if( p != end )
+ {
+ x509_crt_free( crt );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+ }
+
+ end = crt_end;
+
+ /*
+ * }
+ * -- end of TBSCertificate
+ *
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING
+ */
+ if( ( ret = x509_get_alg_null( &p, end, &crt->sig_oid2 ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+
+ if( crt->sig_oid1.len != crt->sig_oid2.len ||
+ memcmp( crt->sig_oid1.p, crt->sig_oid2.p, crt->sig_oid1.len ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( POLARSSL_ERR_X509_CERT_SIG_MISMATCH );
+ }
+
+ if( ( ret = x509_get_sig( &p, end, &crt->sig ) ) != 0 )
+ {
+ x509_crt_free( crt );
+ return( ret );
+ }
+
+ if( p != end )
+ {
+ x509_crt_free( crt );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Parse one X.509 certificate in DER format from a buffer and add them to a
+ * chained list
+ */
+int x509parse_crt_der( x509_cert *chain, const unsigned char *buf, size_t buflen )
+{
+ int ret;
+ x509_cert *crt = chain, *prev = NULL;
+
+ /*
+ * Check for valid input
+ */
+ if( crt == NULL || buf == NULL )
+ return( POLARSSL_ERR_X509_INVALID_INPUT );
+
+ while( crt->version != 0 && crt->next != NULL )
+ {
+ prev = crt;
+ crt = crt->next;
+ }
+
+ /*
+ * Add new certificate on the end of the chain if needed.
+ */
+ if ( crt->version != 0 && crt->next == NULL)
+ {
+ crt->next = (x509_cert *) polarssl_malloc( sizeof( x509_cert ) );
+
+ if( crt->next == NULL )
+ return( POLARSSL_ERR_X509_MALLOC_FAILED );
+
+ prev = crt;
+ crt = crt->next;
+ memset( crt, 0, sizeof( x509_cert ) );
+ }
+
+ if( ( ret = x509parse_crt_der_core( crt, buf, buflen ) ) != 0 )
+ {
+ if( prev )
+ prev->next = NULL;
+
+ if( crt != chain )
+ polarssl_free( crt );
+
+ return( ret );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Parse one or more PEM certificates from a buffer and add them to the chained list
+ */
+int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen )
+{
+ int success = 0, first_error = 0, total_failed = 0;
+ int buf_format = X509_FORMAT_DER;
+
+ /*
+ * Check for valid input
+ */
+ if( chain == NULL || buf == NULL )
+ return( POLARSSL_ERR_X509_INVALID_INPUT );
+
+ /*
+ * Determine buffer content. Buffer contains either one DER certificate or
+ * one or more PEM certificates.
+ */
+#if defined(POLARSSL_PEM_PARSE_C)
+ if( strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL )
+ buf_format = X509_FORMAT_PEM;
+#endif
+
+ if( buf_format == X509_FORMAT_DER )
+ return x509parse_crt_der( chain, buf, buflen );
+
+#if defined(POLARSSL_PEM_PARSE_C)
+ if( buf_format == X509_FORMAT_PEM )
+ {
+ int ret;
+ pem_context pem;
+
+ while( buflen > 0 )
+ {
+ size_t use_len;
+ pem_init( &pem );
+
+ ret = pem_read_buffer( &pem,
+ "-----BEGIN CERTIFICATE-----",
+ "-----END CERTIFICATE-----",
+ buf, NULL, 0, &use_len );
+
+ if( ret == 0 )
+ {
+ /*
+ * Was PEM encoded
+ */
+ buflen -= use_len;
+ buf += use_len;
+ }
+ else if( ret == POLARSSL_ERR_PEM_BAD_INPUT_DATA )
+ {
+ return( ret );
+ }
+ else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+ {
+ pem_free( &pem );
+
+ /*
+ * PEM header and footer were found
+ */
+ buflen -= use_len;
+ buf += use_len;
+
+ if( first_error == 0 )
+ first_error = ret;
+
+ continue;
+ }
+ else
+ break;
+
+ ret = x509parse_crt_der( chain, pem.buf, pem.buflen );
+
+ pem_free( &pem );
+
+ if( ret != 0 )
+ {
+ /*
+ * Quit parsing on a memory error
+ */
+ if( ret == POLARSSL_ERR_X509_MALLOC_FAILED )
+ return( ret );
+
+ if( first_error == 0 )
+ first_error = ret;
+
+ total_failed++;
+ continue;
+ }
+
+ success = 1;
+ }
+ }
+#endif
+
+ if( success )
+ return( total_failed );
+ else if( first_error )
+ return( first_error );
+ else
+ return( POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT );
+}
+
+#if defined(POLARSSL_FS_IO)
+/*
+ * Load one or more certificates and add them to the chained list
+ */
+int x509parse_crtfile( x509_cert *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_crt( chain, buf, n );
+
+ memset( buf, 0, n + 1 );
+ polarssl_free( buf );
+
+ return( ret );
+}
+
+int x509parse_crtpath( x509_cert *chain, const char *path )
+{
+ int ret = 0;
+#if defined(_WIN32)
+ int w_ret;
+ WCHAR szDir[MAX_PATH];
+ char filename[MAX_PATH];
+ char *p;
+ int len = strlen( path );
+
+ WIN32_FIND_DATAW file_data;
+ HANDLE hFind;
+
+ if( len > MAX_PATH - 3 )
+ return( POLARSSL_ERR_X509_INVALID_INPUT );
+
+ memset( szDir, 0, sizeof(szDir) );
+ memset( filename, 0, MAX_PATH );
+ memcpy( filename, path, len );
+ filename[len++] = '\\';
+ p = filename + len;
+ filename[len++] = '*';
+
+ w_ret = MultiByteToWideChar( CP_ACP, 0, path, len, szDir, MAX_PATH - 3 );
+
+ hFind = FindFirstFileW( szDir, &file_data );
+ if (hFind == INVALID_HANDLE_VALUE)
+ return( POLARSSL_ERR_X509_FILE_IO_ERROR );
+
+ len = MAX_PATH - len;
+ do
+ {
+ memset( p, 0, len );
+
+ if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ continue;
+
+ w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName,
+ lstrlenW(file_data.cFileName),
+ p, len - 1,
+ NULL, NULL );
+
+ w_ret = x509parse_crtfile( chain, filename );
+ if( w_ret < 0 )
+ ret++;
+ else
+ ret += w_ret;
+ }
+ while( FindNextFileW( hFind, &file_data ) != 0 );
+
+ if (GetLastError() != ERROR_NO_MORE_FILES)
+ ret = POLARSSL_ERR_X509_FILE_IO_ERROR;
+
+cleanup:
+ FindClose( hFind );
+#else
+ int t_ret, i;
+ struct stat sb;
+ struct dirent entry, *result = NULL;
+ char entry_name[255];
+ DIR *dir = opendir( path );
+
+ if( dir == NULL)
+ return( POLARSSL_ERR_X509_FILE_IO_ERROR );
+
+ while( ( t_ret = readdir_r( dir, &entry, &result ) ) == 0 )
+ {
+ if( result == NULL )
+ break;
+
+ snprintf( entry_name, sizeof(entry_name), "%s/%s", path, entry.d_name );
+
+ i = stat( entry_name, &sb );
+
+ if( i == -1 )
+ {
+ closedir( dir );
+ return( POLARSSL_ERR_X509_FILE_IO_ERROR );
+ }
+
+ if( !S_ISREG( sb.st_mode ) )
+ continue;
+
+ // Ignore parse errors
+ //
+ t_ret = x509parse_crtfile( chain, entry_name );
+ if( t_ret < 0 )
+ ret++;
+ else
+ ret += t_ret;
+ }
+ closedir( dir );
+#endif
+
+ 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"
+int x509parse_cert_info( char *buf, size_t size, const char *prefix,
+ const x509_cert *crt )
+{
+ int ret;
+ size_t n;
+ char *p;
+ const char *desc = NULL;
+ char key_size_str[BEFORE_COLON];
+
+ p = buf;
+ n = size;
+
+ ret = snprintf( p, n, "%scert. version : %d\n",
+ prefix, crt->version );
+ SAFE_SNPRINTF();
+ ret = snprintf( p, n, "%sserial number : ",
+ prefix );
+ SAFE_SNPRINTF();
+
+ ret = x509parse_serial_gets( p, n, &crt->serial);
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n%sissuer name : ", prefix );
+ SAFE_SNPRINTF();
+ ret = x509parse_dn_gets( p, n, &crt->issuer );
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n%ssubject name : ", prefix );
+ SAFE_SNPRINTF();
+ ret = x509parse_dn_gets( p, n, &crt->subject );
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n%sissued on : " \
+ "%04d-%02d-%02d %02d:%02d:%02d", prefix,
+ crt->valid_from.year, crt->valid_from.mon,
+ crt->valid_from.day, crt->valid_from.hour,
+ crt->valid_from.min, crt->valid_from.sec );
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n%sexpires on : " \
+ "%04d-%02d-%02d %02d:%02d:%02d", prefix,
+ crt->valid_to.year, crt->valid_to.mon,
+ crt->valid_to.day, crt->valid_to.hour,
+ crt->valid_to.min, crt->valid_to.sec );
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n%ssigned using : ", prefix );
+ SAFE_SNPRINTF();
+
+ ret = oid_get_sig_alg_desc( &crt->sig_oid1, &desc );
+ if( ret != 0 )
+ ret = snprintf( p, n, "???" );
+ else
+ ret = snprintf( p, n, "%s", desc );
+ SAFE_SNPRINTF();
+
+ if( ( ret = x509_key_size_helper( key_size_str, BEFORE_COLON,
+ pk_get_name( &crt->pk ) ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ ret = snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str,
+ (int) pk_get_size( &crt->pk ) );
+ SAFE_SNPRINTF();
+
+ return( (int) ( size - n ) );
+}
+
+#if defined(POLARSSL_X509_CRL_PARSE_C)
+/*
+ * Return 1 if the certificate is revoked, or 0 otherwise.
+ */
+int x509parse_revoked( const x509_cert *crt, const x509_crl *crl )
+{
+ const x509_crl_entry *cur = &crl->entry;
+
+ while( cur != NULL && cur->serial.len != 0 )
+ {
+ if( crt->serial.len == cur->serial.len &&
+ memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 )
+ {
+ if( x509parse_time_expired( &cur->revocation_date ) )
+ return( 1 );
+ }
+
+ cur = cur->next;
+ }
+
+ return( 0 );
+}
+
+/*
+ * Check that the given certificate is valid accoring to the CRL.
+ */
+static int x509parse_verifycrl(x509_cert *crt, x509_cert *ca,
+ x509_crl *crl_list)
+{
+ int flags = 0;
+ unsigned char hash[POLARSSL_MD_MAX_SIZE];
+ const md_info_t *md_info;
+
+ if( ca == NULL )
+ return( flags );
+
+ /*
+ * TODO: What happens if no CRL is present?
+ * Suggestion: Revocation state should be unknown if no CRL is present.
+ * For backwards compatibility this is not yet implemented.
+ */
+
+ while( crl_list != NULL )
+ {
+ if( crl_list->version == 0 ||
+ crl_list->issuer_raw.len != ca->subject_raw.len ||
+ memcmp( crl_list->issuer_raw.p, ca->subject_raw.p,
+ crl_list->issuer_raw.len ) != 0 )
+ {
+ crl_list = crl_list->next;
+ continue;
+ }
+
+ /*
+ * Check if CRL is correctly signed by the trusted CA
+ */
+ md_info = md_info_from_type( crl_list->sig_md );
+ if( md_info == NULL )
+ {
+ /*
+ * Cannot check 'unknown' hash
+ */
+ flags |= BADCRL_NOT_TRUSTED;
+ break;
+ }
+
+ md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash );
+
+ if( pk_can_do( &ca->pk, crl_list->sig_pk ) == 0 ||
+ pk_verify( &ca->pk, crl_list->sig_md, hash, md_info->size,
+ crl_list->sig.p, crl_list->sig.len ) != 0 )
+ {
+ flags |= BADCRL_NOT_TRUSTED;
+ break;
+ }
+
+ /*
+ * Check for validity of CRL (Do not drop out)
+ */
+ if( x509parse_time_expired( &crl_list->next_update ) )
+ flags |= BADCRL_EXPIRED;
+
+ /*
+ * Check if certificate is revoked
+ */
+ if( x509parse_revoked(crt, crl_list) )
+ {
+ flags |= BADCERT_REVOKED;
+ break;
+ }
+
+ crl_list = crl_list->next;
+ }
+ return flags;
+}
+#endif /* POLARSSL_X509_CRL_PARSE_C */
+
+// Equal == 0, inequal == 1
+static int x509_name_cmp( const void *s1, const void *s2, size_t len )
+{
+ size_t i;
+ unsigned char diff;
+ const unsigned char *n1 = s1, *n2 = s2;
+
+ for( i = 0; i < len; i++ )
+ {
+ diff = n1[i] ^ n2[i];
+
+ if( ( n1[i] >= 'a' || n1[i] <= 'z' ) && ( diff == 0 || diff == 32 ) )
+ continue;
+
+ if( ( n1[i] >= 'A' || n1[i] <= 'Z' ) && ( diff == 0 || diff == 32 ) )
+ continue;
+
+ return( 1 );
+ }
+
+ return( 0 );
+}
+
+static int x509_wildcard_verify( const char *cn, x509_buf *name )
+{
+ size_t i;
+ size_t cn_idx = 0;
+
+ if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' )
+ return( 0 );
+
+ for( i = 0; i < strlen( cn ); ++i )
+ {
+ if( cn[i] == '.' )
+ {
+ cn_idx = i;
+ break;
+ }
+ }
+
+ if( cn_idx == 0 )
+ return( 0 );
+
+ if( strlen( cn ) - cn_idx == name->len - 1 &&
+ x509_name_cmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 )
+ {
+ return( 1 );
+ }
+
+ return( 0 );
+}
+
+static int x509parse_verify_top(
+ x509_cert *child, x509_cert *trust_ca,
+ x509_crl *ca_crl, int path_cnt, int *flags,
+ int (*f_vrfy)(void *, x509_cert *, int, int *),
+ void *p_vrfy )
+{
+ int ret;
+ int ca_flags = 0, check_path_cnt = path_cnt + 1;
+ unsigned char hash[POLARSSL_MD_MAX_SIZE];
+ const md_info_t *md_info;
+
+ if( x509parse_time_expired( &child->valid_to ) )
+ *flags |= BADCERT_EXPIRED;
+
+ /*
+ * Child is the top of the chain. Check against the trust_ca list.
+ */
+ *flags |= BADCERT_NOT_TRUSTED;
+
+ md_info = md_info_from_type( child->sig_md );
+ if( md_info == NULL )
+ {
+ /*
+ * Cannot check 'unknown', no need to try any CA
+ */
+ trust_ca = NULL;
+ }
+ else
+ md( md_info, child->tbs.p, child->tbs.len, hash );
+
+ while( trust_ca != NULL )
+ {
+ if( trust_ca->version == 0 ||
+ child->issuer_raw.len != trust_ca->subject_raw.len ||
+ memcmp( child->issuer_raw.p, trust_ca->subject_raw.p,
+ child->issuer_raw.len ) != 0 )
+ {
+ trust_ca = trust_ca->next;
+ continue;
+ }
+
+ /*
+ * Reduce path_len to check against if top of the chain is
+ * the same as the trusted CA
+ */
+ if( child->subject_raw.len == trust_ca->subject_raw.len &&
+ memcmp( child->subject_raw.p, trust_ca->subject_raw.p,
+ child->issuer_raw.len ) == 0 )
+ {
+ check_path_cnt--;
+ }
+
+ if( trust_ca->max_pathlen > 0 &&
+ trust_ca->max_pathlen < check_path_cnt )
+ {
+ trust_ca = trust_ca->next;
+ continue;
+ }
+
+ if( pk_can_do( &trust_ca->pk, child->sig_pk ) == 0 ||
+ pk_verify( &trust_ca->pk, child->sig_md, hash, md_info->size,
+ child->sig.p, child->sig.len ) != 0 )
+ {
+ trust_ca = trust_ca->next;
+ continue;
+ }
+
+ /*
+ * Top of chain is signed by a trusted CA
+ */
+ *flags &= ~BADCERT_NOT_TRUSTED;
+ break;
+ }
+
+ /*
+ * If top of chain is not the same as the trusted CA send a verify request
+ * to the callback for any issues with validity and CRL presence for the
+ * trusted CA certificate.
+ */
+ if( trust_ca != NULL &&
+ ( child->subject_raw.len != trust_ca->subject_raw.len ||
+ memcmp( child->subject_raw.p, trust_ca->subject_raw.p,
+ child->issuer_raw.len ) != 0 ) )
+ {
+#if defined(POLARSSL_X509_CRL_PARSE_C)
+ /* Check trusted CA's CRL for the chain's top crt */
+ *flags |= x509parse_verifycrl( child, trust_ca, ca_crl );
+#endif
+
+ if( x509parse_time_expired( &trust_ca->valid_to ) )
+ ca_flags |= BADCERT_EXPIRED;
+
+ if( NULL != f_vrfy )
+ {
+ if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1, &ca_flags ) ) != 0 )
+ return( ret );
+ }
+ }
+
+ /* Call callback on top cert */
+ if( NULL != f_vrfy )
+ {
+ if( ( ret = f_vrfy(p_vrfy, child, path_cnt, flags ) ) != 0 )
+ return( ret );
+ }
+
+ *flags |= ca_flags;
+
+ return( 0 );
+}
+
+static int x509parse_verify_child(
+ x509_cert *child, x509_cert *parent, x509_cert *trust_ca,
+ x509_crl *ca_crl, int path_cnt, int *flags,
+ int (*f_vrfy)(void *, x509_cert *, int, int *),
+ void *p_vrfy )
+{
+ int ret;
+ int parent_flags = 0;
+ unsigned char hash[POLARSSL_MD_MAX_SIZE];
+ x509_cert *grandparent;
+ const md_info_t *md_info;
+
+ if( x509parse_time_expired( &child->valid_to ) )
+ *flags |= BADCERT_EXPIRED;
+
+ md_info = md_info_from_type( child->sig_md );
+ if( md_info == NULL )
+ {
+ /*
+ * Cannot check 'unknown' hash
+ */
+ *flags |= BADCERT_NOT_TRUSTED;
+ }
+ else
+ {
+ md( md_info, child->tbs.p, child->tbs.len, hash );
+
+ if( pk_can_do( &parent->pk, child->sig_pk ) == 0 ||
+ pk_verify( &parent->pk, child->sig_md, hash, md_info->size,
+ child->sig.p, child->sig.len ) != 0 )
+ {
+ *flags |= BADCERT_NOT_TRUSTED;
+ }
+ }
+
+#if defined(POLARSSL_X509_CRL_PARSE_C)
+ /* Check trusted CA's CRL for the given crt */
+ *flags |= x509parse_verifycrl(child, parent, ca_crl);
+#endif
+
+ grandparent = parent->next;
+
+ while( grandparent != NULL )
+ {
+ if( grandparent->version == 0 ||
+ grandparent->ca_istrue == 0 ||
+ parent->issuer_raw.len != grandparent->subject_raw.len ||
+ memcmp( parent->issuer_raw.p, grandparent->subject_raw.p,
+ parent->issuer_raw.len ) != 0 )
+ {
+ grandparent = grandparent->next;
+ continue;
+ }
+ break;
+ }
+
+ if( grandparent != NULL )
+ {
+ /*
+ * Part of the chain
+ */
+ ret = x509parse_verify_child( parent, grandparent, trust_ca, ca_crl, path_cnt + 1, &parent_flags, f_vrfy, p_vrfy );
+ if( ret != 0 )
+ return( ret );
+ }
+ else
+ {
+ ret = x509parse_verify_top( parent, trust_ca, ca_crl, path_cnt + 1, &parent_flags, f_vrfy, p_vrfy );
+ if( ret != 0 )
+ return( ret );
+ }
+
+ /* child is verified to be a child of the parent, call verify callback */
+ if( NULL != f_vrfy )
+ if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 )
+ return( ret );
+
+ *flags |= parent_flags;
+
+ return( 0 );
+}
+
+/*
+ * Verify the certificate validity
+ */
+int x509parse_verify( x509_cert *crt,
+ x509_cert *trust_ca,
+ x509_crl *ca_crl,
+ const char *cn, int *flags,
+ int (*f_vrfy)(void *, x509_cert *, int, int *),
+ void *p_vrfy )
+{
+ size_t cn_len;
+ int ret;
+ int pathlen = 0;
+ x509_cert *parent;
+ x509_name *name;
+ x509_sequence *cur = NULL;
+
+ *flags = 0;
+
+ if( cn != NULL )
+ {
+ name = &crt->subject;
+ cn_len = strlen( cn );
+
+ if( crt->ext_types & EXT_SUBJECT_ALT_NAME )
+ {
+ cur = &crt->subject_alt_names;
+
+ while( cur != NULL )
+ {
+ if( cur->buf.len == cn_len &&
+ x509_name_cmp( cn, cur->buf.p, cn_len ) == 0 )
+ break;
+
+ if( cur->buf.len > 2 &&
+ memcmp( cur->buf.p, "*.", 2 ) == 0 &&
+ x509_wildcard_verify( cn, &cur->buf ) )
+ break;
+
+ cur = cur->next;
+ }
+
+ if( cur == NULL )
+ *flags |= BADCERT_CN_MISMATCH;
+ }
+ else
+ {
+ while( name != NULL )
+ {
+ if( OID_CMP( OID_AT_CN, &name->oid ) )
+ {
+ if( name->val.len == cn_len &&
+ x509_name_cmp( name->val.p, cn, cn_len ) == 0 )
+ break;
+
+ if( name->val.len > 2 &&
+ memcmp( name->val.p, "*.", 2 ) == 0 &&
+ x509_wildcard_verify( cn, &name->val ) )
+ break;
+ }
+
+ name = name->next;
+ }
+
+ if( name == NULL )
+ *flags |= BADCERT_CN_MISMATCH;
+ }
+ }
+
+ /*
+ * Iterate upwards in the given cert chain, to find our crt parent.
+ * Ignore any upper cert with CA != TRUE.
+ */
+ parent = crt->next;
+
+ while( parent != NULL && parent->version != 0 )
+ {
+ if( parent->ca_istrue == 0 ||
+ crt->issuer_raw.len != parent->subject_raw.len ||
+ memcmp( crt->issuer_raw.p, parent->subject_raw.p,
+ crt->issuer_raw.len ) != 0 )
+ {
+ parent = parent->next;
+ continue;
+ }
+ break;
+ }
+
+ if( parent != NULL )
+ {
+ /*
+ * Part of the chain
+ */
+ ret = x509parse_verify_child( crt, parent, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy );
+ if( ret != 0 )
+ return( ret );
+ }
+ else
+ {
+ ret = x509parse_verify_top( crt, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy );
+ if( ret != 0 )
+ return( ret );
+ }
+
+ if( *flags != 0 )
+ return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED );
+
+ return( 0 );
+}
+
+/*
+ * Unallocate all certificate data
+ */
+void x509_crt_free( x509_cert *crt )
+{
+ x509_cert *cert_cur = crt;
+ x509_cert *cert_prv;
+ x509_name *name_cur;
+ x509_name *name_prv;
+ x509_sequence *seq_cur;
+ x509_sequence *seq_prv;
+
+ if( crt == NULL )
+ return;
+
+ do
+ {
+ pk_free( &cert_cur->pk );
+
+ name_cur = cert_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 );
+ }
+
+ name_cur = cert_cur->subject.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 );
+ }
+
+ seq_cur = cert_cur->ext_key_usage.next;
+ while( seq_cur != NULL )
+ {
+ seq_prv = seq_cur;
+ seq_cur = seq_cur->next;
+ memset( seq_prv, 0, sizeof( x509_sequence ) );
+ polarssl_free( seq_prv );
+ }
+
+ seq_cur = cert_cur->subject_alt_names.next;
+ while( seq_cur != NULL )
+ {
+ seq_prv = seq_cur;
+ seq_cur = seq_cur->next;
+ memset( seq_prv, 0, sizeof( x509_sequence ) );
+ polarssl_free( seq_prv );
+ }
+
+ if( cert_cur->raw.p != NULL )
+ {
+ memset( cert_cur->raw.p, 0, cert_cur->raw.len );
+ polarssl_free( cert_cur->raw.p );
+ }
+
+ cert_cur = cert_cur->next;
+ }
+ while( cert_cur != NULL );
+
+ cert_cur = crt;
+ do
+ {
+ cert_prv = cert_cur;
+ cert_cur = cert_cur->next;
+
+ memset( cert_prv, 0, sizeof( x509_cert ) );
+ if( cert_prv != crt )
+ polarssl_free( cert_prv );
+ }
+ while( cert_cur != NULL );
+}
+
+#if defined(POLARSSL_SELF_TEST)
+
+#include "polarssl/certs.h"
+
+/*
+ * Checkup routine
+ */
+int x509_self_test( int verbose )
+{
+#if defined(POLARSSL_CERTS_C) && defined(POLARSSL_MD5_C)
+ int ret;
+ int flags;
+ x509_cert cacert;
+ x509_cert clicert;
+ pk_context pkey;
+
+ if( verbose != 0 )
+ printf( " X.509 certificate load: " );
+
+ memset( &clicert, 0, sizeof( x509_cert ) );
+
+ ret = x509parse_crt( &clicert, (const unsigned char *) test_cli_crt,
+ strlen( test_cli_crt ) );
+ if( ret != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( ret );
+ }
+
+ memset( &cacert, 0, sizeof( x509_cert ) );
+
+ ret = x509parse_crt( &cacert, (const unsigned char *) test_ca_crt,
+ strlen( test_ca_crt ) );
+ if( ret != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( ret );
+ }
+
+ if( verbose != 0 )
+ printf( "passed\n X.509 signature verify: ");
+
+ ret = x509parse_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL );
+ if( ret != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ printf("ret = %d, &flags = %04x\n", ret, flags);
+
+ return( ret );
+ }
+
+ if( verbose != 0 )
+ printf( "passed\n\n");
+
+ x509_crt_free( &cacert );
+ x509_crt_free( &clicert );
+ pk_free( &pkey );
+
+ return( 0 );
+#else
+ ((void) verbose);
+ return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
+#endif
+}
+
+#endif
+
+#endif
diff --git a/library/x509_crt_write.c b/library/x509_crt_write.c
new file mode 100644
index 0000000..577097d
--- /dev/null
+++ b/library/x509_crt_write.c
@@ -0,0 +1,426 @@
+/*
+ * X.509 certificate writing
+ *
+ * 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.
+ */
+/*
+ * References:
+ * - certificates: RFC 5280, updated by RFC 6818
+ * - CSRs: PKCS#10 v1.7 aka RFC 2986
+ * - attributes: PKCS#9 v2.0 aka RFC 2985
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_X509_CRT_WRITE_C)
+
+#include "polarssl/x509_crt.h"
+#include "polarssl/oid.h"
+#include "polarssl/asn1write.h"
+#include "polarssl/sha1.h"
+
+#if defined(POLARSSL_PEM_WRITE_C)
+#include "polarssl/pem.h"
+#endif /* POLARSSL_PEM_WRITE_C */
+
+void x509write_crt_init( x509write_cert *ctx )
+{
+ memset( ctx, 0, sizeof(x509write_cert) );
+
+ mpi_init( &ctx->serial );
+ ctx->version = X509_CRT_VERSION_3;
+}
+
+void x509write_crt_free( x509write_cert *ctx )
+{
+ mpi_free( &ctx->serial );
+
+ asn1_free_named_data_list( &ctx->subject );
+ asn1_free_named_data_list( &ctx->issuer );
+ asn1_free_named_data_list( &ctx->extensions );
+
+ memset( ctx, 0, sizeof(x509write_cert) );
+}
+
+void x509write_crt_set_md_alg( x509write_cert *ctx, md_type_t md_alg )
+{
+ ctx->md_alg = md_alg;
+}
+
+void x509write_crt_set_subject_key( x509write_cert *ctx, pk_context *key )
+{
+ ctx->subject_key = key;
+}
+
+void x509write_crt_set_issuer_key( x509write_cert *ctx, pk_context *key )
+{
+ ctx->issuer_key = key;
+}
+
+int x509write_crt_set_subject_name( x509write_cert *ctx, char *subject_name )
+{
+ return x509write_string_to_names( &ctx->subject, subject_name );
+}
+
+int x509write_crt_set_issuer_name( x509write_cert *ctx, char *issuer_name )
+{
+ return x509write_string_to_names( &ctx->issuer, issuer_name );
+}
+
+int x509write_crt_set_serial( x509write_cert *ctx, const mpi *serial )
+{
+ int ret;
+
+ if( ( ret = mpi_copy( &ctx->serial, serial ) ) != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+int x509write_crt_set_validity( x509write_cert *ctx, char *not_before,
+ char *not_after )
+{
+ if( strlen(not_before) != X509_RFC5280_UTC_TIME_LEN - 1 ||
+ strlen(not_after) != X509_RFC5280_UTC_TIME_LEN - 1 )
+ {
+ return( POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA );
+ }
+ strncpy( ctx->not_before, not_before, X509_RFC5280_UTC_TIME_LEN );
+ strncpy( ctx->not_after , not_after , X509_RFC5280_UTC_TIME_LEN );
+ ctx->not_before[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
+ ctx->not_after[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
+
+ return( 0 );
+}
+
+int x509write_crt_set_extension( x509write_cert *ctx,
+ const char *oid, size_t oid_len,
+ int critical,
+ const unsigned char *val, size_t val_len )
+{
+ return x509_set_extension( &ctx->extensions, oid, oid_len,
+ critical, val, val_len );
+}
+
+int x509write_crt_set_basic_constraints( x509write_cert *ctx,
+ int is_ca, int max_pathlen )
+{
+ int ret;
+ unsigned char buf[9];
+ unsigned char *c = buf + sizeof(buf);
+ size_t len = 0;
+
+ memset( buf, 0, sizeof(buf) );
+
+ if( is_ca && max_pathlen > 127 )
+ return( POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA );
+
+ if( is_ca )
+ {
+ if( max_pathlen >= 0 )
+ {
+ ASN1_CHK_ADD( len, asn1_write_int( &c, buf, max_pathlen ) );
+ }
+ ASN1_CHK_ADD( len, asn1_write_bool( &c, buf, 1 ) );
+ }
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ return x509write_crt_set_extension( ctx, OID_BASIC_CONSTRAINTS,
+ OID_SIZE( OID_BASIC_CONSTRAINTS ),
+ 0, buf + sizeof(buf) - len, len );
+}
+
+int x509write_crt_set_subject_key_identifier( x509write_cert *ctx )
+{
+ int ret;
+ unsigned char buf[POLARSSL_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
+ unsigned char *c = buf + sizeof(buf);
+ size_t len = 0;
+
+ memset( buf, 0, sizeof(buf));
+ ASN1_CHK_ADD( len, pk_write_pubkey( &c, buf, ctx->subject_key ) );
+
+ sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 );
+ c = buf + sizeof(buf) - 20;
+ len = 20;
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_OCTET_STRING ) );
+
+ return x509write_crt_set_extension( ctx, OID_SUBJECT_KEY_IDENTIFIER,
+ OID_SIZE( OID_SUBJECT_KEY_IDENTIFIER ),
+ 0, buf + sizeof(buf) - len, len );
+}
+
+int x509write_crt_set_authority_key_identifier( x509write_cert *ctx )
+{
+ int ret;
+ unsigned char buf[POLARSSL_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
+ unsigned char *c = buf + sizeof(buf);
+ size_t len = 0;
+
+ memset( buf, 0, sizeof(buf));
+ ASN1_CHK_ADD( len, pk_write_pubkey( &c, buf, ctx->issuer_key ) );
+
+ sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 );
+ c = buf + sizeof(buf) - 20;
+ len = 20;
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONTEXT_SPECIFIC | 0 ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ return x509write_crt_set_extension( ctx, OID_AUTHORITY_KEY_IDENTIFIER,
+ OID_SIZE( OID_AUTHORITY_KEY_IDENTIFIER ),
+ 0, buf + sizeof(buf) - len, len );
+}
+
+int x509write_crt_set_key_usage( x509write_cert *ctx, unsigned char key_usage )
+{
+ unsigned char buf[4];
+ unsigned char *c;
+ int ret;
+
+ c = buf + 4;
+
+ if( ( ret = asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
+ return( ret );
+
+ ret = x509write_crt_set_extension( ctx, OID_KEY_USAGE,
+ OID_SIZE( OID_KEY_USAGE ),
+ 1, buf, 4 );
+ if( ret != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+int x509write_crt_set_ns_cert_type( x509write_cert *ctx,
+ unsigned char ns_cert_type )
+{
+ unsigned char buf[4];
+ unsigned char *c;
+ int ret;
+
+ c = buf + 4;
+
+ if( ( ret = asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
+ return( ret );
+
+ ret = x509write_crt_set_extension( ctx, OID_NS_CERT_TYPE,
+ OID_SIZE( OID_NS_CERT_TYPE ),
+ 0, buf, 4 );
+ if( ret != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+static int x509_write_time( unsigned char **p, unsigned char *start,
+ const char *time, size_t size )
+{
+ int ret;
+ size_t len = 0;
+
+ /*
+ * write ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
+ */
+ if( time[0] == '2' && time[1] == '0' && time [2] < '5' )
+ {
+ ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
+ (const unsigned char *) time + 2,
+ size - 2 ) );
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_UTC_TIME ) );
+ }
+ else
+ {
+ ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
+ (const unsigned char *) time,
+ size ) );
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_GENERALIZED_TIME ) );
+ }
+
+ return( len );
+}
+
+int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ const char *sig_oid;
+ size_t sig_oid_len = 0;
+ unsigned char *c, *c2;
+ unsigned char hash[64];
+ unsigned char sig[POLARSSL_MPI_MAX_SIZE];
+ unsigned char tmp_buf[2048];
+ size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
+ size_t len = 0;
+ pk_type_t pk_alg;
+
+ /*
+ * Prepare data to be signed in tmp_buf
+ */
+ c = tmp_buf + sizeof( tmp_buf );
+
+ /* Signature algorithm needed in TBS, and later for actual signature */
+ pk_alg = pk_get_type( ctx->issuer_key );
+ if( pk_alg == POLARSSL_PK_ECKEY )
+ pk_alg = POLARSSL_PK_ECDSA;
+
+ if( ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
+ &sig_oid, &sig_oid_len ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ /*
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ */
+ ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3 ) );
+
+ /*
+ * SubjectPublicKeyInfo
+ */
+ ASN1_CHK_ADD( pub_len, pk_write_pubkey_der( ctx->subject_key,
+ tmp_buf, c - tmp_buf ) );
+ c -= pub_len;
+ len += pub_len;
+
+ /*
+ * Subject ::= Name
+ */
+ ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) );
+
+ /*
+ * Validity ::= SEQUENCE {
+ * notBefore Time,
+ * notAfter Time }
+ */
+ sub_len = 0;
+
+ ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after,
+ X509_RFC5280_UTC_TIME_LEN ) );
+
+ ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before,
+ X509_RFC5280_UTC_TIME_LEN ) );
+
+ len += sub_len;
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ /*
+ * Issuer ::= Name
+ */
+ ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->issuer ) );
+
+ /*
+ * Signature ::= AlgorithmIdentifier
+ */
+ ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, tmp_buf,
+ sig_oid, strlen( sig_oid ), 0 ) );
+
+ /*
+ * Serial ::= INTEGER
+ */
+ ASN1_CHK_ADD( len, asn1_write_mpi( &c, tmp_buf, &ctx->serial ) );
+
+ /*
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ */
+ sub_len = 0;
+ ASN1_CHK_ADD( sub_len, asn1_write_int( &c, tmp_buf, ctx->version ) );
+ len += sub_len;
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ /*
+ * Make signature
+ */
+ md( md_info_from_type( ctx->md_alg ), c, len, hash );
+
+ if( ( ret = pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len,
+ f_rng, p_rng ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ /*
+ * Write data to output buffer
+ */
+ c2 = buf + size;
+ ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf,
+ sig_oid, sig_oid_len, sig, sig_len ) );
+
+ c2 -= len;
+ memcpy( c2, c, len );
+
+ len += sig_and_oid_len;
+ ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ return( len );
+}
+
+#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
+#define PEM_END_CRT "-----END CERTIFICATE-----\n"
+
+#if defined(POLARSSL_PEM_WRITE_C)
+int x509write_crt_pem( x509write_cert *crt, unsigned char *buf, size_t size,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ unsigned char output_buf[4096];
+ size_t olen = 0;
+
+ if( ( ret = x509write_crt_der( crt, output_buf, sizeof(output_buf),
+ f_rng, p_rng ) ) < 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT,
+ output_buf + sizeof(output_buf) - ret,
+ ret, buf, size, &olen ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+}
+#endif /* POLARSSL_PEM_WRITE_C */
+
+#endif /* POLARSSL_X509_CRT_WRITE_C */
diff --git a/library/x509_csr.c b/library/x509_csr.c
new file mode 100644
index 0000000..e4b0517
--- /dev/null
+++ b/library/x509_csr.c
@@ -0,0 +1,439 @@
+/*
+ * X.509 Certificate Signing Request (CSR) parsing
+ *
+ * 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_CSR_PARSE_C)
+
+#include "polarssl/x509_csr.h"
+#include "polarssl/oid.h"
+#if defined(POLARSSL_PEM_PARSE_C)
+#include "polarssl/pem.h"
+#endif
+#if defined(POLARSSL_ASN1_WRITE_C)
+#include "polarssl/asn1write.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(POLARSSL_FS_IO)
+#include <stdio.h>
+#endif
+
+/*
+ * Version ::= INTEGER { v1(0) }
+ */
+static int x509_csr_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 );
+}
+
+/*
+ * Parse a CSR
+ */
+int x509parse_csr( x509_csr *csr, const unsigned char *buf, size_t buflen )
+{
+ int ret;
+ size_t len;
+ unsigned char *p, *end;
+#if defined(POLARSSL_PEM_PARSE_C)
+ size_t use_len;
+ pem_context pem;
+#endif
+
+ /*
+ * Check for valid input
+ */
+ if( csr == NULL || buf == NULL )
+ return( POLARSSL_ERR_X509_INVALID_INPUT );
+
+ memset( csr, 0, sizeof( x509_csr ) );
+
+#if defined(POLARSSL_PEM_PARSE_C)
+ pem_init( &pem );
+ ret = pem_read_buffer( &pem,
+ "-----BEGIN CERTIFICATE REQUEST-----",
+ "-----END CERTIFICATE REQUEST-----",
+ 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;
+ }
+
+ csr->raw.p = p;
+ csr->raw.len = len;
+ end = p + len;
+
+ /*
+ * CertificationRequest ::= SEQUENCE {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ */
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ x509_csr_free( csr );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT );
+ }
+
+ if( len != (size_t) ( end - p ) )
+ {
+ x509_csr_free( csr );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+ }
+
+ /*
+ * CertificationRequestInfo ::= SEQUENCE {
+ */
+ csr->cri.p = p;
+
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ x509_csr_free( csr );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+ }
+
+ end = p + len;
+ csr->cri.len = end - csr->cri.p;
+
+ /*
+ * Version ::= INTEGER { v1(0) }
+ */
+ if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 )
+ {
+ x509_csr_free( csr );
+ return( ret );
+ }
+
+ csr->version++;
+
+ if( csr->version != 1 )
+ {
+ x509_csr_free( csr );
+ return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION );
+ }
+
+ /*
+ * subject Name
+ */
+ csr->subject_raw.p = p;
+
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+ {
+ x509_csr_free( csr );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+ }
+
+ if( ( ret = x509_get_name( &p, p + len, &csr->subject ) ) != 0 )
+ {
+ x509_csr_free( csr );
+ return( ret );
+ }
+
+ csr->subject_raw.len = p - csr->subject_raw.p;
+
+ /*
+ * subjectPKInfo SubjectPublicKeyInfo
+ */
+ if( ( ret = pk_parse_get_pubkey( &p, end, &csr->pk ) ) != 0 )
+ {
+ x509_csr_free( csr );
+ return( ret );
+ }
+
+ /*
+ * attributes [0] Attributes
+ */
+ if( ( ret = asn1_get_tag( &p, end, &len,
+ ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC ) ) != 0 )
+ {
+ x509_csr_free( csr );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+ }
+ // TODO Parse Attributes / extension requests
+
+ p += len;
+
+ end = csr->raw.p + csr->raw.len;
+
+ /*
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ */
+ if( ( ret = x509_get_alg_null( &p, end, &csr->sig_oid ) ) != 0 )
+ {
+ x509_csr_free( csr );
+ return( ret );
+ }
+
+ if( ( ret = x509_get_sig_alg( &csr->sig_oid, &csr->sig_md,
+ &csr->sig_pk ) ) != 0 )
+ {
+ x509_csr_free( csr );
+ return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG );
+ }
+
+ if( ( ret = x509_get_sig( &p, end, &csr->sig ) ) != 0 )
+ {
+ x509_csr_free( csr );
+ return( ret );
+ }
+
+ if( p != end )
+ {
+ x509_csr_free( csr );
+ return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
+ POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+ }
+
+ return( 0 );
+}
+
+#if defined(POLARSSL_FS_IO)
+/*
+ * Load a CSR into the structure
+ */
+int x509parse_csrfile( x509_csr *csr, const char *path )
+{
+ int ret;
+ size_t n;
+ unsigned char *buf;
+
+ if ( ( ret = x509_load_file( path, &buf, &n ) ) != 0 )
+ return( ret );
+
+ ret = x509parse_csr( csr, 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; \
+}
+
+#define BEFORE_COLON 14
+#define BC "14"
+/*
+ * Return an informational string about the CSR.
+ */
+int x509parse_csr_info( char *buf, size_t size, const char *prefix,
+ const x509_csr *csr )
+{
+ int ret;
+ size_t n;
+ char *p;
+ const char *desc;
+ char key_size_str[BEFORE_COLON];
+
+ p = buf;
+ n = size;
+
+ ret = snprintf( p, n, "%sCSR version : %d",
+ prefix, csr->version );
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n%ssubject name : ", prefix );
+ SAFE_SNPRINTF();
+ ret = x509parse_dn_gets( p, n, &csr->subject );
+ SAFE_SNPRINTF();
+
+ ret = snprintf( p, n, "\n%ssigned using : ", prefix );
+ SAFE_SNPRINTF();
+
+ ret = oid_get_sig_alg_desc( &csr->sig_oid, &desc );
+ if( ret != 0 )
+ ret = snprintf( p, n, "???" );
+ else
+ ret = snprintf( p, n, "%s", desc );
+ SAFE_SNPRINTF();
+
+ if( ( ret = x509_key_size_helper( key_size_str, BEFORE_COLON,
+ pk_get_name( &csr->pk ) ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ ret = snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str,
+ (int) pk_get_size( &csr->pk ) );
+ SAFE_SNPRINTF();
+
+ return( (int) ( size - n ) );
+}
+
+/*
+ * Unallocate all CSR data
+ */
+void x509_csr_free( x509_csr *csr )
+{
+ x509_name *name_cur;
+ x509_name *name_prv;
+
+ if( csr == NULL )
+ return;
+
+ pk_free( &csr->pk );
+
+ name_cur = csr->subject.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 );
+ }
+
+ if( csr->raw.p != NULL )
+ {
+ memset( csr->raw.p, 0, csr->raw.len );
+ polarssl_free( csr->raw.p );
+ }
+
+ memset( csr, 0, sizeof( x509_csr ) );
+}
+
+#endif /* POLARSSL_X509_CSR_PARSE_C */
diff --git a/library/x509_csr_write.c b/library/x509_csr_write.c
new file mode 100644
index 0000000..b744300
--- /dev/null
+++ b/library/x509_csr_write.c
@@ -0,0 +1,244 @@
+/*
+ * X.509 Certificate Signing Request writing
+ *
+ * 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.
+ */
+/*
+ * References:
+ * - CSRs: PKCS#10 v1.7 aka RFC 2986
+ * - attributes: PKCS#9 v2.0 aka RFC 2985
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_X509_CSR_WRITE_C)
+
+#include "polarssl/x509_csr.h"
+#include "polarssl/oid.h"
+#include "polarssl/asn1write.h"
+
+#if defined(POLARSSL_PEM_WRITE_C)
+#include "polarssl/pem.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+void x509write_csr_init( x509write_csr *ctx )
+{
+ memset( ctx, 0, sizeof(x509write_csr) );
+}
+
+void x509write_csr_free( x509write_csr *ctx )
+{
+ asn1_free_named_data_list( &ctx->subject );
+ asn1_free_named_data_list( &ctx->extensions );
+
+ memset( ctx, 0, sizeof(x509write_csr) );
+}
+
+void x509write_csr_set_md_alg( x509write_csr *ctx, md_type_t md_alg )
+{
+ ctx->md_alg = md_alg;
+}
+
+void x509write_csr_set_key( x509write_csr *ctx, pk_context *key )
+{
+ ctx->key = key;
+}
+
+int x509write_csr_set_subject_name( x509write_csr *ctx, char *subject_name )
+{
+ return x509write_string_to_names( &ctx->subject, subject_name );
+}
+
+int x509write_csr_set_extension( x509write_csr *ctx,
+ const char *oid, size_t oid_len,
+ const unsigned char *val, size_t val_len )
+{
+ return x509_set_extension( &ctx->extensions, oid, oid_len,
+ 0, val, val_len );
+}
+
+int x509write_csr_set_key_usage( x509write_csr *ctx, unsigned char key_usage )
+{
+ unsigned char buf[4];
+ unsigned char *c;
+ int ret;
+
+ c = buf + 4;
+
+ if( ( ret = asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
+ return( ret );
+
+ ret = x509write_csr_set_extension( ctx, OID_KEY_USAGE,
+ OID_SIZE( OID_KEY_USAGE ),
+ buf, 4 );
+ if( ret != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+int x509write_csr_set_ns_cert_type( x509write_csr *ctx,
+ unsigned char ns_cert_type )
+{
+ unsigned char buf[4];
+ unsigned char *c;
+ int ret;
+
+ c = buf + 4;
+
+ if( ( ret = asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
+ return( ret );
+
+ ret = x509write_csr_set_extension( ctx, OID_NS_CERT_TYPE,
+ OID_SIZE( OID_NS_CERT_TYPE ),
+ buf, 4 );
+ if( ret != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+int x509write_csr_der( x509write_csr *ctx, unsigned char *buf, size_t size,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ const char *sig_oid;
+ size_t sig_oid_len = 0;
+ unsigned char *c, *c2;
+ unsigned char hash[64];
+ unsigned char sig[POLARSSL_MPI_MAX_SIZE];
+ unsigned char tmp_buf[2048];
+ size_t pub_len = 0, sig_and_oid_len = 0, sig_len;
+ size_t len = 0;
+ pk_type_t pk_alg;
+
+ /*
+ * Prepare data to be signed in tmp_buf
+ */
+ c = tmp_buf + sizeof( tmp_buf );
+
+ ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
+
+ if( len )
+ {
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SET ) );
+
+ ASN1_CHK_ADD( len, asn1_write_oid( &c, tmp_buf, OID_PKCS9_CSR_EXT_REQ,
+ OID_SIZE( OID_PKCS9_CSR_EXT_REQ ) ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+ }
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC ) );
+
+ ASN1_CHK_ADD( pub_len, pk_write_pubkey_der( ctx->key,
+ tmp_buf, c - tmp_buf ) );
+ c -= pub_len;
+ len += pub_len;
+
+ /*
+ * Subject ::= Name
+ */
+ ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) );
+
+ /*
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ */
+ ASN1_CHK_ADD( len, asn1_write_int( &c, tmp_buf, 0 ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ /*
+ * Prepare signature
+ */
+ md( md_info_from_type( ctx->md_alg ), c, len, hash );
+
+ pk_alg = pk_get_type( ctx->key );
+ if( pk_alg == POLARSSL_PK_ECKEY )
+ pk_alg = POLARSSL_PK_ECDSA;
+
+ if( ( ret = pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len,
+ f_rng, p_rng ) ) != 0 ||
+ ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
+ &sig_oid, &sig_oid_len ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ /*
+ * Write data to output buffer
+ */
+ c2 = buf + size;
+ ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf,
+ sig_oid, sig_oid_len, sig, sig_len ) );
+
+ c2 -= len;
+ memcpy( c2, c, len );
+
+ len += sig_and_oid_len;
+ ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ return( len );
+}
+
+#define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n"
+#define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n"
+
+#if defined(POLARSSL_PEM_WRITE_C)
+int x509write_csr_pem( x509write_csr *ctx, unsigned char *buf, size_t size,
+ int (*f_rng)(void *, unsigned char *, size_t),
+ void *p_rng )
+{
+ int ret;
+ unsigned char output_buf[4096];
+ size_t olen = 0;
+
+ if( ( ret = x509write_csr_der( ctx, output_buf, sizeof(output_buf),
+ f_rng, p_rng ) ) < 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = pem_write_buffer( PEM_BEGIN_CSR, PEM_END_CSR,
+ output_buf + sizeof(output_buf) - ret,
+ ret, buf, size, &olen ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+}
+#endif /* POLARSSL_PEM_WRITE_C */
+
+#endif /* POLARSSL_X509_CSR_WRITE_C */
diff --git a/library/x509parse.c b/library/x509parse.c
deleted file mode 100644
index 331c8a0..0000000
--- a/library/x509parse.c
+++ /dev/null
@@ -1,3393 +0,0 @@
-/*
- * 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_PARSE_C)
-
-#include "polarssl/x509.h"
-#include "polarssl/asn1.h"
-#include "polarssl/oid.h"
-#if defined(POLARSSL_PEM_PARSE_C)
-#include "polarssl/pem.h"
-#endif
-#if defined(POLARSSL_PKCS5_C)
-#include "polarssl/pkcs5.h"
-#endif
-#if defined(POLARSSL_PKCS12_C)
-#include "polarssl/pkcs12.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>
-#if !defined(_WIN32)
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#endif
-#endif
-
-/*
- * Version ::= INTEGER { v1(0), v2(1), v3(2) }
- */
-static int x509_get_version( unsigned char **p,
- const unsigned char *end,
- int *ver )
-{
- int ret;
- size_t len;
-
- if( ( ret = asn1_get_tag( p, end, &len,
- ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ) != 0 )
- {
- if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
- {
- *ver = 0;
- return( 0 );
- }
-
- return( ret );
- }
-
- end = *p + len;
-
- if( ( ret = asn1_get_int( p, end, ver ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_VERSION + ret );
-
- if( *p != end )
- return( POLARSSL_ERR_X509_CERT_INVALID_VERSION +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
-
- return( 0 );
-}
-
-/*
- * 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 );
-}
-
-/*
- * Version ::= INTEGER { v1(0) }
- */
-static int x509_csr_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 );
-}
-
-/*
- * CertificateSerialNumber ::= INTEGER
- */
-static int x509_get_serial( unsigned char **p,
- const unsigned char *end,
- x509_buf *serial )
-{
- int ret;
-
- if( ( end - *p ) < 1 )
- return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL +
- POLARSSL_ERR_ASN1_OUT_OF_DATA );
-
- if( **p != ( ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2 ) &&
- **p != ASN1_INTEGER )
- return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL +
- POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
-
- serial->tag = *(*p)++;
-
- if( ( ret = asn1_get_len( p, end, &serial->len ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + ret );
-
- serial->p = *p;
- *p += serial->len;
-
- return( 0 );
-}
-
-/* Get an algorithm identifier without parameters (eg for signatures)
- *
- * AlgorithmIdentifier ::= SEQUENCE {
- * algorithm OBJECT IDENTIFIER,
- * parameters ANY DEFINED BY algorithm OPTIONAL }
- */
-static int x509_get_alg_null( unsigned char **p, const unsigned char *end,
- x509_buf *alg )
-{
- int ret;
-
- if( ( ret = asn1_get_alg_null( p, end, alg ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret );
-
- return( 0 );
-}
-
-/*
- * AttributeTypeAndValue ::= SEQUENCE {
- * type AttributeType,
- * value AttributeValue }
- *
- * AttributeType ::= OBJECT IDENTIFIER
- *
- * AttributeValue ::= ANY DEFINED BY AttributeType
- */
-static int x509_get_attr_type_value( unsigned char **p,
- const unsigned char *end,
- x509_name *cur )
-{
- int ret;
- size_t len;
- x509_buf *oid;
- x509_buf *val;
-
- if( ( ret = asn1_get_tag( p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret );
-
- if( ( end - *p ) < 1 )
- return( POLARSSL_ERR_X509_CERT_INVALID_NAME +
- POLARSSL_ERR_ASN1_OUT_OF_DATA );
-
- oid = &cur->oid;
- oid->tag = **p;
-
- if( ( ret = asn1_get_tag( p, end, &oid->len, ASN1_OID ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret );
-
- oid->p = *p;
- *p += oid->len;
-
- if( ( end - *p ) < 1 )
- return( POLARSSL_ERR_X509_CERT_INVALID_NAME +
- POLARSSL_ERR_ASN1_OUT_OF_DATA );
-
- if( **p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING &&
- **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING &&
- **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING )
- return( POLARSSL_ERR_X509_CERT_INVALID_NAME +
- POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
-
- val = &cur->val;
- val->tag = *(*p)++;
-
- if( ( ret = asn1_get_len( p, end, &val->len ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret );
-
- val->p = *p;
- *p += val->len;
-
- cur->next = NULL;
-
- return( 0 );
-}
-
-/*
- * RelativeDistinguishedName ::=
- * SET OF AttributeTypeAndValue
- *
- * AttributeTypeAndValue ::= SEQUENCE {
- * type AttributeType,
- * value AttributeValue }
- *
- * AttributeType ::= OBJECT IDENTIFIER
- *
- * AttributeValue ::= ANY DEFINED BY AttributeType
- */
-static int x509_get_name( unsigned char **p,
- const unsigned char *end,
- x509_name *cur )
-{
- int ret;
- size_t len;
- const unsigned char *end2;
- x509_name *use;
-
- if( ( ret = asn1_get_tag( p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SET ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret );
-
- end2 = end;
- end = *p + len;
- use = cur;
-
- do
- {
- if( ( ret = x509_get_attr_type_value( p, end, use ) ) != 0 )
- return( ret );
-
- if( *p != end )
- {
- use->next = (x509_name *) polarssl_malloc(
- sizeof( x509_name ) );
-
- if( use->next == NULL )
- return( POLARSSL_ERR_X509_MALLOC_FAILED );
-
- memset( use->next, 0, sizeof( x509_name ) );
-
- use = use->next;
- }
- }
- while( *p != end );
-
- /*
- * recurse until end of SEQUENCE is reached
- */
- if( *p == end2 )
- return( 0 );
-
- cur->next = (x509_name *) polarssl_malloc(
- sizeof( x509_name ) );
-
- if( cur->next == NULL )
- return( POLARSSL_ERR_X509_MALLOC_FAILED );
-
- memset( cur->next, 0, sizeof( x509_name ) );
-
- return( x509_get_name( p, end2, cur->next ) );
-}
-
-/*
- * Time ::= CHOICE {
- * utcTime UTCTime,
- * generalTime GeneralizedTime }
- */
-static int x509_get_time( unsigned char **p,
- const unsigned char *end,
- x509_time *time )
-{
- int ret;
- size_t len;
- char date[64];
- unsigned char tag;
-
- if( ( end - *p ) < 1 )
- return( POLARSSL_ERR_X509_CERT_INVALID_DATE +
- POLARSSL_ERR_ASN1_OUT_OF_DATA );
-
- tag = **p;
-
- if ( tag == ASN1_UTC_TIME )
- {
- (*p)++;
- ret = asn1_get_len( p, end, &len );
-
- if( ret != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret );
-
- memset( date, 0, sizeof( date ) );
- memcpy( date, *p, ( len < sizeof( date ) - 1 ) ?
- len : sizeof( date ) - 1 );
-
- if( sscanf( date, "%2d%2d%2d%2d%2d%2d",
- &time->year, &time->mon, &time->day,
- &time->hour, &time->min, &time->sec ) < 5 )
- return( POLARSSL_ERR_X509_CERT_INVALID_DATE );
-
- time->year += 100 * ( time->year < 50 );
- time->year += 1900;
-
- *p += len;
-
- return( 0 );
- }
- else if ( tag == ASN1_GENERALIZED_TIME )
- {
- (*p)++;
- ret = asn1_get_len( p, end, &len );
-
- if( ret != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret );
-
- memset( date, 0, sizeof( date ) );
- memcpy( date, *p, ( len < sizeof( date ) - 1 ) ?
- len : sizeof( date ) - 1 );
-
- if( sscanf( date, "%4d%2d%2d%2d%2d%2d",
- &time->year, &time->mon, &time->day,
- &time->hour, &time->min, &time->sec ) < 5 )
- return( POLARSSL_ERR_X509_CERT_INVALID_DATE );
-
- *p += len;
-
- return( 0 );
- }
- else
- return( POLARSSL_ERR_X509_CERT_INVALID_DATE + POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
-}
-
-
-/*
- * Validity ::= SEQUENCE {
- * notBefore Time,
- * notAfter Time }
- */
-static int x509_get_dates( unsigned char **p,
- const unsigned char *end,
- x509_time *from,
- x509_time *to )
-{
- int ret;
- size_t len;
-
- if( ( ret = asn1_get_tag( p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret );
-
- end = *p + len;
-
- if( ( ret = x509_get_time( p, end, from ) ) != 0 )
- return( ret );
-
- if( ( ret = x509_get_time( p, end, to ) ) != 0 )
- return( ret );
-
- if( *p != end )
- return( POLARSSL_ERR_X509_CERT_INVALID_DATE +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
-
- return( 0 );
-}
-
-static int x509_get_sig( unsigned char **p,
- const unsigned char *end,
- x509_buf *sig )
-{
- int ret;
- size_t len;
-
- if( ( end - *p ) < 1 )
- return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE +
- POLARSSL_ERR_ASN1_OUT_OF_DATA );
-
- sig->tag = **p;
-
- if( ( ret = asn1_get_bitstring_null( p, end, &len ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE + ret );
-
- sig->len = len;
- sig->p = *p;
-
- *p += len;
-
- return( 0 );
-}
-
-/*
- * X.509 v2/v3 unique identifier (not parsed)
- */
-static int x509_get_uid( unsigned char **p,
- const unsigned char *end,
- x509_buf *uid, int n )
-{
- int ret;
-
- if( *p == end )
- return( 0 );
-
- uid->tag = **p;
-
- if( ( ret = asn1_get_tag( p, end, &uid->len,
- ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | n ) ) != 0 )
- {
- if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
- return( 0 );
-
- return( ret );
- }
-
- uid->p = *p;
- *p += uid->len;
-
- return( 0 );
-}
-
-/*
- * X.509 Extensions (No parsing of extensions, pointer should
- * be either manually updated or extensions should be parsed!
- */
-static int x509_get_ext( unsigned char **p,
- const unsigned char *end,
- x509_buf *ext, int tag )
-{
- int ret;
- size_t len;
-
- if( *p == end )
- return( 0 );
-
- ext->tag = **p;
-
- if( ( ret = asn1_get_tag( p, end, &ext->len,
- ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | tag ) ) != 0 )
- return( ret );
-
- ext->p = *p;
- end = *p + ext->len;
-
- /*
- * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
- *
- * Extension ::= SEQUENCE {
- * extnID OBJECT IDENTIFIER,
- * critical BOOLEAN DEFAULT FALSE,
- * extnValue OCTET STRING }
- */
- if( ( ret = asn1_get_tag( p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- if( end != *p + len )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
-
- 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 );
-}
-
-static int x509_get_basic_constraints( unsigned char **p,
- const unsigned char *end,
- int *ca_istrue,
- int *max_pathlen )
-{
- int ret;
- size_t len;
-
- /*
- * BasicConstraints ::= SEQUENCE {
- * cA BOOLEAN DEFAULT FALSE,
- * pathLenConstraint INTEGER (0..MAX) OPTIONAL }
- */
- *ca_istrue = 0; /* DEFAULT FALSE */
- *max_pathlen = 0; /* endless */
-
- if( ( ret = asn1_get_tag( p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- if( *p == end )
- return 0;
-
- if( ( ret = asn1_get_bool( p, end, ca_istrue ) ) != 0 )
- {
- if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
- ret = asn1_get_int( p, end, ca_istrue );
-
- if( ret != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- if( *ca_istrue != 0 )
- *ca_istrue = 1;
- }
-
- if( *p == end )
- return 0;
-
- if( ( ret = asn1_get_int( p, end, max_pathlen ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- if( *p != end )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
-
- (*max_pathlen)++;
-
- return 0;
-}
-
-static int x509_get_ns_cert_type( unsigned char **p,
- const unsigned char *end,
- unsigned char *ns_cert_type)
-{
- int ret;
- x509_bitstring bs = { 0, 0, NULL };
-
- if( ( ret = asn1_get_bitstring( p, end, &bs ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- if( bs.len != 1 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_INVALID_LENGTH );
-
- /* Get actual bitstring */
- *ns_cert_type = *bs.p;
- return 0;
-}
-
-static int x509_get_key_usage( unsigned char **p,
- const unsigned char *end,
- unsigned char *key_usage)
-{
- int ret;
- x509_bitstring bs = { 0, 0, NULL };
-
- if( ( ret = asn1_get_bitstring( p, end, &bs ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- if( bs.len < 1 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_INVALID_LENGTH );
-
- /* Get actual bitstring */
- *key_usage = *bs.p;
- return 0;
-}
-
-/*
- * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
- *
- * KeyPurposeId ::= OBJECT IDENTIFIER
- */
-static int x509_get_ext_key_usage( unsigned char **p,
- const unsigned char *end,
- x509_sequence *ext_key_usage)
-{
- int ret;
-
- if( ( ret = asn1_get_sequence_of( p, end, ext_key_usage, ASN1_OID ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- /* Sequence length must be >= 1 */
- if( ext_key_usage->buf.p == NULL )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_INVALID_LENGTH );
-
- return 0;
-}
-
-/*
- * SubjectAltName ::= GeneralNames
- *
- * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
- *
- * GeneralName ::= CHOICE {
- * otherName [0] OtherName,
- * rfc822Name [1] IA5String,
- * dNSName [2] IA5String,
- * x400Address [3] ORAddress,
- * directoryName [4] Name,
- * ediPartyName [5] EDIPartyName,
- * uniformResourceIdentifier [6] IA5String,
- * iPAddress [7] OCTET STRING,
- * registeredID [8] OBJECT IDENTIFIER }
- *
- * OtherName ::= SEQUENCE {
- * type-id OBJECT IDENTIFIER,
- * value [0] EXPLICIT ANY DEFINED BY type-id }
- *
- * EDIPartyName ::= SEQUENCE {
- * nameAssigner [0] DirectoryString OPTIONAL,
- * partyName [1] DirectoryString }
- *
- * NOTE: PolarSSL only parses and uses dNSName at this point.
- */
-static int x509_get_subject_alt_name( unsigned char **p,
- const unsigned char *end,
- x509_sequence *subject_alt_name )
-{
- int ret;
- size_t len, tag_len;
- asn1_buf *buf;
- unsigned char tag;
- asn1_sequence *cur = subject_alt_name;
-
- /* Get main sequence tag */
- if( ( ret = asn1_get_tag( p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- if( *p + len != end )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
-
- while( *p < end )
- {
- if( ( end - *p ) < 1 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_OUT_OF_DATA );
-
- tag = **p;
- (*p)++;
- if( ( ret = asn1_get_len( p, end, &tag_len ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- if( ( tag & ASN1_CONTEXT_SPECIFIC ) != ASN1_CONTEXT_SPECIFIC )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
-
- if( tag != ( ASN1_CONTEXT_SPECIFIC | 2 ) )
- {
- *p += tag_len;
- continue;
- }
-
- buf = &(cur->buf);
- buf->tag = tag;
- buf->p = *p;
- buf->len = tag_len;
- *p += buf->len;
-
- /* Allocate and assign next pointer */
- if (*p < end)
- {
- cur->next = (asn1_sequence *) polarssl_malloc(
- sizeof( asn1_sequence ) );
-
- if( cur->next == NULL )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_MALLOC_FAILED );
-
- memset( cur->next, 0, sizeof( asn1_sequence ) );
- cur = cur->next;
- }
- }
-
- /* Set final sequence entry's next pointer to NULL */
- cur->next = NULL;
-
- if( *p != end )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
-
- return( 0 );
-}
-
-/*
- * X.509 v3 extensions
- *
- * TODO: Perform all of the basic constraints tests required by the RFC
- * TODO: Set values for undetected extensions to a sane default?
- *
- */
-static int x509_get_crt_ext( unsigned char **p,
- const unsigned char *end,
- x509_cert *crt )
-{
- int ret;
- size_t len;
- unsigned char *end_ext_data, *end_ext_octet;
-
- if( ( ret = x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 )
- {
- if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
- return( 0 );
-
- return( ret );
- }
-
- while( *p < end )
- {
- /*
- * Extension ::= SEQUENCE {
- * extnID OBJECT IDENTIFIER,
- * critical BOOLEAN DEFAULT FALSE,
- * extnValue OCTET STRING }
- */
- x509_buf extn_oid = {0, 0, NULL};
- int is_critical = 0; /* DEFAULT FALSE */
- int ext_type = 0;
-
- if( ( ret = asn1_get_tag( p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- end_ext_data = *p + len;
-
- /* Get extension ID */
- extn_oid.tag = **p;
-
- if( ( ret = asn1_get_tag( p, end, &extn_oid.len, ASN1_OID ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- extn_oid.p = *p;
- *p += extn_oid.len;
-
- if( ( end - *p ) < 1 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_OUT_OF_DATA );
-
- /* Get optional critical */
- if( ( ret = asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 &&
- ( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- /* Data should be octet string type */
- if( ( ret = asn1_get_tag( p, end_ext_data, &len,
- ASN1_OCTET_STRING ) ) != 0 )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret );
-
- end_ext_octet = *p + len;
-
- if( end_ext_octet != end_ext_data )
- return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
-
- /*
- * Detect supported extensions
- */
- ret = oid_get_x509_ext_type( &extn_oid, &ext_type );
-
- if( ret != 0 )
- {
- /* No parser found, skip extension */
- *p = end_ext_octet;
-
-#if !defined(POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
- if( is_critical )
- {
- /* Data is marked as critical: fail */
- return ( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS +
- POLARSSL_ERR_ASN1_UNEXPECTED_TAG );
- }
-#endif
- continue;
- }
-
- crt->ext_types |= ext_type;
-
- switch( ext_type )
- {
- case EXT_BASIC_CONSTRAINTS:
- /* Parse basic constraints */
- if( ( ret = x509_get_basic_constraints( p, end_ext_octet,
- &crt->ca_istrue, &crt->max_pathlen ) ) != 0 )
- return ( ret );
- break;
-
- case EXT_KEY_USAGE:
- /* Parse key usage */
- if( ( ret = x509_get_key_usage( p, end_ext_octet,
- &crt->key_usage ) ) != 0 )
- return ( ret );
- break;
-
- case EXT_EXTENDED_KEY_USAGE:
- /* Parse extended key usage */
- if( ( ret = x509_get_ext_key_usage( p, end_ext_octet,
- &crt->ext_key_usage ) ) != 0 )
- return ( ret );
- break;
-
- case EXT_SUBJECT_ALT_NAME:
- /* Parse subject alt name */
- if( ( ret = x509_get_subject_alt_name( p, end_ext_octet,
- &crt->subject_alt_names ) ) != 0 )
- return ( ret );
- break;
-
- case EXT_NS_CERT_TYPE:
- /* Parse netscape certificate type */
- if( ( ret = x509_get_ns_cert_type( p, end_ext_octet,
- &crt->ns_cert_type ) ) != 0 )
- return ( ret );
- break;
-
- default:
- return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
- }
- }
-
- 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 );
-}
-
-static int x509_get_sig_alg( const x509_buf *sig_oid, md_type_t *md_alg,
- pk_type_t *pk_alg )
-{
- int ret = oid_get_sig_alg( sig_oid, md_alg, pk_alg );
-
- if( ret != 0 )
- return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG + ret );
-
- return( 0 );
-}
-
-/*
- * Parse and fill a single X.509 certificate in DER format
- */
-static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf,
- size_t buflen )
-{
- int ret;
- size_t len;
- unsigned char *p, *end, *crt_end;
-
- /*
- * Check for valid input
- */
- if( crt == NULL || buf == NULL )
- return( POLARSSL_ERR_X509_INVALID_INPUT );
-
- p = (unsigned char *) polarssl_malloc( len = buflen );
-
- if( p == NULL )
- return( POLARSSL_ERR_X509_MALLOC_FAILED );
-
- memcpy( p, buf, buflen );
-
- buflen = 0;
-
- crt->raw.p = p;
- crt->raw.len = len;
- end = p + len;
-
- /*
- * Certificate ::= SEQUENCE {
- * tbsCertificate TBSCertificate,
- * signatureAlgorithm AlgorithmIdentifier,
- * signatureValue BIT STRING }
- */
- if( ( ret = asn1_get_tag( &p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- {
- x509_free( crt );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT );
- }
-
- if( len > (size_t) ( end - p ) )
- {
- x509_free( crt );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
- }
- crt_end = p + len;
-
- /*
- * TBSCertificate ::= SEQUENCE {
- */
- crt->tbs.p = p;
-
- if( ( ret = asn1_get_tag( &p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- {
- x509_free( crt );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
- }
-
- end = p + len;
- crt->tbs.len = end - crt->tbs.p;
-
- /*
- * Version ::= INTEGER { v1(0), v2(1), v3(2) }
- *
- * CertificateSerialNumber ::= INTEGER
- *
- * signature AlgorithmIdentifier
- */
- if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 ||
- ( ret = x509_get_serial( &p, end, &crt->serial ) ) != 0 ||
- ( ret = x509_get_alg_null( &p, end, &crt->sig_oid1 ) ) != 0 )
- {
- x509_free( crt );
- return( ret );
- }
-
- crt->version++;
-
- if( crt->version > 3 )
- {
- x509_free( crt );
- return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION );
- }
-
- if( ( ret = x509_get_sig_alg( &crt->sig_oid1, &crt->sig_md,
- &crt->sig_pk ) ) != 0 )
- {
- x509_free( crt );
- return( ret );
- }
-
- /*
- * issuer Name
- */
- crt->issuer_raw.p = p;
-
- if( ( ret = asn1_get_tag( &p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- {
- x509_free( crt );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
- }
-
- if( ( ret = x509_get_name( &p, p + len, &crt->issuer ) ) != 0 )
- {
- x509_free( crt );
- return( ret );
- }
-
- crt->issuer_raw.len = p - crt->issuer_raw.p;
-
- /*
- * Validity ::= SEQUENCE {
- * notBefore Time,
- * notAfter Time }
- *
- */
- if( ( ret = x509_get_dates( &p, end, &crt->valid_from,
- &crt->valid_to ) ) != 0 )
- {
- x509_free( crt );
- return( ret );
- }
-
- /*
- * subject Name
- */
- crt->subject_raw.p = p;
-
- if( ( ret = asn1_get_tag( &p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- {
- x509_free( crt );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
- }
-
- if( len && ( ret = x509_get_name( &p, p + len, &crt->subject ) ) != 0 )
- {
- x509_free( crt );
- return( ret );
- }
-
- crt->subject_raw.len = p - crt->subject_raw.p;
-
- /*
- * SubjectPublicKeyInfo
- */
- if( ( ret = pk_parse_get_pubkey( &p, end, &crt->pk ) ) != 0 )
- {
- x509_free( crt );
- return( ret );
- }
-
- /*
- * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
- * -- If present, version shall be v2 or v3
- * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
- * -- If present, version shall be v2 or v3
- * extensions [3] EXPLICIT Extensions OPTIONAL
- * -- If present, version shall be v3
- */
- if( crt->version == 2 || crt->version == 3 )
- {
- ret = x509_get_uid( &p, end, &crt->issuer_id, 1 );
- if( ret != 0 )
- {
- x509_free( crt );
- return( ret );
- }
- }
-
- if( crt->version == 2 || crt->version == 3 )
- {
- ret = x509_get_uid( &p, end, &crt->subject_id, 2 );
- if( ret != 0 )
- {
- x509_free( crt );
- return( ret );
- }
- }
-
- if( crt->version == 3 )
- {
- ret = x509_get_crt_ext( &p, end, crt);
- if( ret != 0 )
- {
- x509_free( crt );
- return( ret );
- }
- }
-
- if( p != end )
- {
- x509_free( crt );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
- }
-
- end = crt_end;
-
- /*
- * }
- * -- end of TBSCertificate
- *
- * signatureAlgorithm AlgorithmIdentifier,
- * signatureValue BIT STRING
- */
- if( ( ret = x509_get_alg_null( &p, end, &crt->sig_oid2 ) ) != 0 )
- {
- x509_free( crt );
- return( ret );
- }
-
- if( crt->sig_oid1.len != crt->sig_oid2.len ||
- memcmp( crt->sig_oid1.p, crt->sig_oid2.p, crt->sig_oid1.len ) != 0 )
- {
- x509_free( crt );
- return( POLARSSL_ERR_X509_CERT_SIG_MISMATCH );
- }
-
- if( ( ret = x509_get_sig( &p, end, &crt->sig ) ) != 0 )
- {
- x509_free( crt );
- return( ret );
- }
-
- if( p != end )
- {
- x509_free( crt );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
- }
-
- return( 0 );
-}
-
-/*
- * Parse one X.509 certificate in DER format from a buffer and add them to a
- * chained list
- */
-int x509parse_crt_der( x509_cert *chain, const unsigned char *buf, size_t buflen )
-{
- int ret;
- x509_cert *crt = chain, *prev = NULL;
-
- /*
- * Check for valid input
- */
- if( crt == NULL || buf == NULL )
- return( POLARSSL_ERR_X509_INVALID_INPUT );
-
- while( crt->version != 0 && crt->next != NULL )
- {
- prev = crt;
- crt = crt->next;
- }
-
- /*
- * Add new certificate on the end of the chain if needed.
- */
- if ( crt->version != 0 && crt->next == NULL)
- {
- crt->next = (x509_cert *) polarssl_malloc( sizeof( x509_cert ) );
-
- if( crt->next == NULL )
- return( POLARSSL_ERR_X509_MALLOC_FAILED );
-
- prev = crt;
- crt = crt->next;
- memset( crt, 0, sizeof( x509_cert ) );
- }
-
- if( ( ret = x509parse_crt_der_core( crt, buf, buflen ) ) != 0 )
- {
- if( prev )
- prev->next = NULL;
-
- if( crt != chain )
- polarssl_free( crt );
-
- return( ret );
- }
-
- return( 0 );
-}
-
-/*
- * Parse one or more PEM certificates from a buffer and add them to the chained list
- */
-int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen )
-{
- int success = 0, first_error = 0, total_failed = 0;
- int buf_format = X509_FORMAT_DER;
-
- /*
- * Check for valid input
- */
- if( chain == NULL || buf == NULL )
- return( POLARSSL_ERR_X509_INVALID_INPUT );
-
- /*
- * Determine buffer content. Buffer contains either one DER certificate or
- * one or more PEM certificates.
- */
-#if defined(POLARSSL_PEM_PARSE_C)
- if( strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL )
- buf_format = X509_FORMAT_PEM;
-#endif
-
- if( buf_format == X509_FORMAT_DER )
- return x509parse_crt_der( chain, buf, buflen );
-
-#if defined(POLARSSL_PEM_PARSE_C)
- if( buf_format == X509_FORMAT_PEM )
- {
- int ret;
- pem_context pem;
-
- while( buflen > 0 )
- {
- size_t use_len;
- pem_init( &pem );
-
- ret = pem_read_buffer( &pem,
- "-----BEGIN CERTIFICATE-----",
- "-----END CERTIFICATE-----",
- buf, NULL, 0, &use_len );
-
- if( ret == 0 )
- {
- /*
- * Was PEM encoded
- */
- buflen -= use_len;
- buf += use_len;
- }
- else if( ret == POLARSSL_ERR_PEM_BAD_INPUT_DATA )
- {
- return( ret );
- }
- else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
- {
- pem_free( &pem );
-
- /*
- * PEM header and footer were found
- */
- buflen -= use_len;
- buf += use_len;
-
- if( first_error == 0 )
- first_error = ret;
-
- continue;
- }
- else
- break;
-
- ret = x509parse_crt_der( chain, pem.buf, pem.buflen );
-
- pem_free( &pem );
-
- if( ret != 0 )
- {
- /*
- * Quit parsing on a memory error
- */
- if( ret == POLARSSL_ERR_X509_MALLOC_FAILED )
- return( ret );
-
- if( first_error == 0 )
- first_error = ret;
-
- total_failed++;
- continue;
- }
-
- success = 1;
- }
- }
-#endif
-
- if( success )
- return( total_failed );
- else if( first_error )
- return( first_error );
- else
- return( POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT );
-}
-
-/*
- * Parse a CSR
- */
-int x509parse_csr( x509_csr *csr, const unsigned char *buf, size_t buflen )
-{
- int ret;
- size_t len;
- unsigned char *p, *end;
-#if defined(POLARSSL_PEM_PARSE_C)
- size_t use_len;
- pem_context pem;
-#endif
-
- /*
- * Check for valid input
- */
- if( csr == NULL || buf == NULL )
- return( POLARSSL_ERR_X509_INVALID_INPUT );
-
- memset( csr, 0, sizeof( x509_csr ) );
-
-#if defined(POLARSSL_PEM_PARSE_C)
- pem_init( &pem );
- ret = pem_read_buffer( &pem,
- "-----BEGIN CERTIFICATE REQUEST-----",
- "-----END CERTIFICATE REQUEST-----",
- 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;
- }
-
- csr->raw.p = p;
- csr->raw.len = len;
- end = p + len;
-
- /*
- * CertificationRequest ::= SEQUENCE {
- * certificationRequestInfo CertificationRequestInfo,
- * signatureAlgorithm AlgorithmIdentifier,
- * signature BIT STRING
- * }
- */
- if( ( ret = asn1_get_tag( &p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- {
- x509_csr_free( csr );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT );
- }
-
- if( len != (size_t) ( end - p ) )
- {
- x509_csr_free( csr );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
- }
-
- /*
- * CertificationRequestInfo ::= SEQUENCE {
- */
- csr->cri.p = p;
-
- if( ( ret = asn1_get_tag( &p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- {
- x509_csr_free( csr );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
- }
-
- end = p + len;
- csr->cri.len = end - csr->cri.p;
-
- /*
- * Version ::= INTEGER { v1(0) }
- */
- if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 )
- {
- x509_csr_free( csr );
- return( ret );
- }
-
- csr->version++;
-
- if( csr->version != 1 )
- {
- x509_csr_free( csr );
- return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION );
- }
-
- /*
- * subject Name
- */
- csr->subject_raw.p = p;
-
- if( ( ret = asn1_get_tag( &p, end, &len,
- ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
- {
- x509_csr_free( csr );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
- }
-
- if( ( ret = x509_get_name( &p, p + len, &csr->subject ) ) != 0 )
- {
- x509_csr_free( csr );
- return( ret );
- }
-
- csr->subject_raw.len = p - csr->subject_raw.p;
-
- /*
- * subjectPKInfo SubjectPublicKeyInfo
- */
- if( ( ret = pk_parse_get_pubkey( &p, end, &csr->pk ) ) != 0 )
- {
- x509_csr_free( csr );
- return( ret );
- }
-
- /*
- * attributes [0] Attributes
- */
- if( ( ret = asn1_get_tag( &p, end, &len,
- ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC ) ) != 0 )
- {
- x509_csr_free( csr );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
- }
- // TODO Parse Attributes / extension requests
-
- p += len;
-
- end = csr->raw.p + csr->raw.len;
-
- /*
- * signatureAlgorithm AlgorithmIdentifier,
- * signature BIT STRING
- */
- if( ( ret = x509_get_alg_null( &p, end, &csr->sig_oid ) ) != 0 )
- {
- x509_csr_free( csr );
- return( ret );
- }
-
- if( ( ret = x509_get_sig_alg( &csr->sig_oid, &csr->sig_md,
- &csr->sig_pk ) ) != 0 )
- {
- x509_csr_free( csr );
- return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG );
- }
-
- if( ( ret = x509_get_sig( &p, end, &csr->sig ) ) != 0 )
- {
- x509_csr_free( csr );
- return( ret );
- }
-
- if( p != end )
- {
- x509_csr_free( csr );
- return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
- POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
- }
-
- 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 all data from a file into a given buffer.
- */
-static int load_file( const char *path, unsigned char **buf, size_t *n )
-{
- FILE *f;
- long size;
-
- if( ( f = fopen( path, "rb" ) ) == NULL )
- return( POLARSSL_ERR_X509_FILE_IO_ERROR );
-
- fseek( f, 0, SEEK_END );
- if( ( size = ftell( f ) ) == -1 )
- {
- fclose( f );
- return( POLARSSL_ERR_X509_FILE_IO_ERROR );
- }
- fseek( f, 0, SEEK_SET );
-
- *n = (size_t) size;
-
- if( *n + 1 == 0 ||
- ( *buf = (unsigned char *) polarssl_malloc( *n + 1 ) ) == NULL )
- {
- fclose( f );
- return( POLARSSL_ERR_X509_MALLOC_FAILED );
- }
-
- if( fread( *buf, 1, *n, f ) != *n )
- {
- fclose( f );
- polarssl_free( *buf );
- return( POLARSSL_ERR_X509_FILE_IO_ERROR );
- }
-
- fclose( f );
-
- (*buf)[*n] = '\0';
-
- return( 0 );
-}
-
-/*
- * Load one or more certificates and add them to the chained list
- */
-int x509parse_crtfile( x509_cert *chain, const char *path )
-{
- int ret;
- size_t n;
- unsigned char *buf;
-
- if ( ( ret = load_file( path, &buf, &n ) ) != 0 )
- return( ret );
-
- ret = x509parse_crt( chain, buf, n );
-
- memset( buf, 0, n + 1 );
- polarssl_free( buf );
-
- return( ret );
-}
-
-int x509parse_crtpath( x509_cert *chain, const char *path )
-{
- int ret = 0;
-#if defined(_WIN32)
- int w_ret;
- WCHAR szDir[MAX_PATH];
- char filename[MAX_PATH];
- char *p;
- int len = strlen( path );
-
- WIN32_FIND_DATAW file_data;
- HANDLE hFind;
-
- if( len > MAX_PATH - 3 )
- return( POLARSSL_ERR_X509_INVALID_INPUT );
-
- memset( szDir, 0, sizeof(szDir) );
- memset( filename, 0, MAX_PATH );
- memcpy( filename, path, len );
- filename[len++] = '\\';
- p = filename + len;
- filename[len++] = '*';
-
- w_ret = MultiByteToWideChar( CP_ACP, 0, path, len, szDir, MAX_PATH - 3 );
-
- hFind = FindFirstFileW( szDir, &file_data );
- if (hFind == INVALID_HANDLE_VALUE)
- return( POLARSSL_ERR_X509_FILE_IO_ERROR );
-
- len = MAX_PATH - len;
- do
- {
- memset( p, 0, len );
-
- if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
- continue;
-
- w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName,
- lstrlenW(file_data.cFileName),
- p, len - 1,
- NULL, NULL );
-
- w_ret = x509parse_crtfile( chain, filename );
- if( w_ret < 0 )
- ret++;
- else
- ret += w_ret;
- }
- while( FindNextFileW( hFind, &file_data ) != 0 );
-
- if (GetLastError() != ERROR_NO_MORE_FILES)
- ret = POLARSSL_ERR_X509_FILE_IO_ERROR;
-
-cleanup:
- FindClose( hFind );
-#else
- int t_ret, i;
- struct stat sb;
- struct dirent entry, *result = NULL;
- char entry_name[255];
- DIR *dir = opendir( path );
-
- if( dir == NULL)
- return( POLARSSL_ERR_X509_FILE_IO_ERROR );
-
- while( ( t_ret = readdir_r( dir, &entry, &result ) ) == 0 )
- {
- if( result == NULL )
- break;
-
- snprintf( entry_name, sizeof(entry_name), "%s/%s", path, entry.d_name );
-
- i = stat( entry_name, &sb );
-
- if( i == -1 )
- {
- closedir( dir );
- return( POLARSSL_ERR_X509_FILE_IO_ERROR );
- }
-
- if( !S_ISREG( sb.st_mode ) )
- continue;
-
- // Ignore parse errors
- //
- t_ret = x509parse_crtfile( chain, entry_name );
- if( t_ret < 0 )
- ret++;
- else
- ret += t_ret;
- }
- closedir( dir );
-#endif
-
- return( ret );
-}
-
-/*
- * Load a CSR into the structure
- */
-int x509parse_csrfile( x509_csr *csr, const char *path )
-{
- int ret;
- size_t n;
- unsigned char *buf;
-
- if ( ( ret = load_file( path, &buf, &n ) ) != 0 )
- return( ret );
-
- ret = x509parse_csr( csr, buf, n );
-
- memset( buf, 0, n + 1 );
- polarssl_free( buf );
-
- return( ret );
-}
-
-/*
- * 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 = load_file( path, &buf, &n ) ) != 0 )
- return( ret );
-
- ret = x509parse_crl( chain, buf, n );
-
- memset( buf, 0, n + 1 );
- polarssl_free( buf );
-
- return( ret );
-}
-
-#if defined(POLARSSL_RSA_C)
-/*
- * Load and parse a private RSA key
- */
-int x509parse_keyfile_rsa( rsa_context *rsa, const char *path, const char *pwd )
-{
- int ret;
- pk_context pk;
-
- pk_init( &pk );
-
- ret = pk_parse_keyfile( &pk, path, pwd );
-
- if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) )
- ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
-
- if( ret == 0 )
- rsa_copy( rsa, pk_rsa( pk ) );
- else
- rsa_free( rsa );
-
- pk_free( &pk );
-
- return( ret );
-}
-
-/*
- * Load and parse a public RSA key
- */
-int x509parse_public_keyfile_rsa( rsa_context *rsa, const char *path )
-{
- int ret;
- pk_context pk;
-
- pk_init( &pk );
-
- ret = pk_parse_public_keyfile( &pk, path );
-
- if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) )
- ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
-
- if( ret == 0 )
- rsa_copy( rsa, pk_rsa( pk ) );
- else
- rsa_free( rsa );
-
- pk_free( &pk );
-
- return( ret );
-}
-#endif /* POLARSSL_RSA_C */
-#endif /* POLARSSL_FS_IO */
-
-#if defined(POLARSSL_RSA_C)
-/*
- * Parse a private RSA key
- */
-int x509parse_key_rsa( rsa_context *rsa,
- const unsigned char *key, size_t keylen,
- const unsigned char *pwd, size_t pwdlen )
-{
- int ret;
- pk_context pk;
-
- pk_init( &pk );
-
- ret = pk_parse_key( &pk, key, keylen, pwd, pwdlen );
-
- if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) )
- ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
-
- if( ret == 0 )
- rsa_copy( rsa, pk_rsa( pk ) );
- else
- rsa_free( rsa );
-
- pk_free( &pk );
-
- return( ret );
-}
-
-/*
- * Parse a public RSA key
- */
-int x509parse_public_key_rsa( rsa_context *rsa,
- const unsigned char *key, size_t keylen )
-{
- int ret;
- pk_context pk;
-
- pk_init( &pk );
-
- ret = pk_parse_public_key( &pk, key, keylen );
-
- if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) )
- ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
-
- if( ret == 0 )
- rsa_copy( rsa, pk_rsa( pk ) );
- else
- rsa_free( rsa );
-
- pk_free( &pk );
-
- return( ret );
-}
-#endif /* POLARSSL_RSA_C */
-
-#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; \
-}
-
-/*
- * Store the name in printable form into buf; no more
- * than size characters will be written
- */
-int x509parse_dn_gets( char *buf, size_t size, const x509_name *dn )
-{
- int ret;
- size_t i, n;
- unsigned char c;
- const x509_name *name;
- const char *short_name = NULL;
- char s[128], *p;
-
- memset( s, 0, sizeof( s ) );
-
- name = dn;
- p = buf;
- n = size;
-
- while( name != NULL )
- {
- if( !name->oid.p )
- {
- name = name->next;
- continue;
- }
-
- if( name != dn )
- {
- ret = snprintf( p, n, ", " );
- SAFE_SNPRINTF();
- }
-
- ret = oid_get_attr_short_name( &name->oid, &short_name );
-
- if( ret == 0 )
- ret = snprintf( p, n, "%s=", short_name );
- else
- ret = snprintf( p, n, "\?\?=" );
- SAFE_SNPRINTF();
-
- for( i = 0; i < name->val.len; i++ )
- {
- if( i >= sizeof( s ) - 1 )
- break;
-
- c = name->val.p[i];
- if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
- s[i] = '?';
- else s[i] = c;
- }
- s[i] = '\0';
- ret = snprintf( p, n, "%s", s );
- SAFE_SNPRINTF();
- name = name->next;
- }
-
- return( (int) ( size - n ) );
-}
-
-/*
- * Store the serial in printable form into buf; no more
- * than size characters will be written
- */
-int x509parse_serial_gets( char *buf, size_t size, const x509_buf *serial )
-{
- int ret;
- size_t i, n, nr;
- char *p;
-
- p = buf;
- n = size;
-
- nr = ( serial->len <= 32 )
- ? serial->len : 28;
-
- for( i = 0; i < nr; i++ )
- {
- if( i == 0 && nr > 1 && serial->p[i] == 0x0 )
- continue;
-
- ret = snprintf( p, n, "%02X%s",
- serial->p[i], ( i < nr - 1 ) ? ":" : "" );
- SAFE_SNPRINTF();
- }
-
- if( nr != serial->len )
- {
- ret = snprintf( p, n, "...." );
- SAFE_SNPRINTF();
- }
-
- return( (int) ( size - n ) );
-}
-
-/*
- * Helper for writing "RSA key size", "EC key size", etc
- */
-static int x509_key_size_helper( char *buf, size_t size, const char *name )
-{
- char *p = buf;
- size_t n = size;
- int ret;
-
- if( strlen( name ) + sizeof( " key size" ) > size )
- return POLARSSL_ERR_DEBUG_BUF_TOO_SMALL;
-
- ret = snprintf( p, n, "%s key size", name );
- SAFE_SNPRINTF();
-
- return( 0 );
-}
-
-/*
- * Return an informational string about the certificate.
- */
-#define BEFORE_COLON 14
-#define BC "14"
-int x509parse_cert_info( char *buf, size_t size, const char *prefix,
- const x509_cert *crt )
-{
- int ret;
- size_t n;
- char *p;
- const char *desc = NULL;
- char key_size_str[BEFORE_COLON];
-
- p = buf;
- n = size;
-
- ret = snprintf( p, n, "%scert. version : %d\n",
- prefix, crt->version );
- SAFE_SNPRINTF();
- ret = snprintf( p, n, "%sserial number : ",
- prefix );
- SAFE_SNPRINTF();
-
- ret = x509parse_serial_gets( p, n, &crt->serial);
- SAFE_SNPRINTF();
-
- ret = snprintf( p, n, "\n%sissuer name : ", prefix );
- SAFE_SNPRINTF();
- ret = x509parse_dn_gets( p, n, &crt->issuer );
- SAFE_SNPRINTF();
-
- ret = snprintf( p, n, "\n%ssubject name : ", prefix );
- SAFE_SNPRINTF();
- ret = x509parse_dn_gets( p, n, &crt->subject );
- SAFE_SNPRINTF();
-
- ret = snprintf( p, n, "\n%sissued on : " \
- "%04d-%02d-%02d %02d:%02d:%02d", prefix,
- crt->valid_from.year, crt->valid_from.mon,
- crt->valid_from.day, crt->valid_from.hour,
- crt->valid_from.min, crt->valid_from.sec );
- SAFE_SNPRINTF();
-
- ret = snprintf( p, n, "\n%sexpires on : " \
- "%04d-%02d-%02d %02d:%02d:%02d", prefix,
- crt->valid_to.year, crt->valid_to.mon,
- crt->valid_to.day, crt->valid_to.hour,
- crt->valid_to.min, crt->valid_to.sec );
- SAFE_SNPRINTF();
-
- ret = snprintf( p, n, "\n%ssigned using : ", prefix );
- SAFE_SNPRINTF();
-
- ret = oid_get_sig_alg_desc( &crt->sig_oid1, &desc );
- if( ret != 0 )
- ret = snprintf( p, n, "???" );
- else
- ret = snprintf( p, n, "%s", desc );
- SAFE_SNPRINTF();
-
- if( ( ret = x509_key_size_helper( key_size_str, BEFORE_COLON,
- pk_get_name( &crt->pk ) ) ) != 0 )
- {
- return( ret );
- }
-
- ret = snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str,
- (int) pk_get_size( &crt->pk ) );
- SAFE_SNPRINTF();
-
- return( (int) ( size - n ) );
-}
-
-/*
- * Return an informational string describing the given OID
- */
-const char *x509_oid_get_description( x509_buf *oid )
-{
- const char *desc = NULL;
- int ret;
-
- ret = oid_get_extended_key_usage( oid, &desc );
-
- if( ret != 0 )
- return( NULL );
-
- return( desc );
-}
-
-/* Return the x.y.z.... style numeric string for the given OID */
-int x509_oid_get_numeric_string( char *buf, size_t size, x509_buf *oid )
-{
- return oid_get_numeric_string( buf, size, oid );
-}
-
-/*
- * 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 ) );
-}
-
-/*
- * Return an informational string about the CSR.
- */
-int x509parse_csr_info( char *buf, size_t size, const char *prefix,
- const x509_csr *csr )
-{
- int ret;
- size_t n;
- char *p;
- const char *desc;
- char key_size_str[BEFORE_COLON];
-
- p = buf;
- n = size;
-
- ret = snprintf( p, n, "%sCSR version : %d",
- prefix, csr->version );
- SAFE_SNPRINTF();
-
- ret = snprintf( p, n, "\n%ssubject name : ", prefix );
- SAFE_SNPRINTF();
- ret = x509parse_dn_gets( p, n, &csr->subject );
- SAFE_SNPRINTF();
-
- ret = snprintf( p, n, "\n%ssigned using : ", prefix );
- SAFE_SNPRINTF();
-
- ret = oid_get_sig_alg_desc( &csr->sig_oid, &desc );
- if( ret != 0 )
- ret = snprintf( p, n, "???" );
- else
- ret = snprintf( p, n, "%s", desc );
- SAFE_SNPRINTF();
-
- if( ( ret = x509_key_size_helper( key_size_str, BEFORE_COLON,
- pk_get_name( &csr->pk ) ) ) != 0 )
- {
- return( ret );
- }
-
- ret = snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str,
- (int) pk_get_size( &csr->pk ) );
- SAFE_SNPRINTF();
-
- return( (int) ( size - n ) );
-}
-
-/*
- * Return 0 if the x509_time is still valid, or 1 otherwise.
- */
-#if defined(POLARSSL_HAVE_TIME)
-int x509parse_time_expired( const x509_time *to )
-{
- int year, mon, day;
- int hour, min, sec;
-
-#if defined(_WIN32)
- SYSTEMTIME st;
-
- GetLocalTime(&st);
-
- year = st.wYear;
- mon = st.wMonth;
- day = st.wDay;
- hour = st.wHour;
- min = st.wMinute;
- sec = st.wSecond;
-#else
- struct tm *lt;
- time_t tt;
-
- tt = time( NULL );
- lt = localtime( &tt );
-
- year = lt->tm_year + 1900;
- mon = lt->tm_mon + 1;
- day = lt->tm_mday;
- hour = lt->tm_hour;
- min = lt->tm_min;
- sec = lt->tm_sec;
-#endif
-
- if( year > to->year )
- return( 1 );
-
- if( year == to->year &&
- mon > to->mon )
- return( 1 );
-
- if( year == to->year &&
- mon == to->mon &&
- day > to->day )
- return( 1 );
-
- if( year == to->year &&
- mon == to->mon &&
- day == to->day &&
- hour > to->hour )
- return( 1 );
-
- if( year == to->year &&
- mon == to->mon &&
- day == to->day &&
- hour == to->hour &&
- min > to->min )
- return( 1 );
-
- if( year == to->year &&
- mon == to->mon &&
- day == to->day &&
- hour == to->hour &&
- min == to->min &&
- sec > to->sec )
- return( 1 );
-
- return( 0 );
-}
-#else /* POLARSSL_HAVE_TIME */
-int x509parse_time_expired( const x509_time *to )
-{
- ((void) to);
- return( 0 );
-}
-#endif /* POLARSSL_HAVE_TIME */
-
-/*
- * Return 1 if the certificate is revoked, or 0 otherwise.
- */
-int x509parse_revoked( const x509_cert *crt, const x509_crl *crl )
-{
- const x509_crl_entry *cur = &crl->entry;
-
- while( cur != NULL && cur->serial.len != 0 )
- {
- if( crt->serial.len == cur->serial.len &&
- memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 )
- {
- if( x509parse_time_expired( &cur->revocation_date ) )
- return( 1 );
- }
-
- cur = cur->next;
- }
-
- return( 0 );
-}
-
-/*
- * Check that the given certificate is valid accoring to the CRL.
- */
-static int x509parse_verifycrl(x509_cert *crt, x509_cert *ca,
- x509_crl *crl_list)
-{
- int flags = 0;
- unsigned char hash[POLARSSL_MD_MAX_SIZE];
- const md_info_t *md_info;
-
- if( ca == NULL )
- return( flags );
-
- /*
- * TODO: What happens if no CRL is present?
- * Suggestion: Revocation state should be unknown if no CRL is present.
- * For backwards compatibility this is not yet implemented.
- */
-
- while( crl_list != NULL )
- {
- if( crl_list->version == 0 ||
- crl_list->issuer_raw.len != ca->subject_raw.len ||
- memcmp( crl_list->issuer_raw.p, ca->subject_raw.p,
- crl_list->issuer_raw.len ) != 0 )
- {
- crl_list = crl_list->next;
- continue;
- }
-
- /*
- * Check if CRL is correctly signed by the trusted CA
- */
- md_info = md_info_from_type( crl_list->sig_md );
- if( md_info == NULL )
- {
- /*
- * Cannot check 'unknown' hash
- */
- flags |= BADCRL_NOT_TRUSTED;
- break;
- }
-
- md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash );
-
- if( pk_can_do( &ca->pk, crl_list->sig_pk ) == 0 ||
- pk_verify( &ca->pk, crl_list->sig_md, hash, md_info->size,
- crl_list->sig.p, crl_list->sig.len ) != 0 )
- {
- flags |= BADCRL_NOT_TRUSTED;
- break;
- }
-
- /*
- * Check for validity of CRL (Do not drop out)
- */
- if( x509parse_time_expired( &crl_list->next_update ) )
- flags |= BADCRL_EXPIRED;
-
- /*
- * Check if certificate is revoked
- */
- if( x509parse_revoked(crt, crl_list) )
- {
- flags |= BADCERT_REVOKED;
- break;
- }
-
- crl_list = crl_list->next;
- }
- return flags;
-}
-
-// Equal == 0, inequal == 1
-static int x509_name_cmp( const void *s1, const void *s2, size_t len )
-{
- size_t i;
- unsigned char diff;
- const unsigned char *n1 = s1, *n2 = s2;
-
- for( i = 0; i < len; i++ )
- {
- diff = n1[i] ^ n2[i];
-
- if( ( n1[i] >= 'a' || n1[i] <= 'z' ) && ( diff == 0 || diff == 32 ) )
- continue;
-
- if( ( n1[i] >= 'A' || n1[i] <= 'Z' ) && ( diff == 0 || diff == 32 ) )
- continue;
-
- return( 1 );
- }
-
- return( 0 );
-}
-
-static int x509_wildcard_verify( const char *cn, x509_buf *name )
-{
- size_t i;
- size_t cn_idx = 0;
-
- if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' )
- return( 0 );
-
- for( i = 0; i < strlen( cn ); ++i )
- {
- if( cn[i] == '.' )
- {
- cn_idx = i;
- break;
- }
- }
-
- if( cn_idx == 0 )
- return( 0 );
-
- if( strlen( cn ) - cn_idx == name->len - 1 &&
- x509_name_cmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 )
- {
- return( 1 );
- }
-
- return( 0 );
-}
-
-static int x509parse_verify_top(
- x509_cert *child, x509_cert *trust_ca,
- x509_crl *ca_crl, int path_cnt, int *flags,
- int (*f_vrfy)(void *, x509_cert *, int, int *),
- void *p_vrfy )
-{
- int ret;
- int ca_flags = 0, check_path_cnt = path_cnt + 1;
- unsigned char hash[POLARSSL_MD_MAX_SIZE];
- const md_info_t *md_info;
-
- if( x509parse_time_expired( &child->valid_to ) )
- *flags |= BADCERT_EXPIRED;
-
- /*
- * Child is the top of the chain. Check against the trust_ca list.
- */
- *flags |= BADCERT_NOT_TRUSTED;
-
- md_info = md_info_from_type( child->sig_md );
- if( md_info == NULL )
- {
- /*
- * Cannot check 'unknown', no need to try any CA
- */
- trust_ca = NULL;
- }
- else
- md( md_info, child->tbs.p, child->tbs.len, hash );
-
- while( trust_ca != NULL )
- {
- if( trust_ca->version == 0 ||
- child->issuer_raw.len != trust_ca->subject_raw.len ||
- memcmp( child->issuer_raw.p, trust_ca->subject_raw.p,
- child->issuer_raw.len ) != 0 )
- {
- trust_ca = trust_ca->next;
- continue;
- }
-
- /*
- * Reduce path_len to check against if top of the chain is
- * the same as the trusted CA
- */
- if( child->subject_raw.len == trust_ca->subject_raw.len &&
- memcmp( child->subject_raw.p, trust_ca->subject_raw.p,
- child->issuer_raw.len ) == 0 )
- {
- check_path_cnt--;
- }
-
- if( trust_ca->max_pathlen > 0 &&
- trust_ca->max_pathlen < check_path_cnt )
- {
- trust_ca = trust_ca->next;
- continue;
- }
-
- if( pk_can_do( &trust_ca->pk, child->sig_pk ) == 0 ||
- pk_verify( &trust_ca->pk, child->sig_md, hash, md_info->size,
- child->sig.p, child->sig.len ) != 0 )
- {
- trust_ca = trust_ca->next;
- continue;
- }
-
- /*
- * Top of chain is signed by a trusted CA
- */
- *flags &= ~BADCERT_NOT_TRUSTED;
- break;
- }
-
- /*
- * If top of chain is not the same as the trusted CA send a verify request
- * to the callback for any issues with validity and CRL presence for the
- * trusted CA certificate.
- */
- if( trust_ca != NULL &&
- ( child->subject_raw.len != trust_ca->subject_raw.len ||
- memcmp( child->subject_raw.p, trust_ca->subject_raw.p,
- child->issuer_raw.len ) != 0 ) )
- {
- /* Check trusted CA's CRL for the chain's top crt */
- *flags |= x509parse_verifycrl( child, trust_ca, ca_crl );
-
- if( x509parse_time_expired( &trust_ca->valid_to ) )
- ca_flags |= BADCERT_EXPIRED;
-
- if( NULL != f_vrfy )
- {
- if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1, &ca_flags ) ) != 0 )
- return( ret );
- }
- }
-
- /* Call callback on top cert */
- if( NULL != f_vrfy )
- {
- if( ( ret = f_vrfy(p_vrfy, child, path_cnt, flags ) ) != 0 )
- return( ret );
- }
-
- *flags |= ca_flags;
-
- return( 0 );
-}
-
-static int x509parse_verify_child(
- x509_cert *child, x509_cert *parent, x509_cert *trust_ca,
- x509_crl *ca_crl, int path_cnt, int *flags,
- int (*f_vrfy)(void *, x509_cert *, int, int *),
- void *p_vrfy )
-{
- int ret;
- int parent_flags = 0;
- unsigned char hash[POLARSSL_MD_MAX_SIZE];
- x509_cert *grandparent;
- const md_info_t *md_info;
-
- if( x509parse_time_expired( &child->valid_to ) )
- *flags |= BADCERT_EXPIRED;
-
- md_info = md_info_from_type( child->sig_md );
- if( md_info == NULL )
- {
- /*
- * Cannot check 'unknown' hash
- */
- *flags |= BADCERT_NOT_TRUSTED;
- }
- else
- {
- md( md_info, child->tbs.p, child->tbs.len, hash );
-
- if( pk_can_do( &parent->pk, child->sig_pk ) == 0 ||
- pk_verify( &parent->pk, child->sig_md, hash, md_info->size,
- child->sig.p, child->sig.len ) != 0 )
- {
- *flags |= BADCERT_NOT_TRUSTED;
- }
- }
-
- /* Check trusted CA's CRL for the given crt */
- *flags |= x509parse_verifycrl(child, parent, ca_crl);
-
- grandparent = parent->next;
-
- while( grandparent != NULL )
- {
- if( grandparent->version == 0 ||
- grandparent->ca_istrue == 0 ||
- parent->issuer_raw.len != grandparent->subject_raw.len ||
- memcmp( parent->issuer_raw.p, grandparent->subject_raw.p,
- parent->issuer_raw.len ) != 0 )
- {
- grandparent = grandparent->next;
- continue;
- }
- break;
- }
-
- if( grandparent != NULL )
- {
- /*
- * Part of the chain
- */
- ret = x509parse_verify_child( parent, grandparent, trust_ca, ca_crl, path_cnt + 1, &parent_flags, f_vrfy, p_vrfy );
- if( ret != 0 )
- return( ret );
- }
- else
- {
- ret = x509parse_verify_top( parent, trust_ca, ca_crl, path_cnt + 1, &parent_flags, f_vrfy, p_vrfy );
- if( ret != 0 )
- return( ret );
- }
-
- /* child is verified to be a child of the parent, call verify callback */
- if( NULL != f_vrfy )
- if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 )
- return( ret );
-
- *flags |= parent_flags;
-
- return( 0 );
-}
-
-/*
- * Verify the certificate validity
- */
-int x509parse_verify( x509_cert *crt,
- x509_cert *trust_ca,
- x509_crl *ca_crl,
- const char *cn, int *flags,
- int (*f_vrfy)(void *, x509_cert *, int, int *),
- void *p_vrfy )
-{
- size_t cn_len;
- int ret;
- int pathlen = 0;
- x509_cert *parent;
- x509_name *name;
- x509_sequence *cur = NULL;
-
- *flags = 0;
-
- if( cn != NULL )
- {
- name = &crt->subject;
- cn_len = strlen( cn );
-
- if( crt->ext_types & EXT_SUBJECT_ALT_NAME )
- {
- cur = &crt->subject_alt_names;
-
- while( cur != NULL )
- {
- if( cur->buf.len == cn_len &&
- x509_name_cmp( cn, cur->buf.p, cn_len ) == 0 )
- break;
-
- if( cur->buf.len > 2 &&
- memcmp( cur->buf.p, "*.", 2 ) == 0 &&
- x509_wildcard_verify( cn, &cur->buf ) )
- break;
-
- cur = cur->next;
- }
-
- if( cur == NULL )
- *flags |= BADCERT_CN_MISMATCH;
- }
- else
- {
- while( name != NULL )
- {
- if( OID_CMP( OID_AT_CN, &name->oid ) )
- {
- if( name->val.len == cn_len &&
- x509_name_cmp( name->val.p, cn, cn_len ) == 0 )
- break;
-
- if( name->val.len > 2 &&
- memcmp( name->val.p, "*.", 2 ) == 0 &&
- x509_wildcard_verify( cn, &name->val ) )
- break;
- }
-
- name = name->next;
- }
-
- if( name == NULL )
- *flags |= BADCERT_CN_MISMATCH;
- }
- }
-
- /*
- * Iterate upwards in the given cert chain, to find our crt parent.
- * Ignore any upper cert with CA != TRUE.
- */
- parent = crt->next;
-
- while( parent != NULL && parent->version != 0 )
- {
- if( parent->ca_istrue == 0 ||
- crt->issuer_raw.len != parent->subject_raw.len ||
- memcmp( crt->issuer_raw.p, parent->subject_raw.p,
- crt->issuer_raw.len ) != 0 )
- {
- parent = parent->next;
- continue;
- }
- break;
- }
-
- if( parent != NULL )
- {
- /*
- * Part of the chain
- */
- ret = x509parse_verify_child( crt, parent, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy );
- if( ret != 0 )
- return( ret );
- }
- else
- {
- ret = x509parse_verify_top( crt, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy );
- if( ret != 0 )
- return( ret );
- }
-
- if( *flags != 0 )
- return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED );
-
- return( 0 );
-}
-
-/*
- * Unallocate all certificate data
- */
-void x509_free( x509_cert *crt )
-{
- x509_cert *cert_cur = crt;
- x509_cert *cert_prv;
- x509_name *name_cur;
- x509_name *name_prv;
- x509_sequence *seq_cur;
- x509_sequence *seq_prv;
-
- if( crt == NULL )
- return;
-
- do
- {
- pk_free( &cert_cur->pk );
-
- name_cur = cert_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 );
- }
-
- name_cur = cert_cur->subject.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 );
- }
-
- seq_cur = cert_cur->ext_key_usage.next;
- while( seq_cur != NULL )
- {
- seq_prv = seq_cur;
- seq_cur = seq_cur->next;
- memset( seq_prv, 0, sizeof( x509_sequence ) );
- polarssl_free( seq_prv );
- }
-
- seq_cur = cert_cur->subject_alt_names.next;
- while( seq_cur != NULL )
- {
- seq_prv = seq_cur;
- seq_cur = seq_cur->next;
- memset( seq_prv, 0, sizeof( x509_sequence ) );
- polarssl_free( seq_prv );
- }
-
- if( cert_cur->raw.p != NULL )
- {
- memset( cert_cur->raw.p, 0, cert_cur->raw.len );
- polarssl_free( cert_cur->raw.p );
- }
-
- cert_cur = cert_cur->next;
- }
- while( cert_cur != NULL );
-
- cert_cur = crt;
- do
- {
- cert_prv = cert_cur;
- cert_cur = cert_cur->next;
-
- memset( cert_prv, 0, sizeof( x509_cert ) );
- if( cert_prv != crt )
- polarssl_free( cert_prv );
- }
- while( cert_cur != NULL );
-}
-
-/*
- * 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 );
-}
-
-/*
- * Unallocate all CSR data
- */
-void x509_csr_free( x509_csr *csr )
-{
- x509_name *name_cur;
- x509_name *name_prv;
-
- if( csr == NULL )
- return;
-
- pk_free( &csr->pk );
-
- name_cur = csr->subject.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 );
- }
-
- if( csr->raw.p != NULL )
- {
- memset( csr->raw.p, 0, csr->raw.len );
- polarssl_free( csr->raw.p );
- }
-
- memset( csr, 0, sizeof( x509_csr ) );
-}
-
-#if defined(POLARSSL_SELF_TEST)
-
-#include "polarssl/certs.h"
-
-/*
- * Checkup routine
- */
-int x509_self_test( int verbose )
-{
-#if defined(POLARSSL_CERTS_C) && defined(POLARSSL_MD5_C)
- int ret;
- int flags;
- x509_cert cacert;
- x509_cert clicert;
- pk_context pkey;
-
- if( verbose != 0 )
- printf( " X.509 certificate load: " );
-
- memset( &clicert, 0, sizeof( x509_cert ) );
-
- ret = x509parse_crt( &clicert, (const unsigned char *) test_cli_crt,
- strlen( test_cli_crt ) );
- if( ret != 0 )
- {
- if( verbose != 0 )
- printf( "failed\n" );
-
- return( ret );
- }
-
- memset( &cacert, 0, sizeof( x509_cert ) );
-
- ret = x509parse_crt( &cacert, (const unsigned char *) test_ca_crt,
- strlen( test_ca_crt ) );
- if( ret != 0 )
- {
- if( verbose != 0 )
- printf( "failed\n" );
-
- return( ret );
- }
-
-#if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \
- defined(POLARSSL_DES_C) && defined(POLARSSL_AES_C)
- if( verbose != 0 )
- printf( "passed\n X.509 private key load: " );
-
- pk_init( &pkey );
-
- if( ( ret = pk_parse_key( &pkey,
- (const unsigned char *) test_ca_key,
- strlen( test_ca_key ),
- (const unsigned char *) test_ca_pwd,
- strlen( test_ca_pwd ) ) ) != 0 )
- {
- if( verbose != 0 )
- printf( "failed\n" );
-
- return( ret );
- }
-#endif
-
- if( verbose != 0 )
- printf( "passed\n X.509 signature verify: ");
-
- ret = x509parse_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL );
- if( ret != 0 )
- {
- if( verbose != 0 )
- printf( "failed\n" );
-
- printf("ret = %d, &flags = %04x\n", ret, flags);
-
- return( ret );
- }
-
- if( verbose != 0 )
- printf( "passed\n\n");
-
- x509_free( &cacert );
- x509_free( &clicert );
- pk_free( &pkey );
-
- return( 0 );
-#else
- ((void) verbose);
- return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
-#endif
-}
-
-#endif
-
-#endif
diff --git a/library/x509write.c b/library/x509write.c
deleted file mode 100644
index f020b9e..0000000
--- a/library/x509write.c
+++ /dev/null
@@ -1,869 +0,0 @@
-/*
- * X509 buffer writing functionality
- *
- * 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.
- */
-
-/*
- * References:
- * - certificates: RFC 5280, updated by RFC 6818
- * - CSRs: PKCS#10 v1.7 aka RFC 2986
- * - attributes: PKCS#9 v2.0 aka RFC 2985
- */
-
-#include "polarssl/config.h"
-
-#if defined(POLARSSL_X509_WRITE_C)
-
-#include "polarssl/asn1write.h"
-#include "polarssl/x509write.h"
-#include "polarssl/x509.h"
-#include "polarssl/md.h"
-#include "polarssl/oid.h"
-
-#include "polarssl/sha1.h"
-
-#if defined(POLARSSL_PEM_WRITE_C)
-#include "polarssl/pem.h"
-#endif
-
-#if defined(POLARSSL_MEMORY_C)
-#include "polarssl/memory.h"
-#else
-#include <stdlib.h>
-#define polarssl_malloc malloc
-#define polarssl_free free
-#endif
-
-static int x509write_string_to_names( asn1_named_data **head, char *name )
-{
- int ret = 0;
- char *s = name, *c = s;
- char *end = s + strlen( s );
- char *oid = NULL;
- int in_tag = 1;
- asn1_named_data *cur;
-
- /* Clear existing chain if present */
- asn1_free_named_data_list( head );
-
- while( c <= end )
- {
- if( in_tag && *c == '=' )
- {
- if( memcmp( s, "CN", 2 ) == 0 && c - s == 2 )
- oid = OID_AT_CN;
- else if( memcmp( s, "C", 1 ) == 0 && c - s == 1 )
- oid = OID_AT_COUNTRY;
- else if( memcmp( s, "O", 1 ) == 0 && c - s == 1 )
- oid = OID_AT_ORGANIZATION;
- else if( memcmp( s, "L", 1 ) == 0 && c - s == 1 )
- oid = OID_AT_LOCALITY;
- else if( memcmp( s, "R", 1 ) == 0 && c - s == 1 )
- oid = OID_PKCS9_EMAIL;
- else if( memcmp( s, "OU", 2 ) == 0 && c - s == 2 )
- oid = OID_AT_ORG_UNIT;
- else if( memcmp( s, "ST", 2 ) == 0 && c - s == 2 )
- oid = OID_AT_STATE;
- else
- {
- ret = POLARSSL_ERR_X509WRITE_UNKNOWN_OID;
- goto exit;
- }
-
- s = c + 1;
- in_tag = 0;
- }
-
- if( !in_tag && ( *c == ',' || c == end ) )
- {
- if( ( cur = asn1_store_named_data( head, oid, strlen( oid ),
- (unsigned char *) s,
- c - s ) ) == NULL )
- {
- return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
- }
-
- while( c < end && *(c + 1) == ' ' )
- c++;
-
- s = c + 1;
- in_tag = 1;
- }
- c++;
- }
-
-exit:
-
- return( ret );
-}
-
-void x509write_csr_init( x509write_csr *ctx )
-{
- memset( ctx, 0, sizeof(x509write_csr) );
-}
-
-void x509write_csr_free( x509write_csr *ctx )
-{
- asn1_free_named_data_list( &ctx->subject );
- asn1_free_named_data_list( &ctx->extensions );
-
- memset( ctx, 0, sizeof(x509write_csr) );
-}
-
-void x509write_csr_set_md_alg( x509write_csr *ctx, md_type_t md_alg )
-{
- ctx->md_alg = md_alg;
-}
-
-void x509write_csr_set_key( x509write_csr *ctx, pk_context *key )
-{
- ctx->key = key;
-}
-
-int x509write_csr_set_subject_name( x509write_csr *ctx, char *subject_name )
-{
- return x509write_string_to_names( &ctx->subject, subject_name );
-}
-
-/* The first byte of the value in the asn1_named_data structure is reserved
- * to store the critical boolean for us
- */
-static int x509_set_extension( asn1_named_data **head,
- const char *oid, size_t oid_len,
- int critical,
- const unsigned char *val, size_t val_len )
-{
- asn1_named_data *cur;
-
- if( ( cur = asn1_store_named_data( head, oid, oid_len,
- NULL, val_len + 1 ) ) == NULL )
- {
- return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
- }
-
- cur->val.p[0] = critical;
- memcpy( cur->val.p + 1, val, val_len );
-
- return( 0 );
-}
-
-int x509write_csr_set_extension( x509write_csr *ctx,
- const char *oid, size_t oid_len,
- const unsigned char *val, size_t val_len )
-{
- return x509_set_extension( &ctx->extensions, oid, oid_len,
- 0, val, val_len );
-}
-
-int x509write_csr_set_key_usage( x509write_csr *ctx, unsigned char key_usage )
-{
- unsigned char buf[4];
- unsigned char *c;
- int ret;
-
- c = buf + 4;
-
- if( ( ret = asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
- return( ret );
-
- ret = x509write_csr_set_extension( ctx, OID_KEY_USAGE,
- OID_SIZE( OID_KEY_USAGE ),
- buf, 4 );
- if( ret != 0 )
- return( ret );
-
- return( 0 );
-}
-
-int x509write_csr_set_ns_cert_type( x509write_csr *ctx,
- unsigned char ns_cert_type )
-{
- unsigned char buf[4];
- unsigned char *c;
- int ret;
-
- c = buf + 4;
-
- if( ( ret = asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
- return( ret );
-
- ret = x509write_csr_set_extension( ctx, OID_NS_CERT_TYPE,
- OID_SIZE( OID_NS_CERT_TYPE ),
- buf, 4 );
- if( ret != 0 )
- return( ret );
-
- return( 0 );
-}
-
-void x509write_crt_init( x509write_cert *ctx )
-{
- memset( ctx, 0, sizeof(x509write_cert) );
-
- mpi_init( &ctx->serial );
- ctx->version = X509_CRT_VERSION_3;
-}
-
-void x509write_crt_free( x509write_cert *ctx )
-{
- mpi_free( &ctx->serial );
-
- asn1_free_named_data_list( &ctx->subject );
- asn1_free_named_data_list( &ctx->issuer );
- asn1_free_named_data_list( &ctx->extensions );
-
- memset( ctx, 0, sizeof(x509write_csr) );
-}
-
-void x509write_crt_set_md_alg( x509write_cert *ctx, md_type_t md_alg )
-{
- ctx->md_alg = md_alg;
-}
-
-void x509write_crt_set_subject_key( x509write_cert *ctx, pk_context *key )
-{
- ctx->subject_key = key;
-}
-
-void x509write_crt_set_issuer_key( x509write_cert *ctx, pk_context *key )
-{
- ctx->issuer_key = key;
-}
-
-int x509write_crt_set_subject_name( x509write_cert *ctx, char *subject_name )
-{
- return x509write_string_to_names( &ctx->subject, subject_name );
-}
-
-int x509write_crt_set_issuer_name( x509write_cert *ctx, char *issuer_name )
-{
- return x509write_string_to_names( &ctx->issuer, issuer_name );
-}
-
-int x509write_crt_set_serial( x509write_cert *ctx, const mpi *serial )
-{
- int ret;
-
- if( ( ret = mpi_copy( &ctx->serial, serial ) ) != 0 )
- return( ret );
-
- return( 0 );
-}
-
-int x509write_crt_set_validity( x509write_cert *ctx, char *not_before,
- char *not_after )
-{
- if( strlen(not_before) != X509_RFC5280_UTC_TIME_LEN - 1 ||
- strlen(not_after) != X509_RFC5280_UTC_TIME_LEN - 1 )
- {
- return( POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA );
- }
- strncpy( ctx->not_before, not_before, X509_RFC5280_UTC_TIME_LEN );
- strncpy( ctx->not_after , not_after , X509_RFC5280_UTC_TIME_LEN );
- ctx->not_before[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
- ctx->not_after[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
-
- return( 0 );
-}
-
-int x509write_crt_set_extension( x509write_cert *ctx,
- const char *oid, size_t oid_len,
- int critical,
- const unsigned char *val, size_t val_len )
-{
- return x509_set_extension( &ctx->extensions, oid, oid_len,
- critical, val, val_len );
-}
-
-int x509write_crt_set_basic_constraints( x509write_cert *ctx,
- int is_ca, int max_pathlen )
-{
- int ret;
- unsigned char buf[9];
- unsigned char *c = buf + sizeof(buf);
- size_t len = 0;
-
- memset( buf, 0, sizeof(buf) );
-
- if( is_ca && max_pathlen > 127 )
- return( POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA );
-
- if( is_ca )
- {
- if( max_pathlen >= 0 )
- {
- ASN1_CHK_ADD( len, asn1_write_int( &c, buf, max_pathlen ) );
- }
- ASN1_CHK_ADD( len, asn1_write_bool( &c, buf, 1 ) );
- }
-
- ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- return x509write_crt_set_extension( ctx, OID_BASIC_CONSTRAINTS,
- OID_SIZE( OID_BASIC_CONSTRAINTS ),
- 0, buf + sizeof(buf) - len, len );
-}
-
-int x509write_crt_set_subject_key_identifier( x509write_cert *ctx )
-{
- int ret;
- unsigned char buf[POLARSSL_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
- unsigned char *c = buf + sizeof(buf);
- size_t len = 0;
-
- memset( buf, 0, sizeof(buf));
- ASN1_CHK_ADD( len, pk_write_pubkey( &c, buf, ctx->subject_key ) );
-
- sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 );
- c = buf + sizeof(buf) - 20;
- len = 20;
-
- ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_OCTET_STRING ) );
-
- return x509write_crt_set_extension( ctx, OID_SUBJECT_KEY_IDENTIFIER,
- OID_SIZE( OID_SUBJECT_KEY_IDENTIFIER ),
- 0, buf + sizeof(buf) - len, len );
-}
-
-int x509write_crt_set_authority_key_identifier( x509write_cert *ctx )
-{
- int ret;
- unsigned char buf[POLARSSL_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
- unsigned char *c = buf + sizeof(buf);
- size_t len = 0;
-
- memset( buf, 0, sizeof(buf));
- ASN1_CHK_ADD( len, pk_write_pubkey( &c, buf, ctx->issuer_key ) );
-
- sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 );
- c = buf + sizeof(buf) - 20;
- len = 20;
-
- ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONTEXT_SPECIFIC | 0 ) );
-
- ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- return x509write_crt_set_extension( ctx, OID_AUTHORITY_KEY_IDENTIFIER,
- OID_SIZE( OID_AUTHORITY_KEY_IDENTIFIER ),
- 0, buf + sizeof(buf) - len, len );
-}
-
-int x509write_crt_set_key_usage( x509write_cert *ctx, unsigned char key_usage )
-{
- unsigned char buf[4];
- unsigned char *c;
- int ret;
-
- c = buf + 4;
-
- if( ( ret = asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
- return( ret );
-
- ret = x509write_crt_set_extension( ctx, OID_KEY_USAGE,
- OID_SIZE( OID_KEY_USAGE ),
- 1, buf, 4 );
- if( ret != 0 )
- return( ret );
-
- return( 0 );
-}
-
-int x509write_crt_set_ns_cert_type( x509write_cert *ctx,
- unsigned char ns_cert_type )
-{
- unsigned char buf[4];
- unsigned char *c;
- int ret;
-
- c = buf + 4;
-
- if( ( ret = asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
- return( ret );
-
- ret = x509write_crt_set_extension( ctx, OID_NS_CERT_TYPE,
- OID_SIZE( OID_NS_CERT_TYPE ),
- 0, buf, 4 );
- if( ret != 0 )
- return( ret );
-
- return( 0 );
-}
-
-/*
- * RelativeDistinguishedName ::=
- * SET OF AttributeTypeAndValue
- *
- * AttributeTypeAndValue ::= SEQUENCE {
- * type AttributeType,
- * value AttributeValue }
- *
- * AttributeType ::= OBJECT IDENTIFIER
- *
- * AttributeValue ::= ANY DEFINED BY AttributeType
- */
-static int x509_write_name( unsigned char **p, unsigned char *start,
- const char *oid, size_t oid_len,
- const unsigned char *name, size_t name_len )
-{
- int ret;
- size_t len = 0;
-
- // Write PrintableString for all except OID_PKCS9_EMAIL
- //
- if( OID_SIZE( OID_PKCS9_EMAIL ) == oid_len &&
- memcmp( oid, OID_PKCS9_EMAIL, oid_len ) == 0 )
- {
- ASN1_CHK_ADD( len, asn1_write_ia5_string( p, start,
- (const char *) name,
- name_len ) );
- }
- else
- {
- ASN1_CHK_ADD( len, asn1_write_printable_string( p, start,
- (const char *) name,
- name_len ) );
- }
-
- // Write OID
- //
- ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_len ) );
-
- ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SET ) );
-
- return( len );
-}
-
-static int x509_write_names( unsigned char **p, unsigned char *start,
- asn1_named_data *first )
-{
- int ret;
- size_t len = 0;
- asn1_named_data *cur = first;
-
- while( cur != NULL )
- {
- ASN1_CHK_ADD( len, x509_write_name( p, start, (char *) cur->oid.p,
- cur->oid.len,
- cur->val.p, cur->val.len ) );
- cur = cur->next;
- }
-
- ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- return( len );
-}
-
-static int x509_write_sig( unsigned char **p, unsigned char *start,
- const char *oid, size_t oid_len,
- unsigned char *sig, size_t size )
-{
- int ret;
- size_t len = 0;
-
- if( *p - start < (int) size + 1 )
- return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
-
- len = size;
- (*p) -= len;
- memcpy( *p, sig, len );
-
- *--(*p) = 0;
- len += 1;
-
- ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_BIT_STRING ) );
-
- // Write OID
- //
- ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( p, start, oid,
- oid_len, 0 ) );
-
- return( len );
-}
-
-static int x509_write_time( unsigned char **p, unsigned char *start,
- const char *time, size_t size )
-{
- int ret;
- size_t len = 0;
-
- /*
- * write ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
- */
- if( time[0] == '2' && time[1] == '0' && time [2] < '5' )
- {
- ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
- (const unsigned char *) time + 2,
- size - 2 ) );
- ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_UTC_TIME ) );
- }
- else
- {
- ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
- (const unsigned char *) time,
- size ) );
- ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_GENERALIZED_TIME ) );
- }
-
- return( len );
-}
-
-static int x509_write_extension( unsigned char **p, unsigned char *start,
- asn1_named_data *ext )
-{
- int ret;
- size_t len = 0;
-
- ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, ext->val.p + 1,
- ext->val.len - 1 ) );
- ASN1_CHK_ADD( len, asn1_write_len( p, start, ext->val.len - 1 ) );
- ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_OCTET_STRING ) );
-
- if( ext->val.p[0] != 0 )
- {
- ASN1_CHK_ADD( len, asn1_write_bool( p, start, 1 ) );
- }
-
- ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, ext->oid.p,
- ext->oid.len ) );
- ASN1_CHK_ADD( len, asn1_write_len( p, start, ext->oid.len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_OID ) );
-
- ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- return( len );
-}
-
-/*
- * Extension ::= SEQUENCE {
- * extnID OBJECT IDENTIFIER,
- * critical BOOLEAN DEFAULT FALSE,
- * extnValue OCTET STRING
- * -- contains the DER encoding of an ASN.1 value
- * -- corresponding to the extension type identified
- * -- by extnID
- * }
- */
-static int x509_write_extensions( unsigned char **p, unsigned char *start,
- asn1_named_data *first )
-{
- int ret;
- size_t len = 0;
- asn1_named_data *cur_ext = first;
-
- while( cur_ext != NULL )
- {
- ASN1_CHK_ADD( len, x509_write_extension( p, start, cur_ext ) );
- cur_ext = cur_ext->next;
- }
-
- return( len );
-}
-
-int x509write_csr_der( x509write_csr *ctx, unsigned char *buf, size_t size,
- int (*f_rng)(void *, unsigned char *, size_t),
- void *p_rng )
-{
- int ret;
- const char *sig_oid;
- size_t sig_oid_len = 0;
- unsigned char *c, *c2;
- unsigned char hash[64];
- unsigned char sig[POLARSSL_MPI_MAX_SIZE];
- unsigned char tmp_buf[2048];
- size_t pub_len = 0, sig_and_oid_len = 0, sig_len;
- size_t len = 0;
- pk_type_t pk_alg;
-
- /*
- * Prepare data to be signed in tmp_buf
- */
- c = tmp_buf + sizeof( tmp_buf );
-
- ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
-
- if( len )
- {
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SET ) );
-
- ASN1_CHK_ADD( len, asn1_write_oid( &c, tmp_buf, OID_PKCS9_CSR_EXT_REQ,
- OID_SIZE( OID_PKCS9_CSR_EXT_REQ ) ) );
-
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
- }
-
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC ) );
-
- ASN1_CHK_ADD( pub_len, pk_write_pubkey_der( ctx->key,
- tmp_buf, c - tmp_buf ) );
- c -= pub_len;
- len += pub_len;
-
- /*
- * Subject ::= Name
- */
- ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) );
-
- /*
- * Version ::= INTEGER { v1(0), v2(1), v3(2) }
- */
- ASN1_CHK_ADD( len, asn1_write_int( &c, tmp_buf, 0 ) );
-
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- /*
- * Prepare signature
- */
- md( md_info_from_type( ctx->md_alg ), c, len, hash );
-
- pk_alg = pk_get_type( ctx->key );
- if( pk_alg == POLARSSL_PK_ECKEY )
- pk_alg = POLARSSL_PK_ECDSA;
-
- if( ( ret = pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len,
- f_rng, p_rng ) ) != 0 ||
- ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
- &sig_oid, &sig_oid_len ) ) != 0 )
- {
- return( ret );
- }
-
- /*
- * Write data to output buffer
- */
- c2 = buf + size;
- ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf,
- sig_oid, sig_oid_len, sig, sig_len ) );
-
- c2 -= len;
- memcpy( c2, c, len );
-
- len += sig_and_oid_len;
- ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- return( len );
-}
-
-int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size,
- int (*f_rng)(void *, unsigned char *, size_t),
- void *p_rng )
-{
- int ret;
- const char *sig_oid;
- size_t sig_oid_len = 0;
- unsigned char *c, *c2;
- unsigned char hash[64];
- unsigned char sig[POLARSSL_MPI_MAX_SIZE];
- unsigned char tmp_buf[2048];
- size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
- size_t len = 0;
- pk_type_t pk_alg;
-
- /*
- * Prepare data to be signed in tmp_buf
- */
- c = tmp_buf + sizeof( tmp_buf );
-
- /* Signature algorithm needed in TBS, and later for actual signature */
- pk_alg = pk_get_type( ctx->issuer_key );
- if( pk_alg == POLARSSL_PK_ECKEY )
- pk_alg = POLARSSL_PK_ECDSA;
-
- if( ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
- &sig_oid, &sig_oid_len ) ) != 0 )
- {
- return( ret );
- }
-
- /*
- * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
- */
- ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3 ) );
-
- /*
- * SubjectPublicKeyInfo
- */
- ASN1_CHK_ADD( pub_len, pk_write_pubkey_der( ctx->subject_key,
- tmp_buf, c - tmp_buf ) );
- c -= pub_len;
- len += pub_len;
-
- /*
- * Subject ::= Name
- */
- ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) );
-
- /*
- * Validity ::= SEQUENCE {
- * notBefore Time,
- * notAfter Time }
- */
- sub_len = 0;
-
- ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after,
- X509_RFC5280_UTC_TIME_LEN ) );
-
- ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before,
- X509_RFC5280_UTC_TIME_LEN ) );
-
- len += sub_len;
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- /*
- * Issuer ::= Name
- */
- ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->issuer ) );
-
- /*
- * Signature ::= AlgorithmIdentifier
- */
- ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, tmp_buf,
- sig_oid, strlen( sig_oid ), 0 ) );
-
- /*
- * Serial ::= INTEGER
- */
- ASN1_CHK_ADD( len, asn1_write_mpi( &c, tmp_buf, &ctx->serial ) );
-
- /*
- * Version ::= INTEGER { v1(0), v2(1), v3(2) }
- */
- sub_len = 0;
- ASN1_CHK_ADD( sub_len, asn1_write_int( &c, tmp_buf, ctx->version ) );
- len += sub_len;
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) );
-
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- /*
- * Make signature
- */
- md( md_info_from_type( ctx->md_alg ), c, len, hash );
-
- if( ( ret = pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len,
- f_rng, p_rng ) ) != 0 )
- {
- return( ret );
- }
-
- /*
- * Write data to output buffer
- */
- c2 = buf + size;
- ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf,
- sig_oid, sig_oid_len, sig, sig_len ) );
-
- c2 -= len;
- memcpy( c2, c, len );
-
- len += sig_and_oid_len;
- ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) );
- ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
- return( len );
-}
-
-#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n"
-#define PEM_END_CRT "-----END CERTIFICATE-----\n"
-
-#define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n"
-#define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n"
-
-#if defined(POLARSSL_PEM_WRITE_C)
-int x509write_crt_pem( x509write_cert *crt, unsigned char *buf, size_t size,
- int (*f_rng)(void *, unsigned char *, size_t),
- void *p_rng )
-{
- int ret;
- unsigned char output_buf[4096];
- size_t olen = 0;
-
- if( ( ret = x509write_crt_der( crt, output_buf, sizeof(output_buf),
- f_rng, p_rng ) ) < 0 )
- {
- return( ret );
- }
-
- if( ( ret = pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT,
- output_buf + sizeof(output_buf) - ret,
- ret, buf, size, &olen ) ) != 0 )
- {
- return( ret );
- }
-
- return( 0 );
-}
-
-int x509write_csr_pem( x509write_csr *ctx, unsigned char *buf, size_t size,
- int (*f_rng)(void *, unsigned char *, size_t),
- void *p_rng )
-{
- int ret;
- unsigned char output_buf[4096];
- size_t olen = 0;
-
- if( ( ret = x509write_csr_der( ctx, output_buf, sizeof(output_buf),
- f_rng, p_rng ) ) < 0 )
- {
- return( ret );
- }
-
- if( ( ret = pem_write_buffer( PEM_BEGIN_CSR, PEM_END_CSR,
- output_buf + sizeof(output_buf) - ret,
- ret, buf, size, &olen ) ) != 0 )
- {
- return( ret );
- }
-
- return( 0 );
-}
-#endif /* POLARSSL_BASE64_C */
-
-#endif