Merged major refactoring of x509write module into development

This refactoring adds support for proper CSR writing and X509
certificate generation / signing
diff --git a/include/polarssl/asn1.h b/include/polarssl/asn1.h
index ec8cbfa..45fd6cd 100644
--- a/include/polarssl/asn1.h
+++ b/include/polarssl/asn1.h
@@ -154,8 +154,8 @@
 asn1_named_data;
 
 /**
- * Get the length of an ASN.1 element.
- * Updates the pointer to immediately behind the length.
+ * \brief       Get the length of an ASN.1 element.
+ *              Updates the pointer to immediately behind the length.
  *
  * \param p     The position in the ASN.1 data
  * \param end   End of data
@@ -170,8 +170,8 @@
                   size_t *len );
 
 /**
- * Get the tag and length of the tag. Check for the requested tag.
- * Updates the pointer to immediately behind the tag and length.
+ * \brief       Get the tag and length of the tag. Check for the requested tag.
+ *              Updates the pointer to immediately behind the tag and length.
  *
  * \param p     The position in the ASN.1 data
  * \param end   End of data
@@ -186,8 +186,8 @@
                   size_t *len, int tag );
 
 /**
- * Retrieve a boolean ASN.1 tag and its value.
- * Updates the pointer to immediately behind the full tag.
+ * \brief       Retrieve a boolean ASN.1 tag and its value.
+ *              Updates the pointer to immediately behind the full tag.
  *
  * \param p     The position in the ASN.1 data
  * \param end   End of data
@@ -200,8 +200,8 @@
                    int *val );
 
 /**
- * Retrieve an integer ASN.1 tag and its value.
- * Updates the pointer to immediately behind the full tag.
+ * \brief       Retrieve an integer ASN.1 tag and its value.
+ *              Updates the pointer to immediately behind the full tag.
  *
  * \param p     The position in the ASN.1 data
  * \param end   End of data
@@ -214,8 +214,8 @@
                   int *val );
 
 /**
- * Retrieve a bitstring ASN.1 tag and its value.
- * Updates the pointer to immediately behind the full tag.
+ * \brief       Retrieve a bitstring ASN.1 tag and its value.
+ *              Updates the pointer to immediately behind the full tag.
  *
  * \param p     The position in the ASN.1 data
  * \param end   End of data
@@ -227,8 +227,9 @@
                         asn1_bitstring *bs);
 
 /**
- * Retrieve a bitstring ASN.1 tag without unused bits and its value.
- * Updates the pointer to the beginning of the bit/octet string.
+ * \brief       Retrieve a bitstring ASN.1 tag without unused bits and its
+ *              value.
+ *              Updates the pointer to the beginning of the bit/octet string.
  *
  * \param p     The position in the ASN.1 data
  * \param end   End of data
@@ -240,8 +241,8 @@
                              size_t *len );
 
 /**
- * Parses and splits an ASN.1 "SEQUENCE OF <tag>"
- * Updated the pointer to immediately behind the full sequence tag.
+ * \brief       Parses and splits an ASN.1 "SEQUENCE OF <tag>"
+ *              Updated the pointer to immediately behind the full sequence tag.
  *
  * \param p     The position in the ASN.1 data
  * \param end   End of data
@@ -257,8 +258,8 @@
 
 #if defined(POLARSSL_BIGNUM_C)
 /**
- * Retrieve a MPI value from an integer ASN.1 tag.
- * Updates the pointer to immediately behind the full tag.
+ * \brief       Retrieve a MPI value from an integer ASN.1 tag.
+ *              Updates the pointer to immediately behind the full tag.
  *
  * \param p     The position in the ASN.1 data
  * \param end   End of data
@@ -272,8 +273,9 @@
 #endif
 
 /**
- * Retrieve an AlgorithmIdentifier ASN.1 sequence.
- * Updates the pointer to immediately behind the full AlgorithmIdentifier.
+ * \brief       Retrieve an AlgorithmIdentifier ASN.1 sequence.
+ *              Updates the pointer to immediately behind the full
+ *              AlgorithmIdentifier.
  *
  * \param p     The position in the ASN.1 data
  * \param end   End of data
@@ -287,8 +289,10 @@
                   asn1_buf *alg, asn1_buf *params );
 
 /**
- * Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no params.
- * Updates the pointer to immediately behind the full AlgorithmIdentifier.
+ * \brief       Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no
+ *              params.
+ *              Updates the pointer to immediately behind the full
+ *              AlgorithmIdentifier.
  *
  * \param p     The position in the ASN.1 data
  * \param end   End of data
@@ -301,7 +305,8 @@
                        asn1_buf *alg );
 
 /**
- * Find a specific named_data entry in a sequence or list based on the OID.
+ * \brief       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
@@ -313,12 +318,20 @@
                                        const char *oid, size_t len );
 
 /**
- * Free a asn1_named_data entry
+ * \brief       Free a asn1_named_data entry
  *
  * \param entry The named data entry to free
  */
 void asn1_free_named_data( asn1_named_data *entry );
 
+/**
+ * \brief       Free all entries in a asn1_named_data list
+ *              Head will be set to NULL
+ *
+ * \param head  Pointer to the head of the list of named data entries to free
+ */
+void asn1_free_named_data_list( asn1_named_data **head );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/asn1write.h b/include/polarssl/asn1write.h
index 4659b24..d7f7b52 100644
--- a/include/polarssl/asn1write.h
+++ b/include/polarssl/asn1write.h
@@ -29,7 +29,7 @@
 
 #include "asn1.h"
 
-#define ASN1_CHK_ADD(g, f) if( ( ret = f ) < 0 ) return( ret ); else g += ret
+#define ASN1_CHK_ADD(g, f) do { if( ( ret = f ) < 0 ) return( ret ); else g += ret; } while( 0 )
 
 #ifdef __cplusplus
 extern "C" {
@@ -105,24 +105,41 @@
  * \param p         reference to current position pointer
  * \param start     start of the buffer (for bounds-checking)
  * \param oid       the OID to write
+ * \param oid_len   length of the OID
  *
  * \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_oid( unsigned char **p, unsigned char *start,
+                    const char *oid, size_t oid_len );
 
 /**
  * \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
+ * \param oid_len   length of the OID
+ * \param par_len   length of parameters, which must be already written.
+ *                  If 0, NULL parameters are added
  *
  * \return          the length written or a negative error code
  */
 int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
-                                     const char *oid );
+                                     const char *oid, size_t oid_len,
+                                     size_t par_len );
+
+/**
+ * \brief           Write a boolean tag (ASN1_BOOLEAN) 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 boolean   0 or 1
+ *
+ * \return          the length written or a negative error code
+ */
+int asn1_write_bool( unsigned char **p, unsigned char *start, int boolean );
 
 /**
  * \brief           Write an int tag (ASN1_INTEGER) and value in ASN.1 format
@@ -144,11 +161,12 @@
  * \param p         reference to current position pointer
  * \param start     start of the buffer (for bounds-checking)
  * \param text      the text to write
+ * \param text_len  length of the text
  *
  * \return          the length written or a negative error code
  */
 int asn1_write_printable_string( unsigned char **p, unsigned char *start,
-                                 char *text );
+                                 const char *text, size_t text_len );
 
 /**
  * \brief           Write an IA5 string tag (ASN1_IA5_STRING) and
@@ -158,11 +176,12 @@
  * \param p         reference to current position pointer
  * \param start     start of the buffer (for bounds-checking)
  * \param text      the text to write
+ * \param text_len  length of the text
  *
  * \return          the length written or a negative error code
  */
 int asn1_write_ia5_string( unsigned char **p, unsigned char *start,
-                                 char *text );
+                           const char *text, size_t text_len );
 
 /**
  * \brief           Write a bitstring tag (ASN1_BIT_STRING) and
@@ -193,6 +212,28 @@
  */
 int asn1_write_octet_string( unsigned char **p, unsigned char *start,
                              const unsigned char *buf, size_t size );
+
+/**
+ * \brief           Create or find a specific named_data entry for writing in a
+ *                  sequence or list based on the OID. If not already in there,
+ *                  a new entry is added to the head of the list.
+ *                  Warning: Destructive behaviour for the val data!
+ *
+ * \param list      Pointer to the location of the head of the list to seek
+ *                  through (will be updated in case of a new entry)
+ * \param oid       The OID to look for
+ * \param oid_len   Size of the OID
+ * \param val       Data to store (can be NULL if you want to fill it by hand)
+ * \param val_len   Minimum length of the data buffer needed
+ *
+ * \return      NULL if if there was a memory allocation error, or a pointer
+ *              to the new / existing entry.
+ */
+asn1_named_data *asn1_store_named_data( asn1_named_data **list,
+                                        const char *oid, size_t oid_len,
+                                        const unsigned char *val,
+                                        size_t val_len );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/config.h b/include/polarssl/config.h
index b9f3f27..e738dee 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -401,11 +401,11 @@
 /**
  * \def POLARSSL_ERROR_STRERROR_DUMMY
  *
- * Enable a dummy error function to make use of error_strerror() in
+ * Enable a dummy error function to make use of polarssl_strerror() in
  * third party libraries easier.
  *
  * Disable if you run into name conflicts and want to really remove the
- * error_strerror()
+ * polarssl_strerror()
  */
 #define POLARSSL_ERROR_STRERROR_DUMMY
 
@@ -1384,7 +1384,7 @@
  *
  * Module:  library/x509write.c
  *
- * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C, POLARSSL_RSA_C
+ * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C, POLARSSL_PK_C
  *
  * This module is required for X.509 certificate request writing.
  */
diff --git a/include/polarssl/ecp.h b/include/polarssl/ecp.h
index 4343125..346b3a8 100644
--- a/include/polarssl/ecp.h
+++ b/include/polarssl/ecp.h
@@ -133,6 +133,7 @@
  */
 #define POLARSSL_ECP_MAX_BITS     521
 #define POLARSSL_ECP_MAX_BYTES    ( ( POLARSSL_ECP_MAX_BITS + 7 ) / 8 )
+#define POLARSSL_ECP_MAX_PT_LEN   ( 2 * POLARSSL_ECP_MAX_BYTES + 1 )
 
 /*
  * Maximum window size (actually, NAF width) used for point multipliation.
diff --git a/include/polarssl/oid.h b/include/polarssl/oid.h
index ddaf8a7..ba0ce7d 100644
--- a/include/polarssl/oid.h
+++ b/include/polarssl/oid.h
@@ -371,7 +371,20 @@
 int oid_get_pk_alg( const asn1_buf *oid, pk_type_t *pk_alg );
 
 /**
- * \brief          Translate ECParameters OID into an EC group identifier
+ * \brief          Translate pk_type into PublicKeyAlgorithm OID
+ *
+ * \param pk_alg   Public key type to look for
+ * \param oid      place to store ASN.1 OID string pointer
+ * \param olen     length of the OID
+ *
+ * \return         0 if successful, or POLARSSL_ERR_OID_NOT_FOUND
+ */
+int oid_get_oid_by_pk_alg( pk_type_t pk_alg,
+                           const char **oid, size_t *olen );
+
+#if defined(POLARSSL_ECP_C)
+/**
+ * \brief          Translate NamedCurve OID into an EC group identifier
  *
  * \param oid      OID to use
  * \param grp_id   place to store group id
@@ -380,6 +393,19 @@
  */
 int oid_get_ec_grp( const asn1_buf *oid, ecp_group_id *grp_id );
 
+/**
+ * \brief          Translate EC group identifier into NamedCurve OID
+ *
+ * \param grp_id   EC group identifier
+ * \param oid      place to store ASN.1 OID string pointer
+ * \param olen     length of the OID
+ *
+ * \return         0 if successful, or POLARSSL_ERR_OID_NOT_FOUND
+ */
+int oid_get_oid_by_ec_grp( ecp_group_id grp_id,
+                           const char **oid, size_t *olen );
+#endif /* POLARSSL_ECP_C */
+
 #if defined(POLARSSL_MD_C)
 /**
  * \brief          Translate SignatureAlgorithm OID into md_type and pk_type
@@ -409,11 +435,12 @@
  * \param md_alg   message digest algorithm
  * \param pk_alg   public key algorithm
  * \param oid      place to store ASN.1 OID string pointer
+ * \param olen     length of the OID
  *
  * \return         0 if successful, or POLARSSL_ERR_OID_NOT_FOUND
  */
 int oid_get_oid_by_sig_alg( pk_type_t pk_alg, md_type_t md_alg,
-                            const char **oid );
+                            const char **oid, size_t *olen );
 
 /**
  * \brief          Translate hash algorithm OID into md_type
@@ -441,10 +468,11 @@
  *
  * \param md_alg   message digest algorithm
  * \param oid      place to store ASN.1 OID string pointer
+ * \param olen     length of the OID
  *
  * \return         0 if successful, or POLARSSL_ERR_OID_NOT_FOUND
  */
-int oid_get_oid_by_md( md_type_t md_alg, const char **oid );
+int oid_get_oid_by_md( md_type_t md_alg, const char **oid, size_t *olen );
 
 #if defined(POLARSSL_CIPHER_C)
 /**
diff --git a/include/polarssl/pk.h b/include/polarssl/pk.h
index b71a90c..f8c6cc8 100644
--- a/include/polarssl/pk.h
+++ b/include/polarssl/pk.h
@@ -369,6 +369,15 @@
  */
 const char * pk_get_name( const pk_context *ctx );
 
+/**
+ * \brief           Get the key typee
+ *
+ * \param ctx       Context to use
+ *
+ * \return          Type on success, or POLARSSL_PK_NONE
+ */
+pk_type_t pk_get_type( const pk_context *ctx );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h
index e68789c..00e9b0b 100644
--- a/include/polarssl/x509.h
+++ b/include/polarssl/x509.h
@@ -31,8 +31,6 @@
 
 #if defined(POLARSSL_X509_PARSE_C) || defined(POLARSSL_X509_WRITE_C)
 #include "asn1.h"
-#include "rsa.h"
-#include "ecp.h"
 #include "dhm.h"
 #include "md.h"
 #include "pk.h"
@@ -151,7 +149,7 @@
  * \{ */
 
 /**
- * \name Structures for parsing X.509 certificates and CRLs
+ * \name Structures for parsing X.509 certificates, CRLs and CSRs
  * \{
  */
 
@@ -227,12 +225,12 @@
     md_type_t sig_md;           /**< Internal representation of the MD algorithm of the signature algorithm, e.g. POLARSSL_MD_SHA256 */
     pk_type_t sig_pk            /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. POLARSSL_PK_RSA */;
 
-    struct _x509_cert *next;    /**< Next certificate in the CA-chain. */ 
+    struct _x509_cert *next;    /**< Next certificate in the CA-chain. */
 }
 x509_cert;
 
-/** 
- * Certificate revocation list entry. 
+/**
+ * Certificate revocation list entry.
  * Contains the CA-specific serial numbers and revocation dates.
  */
 typedef struct _x509_crl_entry
@@ -249,8 +247,8 @@
 }
 x509_crl_entry;
 
-/** 
- * Certificate revocation list structure. 
+/**
+ * Certificate revocation list structure.
  * Every CRL may have multiple entries.
  */
 typedef struct _x509_crl
@@ -265,7 +263,7 @@
 
     x509_name issuer;       /**< The parsed issuer data (named information object). */
 
-    x509_time this_update;  
+    x509_time this_update;
     x509_time next_update;
 
     x509_crl_entry entry;   /**< The CRL entries containing the certificate revocation times for this CA. */
@@ -277,10 +275,32 @@
     md_type_t sig_md;           /**< Internal representation of the MD algorithm of the signature algorithm, e.g. POLARSSL_MD_SHA256 */
     pk_type_t sig_pk            /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. POLARSSL_PK_RSA */;
 
-    struct _x509_crl *next; 
+    struct _x509_crl *next;
 }
 x509_crl;
-/** \} name Structures for parsing X.509 certificates and CRLs */
+
+/**
+ * Certificate Signing Request (CSR) structure.
+ */
+typedef struct _x509_csr
+{
+    x509_buf raw;           /**< The raw CSR data (DER). */
+    x509_buf cri;           /**< The raw CertificateRequestInfo body (DER). */
+
+    int version;
+
+    x509_buf  subject_raw;  /**< The raw subject data (DER). */
+    x509_name subject;      /**< The parsed subject data (named information object). */
+
+    pk_context pk;          /**< Container for the public key context. */
+
+    x509_buf sig_oid;
+    x509_buf sig;
+    md_type_t sig_md;       /**< Internal representation of the MD algorithm of the signature algorithm, e.g. POLARSSL_MD_SHA256 */
+    pk_type_t sig_pk        /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. POLARSSL_PK_RSA */;
+}
+x509_csr;
+/** \} name Structures for parsing X.509 certificates, CRLs and CSRs */
 /** \} addtogroup x509_module */
 
 /**
@@ -317,6 +337,7 @@
  */
 int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen );
 
+#if defined(POLARSSL_FS_IO)
 /** \ingroup x509_module */
 /**
  * \brief          Load one or more certificates and add them
@@ -348,6 +369,7 @@
  *                 if partly successful or a specific X509 or PEM error code
  */
 int x509parse_crtpath( x509_cert *chain, const char *path );
+#endif /* POLARSSL_FS_IO */
 
 /** \ingroup x509_module */
 /**
@@ -364,6 +386,19 @@
 
 /** \ingroup x509_module */
 /**
+ * \brief          Load a Certificate Signing Request (CSR)
+ *
+ * \param csr      CSR context to fill
+ * \param buf      buffer holding the CRL data
+ * \param buflen   size of the buffer
+ *
+ * \return         0 if successful, or a specific X509 or PEM error code
+ */
+int x509parse_csr( x509_csr *csr, const unsigned char *buf, size_t buflen );
+
+#if defined(POLARSSL_FS_IO)
+/** \ingroup x509_module */
+/**
  * \brief          Load one or more CRLs and add them
  *                 to the chained list
  *
@@ -374,6 +409,18 @@
  */
 int x509parse_crlfile( x509_crl *chain, const char *path );
 
+/** \ingroup x509_module */
+/**
+ * \brief          Load a Certificate Signing Request (CSR)
+ *
+ * \param csr      CSR context to fill
+ * \param path     filename to read the CSR from
+ *
+ * \return         0 if successful, or a specific X509 or PEM error code
+ */
+int x509parse_csrfile( x509_csr *csr, const char *path );
+#endif /* POLARSSL_FS_IO */
+
 #if defined(POLARSSL_RSA_C)
 /** \ingroup x509_module */
 /**
@@ -391,6 +438,7 @@
                        const unsigned char *key, size_t keylen,
                        const unsigned char *pwd, size_t pwdlen );
 
+#if defined(POLARSSL_FS_IO)
 /** \ingroup x509_module */
 /**
  * \brief          Load and parse a private RSA key
@@ -403,6 +451,7 @@
  */
 int x509parse_keyfile_rsa( rsa_context *rsa, const char *path,
                            const char *password );
+#endif /* POLARSSL_FS_IO */
 
 /** \ingroup x509_module */
 /**
@@ -417,6 +466,7 @@
 int x509parse_public_key_rsa( rsa_context *rsa,
                        const unsigned char *key, size_t keylen );
 
+#if defined(POLARSSL_FS_IO)
 /** \ingroup x509_module */
 /**
  * \brief          Load and parse a public RSA key
@@ -427,6 +477,7 @@
  * \return         0 if successful, or a specific X509 or PEM error code
  */
 int x509parse_public_keyfile_rsa( rsa_context *rsa, const char *path );
+#endif /* POLARSSL_FS_IO */
 #endif /* POLARSSL_RSA_C */
 
 /** \ingroup x509_module */
@@ -445,6 +496,7 @@
                    const unsigned char *key, size_t keylen,
                    const unsigned char *pwd, size_t pwdlen );
 
+#if defined(POLARSSL_FS_IO)
 /** \ingroup x509_module */
 /**
  * \brief          Load and parse a private key
@@ -457,6 +509,7 @@
  */
 int x509parse_keyfile( pk_context *ctx,
                        const char *path, const char *password );
+#endif /* POLARSSL_FS_IO */
 
 /** \ingroup x509_module */
 /**
@@ -471,6 +524,7 @@
 int x509parse_public_key( pk_context *ctx,
                           const unsigned char *key, size_t keylen );
 
+#if defined(POLARSSL_FS_IO)
 /** \ingroup x509_module */
 /**
  * \brief          Load and parse a public key
@@ -481,6 +535,7 @@
  * \return         0 if successful, or a specific X509 or PEM error code
  */
 int x509parse_public_keyfile( pk_context *ctx, const char *path );
+#endif /* POLARSSL_FS_IO */
 
 /** \ingroup x509_module */
 /**
@@ -494,6 +549,7 @@
  */
 int x509parse_dhm( dhm_context *dhm, const unsigned char *dhmin, size_t dhminlen );
 
+#if defined(POLARSSL_FS_IO)
 /** \ingroup x509_module */
 /**
  * \brief          Load and parse DHM parameters
@@ -504,6 +560,7 @@
  * \return         0 if successful, or a specific X509 or PEM error code
  */
 int x509parse_dhmfile( dhm_context *dhm, const char *path );
+#endif /* POLARSSL_FS_IO */
 
 /** \} name Functions to read in DHM parameters, a certificate, CRL or private RSA key */
 
@@ -564,6 +621,21 @@
                         const x509_crl *crl );
 
 /**
+ * \brief          Returns an informational string about the
+ *                 CSR.
+ *
+ * \param buf      Buffer to write to
+ * \param size     Maximum size of buffer
+ * \param prefix   A line prefix
+ * \param csr      The X509 CSR to represent
+ *
+ * \return         The amount of data written to the buffer, or -1 in
+ *                 case of an error.
+ */
+int x509parse_csr_info( char *buf, size_t size, const char *prefix,
+                        const x509_csr *csr );
+
+/**
  * \brief          Give an known OID, return its descriptive string.
  *
  * \param oid      buffer containing the oid
@@ -680,6 +752,13 @@
  */
 void x509_crl_free( x509_crl *crl );
 
+/**
+ * \brief          Unallocate all CSR data
+ *
+ * \param csr      CSR to free
+ */
+void x509_csr_free( x509_csr *csr );
+
 /** \} name Functions to clear a certificate, CRL or private RSA key */
 
 
diff --git a/include/polarssl/x509write.h b/include/polarssl/x509write.h
index 1a53c29..552d453 100644
--- a/include/polarssl/x509write.h
+++ b/include/polarssl/x509write.h
@@ -61,28 +61,41 @@
  */
 
 /**
- * Container for CSR named objects
- */
-typedef struct _x509_req_name
-{
-    char oid[128];
-    char name[128];
-
-    struct _x509_req_name *next;
-}
-x509_req_name;
-
-/**
  * Container for a CSR
  */
-typedef struct _x509_csr
+typedef struct _x509write_csr
 {
-    rsa_context *rsa;
-    x509_req_name *subject;
+    pk_context *key;
+    asn1_named_data *subject;
     md_type_t md_alg;
     asn1_named_data *extensions;
 }
-x509_csr;
+x509write_csr;
+
+#define X509_CRT_VERSION_1              0
+#define X509_CRT_VERSION_2              1
+#define X509_CRT_VERSION_3              2
+
+#define X509_RFC5280_MAX_SERIAL_LEN 32
+#define X509_RFC5280_UTC_TIME_LEN   15
+
+/**
+ * Container for writing a certificate (CRT)
+ */
+typedef struct _x509write_cert
+{
+    int version;
+    mpi serial;
+    pk_context *subject_key;
+    pk_context *issuer_key;
+    asn1_named_data *subject;
+    asn1_named_data *issuer;
+    md_type_t md_alg;
+    char not_before[X509_RFC5280_UTC_TIME_LEN + 1];
+    char not_after[X509_RFC5280_UTC_TIME_LEN + 1];
+    asn1_named_data *extensions;
+}
+x509write_cert;
 
 /* \} name */
 /* \} addtogroup x509_module */
@@ -92,7 +105,7 @@
  *
  * \param ctx       CSR context to initialize
  */
-void x509write_csr_init( x509_csr *ctx );
+void x509write_csr_init( x509write_csr *ctx );
 
 /**
  * \brief           Set the subject name for a CSR
@@ -106,16 +119,16 @@
  * \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 );
+int x509write_csr_set_subject_name( x509write_csr *ctx, char *subject_name );
 
 /**
- * \brief           Set the RSA key for a CSR (public key will be included,
+ * \brief           Set the 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
+ * \param key       Asymetric key to include
  */
-void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa );
+void x509write_csr_set_key( x509write_csr *ctx, pk_context *key );
 
 /**
  * \brief           Set the MD algorithm to use for the signature
@@ -124,7 +137,7 @@
  * \param ctx       CSR context to use
  * \param md_alg    MD algorithm to use
  */
-void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg );
+void x509write_csr_set_md_alg( x509write_csr *ctx, md_type_t md_alg );
 
 /**
  * \brief           Set the Key Usage Extension flags
@@ -135,7 +148,7 @@
  *
  * \return          0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED
  */
-int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage );
+int x509write_csr_set_key_usage( x509write_csr *ctx, unsigned char key_usage );
 
 /**
  * \brief           Set the Netscape Cert Type flags
@@ -146,7 +159,8 @@
  *
  * \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 );
+int x509write_csr_set_ns_cert_type( x509write_csr *ctx,
+                                    unsigned char ns_cert_type );
 
 /**
  * \brief           Generic function to add to or replace an extension in the CSR
@@ -159,7 +173,7 @@
  *
  * \return          0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED
  */
-int x509write_csr_set_extension( x509_csr *ctx,
+int x509write_csr_set_extension( x509write_csr *ctx,
                                  const char *oid, size_t oid_len,
                                  const unsigned char *val, size_t val_len );
 
@@ -168,37 +182,242 @@
  *
  * \param ctx       CSR context to free
  */
-void x509write_csr_free( x509_csr *ctx );
+void x509write_csr_free( x509write_csr *ctx );
 
 /**
- * \brief           Write a RSA public key to a PKCS#1 DER structure
+ * \brief           Initialize a CRT writing context
+ *
+ * \param ctx       CRT context to initialize
+ */
+void x509write_crt_init( x509write_cert *ctx );
+
+/**
+ * \brief           Set the verion for a Certificate
+ *                  Default: X509_CRT_VERSION_3
+ *
+ * \param ctx       CRT context to use
+ * \param version   version to set (X509_CRT_VERSION_1, X509_CRT_VERSION_2 or
+ *                                  X509_CRT_VERSION_3)
+ */
+void x509write_crt_set_version( x509write_cert *ctx, int version );
+
+/**
+ * \brief           Set the serial number for a Certificate.
+ *
+ * \param ctx       CRT context to use
+ * \param serial    serial number to set
+ *
+ * \return          0 if successful
+ */
+int x509write_crt_set_serial( x509write_cert *ctx, const mpi *serial );
+
+/**
+ * \brief           Set the validity period for a Certificate
+ *                  Timestamps should be in string format for UTC timezone
+ *                  i.e. "YYYYMMDDhhmmss"
+ *                  e.g. "20131231235959" for December 31st 2013
+ *                       at 23:59:59
+ *
+ * \param ctx       CRT context to use
+ * \param not_before    not_before timestamp
+ * \param not_after     not_after timestamp
+ *
+ * \return          0 if timestamp was parsed successfully, or
+ *                  a specific error code
+ */
+int x509write_crt_set_validity( x509write_cert *ctx, char *not_before,
+                                char *not_after );
+
+/**
+ * \brief           Set the issuer name for a Certificate
+ *                  Issuer names should contain a comma-separated list
+ *                  of OID types and values:
+ *                  e.g. "C=NL,O=Offspark,CN=PolarSSL CA"
+ *
+ * \param ctx           CRT context to use
+ * \param issuer_name   issuer name to set
+ *
+ * \return          0 if issuer name was parsed successfully, or
+ *                  a specific error code
+ */
+int x509write_crt_set_issuer_name( x509write_cert *ctx, char *issuer_name );
+
+/**
+ * \brief           Set the subject name for a Certificate
+ *                  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           CRT 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_crt_set_subject_name( x509write_cert *ctx, char *subject_name );
+
+/**
+ * \brief           Set the subject public key for the certificate
+ *
+ * \param ctx       CRT context to use
+ * \param key       public key to include
+ */
+void x509write_crt_set_subject_key( x509write_cert *ctx, pk_context *key );
+
+/**
+ * \brief           Set the issuer key used for signing the certificate
+ *
+ * \param ctx       CRT context to use
+ * \param key       private key to sign with
+ */
+void x509write_crt_set_issuer_key( x509write_cert *ctx, pk_context *key );
+
+/**
+ * \brief           Set the MD algorithm to use for the signature
+ *                  (e.g. POLARSSL_MD_SHA1)
+ *
+ * \param ctx       CRT context to use
+ * \param md_ald    MD algorithm to use
+ */
+void x509write_crt_set_md_alg( x509write_cert *ctx, md_type_t md_alg );
+
+/**
+ * \brief           Generic function to add to or replace an extension in the
+ *                  CRT
+ *
+ * \param ctx       CRT context to use
+ * \param oid       OID of the extension
+ * \param oid_len   length of the OID
+ * \param critical  if the extension is critical (per the RFC's definition)
+ * \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_crt_set_extension( x509write_cert *ctx,
+                                 const char *oid, size_t oid_len,
+                                 int critical,
+                                 const unsigned char *val, size_t val_len );
+
+/**
+ * \brief           Set the basicConstraints extension for a CRT
+ *
+ * \param ctx       CRT context to use
+ * \param is_ca     is this a CA certificate
+ * \param max_pathlen   maximum length of certificate chains below this
+ *                      certificate (only for CA certificates, -1 is
+ *                      inlimited)
+ *
+ * \return          0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED
+ */
+int x509write_crt_set_basic_constraints( x509write_cert *ctx,
+                                         int is_ca, int max_pathlen );
+
+/**
+ * \brief           Set the subjectKeyIdentifier extension for a CRT
+ *                  Requires that x509write_crt_set_subject_key() has been
+ *                  called before
+ *
+ * \param ctx       CRT context to use
+ *
+ * \return          0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED
+ */
+int x509write_crt_set_subject_key_identifier( x509write_cert *ctx );
+
+/**
+ * \brief           Set the authorityKeyIdentifier extension for a CRT
+ *                  Requires that x509write_crt_set_issuer_key() has been
+ *                  called before
+ *
+ * \param ctx       CRT context to use
+ *
+ * \return          0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED
+ */
+int x509write_crt_set_authority_key_identifier( x509write_cert *ctx );
+
+/**
+ * \brief           Set the Key Usage Extension flags
+ *                  (e.g. KU_DIGITAL_SIGNATURE | KU_KEY_CERT_SIGN)
+ *
+ * \param ctx       CRT context to use
+ * \param key_usage key usage flags to set
+ *
+ * \return          0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED
+ */
+int x509write_crt_set_key_usage( x509write_cert *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           CRT 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_crt_set_ns_cert_type( x509write_cert *ctx,
+                                    unsigned char ns_cert_type );
+
+/**
+ * \brief           Free the contents of a CRT write context
+ *
+ * \param ctx       CRT context to free
+ */
+void x509write_crt_free( x509write_cert *ctx );
+
+/**
+ * \brief           Write a built up certificate to a X509 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 crt       certificate to write away
+ * \param buf       buffer to write to
+ * \param size      size of the buffer
+ * \param f_rng     RNG function (for signature, see note)
+ * \param p_rng     RNG parameter
+ *
+ * \return          length of data written if successful, or a specific
+ *                  error code
+ *
+ * \note            f_rng may be NULL if RSA is used for signature and the
+ *                  signature is made offline (otherwise f_rng is desirable
+ *                  for countermeasures against timing attacks).
+ *                  ECDSA signatures always require a non-NULL f_rng.
+ */
+int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng );
+
+/**
+ * \brief           Write a public key 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 key       public key 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 );
+int x509write_pubkey_der( pk_context *key, unsigned char *buf, size_t size );
 
 /**
- * \brief           Write a RSA key to a PKCS#1 DER structure
+ * \brief           Write a private key to a PKCS#1 or SEC1 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 key       private 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 );
+int x509write_key_der( pk_context *pk, unsigned char *buf, size_t size );
 
 /**
  * \brief           Write a CSR (Certificate Signing Request) to a
@@ -210,34 +429,63 @@
  * \param ctx       CSR to write away
  * \param buf       buffer to write to
  * \param size      size of the buffer
+ * \param f_rng     RNG function (for signature, see note)
+ * \param p_rng     RNG parameter
  *
  * \return          length of data written if successful, or a specific
  *                  error code
+ *
+ * \note            f_rng may be NULL if RSA is used for signature and the
+ *                  signature is made offline (otherwise f_rng is desirable
+ *                  for countermeasures against timing attacks).
+ *                  ECDSA signatures always require a non-NULL f_rng.
  */
-int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size );
+int x509write_csr_der( x509write_csr *ctx, unsigned char *buf, size_t size,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng );
 
 #if defined(POLARSSL_BASE64_C)
 /**
- * \brief           Write a RSA public key to a PKCS#1 PEM string
+ * \brief           Write a built up certificate to a X509 PEM string
  *
- * \param rsa       RSA to write away
+ * \param crt       certificate to write away
  * \param buf       buffer to write to
  * \param size      size of the buffer
+ * \param f_rng     RNG function (for signature, see note)
+ * \param p_rng     RNG parameter
  *
  * \return          0 successful, or a specific error code
+ *
+ * \note            f_rng may be NULL if RSA is used for signature and the
+ *                  signature is made offline (otherwise f_rng is desirable
+ *                  for countermeasures against timing attacks).
+ *                  ECDSA signatures always require a non-NULL f_rng.
  */
-int x509write_pubkey_pem( rsa_context *rsa, unsigned char *buf, size_t size );
+int x509write_crt_pem( x509write_cert *ctx, unsigned char *buf, size_t size,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng );
 
 /**
- * \brief           Write a RSA key to a PKCS#1 PEM string
+ * \brief           Write a public key to a PEM string
  *
- * \param rsa       RSA to write away
+ * \param key       public key 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 );
+int x509write_pubkey_pem( pk_context *key, unsigned char *buf, size_t size );
+
+/**
+ * \brief           Write a private key to a PKCS#1 or SEC1 PEM string
+ *
+ * \param key       private 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( pk_context *key, unsigned char *buf, size_t size );
 
 /**
  * \brief           Write a CSR (Certificate Signing Request) to a
@@ -246,10 +494,19 @@
  * \param ctx       CSR to write away
  * \param buf       buffer to write to
  * \param size      size of the buffer
+ * \param f_rng     RNG function (for signature, see note)
+ * \param p_rng     RNG parameter
  *
  * \return          0 successful, or a specific error code
+ *
+ * \note            f_rng may be NULL if RSA is used for signature and the
+ *                  signature is made offline (otherwise f_rng is desirable
+ *                  for couermeasures against timing attacks).
+ *                  ECDSA signatures always require a non-NULL f_rng.
  */
-int x509write_csr_pem( x509_csr *ctx, unsigned char *buf, size_t size );
+int x509write_csr_pem( x509write_csr *ctx, unsigned char *buf, size_t size,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng );
 #endif /* POLARSSL_BASE64_C */
 
 #ifdef __cplusplus
diff --git a/library/asn1parse.c b/library/asn1parse.c
index f6b271e..9573599 100644
--- a/library/asn1parse.c
+++ b/library/asn1parse.c
@@ -354,6 +354,18 @@
     memset( cur, 0, sizeof( asn1_named_data ) );
 }
 
+void asn1_free_named_data_list( asn1_named_data **head )
+{
+    asn1_named_data *cur;
+
+    while( ( cur = *head ) != NULL )
+    {
+        *head = cur->next;
+        asn1_free_named_data( cur );
+        polarssl_free( cur );
+    }
+}
+
 asn1_named_data *asn1_find_named_data( asn1_named_data *list,
                                        const char *oid, size_t len )
 {
diff --git a/library/asn1write.c b/library/asn1write.c
index 463c730..d4c1d8d 100644
--- a/library/asn1write.c
+++ b/library/asn1write.c
@@ -29,6 +29,14 @@
 
 #include "polarssl/asn1write.h"
 
+#if defined(POLARSSL_MEMORY_C)
+#include "polarssl/memory.h"
+#else
+#include <stdlib.h>
+#define polarssl_malloc     malloc
+#define polarssl_free       free
+#endif
+
 int asn1_write_len( unsigned char **p, unsigned char *start, size_t len )
 {
     if( len < 0x80 )
@@ -135,14 +143,14 @@
     return( len );
 }
 
-int asn1_write_oid( unsigned char **p, unsigned char *start, const char *oid )
+int asn1_write_oid( unsigned char **p, unsigned char *start,
+                    const char *oid, size_t oid_len )
 {
     int ret;
     size_t len = 0;
 
     ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
-                  (const unsigned char *) oid, strlen( oid ) ) );
-
+                                  (const unsigned char *) oid, oid_len ) );
     ASN1_CHK_ADD( len , asn1_write_len( p, start, len ) );
     ASN1_CHK_ADD( len , asn1_write_tag( p, start, ASN1_OID ) );
 
@@ -150,29 +158,43 @@
 }
 
 int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
-                                     const char *oid )
+                                     const char *oid, size_t oid_len,
+                                     size_t par_len )
 {
     int ret;
-    size_t null_len = 0;
-    size_t oid_len = 0;
     size_t len = 0;
 
-    // Write NULL
-    //
-    ASN1_CHK_ADD( null_len, asn1_write_null( p, start ) );
+    if( par_len == 0 )
+        ASN1_CHK_ADD( len, asn1_write_null( p, start ) );
+    else
+        len += par_len;
 
-    // Write OID
-    //
-    ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, oid ) );
+    ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_len ) );
 
-    len = oid_len + null_len;
-    ASN1_CHK_ADD( len, asn1_write_len( p, start, oid_len + null_len ) );
+    ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
     ASN1_CHK_ADD( len, asn1_write_tag( p, start,
                                        ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
 
     return( len );
 }
 
+int asn1_write_bool( unsigned char **p, unsigned char *start, int boolean )
+{
+    int ret;
+    size_t len = 0;
+
+    if( *p - start < 1 )
+        return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+
+    *--(*p) = (boolean) ? 1 : 0;
+    len++;
+
+    ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_BOOLEAN ) );
+
+    return( len );
+}
+
 int asn1_write_int( unsigned char **p, unsigned char *start, int val )
 {
     int ret;
@@ -204,13 +226,13 @@
 }
 
 int asn1_write_printable_string( unsigned char **p, unsigned char *start,
-                                 char *text )
+                                 const char *text, size_t text_len )
 {
     int ret;
     size_t len = 0;
 
     ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
-                  (const unsigned char *) text, strlen( text ) ) );
+                  (const unsigned char *) text, text_len ) );
 
     ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
     ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_PRINTABLE_STRING ) );
@@ -219,13 +241,13 @@
 }
 
 int asn1_write_ia5_string( unsigned char **p, unsigned char *start,
-                           char *text )
+                           const char *text, size_t text_len )
 {
     int ret;
     size_t len = 0;
 
     ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
-                  (const unsigned char *) text, strlen( text ) ) );
+                  (const unsigned char *) text, text_len ) );
 
     ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
     ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_IA5_STRING ) );
@@ -273,4 +295,65 @@
 
     return( len );
 }
+
+asn1_named_data *asn1_store_named_data( asn1_named_data **head,
+                                        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( *head, oid, oid_len ) ) == NULL )
+    {
+        // Add new entry if not present yet based on OID
+        //
+        if( ( cur = polarssl_malloc( sizeof(asn1_named_data) ) ) == NULL )
+            return( NULL );
+
+        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( NULL );
+        }
+
+        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( NULL );
+        }
+
+        memcpy( cur->oid.p, oid, oid_len );
+
+        cur->next = *head;
+        *head = cur;
+    }
+    else if( cur->val.len < val_len )
+    {
+        // Enlarge existing value buffer if needed
+        //
+        polarssl_free( cur->val.p );
+        cur->val.p = NULL;
+
+        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( NULL );
+        }
+    }
+
+    if( val != NULL )
+        memcpy( cur->val.p, val, val_len );
+
+    return( cur );
+}
 #endif
diff --git a/library/oid.c b/library/oid.c
index c5608c3..81b313e 100644
--- a/library/oid.c
+++ b/library/oid.c
@@ -93,12 +93,13 @@
  * attribute from a oid_descriptor_t wrapper.
  */
 #define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1)   \
-int FN_NAME( ATTR1_TYPE ATTR1, const char **oid_str )                       \
+int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen )             \
 {                                                                           \
     const TYPE_T *cur = LIST;                                               \
     while( cur->descriptor.asn1 != NULL ) {                                 \
         if( cur->ATTR1 == ATTR1 ) {                                         \
-            *oid_str = cur->descriptor.asn1;                                \
+            *oid = cur->descriptor.asn1;                                    \
+            *olen = cur->descriptor.asn1_len;                               \
             return( 0 );                                                    \
         }                                                                   \
         cur++;                                                              \
@@ -112,12 +113,14 @@
  */
 #define FN_OID_GET_OID_BY_ATTR2(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1,   \
                                 ATTR2_TYPE, ATTR2)                          \
-int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid_str )     \
+int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid ,         \
+             size_t *olen )                                                 \
 {                                                                           \
     const TYPE_T *cur = LIST;                                               \
     while( cur->descriptor.asn1 != NULL ) {                                 \
         if( cur->ATTR1 == ATTR1 && cur->ATTR2 == ATTR2 ) {                  \
-            *oid_str = cur->descriptor.asn1;                                \
+            *oid = cur->descriptor.asn1;                                    \
+            *olen = cur->descriptor.asn1_len;                               \
             return( 0 );                                                    \
         }                                                                   \
         cur++;                                                              \
@@ -365,7 +368,9 @@
 
 FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg);
 FN_OID_GET_ATTR1(oid_get_pk_alg, oid_pk_alg_t, pk_alg, pk_type_t, pk_alg);
+FN_OID_GET_OID_BY_ATTR1(oid_get_oid_by_pk_alg, oid_pk_alg_t, oid_pk_alg, pk_type_t, pk_alg);
 
+#if defined(POLARSSL_ECP_C)
 /*
  * For namedCurve (RFC 5480)
  */
@@ -404,6 +409,8 @@
 
 FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp);
 FN_OID_GET_ATTR1(oid_get_ec_grp, oid_ecp_grp_t, grp_id, ecp_group_id, grp_id);
+FN_OID_GET_OID_BY_ATTR1(oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, ecp_group_id, grp_id);
+#endif /* POLARSSL_ECP_C */
 
 #if defined(POLARSSL_CIPHER_C)
 /*
diff --git a/library/pk.c b/library/pk.c
index 77f5034..80eccc9 100644
--- a/library/pk.c
+++ b/library/pk.c
@@ -273,4 +273,15 @@
     return( ctx->pk_info->name );
 }
 
+/*
+ * Access the PK type
+ */
+pk_type_t pk_get_type( const pk_context *ctx )
+{
+    if( ctx == NULL || ctx->pk_info == NULL )
+        return( POLARSSL_PK_NONE );
+
+    return( ctx->pk_info->type );
+}
+
 #endif /* POLARSSL_PK_C */
diff --git a/library/rsa.c b/library/rsa.c
index c82ffaa..d39a09b 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -935,10 +935,9 @@
         if( md_info == NULL )
             return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
 
-        if( oid_get_oid_by_md( md_alg, &oid ) != 0 )
+        if( oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
             return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
 
-        oid_size = strlen( oid );
         nb_pad -= 10 + oid_size;
 
         hashlen = md_get_size( md_info );
diff --git a/library/x509parse.c b/library/x509parse.c
index 55cc9e3..d606615 100644
--- a/library/x509parse.c
+++ b/library/x509parse.c
@@ -132,6 +132,29 @@
 }
 
 /*
+ *  Version  ::=  INTEGER  {  v1(0)  }
+ */
+static int x509_csr_get_version( unsigned char **p,
+                             const unsigned char *end,
+                             int *ver )
+{
+    int ret;
+
+    if( ( ret = asn1_get_int( p, end, ver ) ) != 0 )
+    {
+        if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+        {
+            *ver = 0;
+            return( 0 );
+        }
+
+        return( POLARSSL_ERR_X509_CERT_INVALID_VERSION + ret );
+    }
+
+    return( 0 );
+}
+
+/*
  *  CertificateSerialNumber  ::=  INTEGER
  */
 static int x509_get_serial( unsigned char **p,
@@ -1625,6 +1648,205 @@
 }
 
 /*
+ * Parse a CSR
+ */
+int x509parse_csr( x509_csr *csr, const unsigned char *buf, size_t buflen )
+{
+    int ret;
+    size_t len;
+    unsigned char *p, *end;
+#if defined(POLARSSL_PEM_C)
+    size_t use_len;
+    pem_context pem;
+#endif
+
+    /*
+     * Check for valid input
+     */
+    if( csr == NULL || buf == NULL )
+        return( POLARSSL_ERR_X509_INVALID_INPUT );
+
+    memset( csr, 0, sizeof( x509_csr ) );
+
+#if defined(POLARSSL_PEM_C)
+    pem_init( &pem );
+    ret = pem_read_buffer( &pem,
+                           "-----BEGIN CERTIFICATE REQUEST-----",
+                           "-----END CERTIFICATE REQUEST-----",
+                           buf, NULL, 0, &use_len );
+
+    if( ret == 0 )
+    {
+        /*
+         * Was PEM encoded
+         */
+        buflen -= use_len;
+        buf += use_len;
+
+        /*
+         * Steal PEM buffer
+         */
+        p = pem.buf;
+        pem.buf = NULL;
+        len = pem.buflen;
+        pem_free( &pem );
+    }
+    else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+    {
+        pem_free( &pem );
+        return( ret );
+    }
+    else
+#endif
+    {
+        /*
+         * nope, copy the raw DER data
+         */
+        p = (unsigned char *) polarssl_malloc( len = buflen );
+
+        if( p == NULL )
+            return( POLARSSL_ERR_X509_MALLOC_FAILED );
+
+        memcpy( p, buf, buflen );
+
+        buflen = 0;
+    }
+
+    csr->raw.p = p;
+    csr->raw.len = len;
+    end = p + len;
+
+    /*
+     *  CertificationRequest ::= SEQUENCE {
+     *       certificationRequestInfo CertificationRequestInfo,
+     *       signatureAlgorithm AlgorithmIdentifier,
+     *       signature          BIT STRING
+     *  }
+     */
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        x509_csr_free( csr );
+        return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT );
+    }
+
+    if( len != (size_t) ( end - p ) )
+    {
+        x509_csr_free( csr );
+        return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
+                POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+    }
+
+    /*
+     *  CertificationRequestInfo ::= SEQUENCE {
+     */
+    csr->cri.p = p;
+
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        x509_csr_free( csr );
+        return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+    }
+
+    end = p + len;
+    csr->cri.len = end - csr->cri.p;
+
+    /*
+     *  Version  ::=  INTEGER {  v1(0) }
+     */
+    if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 )
+    {
+        x509_csr_free( csr );
+        return( ret );
+    }
+
+    csr->version++;
+
+    if( csr->version != 1 )
+    {
+        x509_csr_free( csr );
+        return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION );
+    }
+
+    /*
+     *  subject               Name
+     */
+    csr->subject_raw.p = p;
+
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        x509_csr_free( csr );
+        return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+    }
+
+    if( ( ret = x509_get_name( &p, p + len, &csr->subject ) ) != 0 )
+    {
+        x509_csr_free( csr );
+        return( ret );
+    }
+
+    csr->subject_raw.len = p - csr->subject_raw.p;
+
+    /*
+     *  subjectPKInfo SubjectPublicKeyInfo
+     */
+    if( ( ret = x509_get_pubkey( &p, end, &csr->pk ) ) != 0 )
+    {
+        x509_csr_free( csr );
+        return( ret );
+    }
+
+    /*
+     *  attributes    [0] Attributes
+     */
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC ) ) != 0 )
+    {
+        x509_csr_free( csr );
+        return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+    }
+    // TODO Parse Attributes / extension requests
+
+    p += len;
+
+    end = csr->raw.p + csr->raw.len;
+
+    /*
+     *  signatureAlgorithm   AlgorithmIdentifier,
+     *  signature            BIT STRING
+     */
+    if( ( ret = x509_get_alg_null( &p, end, &csr->sig_oid ) ) != 0 )
+    {
+        x509_csr_free( csr );
+        return( ret );
+    }
+
+    if( ( ret = x509_get_sig_alg( &csr->sig_oid, &csr->sig_md,
+                                  &csr->sig_pk ) ) != 0 )
+    {
+        x509_csr_free( csr );
+        return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG );
+    }
+
+    if( ( ret = x509_get_sig( &p, end, &csr->sig ) ) != 0 )
+    {
+        x509_csr_free( csr );
+        return( ret );
+    }
+
+    if( p != end )
+    {
+        x509_csr_free( csr );
+        return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
+                POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+    }
+
+    return( 0 );
+}
+
+/*
  * Parse one or more CRLs and add them to the chained list
  */
 int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen )
@@ -1695,6 +1917,7 @@
         return( ret );
     }
     else
+#endif
     {
         /*
          * nope, copy the raw DER data
@@ -1708,16 +1931,6 @@
 
         buflen = 0;
     }
-#else
-    p = (unsigned char *) polarssl_malloc( len = buflen );
-
-    if( p == NULL )
-        return( POLARSSL_ERR_X509_MALLOC_FAILED );
-
-    memcpy( p, buf, buflen );
-
-    buflen = 0;
-#endif
 
     crl->raw.p = p;
     crl->raw.len = len;
@@ -2076,6 +2289,26 @@
 }
 
 /*
+ * Load a CSR into the structure
+ */
+int x509parse_csrfile( x509_csr *csr, const char *path )
+{
+    int ret;
+    size_t n;
+    unsigned char *buf;
+
+    if ( ( ret = load_file( path, &buf, &n ) ) != 0 )
+        return( ret );
+
+    ret = x509parse_csr( csr, buf, n );
+
+    memset( buf, 0, n + 1 );
+    polarssl_free( buf );
+
+    return( ret );
+}
+
+/*
  * Load one or more CRLs and add them to the chained list
  */
 int x509parse_crlfile( x509_crl *chain, const char *path )
@@ -2291,7 +2524,7 @@
     unsigned char *end2;
 
     /*
-     * RFC 5915, orf SEC1 Appendix C.4
+     * RFC 5915, or SEC1 Appendix C.4
      *
      * ECPrivateKey ::= SEQUENCE {
      *      version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
@@ -3288,6 +3521,53 @@
 }
 
 /*
+ * Return an informational string about the CSR.
+ */
+int x509parse_csr_info( char *buf, size_t size, const char *prefix,
+                        const x509_csr *csr )
+{
+    int ret;
+    size_t n;
+    char *p;
+    const char *desc;
+    char key_size_str[BEFORE_COLON];
+
+    p = buf;
+    n = size;
+
+    ret = snprintf( p, n, "%sCSR version   : %d",
+                               prefix, csr->version );
+    SAFE_SNPRINTF();
+
+    ret = snprintf( p, n, "\n%ssubject name  : ", prefix );
+    SAFE_SNPRINTF();
+    ret = x509parse_dn_gets( p, n, &csr->subject );
+    SAFE_SNPRINTF();
+
+    ret = snprintf( p, n, "\n%ssigned using  : ", prefix );
+    SAFE_SNPRINTF();
+
+    ret = oid_get_sig_alg_desc( &csr->sig_oid, &desc );
+    if( ret != 0 )
+        ret = snprintf( p, n, "???"  );
+    else
+        ret = snprintf( p, n, "%s", desc );
+    SAFE_SNPRINTF();
+
+    if( ( ret = x509_key_size_helper( key_size_str, BEFORE_COLON,
+                                      pk_get_name( &csr->pk ) ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    ret = snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str,
+                          (int) pk_get_size( &csr->pk ) );
+    SAFE_SNPRINTF();
+
+    return( (int) ( size - n ) );
+}
+
+/*
  * Return 0 if the x509_time is still valid, or 1 otherwise.
  */
 #if defined(POLARSSL_HAVE_TIME)
@@ -3947,6 +4227,37 @@
     while( crl_cur != NULL );
 }
 
+/*
+ * Unallocate all CSR data
+ */
+void x509_csr_free( x509_csr *csr )
+{
+    x509_name *name_cur;
+    x509_name *name_prv;
+
+    if( csr == NULL )
+        return;
+
+    pk_free( &csr->pk );
+
+    name_cur = csr->subject.next;
+    while( name_cur != NULL )
+    {
+        name_prv = name_cur;
+        name_cur = name_cur->next;
+        memset( name_prv, 0, sizeof( x509_name ) );
+        polarssl_free( name_prv );
+    }
+
+    if( csr->raw.p != NULL )
+    {
+        memset( csr->raw.p, 0, csr->raw.len );
+        polarssl_free( csr->raw.p );
+    }
+
+    memset( csr, 0, sizeof( x509_csr ) );
+}
+
 #if defined(POLARSSL_SELF_TEST)
 
 #include "polarssl/certs.h"
diff --git a/library/x509write.c b/library/x509write.c
index 7e04e12..d4861d7 100644
--- a/library/x509write.c
+++ b/library/x509write.c
@@ -23,6 +23,13 @@
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+/*
+ * References:
+ * - certificates: RFC 5280, updated by RFC 6818
+ * - CSRs: PKCS#10 v1.7 aka RFC 2986
+ * - attributes: PKCS#9 v2.0 aka RFC 2985
+ */
+
 #include "polarssl/config.h"
 
 #if defined(POLARSSL_X509_WRITE_C)
@@ -33,6 +40,8 @@
 #include "polarssl/md.h"
 #include "polarssl/oid.h"
 
+#include "polarssl/sha1.h"
+
 #if defined(POLARSSL_BASE64_C)
 #include "polarssl/base64.h"
 #endif
@@ -45,57 +54,17 @@
 #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 )
+static int x509write_string_to_names( asn1_named_data **head, char *name )
 {
     int ret = 0;
-    char *s = subject_name, *c = s;
+    char *s = name, *c = s;
     char *end = s + strlen( s );
     char *oid = NULL;
     int in_tag = 1;
-    x509_req_name *cur;
+    asn1_named_data *cur;
 
-    while( ctx->subject )
-    {
-        cur = ctx->subject;
-        ctx->subject = ctx->subject->next;
-        polarssl_free( cur );
-    }
+    /* Clear existing chain if present */
+    asn1_free_named_data_list( head );
 
     while( c <= end )
     {
@@ -127,27 +96,15 @@
 
         if( !in_tag && ( *c == ',' || c == end ) )
         {
-            if( c - s > 127 )
+            if( ( cur = asn1_store_named_data( head, oid, strlen( oid ),
+                                               (unsigned char *) s,
+                                               c - s ) ) == NULL )
             {
-                ret = POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA;
-                goto exit;
+                return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
             }
 
-            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 );
+            while( c < end && *(c + 1) == ' ' )
+                c++;
 
             s = c + 1;
             in_tag = 1;
@@ -160,64 +117,158 @@
     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 )
+#if defined(POLARSSL_RSA_C)
+/*
+ *  RSAPublicKey ::= SEQUENCE {
+ *      modulus           INTEGER,  -- n
+ *      publicExponent    INTEGER   -- e
+ *  }
+ */
+static int x509_write_rsa_pubkey( unsigned char **p, unsigned char *start,
+                                  rsa_context *rsa )
+{
+    int ret;
+    size_t len = 0;
+
+    ASN1_CHK_ADD( len, asn1_write_mpi( p, start, &rsa->E ) );
+    ASN1_CHK_ADD( len, asn1_write_mpi( p, start, &rsa->N ) );
+
+    ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+    return( len );
+}
+#endif /* POLARSSL_RSA_C */
+
+#if defined(POLARSSL_ECP_C)
+/*
+ * EC public key is an EC point
+ */
+static int x509_write_ec_pubkey( unsigned char **p, unsigned char *start,
+                                 ecp_keypair *ec )
+{
+    int ret;
+    size_t len = 0;
+    unsigned char buf[POLARSSL_ECP_MAX_PT_LEN];
+
+    if( ( ret = ecp_point_write_binary( &ec->grp, &ec->Q,
+                                        POLARSSL_ECP_PF_UNCOMPRESSED,
+                                        &len, buf, sizeof( buf ) ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    if( *p - start < (int) len )
+        return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+
+    *p -= len;
+    memcpy( *p, buf, len );
+
+    return( len );
+}
+
+/*
+ * ECParameters ::= CHOICE {
+ *   namedCurve         OBJECT IDENTIFIER
+ * }
+ */
+static int x509_write_ec_param( unsigned char **p, unsigned char *start,
+                                ecp_keypair *ec )
+{
+    int ret;
+    size_t len = 0;
+    const char *oid;
+    size_t oid_len;
+
+    if( ( ret = oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 )
+        return( ret );
+
+    ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_len ) );
+
+    return( len );
+}
+#endif /* POLARSSL_ECP_C */
+
+static int x509_write_pubkey( unsigned char **p, unsigned char *start,
+                              const pk_context *key )
+{
+    int ret;
+    size_t len = 0;
+
+#if defined(POLARSSL_RSA_C)
+    if( pk_get_type( key ) == POLARSSL_PK_RSA )
+        ASN1_CHK_ADD( len, x509_write_rsa_pubkey( p, start, pk_rsa( *key ) ) );
+    else
+#endif
+#if defined(POLARSSL_ECP_C)
+    if( pk_get_type( key ) == POLARSSL_PK_ECKEY )
+        ASN1_CHK_ADD( len, x509_write_ec_pubkey( p, start, pk_ec( *key ) ) );
+    else
+#endif
+        return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
+
+    return( len );
+}
+
+void x509write_csr_init( x509write_csr *ctx )
+{
+    memset( ctx, 0, sizeof(x509write_csr) );
+}
+
+void x509write_csr_free( x509write_csr *ctx )
+{
+    asn1_free_named_data_list( &ctx->subject );
+    asn1_free_named_data_list( &ctx->extensions );
+
+    memset( ctx, 0, sizeof(x509write_csr) );
+}
+
+void x509write_csr_set_md_alg( x509write_csr *ctx, md_type_t md_alg )
+{
+    ctx->md_alg = md_alg;
+}
+
+void x509write_csr_set_key( x509write_csr *ctx, pk_context *key )
+{
+    ctx->key = key;
+}
+
+int x509write_csr_set_subject_name( x509write_csr *ctx, char *subject_name )
+{
+    return x509write_string_to_names( &ctx->subject, subject_name );
+}
+
+/* The first byte of the value in the asn1_named_data structure is reserved
+ * to store the critical boolean for us
+ */
+static int x509_set_extension( asn1_named_data **head,
+                               const char *oid, size_t oid_len,
+                               int critical,
+                               const unsigned char *val, size_t val_len )
 {
     asn1_named_data *cur;
 
-    if( ( cur = asn1_find_named_data( ctx->extensions, oid,
-                                      oid_len ) ) == NULL )
+    if( ( cur = asn1_store_named_data( head, oid, oid_len,
+                                       NULL, val_len + 1 ) ) == 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;
+        return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
     }
 
-    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 );
+    cur->val.p[0] = critical;
+    memcpy( cur->val.p + 1, val, val_len );
 
     return( 0 );
 }
 
-int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage )
+int x509write_csr_set_extension( x509write_csr *ctx,
+                                 const char *oid, size_t oid_len,
+                                 const unsigned char *val, size_t val_len )
+{
+    return x509_set_extension( &ctx->extensions, oid, oid_len,
+                               0, val, val_len );
+}
+
+int x509write_csr_set_key_usage( x509write_csr *ctx, unsigned char key_usage )
 {
     unsigned char buf[4];
     unsigned char *c;
@@ -237,7 +288,8 @@
     return( 0 );
 }
 
-int x509write_csr_set_ns_cert_type( x509_csr *ctx, unsigned char ns_cert_type )
+int x509write_csr_set_ns_cert_type( x509write_csr *ctx,
+                                    unsigned char ns_cert_type )
 {
     unsigned char buf[4];
     unsigned char *c;
@@ -257,26 +309,214 @@
     return( 0 );
 }
 
-int x509write_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size )
+void x509write_crt_init( x509write_cert *ctx )
+{
+    memset( ctx, 0, sizeof(x509write_cert) );
+
+    mpi_init( &ctx->serial );
+    ctx->version = X509_CRT_VERSION_3;
+}
+
+void x509write_crt_free( x509write_cert *ctx )
+{
+    mpi_free( &ctx->serial );
+
+    asn1_free_named_data_list( &ctx->subject );
+    asn1_free_named_data_list( &ctx->issuer );
+    asn1_free_named_data_list( &ctx->extensions );
+
+    memset( ctx, 0, sizeof(x509write_csr) );
+}
+
+void x509write_crt_set_md_alg( x509write_cert *ctx, md_type_t md_alg )
+{
+    ctx->md_alg = md_alg;
+}
+
+void x509write_crt_set_subject_key( x509write_cert *ctx, pk_context *key )
+{
+    ctx->subject_key = key;
+}
+
+void x509write_crt_set_issuer_key( x509write_cert *ctx, pk_context *key )
+{
+    ctx->issuer_key = key;
+}
+
+int x509write_crt_set_subject_name( x509write_cert *ctx, char *subject_name )
+{
+    return x509write_string_to_names( &ctx->subject, subject_name );
+}
+
+int x509write_crt_set_issuer_name( x509write_cert *ctx, char *issuer_name )
+{
+    return x509write_string_to_names( &ctx->issuer, issuer_name );
+}
+
+int x509write_crt_set_serial( x509write_cert *ctx, const mpi *serial )
 {
     int ret;
-    unsigned char *c;
+
+    if( ( ret = mpi_copy( &ctx->serial, serial ) ) != 0 )
+        return( ret );
+
+    return( 0 );
+}
+
+int x509write_crt_set_validity( x509write_cert *ctx, char *not_before,
+                                char *not_after )
+{
+    if( strlen(not_before) != X509_RFC5280_UTC_TIME_LEN - 1 ||
+        strlen(not_after)  != X509_RFC5280_UTC_TIME_LEN - 1 )
+    {
+        return( POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA );
+    }
+    strncpy( ctx->not_before, not_before, X509_RFC5280_UTC_TIME_LEN );
+    strncpy( ctx->not_after , not_after , X509_RFC5280_UTC_TIME_LEN );
+    ctx->not_before[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
+    ctx->not_after[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
+
+    return( 0 );
+}
+
+int x509write_crt_set_extension( x509write_cert *ctx,
+                                 const char *oid, size_t oid_len,
+                                 int critical,
+                                 const unsigned char *val, size_t val_len )
+{
+    return x509_set_extension( &ctx->extensions, oid, oid_len,
+                               critical, val, val_len );
+}
+
+int x509write_crt_set_basic_constraints( x509write_cert *ctx,
+                                         int is_ca, int max_pathlen )
+{
+    int ret;
+    unsigned char buf[9];
+    unsigned char *c = buf + sizeof(buf);
     size_t len = 0;
 
-    c = buf + size - 1;
+    memset( buf, 0, sizeof(buf) );
 
-    /*
-    *  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 ) );
+    if( is_ca && max_pathlen > 127 )
+        return( POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA );
+
+    if( is_ca )
+    {
+        if( max_pathlen >= 0 )
+        {
+            ASN1_CHK_ADD( len, asn1_write_int( &c, buf, max_pathlen ) );
+        }
+        ASN1_CHK_ADD( len, asn1_write_bool( &c, buf, 1 ) );
+    }
 
     ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
     ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
 
+    return x509write_crt_set_extension( ctx, OID_BASIC_CONSTRAINTS,
+                                        OID_SIZE( OID_BASIC_CONSTRAINTS ),
+                                        0, buf + sizeof(buf) - len, len );
+}
+
+int x509write_crt_set_subject_key_identifier( x509write_cert *ctx )
+{
+    int ret;
+    unsigned char buf[POLARSSL_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
+    unsigned char *c = buf + sizeof(buf);
+    size_t len = 0;
+
+    memset( buf, 0, sizeof(buf));
+    ASN1_CHK_ADD( len, x509_write_pubkey( &c, buf, ctx->subject_key ) );
+
+    sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 );
+    c = buf + sizeof(buf) - 20;
+    len = 20;
+
+    ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_OCTET_STRING ) );
+
+    return x509write_crt_set_extension( ctx, OID_SUBJECT_KEY_IDENTIFIER,
+                                        OID_SIZE( OID_SUBJECT_KEY_IDENTIFIER ),
+                                        0, buf + sizeof(buf) - len, len );
+}
+
+int x509write_crt_set_authority_key_identifier( x509write_cert *ctx )
+{
+    int ret;
+    unsigned char buf[POLARSSL_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
+    unsigned char *c = buf + sizeof(buf);
+    size_t len = 0;
+
+    memset( buf, 0, sizeof(buf));
+    ASN1_CHK_ADD( len, x509_write_pubkey( &c, buf, ctx->issuer_key ) );
+
+    sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 );
+    c = buf + sizeof(buf) - 20;
+    len = 20;
+
+    ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONTEXT_SPECIFIC | 0 ) );
+
+    ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+    return x509write_crt_set_extension( ctx, OID_AUTHORITY_KEY_IDENTIFIER,
+                                   OID_SIZE( OID_AUTHORITY_KEY_IDENTIFIER ),
+                                   0, buf + sizeof(buf) - len, len );
+}
+
+int x509write_crt_set_key_usage( x509write_cert *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_crt_set_extension( ctx, OID_KEY_USAGE,
+                                       OID_SIZE( OID_KEY_USAGE ),
+                                       1, buf, 4 );
+    if( ret != 0 )
+        return( ret );
+
+    return( 0 );
+}
+
+int x509write_crt_set_ns_cert_type( x509write_cert *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_crt_set_extension( ctx, OID_NS_CERT_TYPE,
+                                       OID_SIZE( OID_NS_CERT_TYPE ),
+                                       0, buf, 4 );
+    if( ret != 0 )
+        return( ret );
+
+    return( 0 );
+}
+
+int x509write_pubkey_der( pk_context *key, unsigned char *buf, size_t size )
+{
+    int ret;
+    unsigned char *c;
+    size_t len = 0, par_len = 0, oid_len;
+    const char *oid;
+
+    c = buf + size;
+
+    ASN1_CHK_ADD( len, x509_write_pubkey( &c, buf, key ) );
+
     if( c - buf < 1 )
         return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
 
@@ -291,7 +531,21 @@
     ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
     ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_BIT_STRING ) );
 
-    ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, buf, OID_PKCS1_RSA ) );
+    if( ( ret = oid_get_oid_by_pk_alg( pk_get_type( key ),
+                                       &oid, &oid_len ) ) != 0 )
+    {
+        return( ret );
+    }
+
+#if defined(POLARSSL_ECP_C)
+    if( pk_get_type( key ) == POLARSSL_PK_ECKEY )
+    {
+        ASN1_CHK_ADD( par_len, x509_write_ec_param( &c, buf, pk_ec( *key ) ) );
+    }
+#endif
+
+    ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, buf, oid, oid_len,
+                                                        par_len ) );
 
     ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
     ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
@@ -299,75 +553,130 @@
     return( len );
 }
 
-int x509write_key_der( rsa_context *rsa, unsigned char *buf, size_t size )
+int x509write_key_der( pk_context *key, unsigned char *buf, size_t size )
 {
     int ret;
-    unsigned char *c;
+    unsigned char *c = buf + size;
     size_t len = 0;
 
-    c = buf + size - 1;
-
-    ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->QP ) );
-    ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DQ ) );
-    ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DP ) );
-    ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->Q ) );
-    ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->P ) );
-    ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->D ) );
-    ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->E ) );
-    ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->N ) );
-    ASN1_CHK_ADD( len, asn1_write_int( &c, buf, 0 ) );
-
-    ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
-    ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
-    // TODO: Make NON RSA Specific variant later on
-/*    *--c = 0;
-    len += 1;
-
-    len += asn1_write_len( &c, len);
-    len += asn1_write_tag( &c, ASN1_BIT_STRING );
-
-    len += asn1_write_oid( &c, OID_PKCS1_RSA );
-
-    len += asn1_write_int( &c, 0 );
-
-    len += asn1_write_len( &c, len);
-    len += asn1_write_tag( &c, ASN1_CONSTRUCTED | ASN1_SEQUENCE );*/
-
-/*    for(i = 0; i < len; ++i)
+#if defined(POLARSSL_RSA_C)
+    if( pk_get_type( key ) == POLARSSL_PK_RSA )
     {
-        if (i % 16 == 0 ) printf("\n");
-        printf("%02x ", c[i]);
+        rsa_context *rsa = pk_rsa( *key );
+
+        ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->QP ) );
+        ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DQ ) );
+        ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DP ) );
+        ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->Q ) );
+        ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->P ) );
+        ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->D ) );
+        ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->E ) );
+        ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->N ) );
+        ASN1_CHK_ADD( len, asn1_write_int( &c, buf, 0 ) );
+
+        ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
+        ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
     }
-    printf("\n");*/
+    else
+#endif
+#if defined(POLARSSL_ECP_C)
+    if( pk_get_type( key ) == POLARSSL_PK_ECKEY )
+    {
+        ecp_keypair *ec = pk_ec( *key );
+        size_t pub_len = 0, par_len = 0;
+
+        /*
+         * RFC 5915, or SEC1 Appendix C.4
+         *
+         * ECPrivateKey ::= SEQUENCE {
+         *      version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+         *      privateKey     OCTET STRING,
+         *      parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
+         *      publicKey  [1] BIT STRING OPTIONAL
+         *    }
+         */
+
+        /* publicKey */
+        ASN1_CHK_ADD( pub_len, x509_write_ec_pubkey( &c, buf, ec ) );
+
+        if( c - buf < 1 )
+            return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+        *--c = 0;
+        pub_len += 1;
+
+        ASN1_CHK_ADD( pub_len, asn1_write_len( &c, buf, pub_len ) );
+        ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, buf, ASN1_BIT_STRING ) );
+
+        ASN1_CHK_ADD( pub_len, asn1_write_len( &c, buf, pub_len ) );
+        ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, buf,
+                            ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1 ) );
+        len += pub_len;
+
+        /* parameters */
+        ASN1_CHK_ADD( par_len, x509_write_ec_param( &c, buf, ec ) );
+
+        ASN1_CHK_ADD( par_len, asn1_write_len( &c, buf, par_len ) );
+        ASN1_CHK_ADD( par_len, asn1_write_tag( &c, buf,
+                            ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) );
+        len += par_len;
+
+        /* privateKey: write as MPI then fix tag */
+        ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &ec->d ) );
+        *c = ASN1_OCTET_STRING;
+
+        /* version */
+        ASN1_CHK_ADD( len, asn1_write_int( &c, buf, 1 ) );
+
+        ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) );
+        ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+    }
+    else
+#endif
+        return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
 
     return( len );
 }
 
-static int x509_write_name( unsigned char **p, unsigned char *start, char *oid,
-                            char *name )
+/*
+ *  RelativeDistinguishedName ::=
+ *    SET OF AttributeTypeAndValue
+ *
+ *  AttributeTypeAndValue ::= SEQUENCE {
+ *    type     AttributeType,
+ *    value    AttributeValue }
+ *
+ *  AttributeType ::= OBJECT IDENTIFIER
+ *
+ *  AttributeValue ::= ANY DEFINED BY AttributeType
+ */
+static int x509_write_name( unsigned char **p, unsigned char *start,
+                            const char *oid, size_t oid_len,
+                            const unsigned char *name, size_t name_len )
 {
     int ret;
-    size_t string_len = 0;
-    size_t oid_len = 0;
     size_t len = 0;
 
     // Write PrintableString for all except OID_PKCS9_EMAIL
     //
-    if( OID_SIZE( OID_PKCS9_EMAIL ) == strlen( oid ) &&
-        memcmp( oid, OID_PKCS9_EMAIL, strlen( oid ) ) == 0 )
+    if( OID_SIZE( OID_PKCS9_EMAIL ) == oid_len &&
+        memcmp( oid, OID_PKCS9_EMAIL, oid_len ) == 0 )
     {
-        ASN1_CHK_ADD( string_len, asn1_write_ia5_string( p, start, name ) );
+        ASN1_CHK_ADD( len, asn1_write_ia5_string( p, start,
+                                                  (const char *) name,
+                                                  name_len ) );
     }
     else
-        ASN1_CHK_ADD( string_len, asn1_write_printable_string( p, start, name ) );
+    {
+        ASN1_CHK_ADD( len, asn1_write_printable_string( p, start,
+                                                        (const char *) name,
+                                                        name_len ) );
+    }
 
     // Write OID
     //
-    ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, oid ) );
+    ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_len ) );
 
-    len = oid_len + string_len;
-    ASN1_CHK_ADD( len, asn1_write_len( p, start, oid_len + string_len ) );
+    ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
     ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
 
     ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
@@ -376,8 +685,30 @@
     return( len );
 }
 
+static int x509_write_names( unsigned char **p, unsigned char *start,
+                             asn1_named_data *first )
+{
+    int ret;
+    size_t len = 0;
+    asn1_named_data *cur = first;
+
+    while( cur != NULL )
+    {
+        ASN1_CHK_ADD( len, x509_write_name( p, start, (char *) cur->oid.p,
+                                            cur->oid.len,
+                                            cur->val.p, cur->val.len ) );
+        cur = cur->next;
+    }
+
+    ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+    return( len );
+}
+
 static int x509_write_sig( unsigned char **p, unsigned char *start,
-                           const char *oid, unsigned char *sig, size_t size )
+                           const char *oid, size_t oid_len,
+                           unsigned char *sig, size_t size )
 {
     int ret;
     size_t len = 0;
@@ -397,47 +728,115 @@
 
     // Write OID
     //
-    ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( p, start, oid ) );
+    ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( p, start, oid,
+                                                        oid_len, 0 ) );
 
     return( len );
 }
 
-int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size )
+static int x509_write_time( unsigned char **p, unsigned char *start,
+                            const char *time, size_t size )
+{
+    int ret;
+    size_t len = 0;
+
+    /*
+     * write ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
+     */
+    if( time[0] == '2' && time[1] == '0' && time [2] < '5' )
+    {
+        ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
+                                             (const unsigned char *) time + 2,
+                                             size - 2 ) );
+        ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+        ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_UTC_TIME ) );
+    }
+    else
+    {
+        ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
+                                                  (const unsigned char *) time,
+                                                  size ) );
+        ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+        ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_GENERALIZED_TIME ) );
+    }
+
+    return( len );
+}
+
+static int x509_write_extension( unsigned char **p, unsigned char *start,
+                                 asn1_named_data *ext )
+{
+    int ret;
+    size_t len = 0;
+
+    ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, ext->val.p + 1,
+                                              ext->val.len - 1 ) );
+    ASN1_CHK_ADD( len, asn1_write_len( p, start, ext->val.len - 1 ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_OCTET_STRING ) );
+
+    if( ext->val.p[0] != 0 )
+    {
+        ASN1_CHK_ADD( len, asn1_write_bool( p, start, 1 ) );
+    }
+
+    ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, ext->oid.p,
+                                              ext->oid.len ) );
+    ASN1_CHK_ADD( len, asn1_write_len( p, start, ext->oid.len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_OID ) );
+
+    ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+    return( len );
+}
+
+/*
+ * Extension  ::=  SEQUENCE  {
+ *     extnID      OBJECT IDENTIFIER,
+ *     critical    BOOLEAN DEFAULT FALSE,
+ *     extnValue   OCTET STRING
+ *                 -- contains the DER encoding of an ASN.1 value
+ *                 -- corresponding to the extension type identified
+ *                 -- by extnID
+ *     }
+ */
+static int x509_write_extensions( unsigned char **p, unsigned char *start,
+                                 asn1_named_data *first )
+{
+    int ret;
+    size_t len = 0;
+    asn1_named_data *cur_ext = first;
+
+    while( cur_ext != NULL )
+    {
+        ASN1_CHK_ADD( len, x509_write_extension( p, start, cur_ext ) );
+        cur_ext = cur_ext->next;
+    }
+
+    return( len );
+}
+
+int x509write_csr_der( x509write_csr *ctx, unsigned char *buf, size_t size,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng )
 {
     int ret;
     const char *sig_oid;
+    size_t sig_oid_len = 0;
     unsigned char *c, *c2;
     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 pub_len = 0, sig_and_oid_len = 0, sig_len;
     size_t len = 0;
-    x509_req_name *cur = ctx->subject;
-    asn1_named_data *cur_ext = ctx->extensions;
+    pk_type_t pk_alg;
 
-    c = tmp_buf + 2048 - 1;
+    /*
+     * Prepare data to be signed in tmp_buf
+     */
+    c = tmp_buf + sizeof( tmp_buf );
 
-    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;
-    }
+    ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
 
     if( len )
     {
@@ -447,7 +846,8 @@
         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_oid( &c, tmp_buf, OID_PKCS9_CSR_EXT_REQ,
+                                          OID_SIZE( 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 ) );
@@ -456,42 +856,15 @@
     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 ) );
-    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 ) );
-
-    if( c - tmp_buf < 1 )
-        return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+    ASN1_CHK_ADD( pub_len, x509write_pubkey_der( ctx->key,
+                                                 tmp_buf, c - tmp_buf ) );
+    c -= pub_len;
+    len += pub_len;
 
     /*
-     *  AlgorithmIdentifier  ::=  SEQUENCE  {
-     *       algorithm               OBJECT IDENTIFIER,
-     *       parameters              ANY DEFINED BY algorithm OPTIONAL  }
+     *  Subject  ::=  Name
      */
-    *--c = 0;
-    pub_len += 1;
-
-    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_BIT_STRING ) );
-
-    ASN1_CHK_ADD( pub_len, asn1_write_algorithm_identifier( &c, tmp_buf, OID_PKCS1_RSA ) );
-
-    len += pub_len;
-    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, pub_len ) );
-    ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
-
-    while( cur != NULL )
-    {
-        ASN1_CHK_ADD( sub_len, x509_write_name( &c, tmp_buf, cur->oid, cur->name ) );
-
-        cur = cur->next;
-    }
-
-    len += sub_len;
-    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 ) );
+    ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) );
 
     /*
      *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
@@ -501,35 +874,179 @@
     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 ) );
 
+    /*
+     * Prepare signature
+     */
     md( md_info_from_type( ctx->md_alg ), c, len, hash );
 
-    rsa_pkcs1_sign( ctx->rsa, NULL, NULL, RSA_PRIVATE, ctx->md_alg, 0, hash, sig );
+    pk_alg = pk_get_type( ctx->key );
+    if( pk_alg == POLARSSL_PK_ECKEY )
+        pk_alg = POLARSSL_PK_ECDSA;
 
-    // Generate correct OID
-    //
-    ret = oid_get_oid_by_sig_alg( POLARSSL_PK_RSA, ctx->md_alg, &sig_oid );
+    if( ( ret = pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len,
+                         f_rng, p_rng ) ) != 0 ||
+        ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
+                                        &sig_oid, &sig_oid_len ) ) != 0 )
+    {
+        return( ret );
+    }
 
-    c2 = buf + size - 1;
-    ASN1_CHK_ADD( sig_len, x509_write_sig( &c2, buf, sig_oid, sig, ctx->rsa->len ) );
+    /*
+     * Write data to output buffer
+     */
+    c2 = buf + size;
+    ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf,
+                                        sig_oid, sig_oid_len, sig, sig_len ) );
 
     c2 -= len;
     memcpy( c2, c, len );
 
-    len += sig_len;
+    len += sig_and_oid_len;
     ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) );
     ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
 
     return( len );
 }
 
+int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng )
+{
+    int ret;
+    const char *sig_oid;
+    size_t sig_oid_len = 0;
+    unsigned char *c, *c2;
+    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_and_oid_len = 0, sig_len;
+    size_t len = 0;
+    pk_type_t pk_alg;
+
+    /*
+     * Prepare data to be signed in tmp_buf
+     */
+    c = tmp_buf + sizeof( tmp_buf );
+
+    /* Signature algorithm needed in TBS, and later for actual signature */
+    pk_alg = pk_get_type( ctx->issuer_key );
+    if( pk_alg == POLARSSL_PK_ECKEY )
+        pk_alg = POLARSSL_PK_ECDSA;
+
+    if( ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
+                                        &sig_oid, &sig_oid_len ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    /*
+     *  Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+     */
+    ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
+    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_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3 ) );
+
+    /*
+     *  SubjectPublicKeyInfo
+     */
+    ASN1_CHK_ADD( pub_len, x509write_pubkey_der( ctx->subject_key,
+                                                 tmp_buf, c - tmp_buf ) );
+    c -= pub_len;
+    len += pub_len;
+
+    /*
+     *  Subject  ::=  Name
+     */
+    ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) );
+
+    /*
+     *  Validity ::= SEQUENCE {
+     *       notBefore      Time,
+     *       notAfter       Time }
+     */
+    sub_len = 0;
+
+    ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after,
+                                            X509_RFC5280_UTC_TIME_LEN ) );
+
+    ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before,
+                                            X509_RFC5280_UTC_TIME_LEN ) );
+
+    len += sub_len;
+    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 ) );
+
+    /*
+     *  Issuer  ::=  Name
+     */
+    ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->issuer ) );
+
+    /*
+     *  Signature   ::=  AlgorithmIdentifier
+     */
+    ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, tmp_buf,
+                       sig_oid, strlen( sig_oid ), 0 ) );
+
+    /*
+     *  Serial   ::=  INTEGER
+     */
+    ASN1_CHK_ADD( len, asn1_write_mpi( &c, tmp_buf, &ctx->serial ) );
+
+    /*
+     *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+     */
+    sub_len = 0;
+    ASN1_CHK_ADD( sub_len, asn1_write_int( &c, tmp_buf, ctx->version ) );
+    len += sub_len;
+    ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 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 ) );
+
+    /*
+     * Make signature
+     */
+    md( md_info_from_type( ctx->md_alg ), c, len, hash );
+
+    if( ( ret = pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len,
+                         f_rng, p_rng ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    /*
+     * Write data to output buffer
+     */
+    c2 = buf + size;
+    ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf,
+                                        sig_oid, sig_oid_len, sig, sig_len ) );
+
+    c2 -= len;
+    memcpy( c2, c, len );
+
+    len += sig_and_oid_len;
+    ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) );
+    ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+    return( len );
+}
+
+#define PEM_BEGIN_CRT           "-----BEGIN CERTIFICATE-----\n"
+#define PEM_END_CRT             "-----END CERTIFICATE-----\n"
+
 #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"
+#define PEM_BEGIN_PRIVATE_KEY_RSA   "-----BEGIN RSA PRIVATE KEY-----\n"
+#define PEM_END_PRIVATE_KEY_RSA     "-----END RSA PRIVATE KEY-----\n"
+#define PEM_BEGIN_PRIVATE_KEY_EC    "-----BEGIN EC PRIVATE KEY-----\n"
+#define PEM_END_PRIVATE_KEY_EC      "-----END EC PRIVATE KEY-----\n"
 
 #if defined(POLARSSL_BASE64_C)
 static int x509write_pemify( const char *begin_str, const char *end_str,
@@ -571,19 +1088,42 @@
     return( 0 );
 }
 
-int x509write_pubkey_pem( rsa_context *rsa, unsigned char *buf, size_t size )
+int x509write_crt_pem( x509write_cert *crt, unsigned char *buf, size_t size,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng )
 {
     int ret;
     unsigned char output_buf[4096];
 
-    if( ( ret = x509write_pubkey_der( rsa, output_buf,
+    if( ( ret = x509write_crt_der( crt, output_buf, sizeof(output_buf),
+                                   f_rng, p_rng ) ) < 0 )
+    {
+        return( ret );
+    }
+
+    if( ( ret = x509write_pemify( PEM_BEGIN_CRT, PEM_END_CRT,
+                                  output_buf + sizeof(output_buf) - ret,
+                                  ret, buf, size ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    return( 0 );
+}
+
+int x509write_pubkey_pem( pk_context *key, unsigned char *buf, size_t size )
+{
+    int ret;
+    unsigned char output_buf[4096];
+
+    if( ( ret = x509write_pubkey_der( key, 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,
+                                  output_buf + sizeof(output_buf) - ret,
                                   ret, buf, size ) ) != 0 )
     {
         return( ret );
@@ -592,19 +1132,38 @@
     return( 0 );
 }
 
-int x509write_key_pem( rsa_context *rsa, unsigned char *buf, size_t size )
+int x509write_key_pem( pk_context *key, unsigned char *buf, size_t size )
 {
     int ret;
     unsigned char output_buf[4096];
+    char *begin, *end;
 
-    if( ( ret = x509write_key_der( rsa, output_buf,
+    if( ( ret = x509write_key_der( key, 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,
+#if defined(POLARSSL_RSA_C)
+    if( pk_get_type( key ) == POLARSSL_PK_RSA )
+    {
+        begin = PEM_BEGIN_PRIVATE_KEY_RSA;
+        end = PEM_END_PRIVATE_KEY_RSA;
+    }
+    else
+#endif
+#if defined(POLARSSL_ECP_C)
+    if( pk_get_type( key ) == POLARSSL_PK_ECKEY )
+    {
+        begin = PEM_BEGIN_PRIVATE_KEY_EC;
+        end = PEM_END_PRIVATE_KEY_EC;
+    }
+    else
+#endif
+        return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
+
+    if( ( ret = x509write_pemify( begin, end,
+                                  output_buf + sizeof(output_buf) - ret,
                                   ret, buf, size ) ) != 0 )
     {
         return( ret );
@@ -613,19 +1172,21 @@
     return( 0 );
 }
 
-int x509write_csr_pem( x509_csr *ctx, unsigned char *buf, size_t size )
+int x509write_csr_pem( x509write_csr *ctx, unsigned char *buf, size_t size,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng )
 {
     int ret;
     unsigned char output_buf[4096];
 
-    if( ( ret = x509write_csr_der( ctx, output_buf,
-                                      sizeof(output_buf) ) ) < 0 )
+    if( ( ret = x509write_csr_der( ctx, output_buf, sizeof(output_buf),
+                                   f_rng, p_rng ) ) < 0 )
     {
         return( ret );
     }
 
     if( ( ret = x509write_pemify( PEM_BEGIN_CSR, PEM_END_CSR,
-                                  output_buf + sizeof(output_buf) - 1 - ret,
+                                  output_buf + sizeof(output_buf) - ret,
                                   ret, buf, size ) ) != 0 )
     {
         return( ret );
diff --git a/programs/.gitignore b/programs/.gitignore
index 2b7510f..32ca900 100644
--- a/programs/.gitignore
+++ b/programs/.gitignore
@@ -40,3 +40,5 @@
 x509/cert_app
 x509/cert_req
 x509/crl_app
+x509/cert_write
+x509/req_app
diff --git a/programs/pkey/ecdsa.c b/programs/pkey/ecdsa.c
index 8d52b67..7e500bb 100644
--- a/programs/pkey/ecdsa.c
+++ b/programs/pkey/ecdsa.c
@@ -51,7 +51,7 @@
 #endif
 #endif /* !defined(ECPARAMS) */
 
-#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_ECDSA_C) || \
+#if !defined(POLARSSL_ECDSA_C) || \
     !defined(POLARSSL_ENTROPY_C) || !defined(POLARSSL_CTR_DRBG_C) || \
     !defined(ECPARAMS)
 int main( int argc, char *argv[] )
@@ -59,9 +59,9 @@
     ((void) argc);
     ((void) argv);
 
-    printf("POLARSSL_BIGNUM_C and/or POLARSSL_ECDSA_C and/or "
+    printf("POLARSSL_ECDSA_C and/or "
            "POLARSSL_ENTROPY_C and/or POLARSSL_CTR_DRBG_C not defined,"
-           "and/or not EC domain parameter available\n" );
+           "and/or no EC domain parameter available\n" );
     return( 0 );
 }
 #else
@@ -194,6 +194,5 @@
 
     return( ret );
 }
-#endif /* POLARSSL_BIGNUM_C && POLARSSL_ECDSA_C &&
-          POLARSSL_ENTROPY_C && POLARSSL_CTR_DRBG_C &&
+#endif /* POLARSSL_ECDSA_C && POLARSSL_ENTROPY_C && POLARSSL_CTR_DRBG_C &&
           ECPARAMS */
diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c
index d9ab45c..371b03a 100644
--- a/programs/pkey/key_app_writer.c
+++ b/programs/pkey/key_app_writer.c
@@ -33,21 +33,16 @@
 
 #include "polarssl/config.h"
 
-#include "polarssl/error.h"
-#include "polarssl/rsa.h"
-#include "polarssl/x509.h"
-#include "polarssl/base64.h"
 #include "polarssl/x509write.h"
+#include "polarssl/error.h"
 
-#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) ||         \
-    !defined(POLARSSL_X509_WRITE_C) || !defined(POLARSSL_FS_IO)
+#if !defined(POLARSSL_X509_WRITE_C) || !defined(POLARSSL_FS_IO)
 int main( int argc, char *argv[] )
 {
     ((void) argc);
     ((void) argv);
 
-    printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or "
-           "POLARSSL_X509_WRITE_C and/or POLARSSL_FS_IO not defined.\n");
+    printf( "POLARSSL_X509_WRITE_C and/or POLARSSL_FS_IO not defined.\n" );
     return( 0 );
 }
 #else
@@ -82,7 +77,7 @@
     int output_format;          /* the output format to use             */
 } opt;
 
-static int write_public_key( rsa_context *rsa, const char *output_file )
+static int write_public_key( pk_context *key, const char *output_file )
 {
     int ret;
     FILE *f;
@@ -94,14 +89,14 @@
 
     if( opt.output_format == OUTPUT_FORMAT_PEM )
     {
-        if( ( ret = x509write_pubkey_pem( rsa, output_buf, 16000 ) ) != 0 )
+        if( ( ret = x509write_pubkey_pem( key, output_buf, 16000 ) ) != 0 )
             return( ret );
 
         len = strlen( (char *) output_buf );
     }
     else
     {
-        if( ( ret = x509write_pubkey_der( rsa, output_buf, 16000 ) ) < 0 )
+        if( ( ret = x509write_pubkey_der( key, output_buf, 16000 ) ) < 0 )
             return( ret );
 
         len = ret;
@@ -119,7 +114,7 @@
     return( 0 );
 }
 
-static int write_private_key( rsa_context *rsa, const char *output_file )
+static int write_private_key( pk_context *key, const char *output_file )
 {
     int ret;
     FILE *f;
@@ -130,14 +125,14 @@
     memset(output_buf, 0, 16000);
     if( opt.output_format == OUTPUT_FORMAT_PEM )
     {
-        if( ( ret = x509write_key_pem( rsa, output_buf, 16000 ) ) != 0 )
+        if( ( ret = x509write_key_pem( key, output_buf, 16000 ) ) != 0 )
             return( ret );
 
         len = strlen( (char *) output_buf );
     }
     else
     {
-        if( ( ret = x509write_key_der( rsa, output_buf, 16000 ) ) < 0 )
+        if( ( ret = x509write_key_der( key, output_buf, 16000 ) ) < 0 )
             return( ret );
 
         len = ret;
@@ -168,7 +163,7 @@
 int main( int argc, char *argv[] )
 {
     int ret = 0;
-    rsa_context rsa;
+    pk_context key;
     char buf[1024];
     int i;
     char *p, *q;
@@ -176,12 +171,13 @@
     /*
      * Set to sane values
      */
-    memset( &rsa, 0, sizeof( rsa_context ) );
-    memset( buf, 0, 1024 );
+    pk_init( &key );
+    memset( buf, 0, sizeof( buf ) );
 
     if( argc == 0 )
     {
     usage:
+        ret = 1;
         printf( USAGE );
         goto exit;
     }
@@ -254,15 +250,11 @@
         printf( "\n  . Loading the private key ..." );
         fflush( stdout );
 
-        ret = x509parse_keyfile_rsa( &rsa, opt.filename, NULL );
+        ret = x509parse_keyfile( &key, opt.filename, NULL );
 
         if( ret != 0 )
         {
-#ifdef POLARSSL_ERROR_C
-            polarssl_strerror( ret, buf, 1024 );
-#endif
-            printf( " failed\n  !  x509parse_key_rsa returned %d - %s\n\n", ret, buf );
-            rsa_free( &rsa );
+            printf( " failed\n  !  x509parse_key returned %d", ret );
             goto exit;
         }
 
@@ -272,14 +264,23 @@
          * 1.2 Print the key
          */
         printf( "  . Key information    ...\n" );
-        mpi_write_file( "N:  ", &rsa.N, 16, NULL );
-        mpi_write_file( "E:  ", &rsa.E, 16, NULL );
-        mpi_write_file( "D:  ", &rsa.D, 16, NULL );
-        mpi_write_file( "P:  ", &rsa.P, 16, NULL );
-        mpi_write_file( "Q:  ", &rsa.Q, 16, NULL );
-        mpi_write_file( "DP: ", &rsa.DP, 16, NULL );
-        mpi_write_file( "DQ:  ", &rsa.DQ, 16, NULL );
-        mpi_write_file( "QP:  ", &rsa.QP, 16, NULL );
+
+#if defined(POLARSSL_RSA_C)
+        if( pk_get_type( &key ) == POLARSSL_PK_RSA )
+        {
+            rsa_context *rsa = pk_rsa( key );
+            mpi_write_file( "N:  ",  &rsa->N,  16, NULL );
+            mpi_write_file( "E:  ",  &rsa->E,  16, NULL );
+            mpi_write_file( "D:  ",  &rsa->D,  16, NULL );
+            mpi_write_file( "P:  ",  &rsa->P,  16, NULL );
+            mpi_write_file( "Q:  ",  &rsa->Q,  16, NULL );
+            mpi_write_file( "DP: ",  &rsa->DP, 16, NULL );
+            mpi_write_file( "DQ:  ", &rsa->DQ, 16, NULL );
+            mpi_write_file( "QP:  ", &rsa->QP, 16, NULL );
+        }
+        else
+#endif
+            printf("key type not supported yet\n");
 
     }
     else if( opt.mode == MODE_PUBLIC )
@@ -290,15 +291,11 @@
         printf( "\n  . Loading the public key ..." );
         fflush( stdout );
 
-        ret = x509parse_public_keyfile_rsa( &rsa, opt.filename );
+        ret = x509parse_public_keyfile( &key, opt.filename );
 
         if( ret != 0 )
         {
-#ifdef POLARSSL_ERROR_C
-            polarssl_strerror( ret, buf, 1024 );
-#endif
-            printf( " failed\n  !  x509parse_public_key_rsa returned %d - %s\n\n", ret, buf );
-            rsa_free( &rsa );
+            printf( " failed\n  !  x509parse_public_key returned %d", ret );
             goto exit;
         }
 
@@ -308,24 +305,43 @@
          * 1.2 Print the key
          */
         printf( "  . Key information    ...\n" );
-        mpi_write_file( "N: ", &rsa.N, 16, NULL );
-        mpi_write_file( "E:  ", &rsa.E, 16, NULL );
+
+#if defined(POLARSSL_RSA_C)
+        if( pk_get_type( &key ) == POLARSSL_PK_RSA )
+        {
+            rsa_context *rsa = pk_rsa( key );
+            mpi_write_file( "N: ", &rsa->N, 16, NULL );
+            mpi_write_file( "E: ", &rsa->E, 16, NULL );
+        }
+        else
+#endif
+            printf("key type not supported yet\n");
     }
     else
         goto usage;
 
     if( opt.output_mode == OUTPUT_MODE_PUBLIC )
     {
-        write_public_key( &rsa, opt.output_file );
+        write_public_key( &key, opt.output_file );
     }
     if( opt.output_mode == OUTPUT_MODE_PRIVATE )
     {
-        write_private_key( &rsa, opt.output_file );
+        write_private_key( &key, opt.output_file );
     }
 
 exit:
 
-    rsa_free( &rsa );
+    if( ret != 0 && ret != 1)
+    {
+#ifdef POLARSSL_ERROR_C
+        polarssl_strerror( ret, buf, sizeof( buf ) );
+        printf( " - %s\n", buf );
+#else
+        printf("\n");
+#endif
+    }
+
+    pk_free( &key );
 
 #if defined(_WIN32)
     printf( "  + Press Enter to exit this program.\n" );
@@ -334,5 +350,4 @@
 
     return( ret );
 }
-#endif /* POLARSSL_BIGNUM_C && POLARSSL_RSA_C &&
-          POLARSSL_X509_WRITE_C && POLARSSL_FS_IO */
+#endif /* POLARSSL_X509_WRITE_C && POLARSSL_FS_IO */
diff --git a/programs/x509/CMakeLists.txt b/programs/x509/CMakeLists.txt
index d07cff8..fe46da5 100644
--- a/programs/x509/CMakeLists.txt
+++ b/programs/x509/CMakeLists.txt
@@ -16,9 +16,15 @@
 add_executable(crl_app crl_app.c)
 target_link_libraries(crl_app ${libs})
 
+add_executable(req_app req_app.c)
+target_link_libraries(req_app ${libs})
+
 add_executable(cert_req cert_req.c)
 target_link_libraries(cert_req ${libs})
 
-install(TARGETS cert_app crl_app cert_req
+add_executable(cert_write cert_write.c)
+target_link_libraries(cert_write ${libs})
+
+install(TARGETS cert_app crl_app req_app cert_req cert_write
         DESTINATION "bin"
         PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
diff --git a/programs/x509/cert_app.c b/programs/x509/cert_app.c
index 40d76d8..0096735 100644
--- a/programs/x509/cert_app.c
+++ b/programs/x509/cert_app.c
@@ -39,6 +39,25 @@
 #include "polarssl/ssl.h"
 #include "polarssl/x509.h"
 
+#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_ENTROPY_C) ||  \
+    !defined(POLARSSL_SSL_TLS_C) || !defined(POLARSSL_SSL_CLI_C) || \
+    !defined(POLARSSL_NET_C) || !defined(POLARSSL_RSA_C) ||         \
+    !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) ||  \
+    !defined(POLARSSL_CTR_DRBG_C)
+int main( int argc, char *argv[] )
+{
+    ((void) argc);
+    ((void) argv);
+
+    printf("POLARSSL_BIGNUM_C and/or POLARSSL_ENTROPY_C and/or "
+           "POLARSSL_SSL_TLS_C and/or POLARSSL_SSL_CLI_C and/or "
+           "POLARSSL_NET_C and/or POLARSSL_RSA_C and/or "
+           "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO and/or "
+           "POLARSSL_CTR_DRBG_C not defined.\n");
+    return( 0 );
+}
+#else
+
 #define MODE_NONE               0
 #define MODE_FILE               1
 #define MODE_SSL                2
@@ -130,24 +149,6 @@
     "    permissive=%%d       default: 0 (disabled)\n"  \
     "\n"
 
-#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_ENTROPY_C) ||  \
-    !defined(POLARSSL_SSL_TLS_C) || !defined(POLARSSL_SSL_CLI_C) || \
-    !defined(POLARSSL_NET_C) || !defined(POLARSSL_RSA_C) ||         \
-    !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) ||  \
-    !defined(POLARSSL_CTR_DRBG_C)
-int main( int argc, char *argv[] )
-{
-    ((void) argc);
-    ((void) argv);
-
-    printf("POLARSSL_BIGNUM_C and/or POLARSSL_ENTROPY_C and/or "
-           "POLARSSL_SSL_TLS_C and/or POLARSSL_SSL_CLI_C and/or "
-           "POLARSSL_NET_C and/or POLARSSL_RSA_C and/or "
-           "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO and/or "
-           "POLARSSL_CTR_DRBG_C not defined.\n");
-    return( 0 );
-}
-#else
 int main( int argc, char *argv[] )
 {
     int ret = 0, server_fd;
diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c
index 384ef08..c0c014f 100644
--- a/programs/x509/cert_req.c
+++ b/programs/x509/cert_req.c
@@ -33,12 +33,26 @@
 
 #include "polarssl/config.h"
 
-#include "polarssl/error.h"
-#include "polarssl/rsa.h"
-#include "polarssl/x509.h"
-#include "polarssl/base64.h"
 #include "polarssl/x509write.h"
-#include "polarssl/oid.h"
+#include "polarssl/entropy.h"
+#include "polarssl/ctr_drbg.h"
+#include "polarssl/error.h"
+
+#if !defined(POLARSSL_X509_WRITE_C) || !defined(POLARSSL_X509_PARSE_C) ||   \
+    !defined(POLARSSL_FS_IO) ||                                             \
+    !defined(POLARSSL_ENTROPY_C) || !defined(POLARSSL_CTR_DRBG_C)
+int main( int argc, char *argv[] )
+{
+    ((void) argc);
+    ((void) argv);
+
+    printf( "POLARSSL_X509_WRITE_C and/or POLARSSL_X509_PARSE_C and/or "
+            "POLARSSL_FS_IO and/or "
+            "POLARSSL_ENTROPY_C and/or POLARSSL_CTR_DRBG_C "
+            "not defined.\n");
+    return( 0 );
+}
+#else
 
 #define DFL_FILENAME            "keyfile.key"
 #define DFL_DEBUG_LEVEL         0
@@ -60,7 +74,9 @@
     unsigned char ns_cert_type; /* NS cert type                         */
 } opt;
 
-int write_certificate_request( x509_csr *req, char *output_file )
+int write_certificate_request( x509write_csr *req, char *output_file,
+                               int (*f_rng)(void *, unsigned char *, size_t),
+                               void *p_rng )
 {
     int ret;
     FILE *f;
@@ -68,7 +84,7 @@
     size_t len = 0;
 
     memset( output_buf, 0, 4096 );
-    if( ( ret = x509write_csr_pem( req, output_buf, 4096 ) ) < 0 )
+    if( ( ret = x509write_csr_pem( req, output_buf, 4096, f_rng, p_rng ) ) < 0 )
         return( ret );
 
     len = strlen( (char *) output_buf );
@@ -85,7 +101,7 @@
 }
 
 #define USAGE \
-    "\n usage: key_app param=<>...\n"                   \
+    "\n usage: cert_req param=<>...\n"                  \
     "\n acceptable parameters:\n"                       \
     "    filename=%%s         default: keyfile.key\n"   \
     "    debug_level=%%d      default: 0 (disabled)\n"  \
@@ -111,34 +127,25 @@
     "                          object_signing_ca\n"     \
     "\n"
 
-#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) ||         \
-    !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO)
-int main( int argc, char *argv[] )
-{
-    ((void) argc);
-    ((void) argv);
-
-    printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or "
-           "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO not defined.\n");
-    return( 0 );
-}
-#else
 int main( int argc, char *argv[] )
 {
     int ret = 0;
-    rsa_context rsa;
+    pk_context key;
     char buf[1024];
     int i, j, n;
     char *p, *q, *r;
-    x509_csr req;
+    x509write_csr req;
+    entropy_context entropy;
+    ctr_drbg_context ctr_drbg;
+    const char *pers = "csr example app";
 
     /*
      * 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 );
+    pk_init( &key );
+    memset( buf, 0, sizeof( buf ) );
 
     if( argc == 0 )
     {
@@ -249,35 +256,51 @@
         x509write_csr_set_ns_cert_type( &req, opt.ns_cert_type );
 
     /*
-     * 1.0. Check the subject name for validity
+     * 0. Seed the PRNG
      */
-    if( ( ret = x509write_csr_set_subject_name( &req, opt.subject_name ) ) != 0 )
+    printf( "  . Seeding the random number generator..." );
+    fflush( stdout );
+
+    entropy_init( &entropy );
+    if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
+                               (const unsigned char *) pers,
+                               strlen( pers ) ) ) != 0 )
     {
-#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 );
+        printf( " failed\n  !  ctr_drbg_init returned %d", ret );
         goto exit;
     }
 
+    printf( " ok\n" );
+
+    /*
+     * 1.0. Check the subject name for validity
+     */
+    printf( "  . Checking subjet name..." );
+    fflush( stdout );
+
+    if( ( ret = x509write_csr_set_subject_name( &req, opt.subject_name ) ) != 0 )
+    {
+        printf( " failed\n  !  x509write_csr_set_subject_name returned %d", ret );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
     /*
      * 1.1. Load the key
      */
-    printf( "\n  . Loading the private key ..." );
+    printf( "  . Loading the private key ..." );
     fflush( stdout );
 
-    ret = x509parse_keyfile_rsa( &rsa, opt.filename, NULL );
+    ret = x509parse_keyfile( &key, opt.filename, NULL );
 
     if( ret != 0 )
     {
-#ifdef POLARSSL_ERROR_C
-        error_strerror( ret, buf, 1024 );
-#endif
-        printf( " failed\n  !  x509parse_key_rsa returned %d - %s\n\n", ret, buf );
+        printf( " failed\n  !  x509parse_keyfile returned %d", ret );
         goto exit;
     }
 
-    x509write_csr_set_rsa_key( &req, &rsa );
+    x509write_csr_set_key( &req, &key );
 
     printf( " ok\n" );
 
@@ -287,20 +310,29 @@
     printf( "  . Writing the certificate request ..." );
     fflush( stdout );
 
-    if( ( ret = write_certificate_request( &req, opt.output_file ) ) != 0 )
+    if( ( ret = write_certificate_request( &req, opt.output_file,
+                                           ctr_drbg_random, &ctr_drbg ) ) != 0 )
     {
-#ifdef POLARSSL_ERROR_C
-        error_strerror( ret, buf, 1024 );
-#endif
-        printf( " failed\n  !  write_certifcate_request %d - %s\n\n", ret, buf );
+        printf( " failed\n  !  write_certifcate_request %d", ret );
         goto exit;
     }
 
     printf( " ok\n" );
 
 exit:
+
+    if( ret != 0 && ret != 1)
+    {
+#ifdef POLARSSL_ERROR_C
+        polarssl_strerror( ret, buf, sizeof( buf ) );
+        printf( " - %s\n", buf );
+#else
+        printf("\n");
+#endif
+    }
+
     x509write_csr_free( &req );
-    rsa_free( &rsa );
+    pk_free( &key );
 
 #if defined(_WIN32)
     printf( "  + Press Enter to exit this program.\n" );
@@ -309,5 +341,5 @@
 
     return( ret );
 }
-#endif /* POLARSSL_BIGNUM_C && POLARSSL_RSA_C &&
-          POLARSSL_X509_PARSE_C && POLARSSL_FS_IO */
+#endif /* POLARSSL_X509_WRITE_C && POLARSSL_X509_PARSE_C && POLARSSL_FS_IO &&
+          POLARSSL_ENTROPY_C && POLARSSL_CTR_DRBG_C */
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
new file mode 100644
index 0000000..37cea58
--- /dev/null
+++ b/programs/x509/cert_write.c
@@ -0,0 +1,653 @@
+/*
+ *  Certificate generation and signing
+ *
+ *  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/x509write.h"
+#include "polarssl/entropy.h"
+#include "polarssl/ctr_drbg.h"
+#include "polarssl/error.h"
+
+#if !defined(POLARSSL_X509_WRITE_C) || !defined(POLARSSL_X509_PARSE_C) ||   \
+    !defined(POLARSSL_FS_IO) ||                                             \
+    !defined(POLARSSL_ENTROPY_C) || !defined(POLARSSL_CTR_DRBG_C) ||        \
+    !defined(POLARSSL_ERROR_C)
+int main( int argc, char *argv[] )
+{
+    ((void) argc);
+    ((void) argv);
+
+    printf( "POLARSSL_X509_WRITE_C and/or POLARSSL_X509_PARSE_C and/or "
+            "POLARSSL_FS_IO and/or "
+            "POLARSSL_ENTROPY_C and/or POLARSSL_CTR_DRBG_C and/or "
+            "POLARSSL_ERROR_C not defined.\n");
+    return( 0 );
+}
+#else
+
+#define DFL_ISSUER_CRT          ""
+#define DFL_REQUEST_FILE        ""
+#define DFL_SUBJECT_KEY         "subject.key"
+#define DFL_ISSUER_KEY          "ca.key"
+#define DFL_SUBJECT_PWD         ""
+#define DFL_ISSUER_PWD          ""
+#define DFL_OUTPUT_FILENAME     "cert.crt"
+#define DFL_SUBJECT_NAME        "CN=Cert,O=PolarSSL,C=NL"
+#define DFL_ISSUER_NAME         "CN=CA,O=PolarSSL,C=NL"
+#define DFL_NOT_BEFORE          "20010101000000"
+#define DFL_NOT_AFTER           "20301231235959"
+#define DFL_SERIAL              "1"
+#define DFL_SELFSIGN            0
+#define DFL_IS_CA               0
+#define DFL_MAX_PATHLEN         -1
+#define DFL_KEY_USAGE           0
+#define DFL_NS_CERT_TYPE        0
+
+/*
+ * global options
+ */
+struct options
+{
+    char *issuer_crt;           /* filename of the issuer certificate   */
+    char *request_file;         /* filename of the certificate request  */
+    char *subject_key;          /* filename of the subject key file     */
+    char *issuer_key;           /* filename of the issuer key file      */
+    char *subject_pwd;          /* password for the subject key file    */
+    char *issuer_pwd;           /* password for the issuer key file     */
+    char *output_file;          /* where to store the constructed key file  */
+    char *subject_name;         /* subject name for certificate         */
+    char *issuer_name;          /* issuer name for certificate          */
+    char *not_before;           /* validity period not before           */
+    char *not_after;            /* validity period not after            */
+    char *serial;               /* serial number string                 */
+    int selfsign;               /* selfsign the certificate             */
+    int is_ca;                  /* is a CA certificate                  */
+    int max_pathlen;            /* maximum CA path length               */
+    unsigned char key_usage;    /* key usage flags                      */
+    unsigned char ns_cert_type; /* NS cert type                         */
+} opt;
+
+int write_certificate( x509write_cert *crt, char *output_file,
+                       int (*f_rng)(void *, unsigned char *, size_t),
+                       void *p_rng )
+{
+    int ret;
+    FILE *f;
+    unsigned char output_buf[4096];
+    size_t len = 0;
+
+    memset( output_buf, 0, 4096 );
+    if( ( ret = x509write_crt_pem( crt, output_buf, 4096, f_rng, p_rng ) ) < 0 )
+        return( ret );
+
+    len = strlen( (char *) output_buf );
+
+    if( ( f = fopen( output_file, "w" ) ) == NULL )
+        return( -1 );
+
+    if( fwrite( output_buf, 1, len, f ) != len )
+        return( -1 );
+
+    fclose(f);
+
+    return( 0 );
+}
+
+#define USAGE \
+    "\n usage: cert_write param=<>...\n"                \
+    "\n acceptable parameters:\n"                       \
+    "    request_file=%%s     default: (empty)\n"       \
+    "                        If request_file is specified, subject_key,\n"  \
+    "                        subject_pwd and subject_name are ignored!\n"  \
+    "    subject_key=%%s      default: subject.key\n"   \
+    "    subject_pwd=%%s      default: (empty)\n"       \
+    "    subject_name=%%s     default: CN=Cert,O=PolarSSL,C=NL\n"   \
+    "\n"                                                \
+    "    issuer_crt=%%s       default: (empty)\n"       \
+    "                        If issuer_crt is specified, issuer_name is\n"  \
+    "                        ignored!\n"                \
+    "    issuer_name=%%s      default: CN=CA,O=PolarSSL,C=NL\n"     \
+    "\n"                                                \
+    "    selfsign=%%d         default: 0 (false)\n"     \
+    "                        If selfsign is enabled, issuer_name and\n" \
+    "                        issuer_key are required (issuer_crt and\n" \
+    "                        subject_* are ignored\n"   \
+    "    issuer_key=%%s       default: ca.key\n"        \
+    "    issuer_pwd=%%s       default: (empty)\n"       \
+    "    output_file=%%s      default: cert.crt\n"      \
+    "    serial=%%s           default: 1\n"             \
+    "    not_before=%%s       default: 20010101000000\n"\
+    "    not_after=%%s        default: 20301231235959\n"\
+    "    is_ca=%%d            default: 0 (disabled)\n"  \
+    "    max_pathlen=%%d      default: -1 (none)\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"
+
+int main( int argc, char *argv[] )
+{
+    int ret = 0;
+    x509_cert issuer_crt;
+    pk_context loaded_issuer_key, loaded_subject_key;
+    pk_context *issuer_key = &loaded_issuer_key,
+                *subject_key = &loaded_subject_key;
+    char buf[1024];
+    char issuer_name[128];
+    char subject_name[128];
+    int i, j, n;
+    char *p, *q, *r;
+    x509_csr csr;
+    x509write_cert crt;
+    mpi serial;
+    entropy_context entropy;
+    ctr_drbg_context ctr_drbg;
+    const char *pers = "crt example app";
+
+    /*
+     * Set to sane values
+     */
+    x509write_crt_init( &crt );
+    x509write_crt_set_md_alg( &crt, POLARSSL_MD_SHA1 );
+    pk_init( &loaded_issuer_key );
+    pk_init( &loaded_subject_key );
+    mpi_init( &serial );
+    memset( &csr, 0, sizeof(x509_csr) );
+    memset( &issuer_crt, 0, sizeof(x509_cert) );
+    memset( buf, 0, 1024 );
+
+    if( argc == 0 )
+    {
+    usage:
+        printf( USAGE );
+        ret = 1;
+        goto exit;
+    }
+
+    opt.issuer_crt          = DFL_ISSUER_CRT;
+    opt.request_file        = DFL_REQUEST_FILE;
+    opt.request_file        = DFL_REQUEST_FILE;
+    opt.subject_key         = DFL_SUBJECT_KEY;
+    opt.issuer_key          = DFL_ISSUER_KEY;
+    opt.subject_pwd         = DFL_SUBJECT_PWD;
+    opt.issuer_pwd          = DFL_ISSUER_PWD;
+    opt.output_file         = DFL_OUTPUT_FILENAME;
+    opt.subject_name        = DFL_SUBJECT_NAME;
+    opt.issuer_name         = DFL_ISSUER_NAME;
+    opt.not_before          = DFL_NOT_BEFORE;
+    opt.not_after           = DFL_NOT_AFTER;
+    opt.serial              = DFL_SERIAL;
+    opt.selfsign            = DFL_SELFSIGN;
+    opt.is_ca               = DFL_IS_CA;
+    opt.max_pathlen         = DFL_MAX_PATHLEN;
+    opt.key_usage           = DFL_KEY_USAGE;
+    opt.ns_cert_type        = DFL_NS_CERT_TYPE;
+
+    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, "request_file" ) == 0 )
+            opt.request_file = q;
+        else if( strcmp( p, "subject_key" ) == 0 )
+            opt.subject_key = q;
+        else if( strcmp( p, "issuer_key" ) == 0 )
+            opt.issuer_key = q;
+        else if( strcmp( p, "subject_pwd" ) == 0 )
+            opt.subject_pwd = q;
+        else if( strcmp( p, "issuer_pwd" ) == 0 )
+            opt.issuer_pwd = q;
+        else if( strcmp( p, "issuer_crt" ) == 0 )
+            opt.issuer_crt = q;
+        else if( strcmp( p, "output_file" ) == 0 )
+            opt.output_file = q;
+        else if( strcmp( p, "subject_name" ) == 0 )
+        {
+            opt.subject_name = q;
+        }
+        else if( strcmp( p, "issuer_name" ) == 0 )
+        {
+            opt.issuer_name = q;
+        }
+        else if( strcmp( p, "not_before" ) == 0 )
+        {
+            opt.not_before = q;
+        }
+        else if( strcmp( p, "not_after" ) == 0 )
+        {
+            opt.not_after = q;
+        }
+        else if( strcmp( p, "serial" ) == 0 )
+        {
+            opt.serial = q;
+        }
+        else if( strcmp( p, "selfsign" ) == 0 )
+        {
+            opt.selfsign = atoi( q );
+            if( opt.selfsign < 0 || opt.selfsign > 1 )
+                goto usage;
+        }
+        else if( strcmp( p, "is_ca" ) == 0 )
+        {
+            opt.is_ca = atoi( q );
+            if( opt.is_ca < 0 || opt.is_ca > 1 )
+                goto usage;
+        }
+        else if( strcmp( p, "max_pathlen" ) == 0 )
+        {
+            opt.max_pathlen = atoi( q );
+            if( opt.max_pathlen < -1 || opt.max_pathlen > 127 )
+                goto usage;
+        }
+        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;
+    }
+
+    printf("\n");
+
+    /*
+     * 0. Seed the PRNG
+     */
+    printf( "  . Seeding the random number generator..." );
+    fflush( stdout );
+
+    entropy_init( &entropy );
+    if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
+                               (const unsigned char *) pers,
+                               strlen( pers ) ) ) != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  ctr_drbg_init returned %d - %s\n", ret, buf );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    // Parse serial to MPI
+    //
+    printf( "  . Reading serial number..." );
+    fflush( stdout );
+
+    if( ( ret = mpi_read_string( &serial, 10, opt.serial ) ) != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  mpi_read_string returned -0x%02x - %s\n\n", -ret, buf );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    // Parse issuer certificate if present
+    //
+    if( !opt.selfsign && strlen( opt.issuer_crt ) )
+    {
+        /*
+         * 1.0.a. Load the certificates
+         */
+        printf( "  . Loading the issuer certificate ..." );
+        fflush( stdout );
+
+        if( ( ret = x509parse_crtfile( &issuer_crt, opt.issuer_crt ) ) != 0 )
+        {
+            error_strerror( ret, buf, 1024 );
+            printf( " failed\n  !  x509parse_crtfile returned -0x%02x - %s\n\n", -ret, buf );
+            goto exit;
+        }
+
+        ret = x509parse_dn_gets( issuer_name, sizeof(issuer_name),
+                                 &issuer_crt.issuer );
+        if( ret < 0 )
+        {
+            error_strerror( ret, buf, 1024 );
+            printf( " failed\n  !  x509parse_dn_gets returned -0x%02x - %s\n\n", -ret, buf );
+            goto exit;
+        }
+
+        opt.issuer_name = issuer_name;
+
+        printf( " ok\n" );
+    }
+
+    // Parse certificate request if present
+    //
+    if( !opt.selfsign && strlen( opt.request_file ) )
+    {
+        /*
+         * 1.0.b. Load the CSR
+         */
+        printf( "  . Loading the certificate request ..." );
+        fflush( stdout );
+
+        if( ( ret = x509parse_csrfile( &csr, opt.request_file ) ) != 0 )
+        {
+            error_strerror( ret, buf, 1024 );
+            printf( " failed\n  !  x509parse_csrfile returned -0x%02x - %s\n\n", -ret, buf );
+            goto exit;
+        }
+
+        ret = x509parse_dn_gets( subject_name, sizeof(subject_name),
+                                 &csr.subject );
+        if( ret < 0 )
+        {
+            error_strerror( ret, buf, 1024 );
+            printf( " failed\n  !  x509parse_dn_gets returned -0x%02x - %s\n\n", -ret, buf );
+            goto exit;
+        }
+
+        opt.subject_name = subject_name;
+        subject_key = &csr.pk;
+
+        printf( " ok\n" );
+    }
+
+    /*
+     * 1.1. Load the keys
+     */
+    if( !opt.selfsign && !strlen( opt.request_file ) )
+    {
+        printf( "  . Loading the subject key ..." );
+        fflush( stdout );
+
+        ret = x509parse_keyfile( &loaded_subject_key, opt.subject_key,
+                                 opt.subject_pwd );
+        if( ret != 0 )
+        {
+            error_strerror( ret, buf, 1024 );
+            printf( " failed\n  !  x509parse_keyfile returned -0x%02x - %s\n\n", -ret, buf );
+            goto exit;
+        }
+
+        printf( " ok\n" );
+    }
+
+    printf( "  . Loading the issuer key ..." );
+    fflush( stdout );
+
+    ret = x509parse_keyfile( &loaded_issuer_key, opt.issuer_key,
+                                 opt.issuer_pwd );
+    if( ret != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  x509parse_keyfile returned -x%02x - %s\n\n", -ret, buf );
+        goto exit;
+    }
+
+    // Check if key and issuer certificate match
+    //
+    if( strlen( opt.issuer_crt ) )
+    {
+        if( !pk_can_do( &issuer_crt.pk, POLARSSL_PK_RSA ) ||
+            mpi_cmp_mpi( &pk_rsa( issuer_crt.pk )->N,
+                         &pk_rsa( *issuer_key )->N ) != 0 ||
+            mpi_cmp_mpi( &pk_rsa( issuer_crt.pk )->E,
+                         &pk_rsa( *issuer_key )->E ) != 0 )
+        {
+            printf( " failed\n  !  issuer_key does not match issuer certificate\n\n" );
+            ret = -1;
+            goto exit;
+        }
+    }
+
+    printf( " ok\n" );
+
+    if( opt.selfsign )
+    {
+        opt.issuer_name = opt.subject_name;
+        subject_key = issuer_key;
+    }
+
+    x509write_crt_set_subject_key( &crt, subject_key );
+    x509write_crt_set_issuer_key( &crt, issuer_key );
+
+    /*
+     * 1.0. Check the names for validity
+     */
+    if( ( ret = x509write_crt_set_subject_name( &crt, opt.subject_name ) ) != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  x509write_crt_set_subject_name returned -0x%02x - %s\n\n", -ret, buf );
+        goto exit;
+    }
+
+    if( ( ret = x509write_crt_set_issuer_name( &crt, opt.issuer_name ) ) != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  x509write_crt_set_issuer_name returned -0x%02x - %s\n\n", -ret, buf );
+        goto exit;
+    }
+
+    printf( "  . Setting certificate values ..." );
+    fflush( stdout );
+
+    ret = x509write_crt_set_serial( &crt, &serial );
+    if( ret != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  x509write_crt_set_serial returned -0x%02x - %s\n\n", -ret, buf );
+        goto exit;
+    }
+
+    ret = x509write_crt_set_validity( &crt, opt.not_before, opt.not_after );
+    if( ret != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  x509write_crt_set_validity returned -0x%02x - %s\n\n", -ret, buf );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    printf( "  . Adding the Basic Constraints extension ..." );
+    fflush( stdout );
+
+    ret = x509write_crt_set_basic_constraints( &crt, opt.is_ca,
+                                               opt.max_pathlen );
+    if( ret != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  x509write_crt_set_basic_contraints returned -0x%02x - %s\n\n", -ret, buf );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    printf( "  . Adding the Subject Key Identifier ..." );
+    fflush( stdout );
+
+    ret = x509write_crt_set_subject_key_identifier( &crt );
+    if( ret != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  x509write_crt_set_subject_key_identifier returned -0x%02x - %s\n\n", -ret, buf );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    printf( "  . Adding the Authority Key Identifier ..." );
+    fflush( stdout );
+
+    ret = x509write_crt_set_authority_key_identifier( &crt );
+    if( ret != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  x509write_crt_set_authority_key_identifier returned -0x%02x - %s\n\n", -ret, buf );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    if( opt.key_usage )
+    {
+        printf( "  . Adding the Key Usage extension ..." );
+        fflush( stdout );
+
+        ret = x509write_crt_set_key_usage( &crt, opt.key_usage );
+        if( ret != 0 )
+        {
+            error_strerror( ret, buf, 1024 );
+            printf( " failed\n  !  x509write_crt_set_key_usage returned -0x%02x - %s\n\n", -ret, buf );
+            goto exit;
+        }
+
+        printf( " ok\n" );
+    }
+
+    if( opt.ns_cert_type )
+    {
+        printf( "  . Adding the NS Cert Type extension ..." );
+        fflush( stdout );
+
+        ret = x509write_crt_set_ns_cert_type( &crt, opt.ns_cert_type );
+        if( ret != 0 )
+        {
+            error_strerror( ret, buf, 1024 );
+            printf( " failed\n  !  x509write_crt_set_ns_cert_type returned -0x%02x - %s\n\n", -ret, buf );
+            goto exit;
+        }
+
+        printf( " ok\n" );
+    }
+
+    /*
+     * 1.2. Writing the request
+     */
+    printf( "  . Writing the certificate..." );
+    fflush( stdout );
+
+    if( ( ret = write_certificate( &crt, opt.output_file,
+                                   ctr_drbg_random, &ctr_drbg ) ) != 0 )
+    {
+        error_strerror( ret, buf, 1024 );
+        printf( " failed\n  !  write_certifcate -0x%02x - %s\n\n", -ret, buf );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+exit:
+    x509write_crt_free( &crt );
+    pk_free( &loaded_subject_key );
+    pk_free( &loaded_issuer_key );
+    mpi_free( &serial );
+
+#if defined(_WIN32)
+    printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
+#endif /* POLARSSL_X509_WRITE_C && POLARSSL_X509_PARSE_C && POLARSSL_FS_IO &&
+          POLARSSL_ENTROPY_C && POLARSSL_CTR_DRBG_C &&
+          POLARSSL_ERROR_C */
diff --git a/programs/x509/crl_app.c b/programs/x509/crl_app.c
index b98e743..c9c3ef0 100644
--- a/programs/x509/crl_app.c
+++ b/programs/x509/crl_app.c
@@ -35,6 +35,19 @@
 
 #include "polarssl/x509.h"
 
+#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) ||  \
+    !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO)
+int main( int argc, char *argv[] )
+{
+    ((void) argc);
+    ((void) argv);
+
+    printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or "
+           "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO not defined.\n");
+    return( 0 );
+}
+#else
+
 #define DFL_FILENAME            "crl.pem"
 #define DFL_DEBUG_LEVEL         0
 
@@ -52,18 +65,6 @@
     "    filename=%%s         default: crl.pem\n"      \
     "\n"
 
-#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) ||  \
-    !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO)
-int main( int argc, char *argv[] )
-{
-    ((void) argc);
-    ((void) argv);
-
-    printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or "
-           "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO not defined.\n");
-    return( 0 );
-}
-#else
 int main( int argc, char *argv[] )
 {
     int ret = 0;
diff --git a/programs/x509/req_app.c b/programs/x509/req_app.c
new file mode 100644
index 0000000..e2faab4
--- /dev/null
+++ b/programs/x509/req_app.c
@@ -0,0 +1,153 @@
+/*
+ *  Certificate request reading application
+ *
+ *  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/x509.h"
+
+#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) ||  \
+    !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO)
+int main( int argc, char *argv[] )
+{
+    ((void) argc);
+    ((void) argv);
+
+    printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or "
+           "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO not defined.\n");
+    return( 0 );
+}
+#else
+
+#define DFL_FILENAME            "cert.req"
+#define DFL_DEBUG_LEVEL         0
+
+/*
+ * global options
+ */
+struct options
+{
+    const char *filename;       /* filename of the certificate request  */
+} opt;
+
+#define USAGE \
+    "\n usage: req_app param=<>...\n"                   \
+    "\n acceptable parameters:\n"                       \
+    "    filename=%%s         default: cert.req\n"      \
+    "\n"
+
+int main( int argc, char *argv[] )
+{
+    int ret = 0;
+    unsigned char buf[100000];
+    x509_csr csr;
+    int i, j, n;
+    char *p, *q;
+
+    /*
+     * Set to sane values
+     */
+    memset( &csr, 0, sizeof( x509_csr ) );
+
+    if( argc == 0 )
+    {
+    usage:
+        printf( USAGE );
+        goto exit;
+    }
+
+    opt.filename            = DFL_FILENAME;
+
+    for( i = 1; i < argc; i++ )
+    {
+        n = strlen( argv[i] );
+
+        for( j = 0; j < n; j++ )
+        {
+            if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' )
+                argv[i][j] |= 0x20;
+        }
+
+        p = argv[i];
+        if( ( q = strchr( p, '=' ) ) == NULL )
+            goto usage;
+        *q++ = '\0';
+
+        if( strcmp( p, "filename" ) == 0 )
+            opt.filename = q;
+        else
+            goto usage;
+    }
+
+    /*
+     * 1.1. Load the CSR
+     */
+    printf( "\n  . Loading the CSR ..." );
+    fflush( stdout );
+
+    ret = x509parse_csrfile( &csr, opt.filename );
+
+    if( ret != 0 )
+    {
+        printf( " failed\n  !  x509parse_csr returned %d\n\n", ret );
+        x509_csr_free( &csr );
+        goto exit;
+    }
+
+    printf( " ok\n" );
+
+    /*
+     * 1.2 Print the CSR
+     */
+    printf( "  . CSR information    ...\n" );
+    ret = x509parse_csr_info( (char *) buf, sizeof( buf ) - 1, "      ", &csr );
+    if( ret == -1 )
+    {
+        printf( " failed\n  !  x509parse_csr_info returned %d\n\n", ret );
+        x509_csr_free( &csr );
+        goto exit;
+    }
+
+    printf( "%s\n", buf );
+
+exit:
+    x509_csr_free( &csr );
+
+#if defined(_WIN32)
+    printf( "  + Press Enter to exit this program.\n" );
+    fflush( stdout ); getchar();
+#endif
+
+    return( ret );
+}
+#endif /* POLARSSL_BIGNUM_C && POLARSSL_RSA_C && POLARSSL_X509_PARSE_C &&
+          POLARSSL_FS_IO */
diff --git a/tests/data_files/server1.pubkey b/tests/data_files/server1.pubkey
new file mode 100644
index 0000000..93c669c
--- /dev/null
+++ b/tests/data_files/server1.pubkey
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJl
+LhVhXom/uOhFkNvuiBZS0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA
+0INq1UFDd185fAkER4KwVzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMP
+QPhtgSVfCrFTxjB+FTms+Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZ
+vq1lLGTrlZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokL
+BNsupk9wbp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJU
+sQIDAQAB
+-----END PUBLIC KEY-----
diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data
index 7490b7c..fc9bb92 100644
--- a/tests/suites/test_suite_x509write.data
+++ b/tests/suites/test_suite_x509write.data
@@ -25,3 +25,23 @@
 Certificate Request check Server1 MD5
 depends_on:POLARSSL_MD5_C:POLARSSL_RSA_C:POLARSSL_PKCS1_V15
 x509_csr_check:"data_files/server1.key":POLARSSL_MD_MD5:"data_files/server1.req.md5"
+
+Certificate write check Server1 SHA1
+depends_on:POLARSSL_SHA1_C:POLARSSL_RSA_C:POLARSSL_PKCS1_V15
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":POLARSSL_MD_SHA1:"data_files/server1.crt"
+
+Public key write check RSA
+depends_on:POLARSSL_RSA_C:POLARSSL_BASE64_C
+x509_pubkey_check:"data_files/server1.pubkey"
+
+Public key write check EC
+depends_on:POLARSSL_ECP_C:POLARSSL_BASE64_C:POLARSSL_ECP_DP_SECP192R1_ENABLED
+x509_pubkey_check:"data_files/ec_pub.pem"
+
+Private key write check RSA
+depends_on:POLARSSL_RSA_C:POLARSSL_BASE64_C
+x509_key_check:"data_files/server1.key"
+
+Private key write check EC
+depends_on:POLARSSL_ECP_C:POLARSSL_BASE64_C:POLARSSL_ECP_DP_SECP192R1_ENABLED
+x509_key_check:"data_files/ec_prv.sec1.pem"
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index d3c801a..9352c9e 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -14,46 +14,174 @@
 void x509_csr_check( char *key_file, int md_type,
                           char *cert_req_check_file )
 {
-    rsa_context rsa;
+    pk_context key;
     pem_context pem;
-    x509_csr req;
+    x509write_csr req;
     unsigned char *c;
     unsigned char buf[4000];
     unsigned char check_buf[4000];
     int ret;
-    size_t olen = 2000;
+    size_t olen = sizeof( check_buf );
     FILE *f;
     char *subject_name = "C=NL,O=PolarSSL,CN=PolarSSL Server 1";
+    rnd_pseudo_info rnd_info;
 
-    memset( &rsa, 0, sizeof(rsa_context) );
-    ret = x509parse_keyfile_rsa( &rsa, key_file, NULL );
-    TEST_ASSERT( ret == 0 );
-    if( ret != 0 )
-        return;
+    memset( &rnd_info, 0x2a, sizeof( rnd_pseudo_info ) );
+
+    pk_init( &key );
+    TEST_ASSERT( x509parse_keyfile( &key, key_file, NULL ) == 0 );
 
     x509write_csr_init( &req );
     x509write_csr_set_md_alg( &req, md_type );
-    x509write_csr_set_rsa_key( &req, &rsa );
+    x509write_csr_set_key( &req, &key );
     TEST_ASSERT( x509write_csr_set_subject_name( &req, subject_name ) == 0 );
 
-    ret = x509write_csr_der( &req, buf, 4000 );
+    ret = x509write_csr_der( &req, buf, sizeof( buf ),
+                             rnd_pseudo_rand, &rnd_info );
     TEST_ASSERT( ret >= 0 );
 
-    c = buf + 3999 - ret;
+    c = buf + sizeof( buf ) - ret;
 
     f = fopen( cert_req_check_file, "r" );
     TEST_ASSERT( f != NULL );
-    fread( check_buf, 1, 4000, f );
+    fread( check_buf, 1, sizeof( check_buf ), f );
     fclose( f );
 
     pem_init( &pem );
     pem_read_buffer( &pem, "-----BEGIN CERTIFICATE REQUEST-----", "-----END CERTIFICATE REQUEST-----", check_buf, NULL, 0, &olen );
 
-    TEST_ASSERT( memcmp( c, pem.buf, pem.buflen ) == 0 );
     TEST_ASSERT( pem.buflen == (size_t) ret );
+    TEST_ASSERT( memcmp( c, pem.buf, pem.buflen ) == 0 );
 
     x509write_csr_free( &req );
-    rsa_free( &rsa );
     pem_free( &pem );
+    pk_free( &key );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void x509_crt_check( char *subject_key_file, char *subject_pwd,
+                     char *subject_name, char *issuer_key_file,
+                     char *issuer_pwd, char *issuer_name,
+                     char *serial_str, char *not_before, char *not_after,
+                     int md_type, char *cert_check_file )
+{
+    pk_context subject_key, issuer_key;
+    pem_context pem;
+    x509write_cert crt;
+    unsigned char *c;
+    unsigned char buf[4000];
+    unsigned char check_buf[5000];
+    mpi serial;
+    int ret;
+    size_t olen = sizeof( check_buf );
+    FILE *f;
+    rnd_pseudo_info rnd_info;
+
+    memset( &rnd_info, 0x2a, sizeof( rnd_pseudo_info ) );
+    mpi_init( &serial );
+    pk_init( &subject_key );
+    pk_init( &issuer_key );
+
+    TEST_ASSERT( x509parse_keyfile( &subject_key, subject_key_file,
+                                         subject_pwd ) == 0 );
+    TEST_ASSERT( x509parse_keyfile( &issuer_key, issuer_key_file,
+                                         issuer_pwd ) == 0 );
+    TEST_ASSERT( mpi_read_string( &serial, 10, serial_str ) == 0 );
+
+    x509write_crt_init( &crt );
+    x509write_crt_set_serial( &crt, &serial );
+    TEST_ASSERT( x509write_crt_set_validity( &crt, not_before,
+                                                   not_after ) == 0 );
+    x509write_crt_set_md_alg( &crt, md_type );
+    TEST_ASSERT( x509write_crt_set_issuer_name( &crt, issuer_name ) == 0 );
+    TEST_ASSERT( x509write_crt_set_subject_name( &crt, subject_name ) == 0 );
+    x509write_crt_set_subject_key( &crt, &subject_key );
+    x509write_crt_set_issuer_key( &crt, &issuer_key );
+
+    TEST_ASSERT( x509write_crt_set_basic_constraints( &crt, 0, 0 ) == 0 );
+    TEST_ASSERT( x509write_crt_set_subject_key_identifier( &crt ) == 0 );
+    TEST_ASSERT( x509write_crt_set_authority_key_identifier( &crt ) == 0 );
+
+    ret = x509write_crt_der( &crt, buf, sizeof(buf),
+                             rnd_pseudo_rand, &rnd_info );
+    TEST_ASSERT( ret >= 0 );
+
+    c = buf + sizeof( buf ) - ret;
+
+    f = fopen( cert_check_file, "r" );
+    TEST_ASSERT( f != NULL );
+    TEST_ASSERT( fread( check_buf, 1, sizeof(check_buf), f ) < sizeof(check_buf) );
+    fclose( f );
+
+    pem_init( &pem );
+    TEST_ASSERT( pem_read_buffer( &pem, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----", check_buf, NULL, 0, &olen ) >= 0 );
+
+    TEST_ASSERT( pem.buflen == (size_t) ret );
+    TEST_ASSERT( memcmp( c, pem.buf, pem.buflen ) == 0 );
+
+    x509write_crt_free( &crt );
+    pk_free( &issuer_key );
+    pk_free( &subject_key );
+    pem_free( &pem );
+    mpi_free( &serial );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void x509_pubkey_check( char *key_file )
+{
+    pk_context key;
+    unsigned char buf[5000];
+    unsigned char check_buf[5000];
+    int ret;
+    FILE *f;
+
+    memset( buf, 0, sizeof( buf ) );
+    memset( check_buf, 0, sizeof( check_buf ) );
+
+    pk_init( &key );
+    TEST_ASSERT( x509parse_public_keyfile( &key, key_file ) == 0 );
+
+    ret = x509write_pubkey_pem( &key, buf, sizeof( buf ) - 1);
+    TEST_ASSERT( ret >= 0 );
+
+    f = fopen( key_file, "r" );
+    TEST_ASSERT( f != NULL );
+    fread( check_buf, 1, sizeof( check_buf ) - 1, f );
+    fclose( f );
+
+    TEST_ASSERT( strncmp( (char *) buf, (char *) check_buf, sizeof( buf ) ) == 0 );
+
+    pk_free( &key );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void x509_key_check( char *key_file )
+{
+    pk_context key;
+    unsigned char buf[5000];
+    unsigned char check_buf[5000];
+    int ret;
+    FILE *f;
+
+    memset( buf, 0, sizeof( buf ) );
+    memset( check_buf, 0, sizeof( check_buf ) );
+
+    pk_init( &key );
+    TEST_ASSERT( x509parse_keyfile( &key, key_file, NULL ) == 0 );
+
+    ret = x509write_key_pem( &key, buf, sizeof( buf ) - 1);
+    TEST_ASSERT( ret >= 0 );
+
+    f = fopen( key_file, "r" );
+    TEST_ASSERT( f != NULL );
+    fread( check_buf, 1, sizeof( check_buf ) - 1, f );
+    fclose( f );
+
+    TEST_ASSERT( strncmp( (char *) buf, (char *) check_buf, sizeof( buf ) ) == 0 );
+
+    pk_free( &key );
 }
 /* END_CASE */