CSR Parsing (without attributes / extensions) implemented
diff --git a/library/x509parse.c b/library/x509parse.c
index c175df4..2290b7b 100644
--- a/library/x509parse.c
+++ b/library/x509parse.c
@@ -132,6 +132,29 @@
}
/*
+ * 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,
@@ -1625,6 +1648,214 @@
}
/*
+ * 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_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_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
+ {
+ /*
+ * 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;
+ }
+#else
+ p = (unsigned char *) polarssl_malloc( len = buflen );
+
+ if( p == NULL )
+ return( POLARSSL_ERR_X509_MALLOC_FAILED );
+
+ memcpy( p, buf, buflen );
+
+ buflen = 0;
+#endif
+
+ 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 = x509_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 )
@@ -2073,6 +2304,26 @@
}
/*
+ * 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 )
@@ -3285,6 +3536,53 @@
}
/*
+ * 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)
@@ -3921,6 +4219,37 @@
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"