From fde42701861f55befe62e7382a5fccb199dea6c5 Mon Sep 17 00:00:00 2001
From: Paul Bakker <p.j.bakker@polarssl.org>
Date: Sun, 25 Aug 2013 14:47:27 +0200
Subject: [PATCH] Added support for writing key_usage extension

---
 include/polarssl/oid.h       |  5 +++++
 include/polarssl/x509write.h | 12 ++++++++++-
 library/x509write.c          | 39 ++++++++++++++++++++++++++++++++++--
 3 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/include/polarssl/oid.h b/include/polarssl/oid.h
index ebb5bad98..025a15f0a 100644
--- a/include/polarssl/oid.h
+++ b/include/polarssl/oid.h
@@ -227,6 +227,11 @@
 #define OID_PKCS5_PBE_SHA1_DES_CBC      OID_PKCS5 "\x0a" /**< pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10} */
 #define OID_PKCS5_PBE_SHA1_RC2_CBC      OID_PKCS5 "\x0b" /**< pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} */
 
+/*
+ * PKCS#8 OIDs
+ */
+#define OID_PKCS9_CSR_EXT_REQ           OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */
+
 /*
  * PKCS#12 PBE OIDs
  */
diff --git a/include/polarssl/x509write.h b/include/polarssl/x509write.h
index acff33dde..aa4d05352 100644
--- a/include/polarssl/x509write.h
+++ b/include/polarssl/x509write.h
@@ -29,7 +29,7 @@
 
 #include "config.h"
 
-#include "rsa.h"
+#include "x509.h"
 
 /**
  * \addtogroup x509_module
@@ -80,6 +80,7 @@ typedef struct _x509_csr
     rsa_context *rsa;
     x509_req_name *subject;
     md_type_t md_alg;
+    unsigned char key_usage;
 }
 x509_csr;
 
@@ -124,6 +125,15 @@ void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa );
  */
 void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg );
 
+/**
+ * \brief           Set the Key Usage Extension flags
+ *                  (e.g. KU_DIGITAL_SIGNATURE | KU_KEY_CERT_SIGN)
+ *
+ * \param ctx       CSR context to use
+ * \param key_usage key usage bitstring to set
+ */
+void x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage );
+
 /**
  * \brief           Free the contents of a CSR context
  *
diff --git a/library/x509write.c b/library/x509write.c
index 337f4c25c..adeb55123 100644
--- a/library/x509write.c
+++ b/library/x509write.c
@@ -148,6 +148,11 @@ exit:
     return( ret );
 }
 
+void x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage )
+{
+    ctx->key_usage = key_usage;
+}
+
 int x509write_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size )
 {
     int ret;
@@ -301,13 +306,43 @@ 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;
+    size_t sub_len = 0, pub_len = 0, sig_len = 0, ext_len = 0;
     size_t len = 0;
     x509_req_name *cur = ctx->subject;
 
     c = tmp_buf + 2048 - 1;
 
-    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, 0 ) );
+    /*
+     * Extension  ::=  SEQUENCE  {
+     *      extnID      OBJECT IDENTIFIER,
+     *      extnValue   OCTET STRING  }
+     */
+    if( ctx->key_usage )
+    {
+        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 ) );
+        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_len( &c, tmp_buf, ext_len ) );
+        ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+    }
+
+    if( ext_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( 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( ext_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 ) );
+    }
+
+    len += ext_len;
+    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, ext_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 ) );