Merged refactored x509write module into development
diff --git a/ChangeLog b/ChangeLog
index 549e436..6cfdd00 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,6 +20,8 @@
    * Support for zeros-and-length (ANSI X.923) padding, one-and-zeros
      (ISO/IEC 7816-4) padding and zero padding in the cipher layer
    * Support for session tickets (RFC 5077)
+   * Certificate Request (CSR) generation with extensions (key_usage,
+     ns_cert_type)
 
 Changes
    * Ability to enable / disable SSL v3 / TLS 1.0 / TLS 1.1 / TLS 1.2
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/asn1write.h b/include/polarssl/asn1write.h
index 459b282..4659b24 100644
--- a/include/polarssl/asn1write.h
+++ b/include/polarssl/asn1write.h
@@ -35,20 +35,164 @@
 extern "C" {
 #endif
 
+/**
+ * \brief           Write a length field in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param len       the length to write
+ *
+ * \return          the length written or a negative error code
+ */
 int asn1_write_len( unsigned char **p, unsigned char *start, size_t len );
+
+/**
+ * \brief           Write a ASN.1 tag in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param tag       the tag to write
+ *
+ * \return          the length written or a negative error code
+ */
 int asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag );
+
+/**
+ * \brief           Write raw buffer data
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param buf       data buffer to write
+ * \param size      length of the data buffer
+ *
+ * \return          the length written or a negative error code
+ */
+int asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
+                           const unsigned char *buf, size_t size );
+
 #if defined(POLARSSL_BIGNUM_C)
+/**
+ * \brief           Write a big number (ASN1_INTEGER) in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param X         the MPI to write
+ *
+ * \return          the length written or a negative error code
+ */
 int asn1_write_mpi( unsigned char **p, unsigned char *start, mpi *X );
 #endif
+
+/**
+ * \brief           Write a NULL tag (ASN1_NULL) with zero data in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ *
+ * \return          the length written or a negative error code
+ */
 int asn1_write_null( unsigned char **p, unsigned char *start );
+
+/**
+ * \brief           Write an OID tag (ASN1_OID) and data in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param oid       the OID to write
+ *
+ * \return          the length written or a negative error code
+ */
 int asn1_write_oid( unsigned char **p, unsigned char *start, const char *oid );
-int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, const char *algorithm_oid );
+
+/**
+ * \brief           Write an AlgorithmIdentifier sequence in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *                  Note: Uses NULL as algorithm parameter
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param oid       the OID of the algorithm
+ *
+ * \return          the length written or a negative error code
+ */
+int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
+                                     const char *oid );
+
+/**
+ * \brief           Write an int tag (ASN1_INTEGER) and value in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param val       the integer value
+ *
+ * \return          the length written or a negative error code
+ */
 int asn1_write_int( unsigned char **p, unsigned char *start, int val );
+
+/**
+ * \brief           Write a printable string tag (ASN1_PRINTABLE_STRING) and
+ *                  value in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param text      the text to write
+ *
+ * \return          the length written or a negative error code
+ */
 int asn1_write_printable_string( unsigned char **p, unsigned char *start,
                                  char *text );
+
+/**
+ * \brief           Write an IA5 string tag (ASN1_IA5_STRING) and
+ *                  value in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param text      the text to write
+ *
+ * \return          the length written or a negative error code
+ */
 int asn1_write_ia5_string( unsigned char **p, unsigned char *start,
                                  char *text );
 
+/**
+ * \brief           Write a bitstring tag (ASN1_BIT_STRING) and
+ *                  value in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param buf       the bitstring
+ * \param bits      the total number of bits in the bitstring
+ *
+ * \return          the length written or a negative error code
+ */
+int asn1_write_bitstring( unsigned char **p, unsigned char *start,
+                          const unsigned char *buf, size_t bits );
+
+/**
+ * \brief           Write an octet string tag (ASN1_OCTET_STRING) and
+ *                  value in ASN.1 format
+ *                  Note: function works backwards in data buffer
+ *
+ * \param p         reference to current position pointer
+ * \param start     start of the buffer (for bounds-checking)
+ * \param buf       data buffer to write
+ * \param size      length of the data buffer
+ *
+ * \return          the length written or a negative error code
+ */
+int asn1_write_octet_string( unsigned char **p, unsigned char *start,
+                             const unsigned char *buf, size_t size );
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/error.h b/include/polarssl/error.h
index 889e4be..4c9ef7c 100644
--- a/include/polarssl/error.h
+++ b/include/polarssl/error.h
@@ -73,19 +73,20 @@
  * PBKDF2    1  0x007C-0x007C
  *
  * High-level module nr (3 bits - 0x1...-0x8...)
- * Name     ID  Nr of Errors
- * PEM      1   9
- * PKCS#12  1   4 (Started from top)
- * X509     2   25
- * PK       2   3 (Started from top)
- * DHM      3   6
- * PKCS5    3   4 (Started from top)
- * RSA      4   9
- * ECP      4   4 (Started from top)
- * MD       5   4
- * CIPHER   6   5
- * SSL      6   6 (Started from top)
- * SSL      7   31
+ * Name      ID  Nr of Errors
+ * PEM       1   9
+ * PKCS#12   1   4 (Started from top)
+ * X509      2   25
+ * PK        2   3 (Started from top)
+ * DHM       3   6
+ * PKCS5     3   4 (Started from top)
+ * RSA       4   9
+ * ECP       4   4 (Started from top)
+ * MD        5   4
+ * X509WRITE 5   3 (Started from top)
+ * CIPHER    6   5
+ * SSL       6   6 (Started from top)
+ * SSL       7   31
  *
  * Module dependent error code (5 bits 0x.08.-0x.F8.)
  */
diff --git a/include/polarssl/oid.h b/include/polarssl/oid.h
index ebb5bad..025a15f 100644
--- a/include/polarssl/oid.h
+++ b/include/polarssl/oid.h
@@ -228,6 +228,11 @@
 #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
  */
 #define OID_PKCS12_PBE                      OID_PKCS12 "\x01" /**< pkcs-12PbeIds OBJECT IDENTIFIER ::= {pkcs-12 1} */
diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h
index 8785862..e68789c 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
@@ -290,42 +284,6 @@
 /** \} addtogroup x509_module */
 
 /**
- * \name Structures for writing X.509 certificates.
- * XvP: commented out as they are not used.
- * - <tt>typedef struct _x509_node x509_node;</tt>
- * - <tt>typedef struct _x509_raw x509_raw;</tt>
- */
-/*
-typedef struct _x509_node
-{
-    unsigned char *data;
-    unsigned char *p;
-    unsigned char *end;
-
-    size_t len;
-}
-x509_node;
-
-typedef struct _x509_raw
-{
-    x509_node raw;
-    x509_node tbs;
-
-    x509_node version;
-    x509_node serial;
-    x509_node tbs_signalg;
-    x509_node issuer;
-    x509_node validity;
-    x509_node subject;
-    x509_node subpubkey;
-
-    x509_node signalg;
-    x509_node sign;
-}
-x509_raw;
-*/
-
-/**
  * \name Functions to read in DHM parameters, a certificate, CRL or private RSA key
  * \{
  */
diff --git a/include/polarssl/x509write.h b/include/polarssl/x509write.h
index 0d94f01..0e443ee 100644
--- a/include/polarssl/x509write.h
+++ b/include/polarssl/x509write.h
@@ -29,14 +29,40 @@
 
 #include "config.h"
 
-#if defined(POLARSSL_X509_WRITE_C)
+#include "x509.h"
 
-#include "rsa.h"
+/**
+ * \addtogroup x509_module
+ * \{
+ */
+
+/**
+ * \name X509 Write Error codes
+ * \{
+ */
+#define POLARSSL_ERR_X509WRITE_UNKNOWN_OID                -0x5F80  /**< Requested OID is unknown. */
+#define POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA             -0x5F00  /**< Failed to allocate memory. */
+#define POLARSSL_ERR_X509WRITE_MALLOC_FAILED              -0x5E80  /**< Failed to allocate memory. */
+/* \} name */
+/* \} addtogroup x509_module */
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/**
+ * \addtogroup x509_module
+ * \{
+ */
+
+/**
+ * \name Structures for writing X.509 CSRs (Certificate Signing Request) 
+ * \{
+ */
+
+/**
+ * Container for CSR named objects
+ */
 typedef struct _x509_req_name
 {
     char oid[128];
@@ -46,15 +72,187 @@
 }
 x509_req_name;
 
-int x509_write_pubkey_der( unsigned char *buf, size_t size, rsa_context *rsa );
-int x509_write_key_der( unsigned char *buf, size_t size, rsa_context *rsa );
-int x509_write_cert_req( unsigned char *buf, size_t size, rsa_context *rsa,
-                         x509_req_name *req_name, md_type_t md_alg );
+/**
+ * Container for a CSR
+ */
+typedef struct _x509_csr
+{
+    rsa_context *rsa;
+    x509_req_name *subject;
+    md_type_t md_alg;
+    asn1_named_data *extensions;
+}
+x509_csr;
+
+/* \} addtogroup x509_module */
+
+/**
+ * \brief           Initialize a CSR context
+ *
+ * \param ctx       CSR context to initialize
+ */
+void x509write_csr_init( x509_csr *ctx );
+
+/**
+ * \brief           Set the subject name for a CSR
+ *                  Subject names should contain a comma-separated list
+ *                  of OID types and values:
+ *                  e.g. "C=NL,O=Offspark,CN=PolarSSL Server 1"
+ *
+ * \param ctx           CSR context to use
+ * \param subject_name  subject name to set
+ *
+ * \return          0 if subject name was parsed successfully, or
+ *                  a specific error code
+ */
+int x509write_csr_set_subject_name( x509_csr *ctx, char *subject_name );
+
+/**
+ * \brief           Set the RSA key for a CSR (public key will be included,
+ *                  private key used to sign the CSR when writing it)
+ *
+ * \param ctx       CSR context to use
+ * \param rsa       RSA key to include
+ */
+void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa );
+
+/**
+ * \brief           Set the MD algorithm to use for the signature
+ *                  (e.g. POLARSSL_MD_SHA1)
+ *
+ * \param ctx       CSR context to use
+ * \param md_ald    MD algorithm to use
+ */
+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 flags to set
+ *
+ * \return          0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED
+ */
+int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage );
+
+/**
+ * \brief           Set the Netscape Cert Type flags
+ *                  (e.g. NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_EMAIL)
+ *
+ * \param ctx           CSR context to use
+ * \param ns_cert_type  Netscape Cert Type flags to set
+ *
+ * \return          0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED
+ */
+int x509write_csr_set_ns_cert_type( x509_csr *ctx, unsigned char ns_cert_type );
+
+/**
+ * \brief           Generic function to add to or replace an extension in the CSR
+ *
+ * \param ctx       CSR context to use
+ * \param oid       OID of the extension
+ * \param oid_len   length of the OID
+ * \param val       value of the extension OCTET STRING
+ * \param val_len   length of the value data
+ *
+ * \return          0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED
+ */
+int x509write_csr_set_extension( x509_csr *ctx,
+                                 const char *oid, size_t oid_len,
+                                 const unsigned char *val, size_t val_len );
+
+/**
+ * \brief           Free the contents of a CSR context
+ *
+ * \param ctx       CSR context to free
+ */
+void x509write_csr_free( x509_csr *ctx );
+
+/**
+ * \brief           Write a RSA public key to a PKCS#1 DER structure
+ *                  Note: data is written at the end of the buffer! Use the
+ *                        return value to determine where you should start
+ *                        using the buffer
+ *
+ * \param rsa       RSA to write away
+ * \param buf       buffer to write to
+ * \param size      size of the buffer
+ *
+ * \return          length of data written if successful, or a specific
+ *                  error code
+ */
+int x509write_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size );
+
+/**
+ * \brief           Write a RSA key to a PKCS#1 DER structure
+ *                  Note: data is written at the end of the buffer! Use the
+ *                        return value to determine where you should start
+ *                        using the buffer
+ *
+ * \param rsa       RSA to write away
+ * \param buf       buffer to write to
+ * \param size      size of the buffer
+ *
+ * \return          length of data written if successful, or a specific
+ *                  error code
+ */
+int x509write_key_der( rsa_context *rsa, unsigned char *buf, size_t size );
+
+/**
+ * \brief           Write a CSR (Certificate Signing Request) to a
+ *                  DER structure
+ *                  Note: data is written at the end of the buffer! Use the
+ *                        return value to determine where you should start
+ *                        using the buffer
+ *
+ * \param rsa       CSR to write away
+ * \param buf       buffer to write to
+ * \param size      size of the buffer
+ *
+ * \return          length of data written if successful, or a specific
+ *                  error code
+ */
+int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size );
+
+#if defined(POLARSSL_BASE64_C)
+/**
+ * \brief           Write a RSA public key to a PKCS#1 PEM string
+ *
+ * \param rsa       RSA to write away
+ * \param buf       buffer to write to
+ * \param size      size of the buffer
+ *
+ * \return          0 successful, or a specific error code
+ */
+int x509write_pubkey_pem( rsa_context *rsa, unsigned char *buf, size_t size );
+
+/**
+ * \brief           Write a RSA key to a PKCS#1 PEM string
+ *
+ * \param rsa       RSA to write away
+ * \param buf       buffer to write to
+ * \param size      size of the buffer
+ *
+ * \return          0 successful, or a specific error code
+ */
+int x509write_key_pem( rsa_context *rsa, unsigned char *buf, size_t size );
+
+/**
+ * \brief           Write a CSR (Certificate Signing Request) to a
+ *                  PEM string
+ *
+ * \param rsa       CSR to write away
+ * \param buf       buffer to write to
+ * \param size      size of the buffer
+ *
+ * \return          0 successful, or a specific error code
+ */
+int x509write_csr_pem( x509_csr *ctx, unsigned char *buf, size_t size );
+#endif /* POLARSSL_BASE64_C */
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* POLARSSL_X509_WRITE_C */
-
 #endif /* POLARSSL_X509_WRITE_H */
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/asn1write.c b/library/asn1write.c
index b1d6839..463c730 100644
--- a/library/asn1write.c
+++ b/library/asn1write.c
@@ -72,6 +72,21 @@
     return( 1 );
 }
 
+int asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
+                           const unsigned char *buf, size_t size )
+{
+    size_t len = 0;
+
+    if( *p - start < (int) size )
+        return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+
+    len = size;
+    (*p) -= len;
+    memcpy( *p, buf, len );
+
+    return( len );
+}
+
 #if defined(POLARSSL_BIGNUM_C)
 int asn1_write_mpi( unsigned char **p, unsigned char *start, mpi *X )
 {
@@ -125,15 +140,8 @@
     int ret;
     size_t len = 0;
 
-    // Write OID
-    //
-    len = strlen( oid );
-
-    if( *p - start < (int) len )
-        return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
-
-    (*p) -= len;
-    memcpy( *p, oid, len );
+    ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
+                  (const unsigned char *) oid, strlen( oid ) ) );
 
     ASN1_CHK_ADD( len , asn1_write_len( p, start, len ) );
     ASN1_CHK_ADD( len , asn1_write_tag( p, start, ASN1_OID ) );
@@ -142,7 +150,7 @@
 }
 
 int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
-                                     const char *algorithm_oid )
+                                     const char *oid )
 {
     int ret;
     size_t null_len = 0;
@@ -155,7 +163,7 @@
 
     // Write OID
     //
-    ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, algorithm_oid ) );
+    ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, oid ) );
 
     len = oid_len + null_len;
     ASN1_CHK_ADD( len, asn1_write_len( p, start, oid_len + null_len ) );
@@ -201,43 +209,68 @@
     int ret;
     size_t len = 0;
 
-    // Write string
-    //
-    len = strlen( text );
-
-    if( *p - start < (int) len )
-        return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
-
-    (*p) -= len;
-    memcpy( *p, text, len );
+    ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
+                  (const unsigned char *) text, strlen( text ) ) );
 
     ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
     ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_PRINTABLE_STRING ) );
 
     return( len );
 }
-    
+
 int asn1_write_ia5_string( unsigned char **p, unsigned char *start,
-                          char *text )
+                           char *text )
 {
     int ret;
     size_t len = 0;
 
-    // Write string
-    //
-    len = strlen( text );
-
-    if( *p - start < (int) len )
-        return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
-
-    (*p) -= len;
-    memcpy( *p, text, len );
+    ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
+                  (const unsigned char *) text, strlen( text ) ) );
 
     ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
     ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_IA5_STRING ) );
 
     return( len );
 }
-    
 
+int asn1_write_bitstring( unsigned char **p, unsigned char *start,
+                          const unsigned char *buf, size_t bits )
+{
+    int ret;
+    size_t len = 0, size;
+
+    size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 );
+
+    // Calculate byte length
+    //
+    if( *p - start < (int) size + 1 )
+        return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+
+    len = size + 1;
+    (*p) -= size;
+    memcpy( *p, buf, size );
+
+    // Write unused bits
+    //
+    *--(*p) = size * 8 - bits;
+
+    ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_BIT_STRING ) );
+
+    return( len );
+}
+
+int asn1_write_octet_string( unsigned char **p, unsigned char *start,
+                             const unsigned char *buf, size_t size )
+{
+    int ret;
+    size_t len = 0;
+
+    ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, buf, size ) );
+
+    ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_OCTET_STRING ) );
+
+    return( len );
+}
 #endif
diff --git a/library/error.c b/library/error.c
index 35a4af0..86586dd 100644
--- a/library/error.c
+++ b/library/error.c
@@ -149,6 +149,10 @@
 #include "polarssl/x509.h"
 #endif
 
+#if defined(POLARSSL_X509_WRITE_C)
+#include "polarssl/x509write.h"
+#endif
+
 #if defined(POLARSSL_XTEA_C)
 #include "polarssl/xtea.h"
 #endif
@@ -432,6 +436,15 @@
             snprintf( buf, buflen, "X509 - Elliptic curve is unsupported (only NIST curves are supported)" );
 #endif /* POLARSSL_X509_PARSE_C */
 
+#if defined(POLARSSL_X509_WRITE_C)
+        if( use_ret == -(POLARSSL_ERR_X509WRITE_UNKNOWN_OID) )
+            snprintf( buf, buflen, "X509WRITE - Requested OID is unknown" );
+        if( use_ret == -(POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA) )
+            snprintf( buf, buflen, "X509WRITE - Failed to allocate memory" );
+        if( use_ret == -(POLARSSL_ERR_X509WRITE_MALLOC_FAILED) )
+            snprintf( buf, buflen, "X509WRITE - Failed to allocate memory" );
+#endif /* POLARSSL_X509_WRITE_C */
+
         if( strlen( buf ) == 0 )
             snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret );
     }
diff --git a/library/x509write.c b/library/x509write.c
index 7aa65ce..7e04e12 100644
--- a/library/x509write.c
+++ b/library/x509write.c
@@ -33,7 +33,231 @@
 #include "polarssl/md.h"
 #include "polarssl/oid.h"
 
-int x509_write_pubkey_der( unsigned char *buf, size_t size, rsa_context *rsa )
+#if defined(POLARSSL_BASE64_C)
+#include "polarssl/base64.h"
+#endif
+
+#if defined(POLARSSL_MEMORY_C)
+#include "polarssl/memory.h"
+#else
+#include <stdlib.h>
+#define polarssl_malloc     malloc
+#define polarssl_free       free
+#endif
+
+void x509write_csr_init( x509_csr *ctx )
+{
+    memset( ctx, 0, sizeof(x509_csr) );
+}
+
+void x509write_csr_free( x509_csr *ctx )
+{
+    x509_req_name *cur;
+    asn1_named_data *cur_ext;
+
+    while( ( cur = ctx->subject ) != NULL )
+    {
+        ctx->subject = cur->next;
+        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) );
+}
+
+void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg )
+{
+    ctx->md_alg = md_alg;
+}
+
+void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa )
+{
+    ctx->rsa = rsa;
+}
+
+int x509write_csr_set_subject_name( x509_csr *ctx, char *subject_name )
+{
+    int ret = 0;
+    char *s = subject_name, *c = s;
+    char *end = s + strlen( s );
+    char *oid = NULL;
+    int in_tag = 1;
+    x509_req_name *cur;
+
+    while( ctx->subject )
+    {
+        cur = ctx->subject;
+        ctx->subject = ctx->subject->next;
+        polarssl_free( cur );
+    }
+
+    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( c - s > 127 )
+            {
+                ret = POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA;
+                goto exit;
+            }
+
+            cur = polarssl_malloc( sizeof(x509_req_name) );
+
+            if( cur == NULL )
+            {
+                ret = POLARSSL_ERR_X509WRITE_MALLOC_FAILED;
+                goto exit;
+            }
+
+            memset( cur, 0, sizeof(x509_req_name) );
+
+            cur->next = ctx->subject;
+            ctx->subject = cur;
+
+            strncpy( cur->oid, oid, strlen( oid ) );
+            strncpy( cur->name, s, c - s );
+
+            s = c + 1;
+            in_tag = 1;
+        }
+        c++;
+    }
+
+exit:
+
+    return( ret );
+}
+
+int x509write_csr_set_extension( x509_csr *ctx,
+                                 const char *oid, size_t oid_len,
+                                 const unsigned char *val, size_t val_len )
+{
+    asn1_named_data *cur;
+
+    if( ( cur = asn1_find_named_data( ctx->extensions, oid,
+                                      oid_len ) ) == 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_len;
+        cur->oid.p = polarssl_malloc( oid_len );
+        if( cur->oid.p == NULL )
+        {
+            polarssl_free( cur );
+            return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
+        }
+
+        cur->val.len = val_len;
+        cur->val.p = polarssl_malloc( val_len );
+        if( cur->val.p == NULL )
+        {
+            polarssl_free( cur->oid.p );
+            polarssl_free( cur );
+            return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
+        }
+
+        memcpy( cur->oid.p, oid, oid_len );
+
+        cur->next = ctx->extensions;
+        ctx->extensions = cur;
+    }
+
+    if( cur->val.len != val_len )
+    {
+        polarssl_free( cur->val.p );
+
+        cur->val.len = val_len;
+        cur->val.p = polarssl_malloc( val_len );
+        if( cur->val.p == NULL )
+        {
+            polarssl_free( cur->oid.p );
+            polarssl_free( cur );
+            return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
+        }
+    }
+
+    memcpy( cur->val.p, val, val_len );
+
+    return( 0 );
+}
+
+int x509write_csr_set_key_usage( x509_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( x509_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_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size )
 {
     int ret;
     unsigned char *c;
@@ -41,6 +265,12 @@
 
     c = buf + size - 1;
 
+    /*
+    *  RSAPublicKey ::= SEQUENCE {
+    *      modulus           INTEGER,  -- n
+    *      publicExponent    INTEGER   -- e
+    *  }
+    */
     ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->E ) );
     ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->N ) );
 
@@ -50,6 +280,11 @@
     if( c - buf < 1 )
         return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
 
+    /*
+     *  SubjectPublicKeyInfo  ::=  SEQUENCE  {
+     *       algorithm            AlgorithmIdentifier,
+     *       subjectPublicKey     BIT STRING }
+     */
     *--c = 0;
     len += 1;
 
@@ -64,7 +299,7 @@
     return( len );
 }
 
-int x509_write_key_der( unsigned char *buf, size_t size, rsa_context *rsa )
+int x509write_key_der( rsa_context *rsa, unsigned char *buf, size_t size )
 {
     int ret;
     unsigned char *c;
@@ -167,8 +402,7 @@
     return( len );
 }
 
-int x509_write_cert_req( unsigned char *buf, size_t size, rsa_context *rsa,
-                         x509_req_name *req_name, md_type_t md_alg )
+int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size )
 {
     int ret;
     const char *sig_oid;
@@ -178,15 +412,52 @@
     unsigned char tmp_buf[2048];
     size_t sub_len = 0, pub_len = 0, sig_len = 0;
     size_t len = 0;
-    x509_req_name *cur = req_name;
+    x509_req_name *cur = ctx->subject;
+    asn1_named_data *cur_ext = ctx->extensions;
 
     c = tmp_buf + 2048 - 1;
 
-    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, 0 ) );
+    while( cur_ext != NULL )
+    {
+        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_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( 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 ) );
+
+        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, asn1_write_mpi( &c, tmp_buf, &rsa->E ) );
-    ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &rsa->N ) );
+    ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &ctx->rsa->E ) );
+    ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &ctx->rsa->N ) );
 
     ASN1_CHK_ADD( pub_len, asn1_write_len( &c, tmp_buf, pub_len ) );
     ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
@@ -194,6 +465,11 @@
     if( c - tmp_buf < 1 )
         return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
 
+    /*
+     *  AlgorithmIdentifier  ::=  SEQUENCE  {
+     *       algorithm               OBJECT IDENTIFIER,
+     *       parameters              ANY DEFINED BY algorithm OPTIONAL  }
+     */
     *--c = 0;
     pub_len += 1;
 
@@ -217,21 +493,24 @@
     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 ) );
 
+    /*
+     *  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 ) );
 
-    md( md_info_from_type( md_alg ), c, len, hash );
+    md( md_info_from_type( ctx->md_alg ), c, len, hash );
 
-    rsa_pkcs1_sign( rsa, NULL, NULL, RSA_PRIVATE, md_alg, 0, hash, sig );
+    rsa_pkcs1_sign( ctx->rsa, NULL, NULL, RSA_PRIVATE, ctx->md_alg, 0, hash, sig );
 
     // Generate correct OID
     //
-    ret = oid_get_oid_by_sig_alg( POLARSSL_PK_RSA, md_alg, &sig_oid );
+    ret = oid_get_oid_by_sig_alg( POLARSSL_PK_RSA, ctx->md_alg, &sig_oid );
 
     c2 = buf + size - 1;
-    ASN1_CHK_ADD( sig_len, x509_write_sig( &c2, buf, sig_oid, sig, rsa->len ) );
+    ASN1_CHK_ADD( sig_len, x509_write_sig( &c2, buf, sig_oid, sig, ctx->rsa->len ) );
 
     c2 -= len;
     memcpy( c2, c, len );
@@ -243,4 +522,117 @@
     return( len );
 }
 
+#define PEM_BEGIN_CSR           "-----BEGIN CERTIFICATE REQUEST-----\n"
+#define PEM_END_CSR             "-----END CERTIFICATE REQUEST-----\n"
+
+#define PEM_BEGIN_PUBLIC_KEY    "-----BEGIN PUBLIC KEY-----\n"
+#define PEM_END_PUBLIC_KEY      "-----END PUBLIC KEY-----\n"
+
+#define PEM_BEGIN_PRIVATE_KEY   "-----BEGIN RSA PRIVATE KEY-----\n"
+#define PEM_END_PRIVATE_KEY     "-----END RSA PRIVATE KEY-----\n"
+
+#if defined(POLARSSL_BASE64_C)
+static int x509write_pemify( const char *begin_str, const char *end_str,
+                             const unsigned char *der_data, size_t der_len,
+                             unsigned char *buf, size_t size )
+{
+    int ret;
+    unsigned char base_buf[4096];
+    unsigned char *c = base_buf, *p = buf;
+    size_t len = 0, olen = sizeof(base_buf);
+
+    if( ( ret = base64_encode( base_buf, &olen, der_data, der_len ) ) != 0 )
+        return( ret );
+
+    if( olen + strlen( begin_str ) + strlen( end_str ) +
+        olen / 64 > size )
+    {
+        return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
+    }
+
+    memcpy( p, begin_str, strlen( begin_str ) );
+    p += strlen( begin_str );
+
+    while( olen )
+    {
+        len = ( olen > 64 ) ? 64 : olen;
+        memcpy( p, c, len );
+        olen -= len;
+        p += len;
+        c += len;
+        *p++ = '\n';
+    }
+
+    memcpy( p, end_str, strlen( end_str ) );
+    p += strlen( end_str );
+
+    *p = '\0';
+
+    return( 0 );
+}
+
+int x509write_pubkey_pem( rsa_context *rsa, unsigned char *buf, size_t size )
+{
+    int ret;
+    unsigned char output_buf[4096];
+
+    if( ( ret = x509write_pubkey_der( rsa, output_buf,
+                                      sizeof(output_buf) ) ) < 0 )
+    {
+        return( ret );
+    }
+
+    if( ( ret = x509write_pemify( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
+                                  output_buf + sizeof(output_buf) - 1 - ret,
+                                  ret, buf, size ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    return( 0 );
+}
+
+int x509write_key_pem( rsa_context *rsa, unsigned char *buf, size_t size )
+{
+    int ret;
+    unsigned char output_buf[4096];
+
+    if( ( ret = x509write_key_der( rsa, output_buf,
+                                      sizeof(output_buf) ) ) < 0 )
+    {
+        return( ret );
+    }
+
+    if( ( ret = x509write_pemify( PEM_BEGIN_PRIVATE_KEY, PEM_END_PRIVATE_KEY,
+                                  output_buf + sizeof(output_buf) - 1 - ret,
+                                  ret, buf, size ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    return( 0 );
+}
+
+int x509write_csr_pem( x509_csr *ctx, unsigned char *buf, size_t size )
+{
+    int ret;
+    unsigned char output_buf[4096];
+
+    if( ( ret = x509write_csr_der( ctx, output_buf,
+                                      sizeof(output_buf) ) ) < 0 )
+    {
+        return( ret );
+    }
+
+    if( ( ret = x509write_pemify( PEM_BEGIN_CSR, PEM_END_CSR,
+                                  output_buf + sizeof(output_buf) - 1 - ret,
+                                  ret, buf, size ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    return( 0 );
+}
+#endif /* POLARSSL_BASE64_C */
+
 #endif
diff --git a/programs/.gitignore b/programs/.gitignore
index e9f4e54..2b7510f 100644
--- a/programs/.gitignore
+++ b/programs/.gitignore
@@ -35,6 +35,7 @@
 test/selftest
 test/ssl_cert_test
 test/ssl_test
+util/pem2der
 util/strerror
 x509/cert_app
 x509/cert_req
diff --git a/programs/Makefile b/programs/Makefile
index 1c2b5fc..ea024fa 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -39,7 +39,7 @@
 	test/ssl_cert_test	test/benchmark		\
 	test/selftest		test/ssl_test		\
 	test/ecp-bench							\
-	util/strerror							\
+	util/pem2der		util/strerror		\
 	x509/cert_app		x509/crl_app		\
 	x509/cert_req
 
@@ -195,6 +195,10 @@
 	echo   "  CC    test/o_p_test.c"
 	$(CC) $(CFLAGS) $(OFLAGS) test/o_p_test.c    $(LDFLAGS) -o $@ -lssl -lcrypto
 
+util/pem2der: util/pem2der.c ../library/libpolarssl.a
+	echo   "  CC    util/pem2der.c"
+	$(CC) $(CFLAGS) $(OFLAGS) util/pem2der.c    $(LDFLAGS) -o $@
+
 util/strerror: util/strerror.c ../library/libpolarssl.a
 	echo   "  CC    util/strerror.c"
 	$(CC) $(CFLAGS) $(OFLAGS) util/strerror.c    $(LDFLAGS) -o $@
diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c
index 88cb907..d9ab45c 100644
--- a/programs/pkey/key_app_writer.c
+++ b/programs/pkey/key_app_writer.c
@@ -1,5 +1,5 @@
 /*
- *  Key reading application
+ *  Key writing application
  *
  *  Copyright (C) 2006-2013, Brainspark B.V.
  *
@@ -60,11 +60,15 @@
 #define OUTPUT_MODE_PRIVATE            1
 #define OUTPUT_MODE_PUBLIC             2
 
+#define OUTPUT_FORMAT_PEM              0
+#define OUTPUT_FORMAT_DER              1
+
 #define DFL_MODE                MODE_NONE
 #define DFL_FILENAME            "keyfile.key"
 #define DFL_DEBUG_LEVEL         0
-#define DFL_OUTPUT_MODE          OUTPUT_MODE_NONE
+#define DFL_OUTPUT_MODE         OUTPUT_MODE_NONE
 #define DFL_OUTPUT_FILENAME     "keyfile.pem"
+#define DFL_OUTPUT_FORMAT       OUTPUT_FORMAT_PEM
 
 /*
  * global options
@@ -75,79 +79,80 @@
     const char *filename;       /* filename of the key file             */
     int output_mode;            /* the output mode to use               */
     const char *output_file;    /* where to store the constructed key file  */
+    int output_format;          /* the output format to use             */
 } opt;
 
-static void write_public_key( rsa_context *rsa, const char *output_file )
+static int write_public_key( rsa_context *rsa, const char *output_file )
 {
+    int ret;
     FILE *f;
     unsigned char output_buf[16000];
-    unsigned char base_buf[16000];
-    unsigned char *c;
-    int ret;
-    size_t len = 0, olen = 16000;
+    unsigned char *c = output_buf;
+    size_t len = 0;
 
     memset(output_buf, 0, 16000);
-    ret = x509_write_pubkey_der( output_buf, 16000, rsa );
 
-    if( ret < 0 )
-        return;
-
-    len = ret;
-    c = output_buf + 15999 - len;
-
-    base64_encode( base_buf, &olen, c, len );
-
-    c = base_buf;
-
-    f = fopen( output_file, "w" );
-    fprintf(f, "-----BEGIN PUBLIC KEY-----\n");
-    while (olen)
+    if( opt.output_format == OUTPUT_FORMAT_PEM )
     {
-        int use_len = olen;
-        if (use_len > 64) use_len = 64;
-        fwrite( c, 1, use_len, f );
-        olen -= use_len;
-        c += use_len;
-        fprintf(f, "\n");
+        if( ( ret = x509write_pubkey_pem( rsa, output_buf, 16000 ) ) != 0 )
+            return( ret );
+
+        len = strlen( (char *) output_buf );
     }
-    fprintf(f, "-----END PUBLIC KEY-----\n");
+    else
+    {
+        if( ( ret = x509write_pubkey_der( rsa, output_buf, 16000 ) ) < 0 )
+            return( ret );
+
+        len = ret;
+        c = output_buf + sizeof(output_buf) - len - 1;
+    }
+
+    if( ( f = fopen( output_file, "w" ) ) == NULL )
+        return( -1 );
+
+    if( fwrite( c, 1, len, f ) != len )
+        return( -1 );
+
     fclose(f);
+
+    return( 0 );
 }
 
-static void write_private_key( rsa_context *rsa, const char *output_file )
+static int write_private_key( rsa_context *rsa, const char *output_file )
 {
+    int ret;
     FILE *f;
     unsigned char output_buf[16000];
-    unsigned char base_buf[16000];
-    unsigned char *c;
-    int ret;
-    size_t len = 0, olen = 16000;
+    unsigned char *c = output_buf;
+    size_t len = 0;
 
     memset(output_buf, 0, 16000);
-    ret = x509_write_key_der( output_buf, 16000, rsa );
-    if( ret < 0 )
-        return;
-
-    len = ret;
-    c = output_buf + 15999 - len;
-
-    base64_encode( base_buf, &olen, c, len );
-
-    c = base_buf;
-
-    f = fopen( output_file, "w" );
-    fprintf(f, "-----BEGIN RSA PRIVATE KEY-----\n");
-    while (olen)
+    if( opt.output_format == OUTPUT_FORMAT_PEM )
     {
-        int use_len = olen;
-        if (use_len > 64) use_len = 64;
-        fwrite( c, 1, use_len, f );
-        olen -= use_len;
-        c += use_len;
-        fprintf(f, "\n");
+        if( ( ret = x509write_key_pem( rsa, output_buf, 16000 ) ) != 0 )
+            return( ret );
+
+        len = strlen( (char *) output_buf );
     }
-    fprintf(f, "-----END RSA PRIVATE KEY-----\n");
+    else
+    {
+        if( ( ret = x509write_key_der( rsa, output_buf, 16000 ) ) < 0 )
+            return( ret );
+
+        len = ret;
+        c = output_buf + sizeof(output_buf) - len - 1;
+    }
+
+    if( ( f = fopen( output_file, "w" ) ) == NULL )
+        return( -1 );
+
+    if( fwrite( c, 1, len, f ) != len )
+        return( -1 );
+
     fclose(f);
+
+    return( 0 );
 }
 
 #define USAGE \
@@ -156,7 +161,8 @@
     "    mode=private|public default: none\n"           \
     "    filename=%%s         default: keyfile.key\n"   \
     "    output_mode=private|public default: none\n"    \
-    "    output_file=%%s      defeult: keyfile.pem\n"   \
+    "    output_file=%%s      default: keyfile.pem\n"   \
+    "    output_format=pem|der default: pem\n"          \
     "\n"
 
 int main( int argc, char *argv[] )
@@ -184,6 +190,7 @@
     opt.filename            = DFL_FILENAME;
     opt.output_mode         = DFL_OUTPUT_MODE;
     opt.output_file         = DFL_OUTPUT_FILENAME;
+    opt.output_format       = DFL_OUTPUT_FORMAT;
 
     for( i = 1; i < argc; i++ )
     {
@@ -210,6 +217,15 @@
             else
                 goto usage;
         }
+        else if( strcmp( p, "output_format" ) == 0 )
+        {
+            if( strcmp( q, "pem" ) == 0 )
+                opt.output_format = OUTPUT_FORMAT_PEM;
+            else if( strcmp( q, "der" ) == 0 )
+                opt.output_format = OUTPUT_FORMAT_DER;
+            else
+                goto usage;
+        }
         else if( strcmp( p, "filename" ) == 0 )
             opt.filename = q;
         else if( strcmp( p, "output_file" ) == 0 )
diff --git a/programs/util/CMakeLists.txt b/programs/util/CMakeLists.txt
index c0f2e4c..aedd94f 100644
--- a/programs/util/CMakeLists.txt
+++ b/programs/util/CMakeLists.txt
@@ -5,6 +5,9 @@
 add_executable(strerror strerror.c)
 target_link_libraries(strerror ${libs})
 
-install(TARGETS strerror
+add_executable(pem2der pem2der.c)
+target_link_libraries(pem2der ${libs})
+
+install(TARGETS strerror pem2der
         DESTINATION "bin"
         PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
diff --git a/programs/util/pem2der.c b/programs/util/pem2der.c
new file mode 100644
index 0000000..0315f02
--- /dev/null
+++ b/programs/util/pem2der.c
@@ -0,0 +1,288 @@
+/*
+ *  Convert PEM to DER
+ *
+ *  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.
+ */
+
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "polarssl/config.h"
+
+#include "polarssl/error.h"
+#include "polarssl/base64.h"
+
+#define DFL_FILENAME            "file.pem"
+#define DFL_OUTPUT_FILENAME     "file.der"
+
+/*
+ * global options
+ */
+struct options
+{
+    char *filename;             /* filename of the input file             */
+    char *output_file;          /* where to store the output              */
+} opt;
+
+int convert_pem_to_der( const unsigned char *input, size_t ilen,
+                        unsigned char *output, size_t *olen )
+{
+    int ret;
+    const unsigned char *s1, *s2, *end = input + ilen;
+    size_t len = 0;
+
+    s1 = (unsigned char *) strstr( (char *) input, "-----BEGIN" );
+    if( s1 == NULL )
+        return( -1 );
+
+    s2 = (unsigned char *) strstr( (char *) input, "-----END" );
+    if( s2 == NULL )
+        return( -1 );
+
+    s1 += 10;
+    while( s1 < end && *s1 != '-' )
+        s1++;
+    while( s1 < end && *s1 == '-' )
+        s1++;
+    if( *s1 == '\r' ) s1++;
+    if( *s1 == '\n' ) s1++;
+
+    if( s2 <= s1 || s2 > end )
+        return( -1 );
+
+    ret = base64_decode( NULL, &len, (const unsigned char *) s1, s2 - s1 );
+    if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER )
+        return( ret );
+
+    if( len > *olen )
+        return( -1 );
+
+    if( ( ret = base64_decode( output, &len, (const unsigned char *) s1,
+                               s2 - s1 ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    *olen = len;
+
+    return( 0 );
+}
+
+/*
+ * 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( -1 );
+
+    fseek( f, 0, SEEK_END );
+    if( ( size = ftell( f ) ) == -1 )
+    {
+        fclose( f );
+        return( -1 );
+    }
+    fseek( f, 0, SEEK_SET );
+
+    *n = (size_t) size;
+
+    if( *n + 1 == 0 ||
+        ( *buf = (unsigned char *) malloc( *n + 1 ) ) == NULL )
+    {
+        fclose( f );
+        return( -1 );
+    }
+
+    if( fread( *buf, 1, *n, f ) != *n )
+    {
+        fclose( f );
+        free( *buf );
+        return( -1 );
+    }
+
+    fclose( f );
+
+    (*buf)[*n] = '\0';
+
+    return( 0 );
+}
+
+/*
+ * Write buffer to a file
+ */
+static int write_file( const char *path, unsigned char *buf, size_t n )
+{
+    FILE *f;
+
+    if( ( f = fopen( path, "wb" ) ) == NULL )
+        return( -1 );
+
+    if( fwrite( buf, 1, n, f ) != n )
+    {
+        fclose( f );
+        return( -1 );
+    }
+
+    fclose( f );
+    return( 0 );
+}
+
+#define USAGE \
+    "\n usage: pem2der param=<>...\n"                   \
+    "\n acceptable parameters:\n"                       \
+    "    filename=%%s         default: file.pem\n"      \
+    "    output_file=%%s      default: file.der\n"      \
+    "\n"
+
+#if !defined(POLARSSL_BASE64_C) || !defined(POLARSSL_FS_IO)
+int main( int argc, char *argv[] )
+{
+    ((void) argc);
+    ((void) argv);
+
+    printf("POLARSSL_BASE64_C and/or POLARSSL_FS_IO not defined.\n");
+    return( 0 );
+}
+#else
+int main( int argc, char *argv[] )
+{
+    int ret = 0;
+    unsigned char *pem_buffer = NULL;
+    unsigned char der_buffer[4096];
+    char buf[1024];
+    size_t pem_size, der_size = sizeof(der_buffer);
+    int i, j, n;
+    char *p, *q;
+
+    /*
+     * Set to sane values
+     */
+    memset( buf, 0, sizeof(buf) );
+    memset( der_buffer, 0, sizeof(der_buffer) );
+
+    if( argc == 0 )
+    {
+    usage:
+        printf( USAGE );
+        goto exit;
+    }
+
+    opt.filename            = DFL_FILENAME;
+    opt.output_file         = DFL_OUTPUT_FILENAME;
+
+    for( i = 1; i < argc; i++ )
+    {
+
+        p = argv[i];
+        if( ( q = strchr( p, '=' ) ) == NULL )
+            goto usage;
+        *q++ = '\0';
+
+        n = strlen( p );
+        for( j = 0; j < n; j++ )
+        {
+            if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' )
+                argv[i][j] |= 0x20;
+        }
+
+        if( strcmp( p, "filename" ) == 0 )
+            opt.filename = q;
+        else if( strcmp( p, "output_file" ) == 0 )
+            opt.output_file = q;
+        else
+            goto usage;
+    }
+
+    /*
+     * 1.1. Load the PEM file
+     */
+    printf( "\n  . Loading the PEM file ..." );
+    fflush( stdout );
+
+    ret = load_file( opt.filename, &pem_buffer, &pem_size );
+
+    if( ret != 0 )
+    {
+#ifdef POLARSSL_ERROR_C
+        error_strerror( ret, buf, 1024 );
+#endif
+        printf( " failed\n  !  load_file returned %d - %s\n\n", ret, buf );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 1.2. Convert from PEM to DER
+     */
+    printf( "  . Converting from PEM to DER ..." );
+    fflush( stdout );
+
+    if( ( ret = convert_pem_to_der( pem_buffer, pem_size, der_buffer, &der_size ) ) != 0 )
+    {
+#ifdef POLARSSL_ERROR_C
+        error_strerror( ret, buf, 1024 );
+#endif
+        printf( " failed\n  !  convert_pem_to_der %d - %s\n\n", ret, buf );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 1.3. Write the DER file
+     */
+    printf( "  . Writing the DER file ..." );
+    fflush( stdout );
+
+    ret = write_file( opt.output_file, der_buffer, der_size );
+
+    if( ret != 0 )
+    {
+#ifdef POLARSSL_ERROR_C
+        error_strerror( ret, buf, 1024 );
+#endif
+        printf( " failed\n  !  write_file returned %d - %s\n\n", ret, buf );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+exit:
+    free( pem_buffer );
+
+#if defined(_WIN32)
+    printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
+#endif /* POLARSSL_BASE64_C && POLARSSL_FS_IO */
diff --git a/programs/x509/CMakeLists.txt b/programs/x509/CMakeLists.txt
index 08a962a..d07cff8 100644
--- a/programs/x509/CMakeLists.txt
+++ b/programs/x509/CMakeLists.txt
@@ -16,6 +16,9 @@
 add_executable(crl_app crl_app.c)
 target_link_libraries(crl_app ${libs})
 
-install(TARGETS cert_app crl_app
+add_executable(cert_req cert_req.c)
+target_link_libraries(cert_req ${libs})
+
+install(TARGETS cert_app crl_app cert_req
         DESTINATION "bin"
         PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c
index cbd6252..384ef08 100644
--- a/programs/x509/cert_req.c
+++ b/programs/x509/cert_req.c
@@ -44,6 +44,8 @@
 #define DFL_DEBUG_LEVEL         0
 #define DFL_OUTPUT_FILENAME     "cert.req"
 #define DFL_SUBJECT_NAME        "CN=Cert,O=PolarSSL,C=NL"
+#define DFL_KEY_USAGE           0
+#define DFL_NS_CERT_TYPE        0
 
 /*
  * global options
@@ -54,53 +56,32 @@
     int debug_level;            /* level of debugging                   */
     char *output_file;          /* where to store the constructed key file  */
     char *subject_name;         /* subject name for certificate request */
+    unsigned char key_usage;    /* key usage flags                      */
+    unsigned char ns_cert_type; /* NS cert type                         */
 } opt;
 
-void my_debug( void *ctx, int level, const char *str )
+int write_certificate_request( x509_csr *req, char *output_file )
 {
-    if( level < opt.debug_level )
-    {
-        fprintf( (FILE *) ctx, "%s", str );
-        fflush(  (FILE *) ctx  );
-    }
-}
-
-void write_certificate_request( rsa_context *rsa, x509_req_name *req_name,
-                                char *output_file )
-{
+    int ret;
     FILE *f;
     unsigned char output_buf[4096];
-    unsigned char base_buf[4096];
-    unsigned char *c;
-    int ret;
-    size_t len = 0, olen = 4096;
+    size_t len = 0;
 
-    memset(output_buf, 0, 4096);
-    ret = x509_write_cert_req( output_buf, 4096, rsa, req_name, POLARSSL_MD_SHA1 );
+    memset( output_buf, 0, 4096 );
+    if( ( ret = x509write_csr_pem( req, output_buf, 4096 ) ) < 0 )
+        return( ret );
 
-    if( ret < 0 )
-        return;
+    len = strlen( (char *) output_buf );
 
-    len = ret;
-    c = output_buf + 4095 - len;
+    if( ( f = fopen( output_file, "w" ) ) == NULL )
+        return( -1 );
 
-    base64_encode( base_buf, &olen, c, len );
+    if( fwrite( output_buf, 1, len, f ) != len )
+        return( -1 );
 
-    c = base_buf;
-
-    f = fopen( output_file, "w" );
-    fprintf(f, "-----BEGIN CERTIFICATE REQUEST-----\n");
-    while (olen)
-    {
-        int use_len = olen;
-        if (use_len > 64) use_len = 64;
-        fwrite( c, 1, use_len, f );
-        olen -= use_len;
-        c += use_len;
-        fprintf(f, "\n");
-    }
-    fprintf(f, "-----END CERTIFICATE REQUEST-----\n");
     fclose(f);
+
+    return( 0 );
 }
 
 #define USAGE \
@@ -110,6 +91,24 @@
     "    debug_level=%%d      default: 0 (disabled)\n"  \
     "    output_file=%%s      default: cert.req\n"      \
     "    subject_name=%%s     default: CN=Cert,O=PolarSSL,C=NL\n"   \
+    "    key_usage=%%s        default: (empty)\n"       \
+    "                        Comma-separated-list of values:\n"     \
+    "                          digital_signature\n"     \
+    "                          non_repudiation\n"       \
+    "                          key_encipherment\n"      \
+    "                          data_encipherment\n"     \
+    "                          key_agreement\n"         \
+    "                          key_certificate_sign\n"  \
+    "                          crl_sign\n"              \
+    "    ns_cert_type=%%s     default: (empty)\n"       \
+    "                        Comma-separated-list of values:\n"     \
+    "                          ssl_client\n"            \
+    "                          ssl_server\n"            \
+    "                          email\n"                 \
+    "                          object_signing\n"        \
+    "                          ssl_ca\n"                \
+    "                          email_ca\n"              \
+    "                          object_signing_ca\n"     \
     "\n"
 
 #if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) ||         \
@@ -130,16 +129,14 @@
     rsa_context rsa;
     char buf[1024];
     int i, j, n;
-    char *p, *q;
-    char *s, *c, *end;
-    int in_tag;
-    char *oid = NULL;
-    x509_req_name *req_name = NULL;
-    x509_req_name *cur = req_name;
+    char *p, *q, *r;
+    x509_csr req;
 
     /*
      * Set to sane values
      */
+    x509write_csr_init( &req );
+    x509write_csr_set_md_alg( &req, POLARSSL_MD_SHA1 );
     memset( &rsa, 0, sizeof( rsa_context ) );
     memset( buf, 0, 1024 );
 
@@ -147,6 +144,7 @@
     {
     usage:
         printf( USAGE );
+        ret = 1;
         goto exit;
     }
 
@@ -154,6 +152,8 @@
     opt.debug_level         = DFL_DEBUG_LEVEL;
     opt.output_file         = DFL_OUTPUT_FILENAME;
     opt.subject_name        = DFL_SUBJECT_NAME;
+    opt.key_usage           = DFL_KEY_USAGE;
+    opt.ns_cert_type        = DFL_NS_CERT_TYPE;
 
     for( i = 1; i < argc; i++ )
     {
@@ -184,81 +184,80 @@
         {
             opt.subject_name = q;
         }
+        else if( strcmp( p, "key_usage" ) == 0 )
+        {
+            while( q != NULL )
+            {
+                if( ( r = strchr( q, ',' ) ) != NULL )
+                    *r++ = '\0';
+
+                if( strcmp( q, "digital_signature" ) == 0 )
+                    opt.key_usage |= KU_DIGITAL_SIGNATURE;
+                else if( strcmp( q, "non_repudiation" ) == 0 )
+                    opt.key_usage |= KU_NON_REPUDIATION;
+                else if( strcmp( q, "key_encipherment" ) == 0 )
+                    opt.key_usage |= KU_KEY_ENCIPHERMENT;
+                else if( strcmp( q, "data_encipherment" ) == 0 )
+                    opt.key_usage |= KU_DATA_ENCIPHERMENT;
+                else if( strcmp( q, "key_agreement" ) == 0 )
+                    opt.key_usage |= KU_KEY_AGREEMENT;
+                else if( strcmp( q, "key_cert_sign" ) == 0 )
+                    opt.key_usage |= KU_KEY_CERT_SIGN;
+                else if( strcmp( q, "crl_sign" ) == 0 )
+                    opt.key_usage |= KU_CRL_SIGN;
+                else
+                    goto usage;
+
+                q = r;
+            }
+        }
+        else if( strcmp( p, "ns_cert_type" ) == 0 )
+        {
+            while( q != NULL )
+            {
+                if( ( r = strchr( q, ',' ) ) != NULL )
+                    *r++ = '\0';
+
+                if( strcmp( q, "ssl_client" ) == 0 )
+                    opt.ns_cert_type |= NS_CERT_TYPE_SSL_CLIENT;
+                else if( strcmp( q, "ssl_server" ) == 0 )
+                    opt.ns_cert_type |= NS_CERT_TYPE_SSL_SERVER;
+                else if( strcmp( q, "email" ) == 0 )
+                    opt.ns_cert_type |= NS_CERT_TYPE_EMAIL;
+                else if( strcmp( q, "object_signing" ) == 0 )
+                    opt.ns_cert_type |= NS_CERT_TYPE_OBJECT_SIGNING;
+                else if( strcmp( q, "ssl_ca" ) == 0 )
+                    opt.ns_cert_type |= NS_CERT_TYPE_SSL_CA;
+                else if( strcmp( q, "email_ca" ) == 0 )
+                    opt.ns_cert_type |= NS_CERT_TYPE_EMAIL_CA;
+                else if( strcmp( q, "object_signing_ca" ) == 0 )
+                    opt.ns_cert_type |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
+                else
+                    goto usage;
+
+                q = r;
+            }
+        }
         else
             goto usage;
     }
 
+    if( opt.key_usage )
+        x509write_csr_set_key_usage( &req, opt.key_usage );
+
+    if( opt.ns_cert_type )
+        x509write_csr_set_ns_cert_type( &req, opt.ns_cert_type );
+
     /*
      * 1.0. Check the subject name for validity
      */
-    s = opt.subject_name;
-    end = s + strlen( s );
-
-    c = s;
-
-    in_tag = 1;
-    while( c <= end )
+    if( ( ret = x509write_csr_set_subject_name( &req, opt.subject_name ) ) != 0 )
     {
-        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
-            {
-                printf("Failed to parse subject name.\n");
-                goto exit;
-            }
-
-            s = c + 1;
-            in_tag = 0;
-        }
-        
-        if( !in_tag && ( *c == ',' || c == end ) )
-        {
-            if( c - s > 127 )
-            {
-                printf("Name too large for buffer.\n");
-                goto exit;
-            }
-
-            if( cur == NULL )
-            {
-                req_name = malloc( sizeof(x509_req_name) );
-                cur = req_name;
-            }
-            else
-            {
-                cur->next = malloc( sizeof(x509_req_name) );
-                cur = cur->next;
-            }
-
-            if( cur == NULL )
-            {
-                printf( "Failed to allocate memory.\n" );
-                goto exit;
-            }
-
-            memset( cur, 0, sizeof(x509_req_name) );
-
-            strncpy( cur->oid, oid, strlen( oid ) );
-            strncpy( cur->name, s, c - s );
-
-            s = c + 1;
-            in_tag = 1;
-        }
-        c++;
+#ifdef POLARSSL_ERROR_C
+        error_strerror( ret, buf, 1024 );
+#endif
+        printf( " failed\n  !  x509write_csr_set_subject_name returned %d - %s\n\n", ret, buf );
+        goto exit;
     }
 
     /*
@@ -275,16 +274,32 @@
         error_strerror( ret, buf, 1024 );
 #endif
         printf( " failed\n  !  x509parse_key_rsa returned %d - %s\n\n", ret, buf );
-        rsa_free( &rsa );
+        goto exit;
+    }
+
+    x509write_csr_set_rsa_key( &req, &rsa );
+
+    printf( " ok\n" );
+
+    /*
+     * 1.2. Writing the request
+     */
+    printf( "  . Writing the certificate request ..." );
+    fflush( stdout );
+
+    if( ( ret = write_certificate_request( &req, opt.output_file ) ) != 0 )
+    {
+#ifdef POLARSSL_ERROR_C
+        error_strerror( ret, buf, 1024 );
+#endif
+        printf( " failed\n  !  write_certifcate_request %d - %s\n\n", ret, buf );
         goto exit;
     }
 
     printf( " ok\n" );
 
-    write_certificate_request( &rsa, req_name, opt.output_file );
-
 exit:
-
+    x509write_csr_free( &req );
     rsa_free( &rsa );
 
 #if defined(_WIN32)
diff --git a/scripts/generate_errors.pl b/scripts/generate_errors.pl
index 7257ae6..5b95494 100755
--- a/scripts/generate_errors.pl
+++ b/scripts/generate_errors.pl
@@ -13,7 +13,7 @@
                           "PADLOCK", "DES", "NET", "CTR_DRBG", "ENTROPY",
                           "MD2", "MD4", "MD5", "SHA1", "SHA256", "SHA512", "GCM" );
 my @high_level_modules = ( "PEM", "X509", "DHM", "RSA", "ECP", "MD", "CIPHER", "SSL",
-                           "PK", "PKCS12", "PKCS5" );
+                           "PK", "PKCS12", "PKCS5", "X509WRITE" );
 
 my $line_separator = $/;
 undef $/;
@@ -49,6 +49,7 @@
 
     my $define_name = $module_name;
     $define_name = "X509_PARSE" if ($define_name eq "X509");
+    $define_name = "X509_WRITE" if ($define_name eq "X509WRITE");
     $define_name = "ASN1_PARSE" if ($define_name eq "ASN1");
     $define_name = "SSL_TLS" if ($define_name eq "SSL");
 
diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data
index c498436..7a48440 100644
--- a/tests/suites/test_suite_x509write.data
+++ b/tests/suites/test_suite_x509write.data
@@ -1,27 +1,27 @@
 Certificate Request check Server1 SHA1
 depends_on:POLARSSL_SHA1_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_SHA1:"data_files/server1.req.sha1"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_SHA1:"data_files/server1.req.sha1"
 
 Certificate Request check Server1 SHA224
 depends_on:POLARSSL_SHA256_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_SHA224:"data_files/server1.req.sha224"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_SHA224:"data_files/server1.req.sha224"
 
 Certificate Request check Server1 SHA256
 depends_on:POLARSSL_SHA256_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_SHA256:"data_files/server1.req.sha256"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_SHA256:"data_files/server1.req.sha256"
 
 Certificate Request check Server1 SHA384
 depends_on:POLARSSL_SHA512_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_SHA384:"data_files/server1.req.sha384"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_SHA384:"data_files/server1.req.sha384"
 
 Certificate Request check Server1 SHA512
 depends_on:POLARSSL_SHA512_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_SHA512:"data_files/server1.req.sha512"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_SHA512:"data_files/server1.req.sha512"
 
 Certificate Request check Server1 MD4
 depends_on:POLARSSL_MD4_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_MD4:"data_files/server1.req.md4"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_MD4:"data_files/server1.req.md4"
 
 Certificate Request check Server1 MD5
 depends_on:POLARSSL_MD5_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_MD5:"data_files/server1.req.md5"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_MD5:"data_files/server1.req.md5"
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index 680dfb4..d3c801a 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -11,36 +11,19 @@
  */
 
 /* BEGIN_CASE */
-void x509_cert_req_check( char *key_file, int md_type,
+void x509_csr_check( char *key_file, int md_type,
                           char *cert_req_check_file )
 {
     rsa_context rsa;
     pem_context pem;
-    x509_req_name req_name, *cur;
+    x509_csr req;
     unsigned char *c;
     unsigned char buf[4000];
     unsigned char check_buf[4000];
     int ret;
     size_t olen = 2000;
     FILE *f;
-
-    cur = &req_name;
-
-    memset( cur, 0, sizeof(x509_req_name) );
-    strcpy( cur->oid, OID_AT_CN );
-    strcpy( cur->name, "PolarSSL Server 1" );
-    cur->next = malloc( sizeof(x509_req_name) );
-    cur = cur->next;
-
-    memset( cur, 0, sizeof(x509_req_name) );
-    strcpy( cur->oid, OID_AT_ORGANIZATION );
-    strcpy( cur->name, "PolarSSL" );
-    cur->next = malloc( sizeof(x509_req_name) );
-    cur = cur->next;
-
-    memset( cur, 0, sizeof(x509_req_name) );
-    strcpy( cur->oid, OID_AT_COUNTRY );
-    strcpy( cur->name, "NL" );
+    char *subject_name = "C=NL,O=PolarSSL,CN=PolarSSL Server 1";
 
     memset( &rsa, 0, sizeof(rsa_context) );
     ret = x509parse_keyfile_rsa( &rsa, key_file, NULL );
@@ -48,7 +31,12 @@
     if( ret != 0 )
         return;
 
-    ret = x509_write_cert_req( buf, 4000, &rsa, &req_name, md_type );
+    x509write_csr_init( &req );
+    x509write_csr_set_md_alg( &req, md_type );
+    x509write_csr_set_rsa_key( &req, &rsa );
+    TEST_ASSERT( x509write_csr_set_subject_name( &req, subject_name ) == 0 );
+
+    ret = x509write_csr_der( &req, buf, 4000 );
     TEST_ASSERT( ret >= 0 );
 
     c = buf + 3999 - ret;
@@ -64,12 +52,7 @@
     TEST_ASSERT( memcmp( c, pem.buf, pem.buflen ) == 0 );
     TEST_ASSERT( pem.buflen == (size_t) ret );
 
-    while( ( cur = req_name.next ) != NULL )
-    {
-        req_name.next = cur->next;
-        free( cur );
-    }
-
+    x509write_csr_free( &req );
     rsa_free( &rsa );
     pem_free( &pem );
 }