Generalized the x509write_csr_set_key_usage() function and key_usage
storage
diff --git a/include/polarssl/asn1.h b/include/polarssl/asn1.h
index 195ebcb..ec8cbfa 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 )
@@ -140,6 +143,17 @@
 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 @@
                        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 45c60ad..dc15bb6 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 @@
  * \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_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 @@
 }
 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 aa4d053..6710474 100644
--- a/include/polarssl/x509write.h
+++ b/include/polarssl/x509write.h
@@ -80,7 +80,7 @@
     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 @@
  *
  * \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 ff566c9..f6b271e 100644
--- a/library/asn1parse.c
+++ b/library/asn1parse.c
@@ -343,4 +343,32 @@
     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 adeb551..0ca7733 100644
--- a/library/x509write.c
+++ b/library/x509write.c
@@ -49,6 +49,7 @@
 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 @@
         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 @@
     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 @@
     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 ) );