From e5eae76bf015d1ec613adfdae3fceb7e86fc48a5 Mon Sep 17 00:00:00 2001 From: Paul Bakker Date: Mon, 26 Aug 2013 12:05:14 +0200 Subject: [PATCH] Generalized the x509write_csr_set_key_usage() function and key_usage storage --- include/polarssl/asn1.h | 35 ++++++++++++- include/polarssl/x509.h | 18 +++---- include/polarssl/x509write.h | 6 ++- library/asn1parse.c | 28 ++++++++++ library/x509write.c | 99 ++++++++++++++++++++++++++++-------- 5 files changed, 149 insertions(+), 37 deletions(-) diff --git a/include/polarssl/asn1.h b/include/polarssl/asn1.h index 195ebcb84..ec8cbfafc 100644 --- a/include/polarssl/asn1.h +++ b/include/polarssl/asn1.h @@ -93,7 +93,10 @@ /** Returns the size of the binary string, without the trailing \\0 */ #define OID_SIZE(x) (sizeof(x) - 1) -/** Compares two asn1_buf structures for the same OID */ +/** Compares two asn1_buf structures for the same OID. Only works for + * 'defined' oid_str values (OID_HMAC_SHA1), you cannot use a 'unsigned + * char *oid' here! + */ #define OID_CMP(oid_str, oid_buf) \ ( ( OID_SIZE(oid_str) == (oid_buf)->len ) && \ memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) == 0 ) @@ -139,6 +142,17 @@ typedef struct _asn1_sequence } asn1_sequence; +/** + * Container for a sequence or list of 'named' ASN.1 data items + */ +typedef struct _asn1_named_data +{ + asn1_buf oid; /**< The object identifier. */ + asn1_buf val; /**< The named value. */ + struct _asn1_named_data *next; /**< The next entry in the sequence. */ +} +asn1_named_data; + /** * Get the length of an ASN.1 element. * Updates the pointer to immediately behind the length. @@ -286,6 +300,25 @@ int asn1_get_alg_null( unsigned char **p, const unsigned char *end, asn1_buf *alg ); +/** + * Find a specific named_data entry in a sequence or list based on the OID. + * + * \param list The list to seek through + * \param oid The OID to look for + * \param len Size of the OID + * + * \return NULL if not found, or a pointer to the existing entry. + */ +asn1_named_data *asn1_find_named_data( asn1_named_data *list, + const char *oid, size_t len ); + +/** + * Free a asn1_named_data entry + * + * \param entry The named data entry to free + */ +void asn1_free_named_data( asn1_named_data *entry ); + #ifdef __cplusplus } #endif diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h index 45c60ad42..dc15bb648 100644 --- a/include/polarssl/x509.h +++ b/include/polarssl/x509.h @@ -146,7 +146,7 @@ extern "C" { #endif -/** +/** * \addtogroup x509_module * \{ */ @@ -154,8 +154,8 @@ extern "C" { * \name Structures for parsing X.509 certificates and CRLs * \{ */ - -/** + +/** * Type-length-value structure that allows for ASN1 using DER. */ typedef asn1_buf x509_buf; @@ -166,16 +166,10 @@ typedef asn1_buf x509_buf; typedef asn1_bitstring x509_bitstring; /** - * Container for ASN1 named information objects. + * Container for ASN1 named information objects. * It allows for Relative Distinguished Names (e.g. cn=polarssl,ou=code,etc.). */ -typedef struct _x509_name -{ - x509_buf oid; /**< The object identifier. */ - x509_buf val; /**< The named value. */ - struct _x509_name *next; /**< The next named information object. */ -} -x509_name; +typedef asn1_named_data x509_name; /** * Container for a sequence of ASN.1 items @@ -190,7 +184,7 @@ typedef struct _x509_time } x509_time; -/** +/** * Container for an X.509 certificate. The certificate may be chained. */ typedef struct _x509_cert diff --git a/include/polarssl/x509write.h b/include/polarssl/x509write.h index aa4d05352..671047429 100644 --- a/include/polarssl/x509write.h +++ b/include/polarssl/x509write.h @@ -80,7 +80,7 @@ typedef struct _x509_csr rsa_context *rsa; x509_req_name *subject; md_type_t md_alg; - unsigned char key_usage; + asn1_named_data *extensions; } x509_csr; @@ -131,8 +131,10 @@ void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg ); * * \param ctx CSR context to use * \param key_usage key usage bitstring to set + * + * \return 0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED */ -void x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage ); +int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage ); /** * \brief Free the contents of a CSR context diff --git a/library/asn1parse.c b/library/asn1parse.c index ff566c9ce..f6b271ec5 100644 --- a/library/asn1parse.c +++ b/library/asn1parse.c @@ -343,4 +343,32 @@ int asn1_get_alg_null( unsigned char **p, return( 0 ); } +void asn1_free_named_data( asn1_named_data *cur ) +{ + if( cur == NULL ) + return; + + polarssl_free( cur->oid.p ); + polarssl_free( cur->val.p ); + + memset( cur, 0, sizeof( asn1_named_data ) ); +} + +asn1_named_data *asn1_find_named_data( asn1_named_data *list, + const char *oid, size_t len ) +{ + while( list != NULL ) + { + if( list->oid.len == len && + memcmp( list->oid.p, oid, len ) == 0 ) + { + break; + } + + list = list->next; + } + + return( list ); +} + #endif diff --git a/library/x509write.c b/library/x509write.c index adeb55123..0ca7733b2 100644 --- a/library/x509write.c +++ b/library/x509write.c @@ -49,6 +49,7 @@ void x509write_csr_init( x509_csr *ctx ) void x509write_csr_free( x509_csr *ctx ) { x509_req_name *cur; + asn1_named_data *cur_ext; while( ( cur = ctx->subject ) != NULL ) { @@ -56,6 +57,13 @@ void x509write_csr_free( x509_csr *ctx ) polarssl_free( cur ); } + while( ( cur_ext = ctx->extensions ) != NULL ) + { + ctx->extensions = cur_ext->next; + asn1_free_named_data( cur_ext ); + polarssl_free( cur_ext ); + } + memset( ctx, 0, sizeof(x509_csr) ); } @@ -148,9 +156,49 @@ exit: return( ret ); } -void x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage ) +int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage ) { - ctx->key_usage = key_usage; + asn1_named_data *cur; + unsigned char *c; + int len; + + if( ( cur = asn1_find_named_data( ctx->extensions, OID_KEY_USAGE, + OID_SIZE( OID_KEY_USAGE ) ) ) == NULL ) + { + cur = polarssl_malloc( sizeof(asn1_named_data) ); + if( cur == NULL ) + return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); + + memset( cur, 0, sizeof(asn1_named_data) ); + + cur->oid.len = OID_SIZE( OID_KEY_USAGE ); + cur->oid.p = polarssl_malloc( cur->oid.len ); + if( cur->oid.p == NULL ) + { + free( cur ); + return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); + } + + cur->val.len = 4; + cur->val.p = polarssl_malloc( cur->val.len ); + if( cur->val.p == NULL ) + { + free( cur->oid.p ); + free( cur ); + return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); + } + + memcpy( cur->oid.p, OID_KEY_USAGE, OID_SIZE( OID_KEY_USAGE ) ); + + cur->next = ctx->extensions; + ctx->extensions = cur; + } + + c = cur->val.p + cur->val.len; + if( ( len = asn1_write_bitstring( &c, cur->val.p, &key_usage, 6 ) ) < 0 ) +exit(1); + + return( 0 ); } int x509write_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size ) @@ -306,43 +354,50 @@ int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size ) 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_len = 0, ext_len = 0; + size_t sub_len = 0, pub_len = 0, sig_len = 0; size_t len = 0; x509_req_name *cur = ctx->subject; + asn1_named_data *cur_ext = ctx->extensions; c = tmp_buf + 2048 - 1; - /* - * Extension ::= SEQUENCE { - * extnID OBJECT IDENTIFIER, - * extnValue OCTET STRING } - */ - if( ctx->key_usage ) + while( cur_ext != NULL ) { - ASN1_CHK_ADD( ext_len, asn1_write_bitstring( &c, tmp_buf, &ctx->key_usage, 6 ) ); - ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, ext_len ) ); + size_t ext_len = 0; + + ASN1_CHK_ADD( ext_len, asn1_write_raw_buffer( &c, tmp_buf, cur_ext->val.p, + cur_ext->val.len ) ); + ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, cur_ext->val.len ) ); ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_OCTET_STRING ) ); - ASN1_CHK_ADD( ext_len, asn1_write_oid( &c, tmp_buf, OID_KEY_USAGE ) ); + + ASN1_CHK_ADD( ext_len, asn1_write_raw_buffer( &c, tmp_buf, cur_ext->oid.p, + cur_ext->oid.len ) ); + ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, cur_ext->oid.len ) ); + ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_OID ) ); + ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, ext_len ) ); ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + cur_ext = cur_ext->next; + + len += ext_len; } - if( ext_len ) + if( len ) { - ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, ext_len ) ); - ASN1_CHK_ADD( ext_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_SEQUENCE ) ); - ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, ext_len ) ); - ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SET ) ); + 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( ext_len, asn1_write_oid( &c, tmp_buf, OID_PKCS9_CSR_EXT_REQ ) ); + ASN1_CHK_ADD( len, asn1_write_oid( &c, tmp_buf, OID_PKCS9_CSR_EXT_REQ ) ); - ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, ext_len ) ); - ASN1_CHK_ADD( ext_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_SEQUENCE ) ); } - len += ext_len; - ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, ext_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_CONTEXT_SPECIFIC ) ); ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &ctx->rsa->E ) );