diff --git a/ChangeLog b/ChangeLog
index 549e43659..6cfdd0021 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,6 +20,8 @@ Features
* Support for zeros-and-length (ANSI X.923) padding, one-and-zeros
(ISO/IEC 7816-4) padding and zero padding in the cipher layer
* Support for session tickets (RFC 5077)
+ * Certificate Request (CSR) generation with extensions (key_usage,
+ ns_cert_type)
Changes
* Ability to enable / disable SSL v3 / TLS 1.0 / TLS 1.1 / TLS 1.2
diff --git a/include/polarssl/asn1.h b/include/polarssl/asn1.h
index 195ebcb84..ec8cbfafc 100644
--- a/include/polarssl/asn1.h
+++ b/include/polarssl/asn1.h
@@ -93,7 +93,10 @@
/** Returns the size of the binary string, without the trailing \\0 */
#define OID_SIZE(x) (sizeof(x) - 1)
-/** Compares two asn1_buf structures for the same OID */
+/** Compares two asn1_buf structures for the same OID. Only works for
+ * 'defined' oid_str values (OID_HMAC_SHA1), you cannot use a 'unsigned
+ * char *oid' here!
+ */
#define OID_CMP(oid_str, oid_buf) \
( ( OID_SIZE(oid_str) == (oid_buf)->len ) && \
memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) == 0 )
@@ -139,6 +142,17 @@ typedef struct _asn1_sequence
}
asn1_sequence;
+/**
+ * Container for a sequence or list of 'named' ASN.1 data items
+ */
+typedef struct _asn1_named_data
+{
+ asn1_buf oid; /**< The object identifier. */
+ asn1_buf val; /**< The named value. */
+ struct _asn1_named_data *next; /**< The next entry in the sequence. */
+}
+asn1_named_data;
+
/**
* Get the length of an ASN.1 element.
* Updates the pointer to immediately behind the length.
@@ -286,6 +300,25 @@ int asn1_get_alg_null( unsigned char **p,
const unsigned char *end,
asn1_buf *alg );
+/**
+ * Find a specific named_data entry in a sequence or list based on the OID.
+ *
+ * \param list The list to seek through
+ * \param oid The OID to look for
+ * \param len Size of the OID
+ *
+ * \return NULL if not found, or a pointer to the existing entry.
+ */
+asn1_named_data *asn1_find_named_data( asn1_named_data *list,
+ const char *oid, size_t len );
+
+/**
+ * Free a asn1_named_data entry
+ *
+ * \param entry The named data entry to free
+ */
+void asn1_free_named_data( asn1_named_data *entry );
+
#ifdef __cplusplus
}
#endif
diff --git a/include/polarssl/asn1write.h b/include/polarssl/asn1write.h
index 459b28256..4659b24c1 100644
--- a/include/polarssl/asn1write.h
+++ b/include/polarssl/asn1write.h
@@ -35,20 +35,164 @@
extern "C" {
#endif
+/**
+ * \brief Write a length field in ASN.1 format
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param len the length to write
+ *
+ * \return the length written or a negative error code
+ */
int asn1_write_len( unsigned char **p, unsigned char *start, size_t len );
+
+/**
+ * \brief Write a ASN.1 tag in ASN.1 format
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param tag the tag to write
+ *
+ * \return the length written or a negative error code
+ */
int asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag );
+
+/**
+ * \brief Write raw buffer data
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param buf data buffer to write
+ * \param size length of the data buffer
+ *
+ * \return the length written or a negative error code
+ */
+int asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
+ const unsigned char *buf, size_t size );
+
#if defined(POLARSSL_BIGNUM_C)
+/**
+ * \brief Write a big number (ASN1_INTEGER) in ASN.1 format
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param X the MPI to write
+ *
+ * \return the length written or a negative error code
+ */
int asn1_write_mpi( unsigned char **p, unsigned char *start, mpi *X );
#endif
+
+/**
+ * \brief Write a NULL tag (ASN1_NULL) with zero data in ASN.1 format
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ *
+ * \return the length written or a negative error code
+ */
int asn1_write_null( unsigned char **p, unsigned char *start );
+
+/**
+ * \brief Write an OID tag (ASN1_OID) and data in ASN.1 format
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param oid the OID to write
+ *
+ * \return the length written or a negative error code
+ */
int asn1_write_oid( unsigned char **p, unsigned char *start, const char *oid );
-int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, const char *algorithm_oid );
+
+/**
+ * \brief Write an AlgorithmIdentifier sequence in ASN.1 format
+ * Note: function works backwards in data buffer
+ * Note: Uses NULL as algorithm parameter
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param oid the OID of the algorithm
+ *
+ * \return the length written or a negative error code
+ */
+int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
+ const char *oid );
+
+/**
+ * \brief Write an int tag (ASN1_INTEGER) and value in ASN.1 format
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param val the integer value
+ *
+ * \return the length written or a negative error code
+ */
int asn1_write_int( unsigned char **p, unsigned char *start, int val );
+
+/**
+ * \brief Write a printable string tag (ASN1_PRINTABLE_STRING) and
+ * value in ASN.1 format
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param text the text to write
+ *
+ * \return the length written or a negative error code
+ */
int asn1_write_printable_string( unsigned char **p, unsigned char *start,
char *text );
+
+/**
+ * \brief Write an IA5 string tag (ASN1_IA5_STRING) and
+ * value in ASN.1 format
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param text the text to write
+ *
+ * \return the length written or a negative error code
+ */
int asn1_write_ia5_string( unsigned char **p, unsigned char *start,
char *text );
+/**
+ * \brief Write a bitstring tag (ASN1_BIT_STRING) and
+ * value in ASN.1 format
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param buf the bitstring
+ * \param bits the total number of bits in the bitstring
+ *
+ * \return the length written or a negative error code
+ */
+int asn1_write_bitstring( unsigned char **p, unsigned char *start,
+ const unsigned char *buf, size_t bits );
+
+/**
+ * \brief Write an octet string tag (ASN1_OCTET_STRING) and
+ * value in ASN.1 format
+ * Note: function works backwards in data buffer
+ *
+ * \param p reference to current position pointer
+ * \param start start of the buffer (for bounds-checking)
+ * \param buf data buffer to write
+ * \param size length of the data buffer
+ *
+ * \return the length written or a negative error code
+ */
+int asn1_write_octet_string( unsigned char **p, unsigned char *start,
+ const unsigned char *buf, size_t size );
#ifdef __cplusplus
}
#endif
diff --git a/include/polarssl/error.h b/include/polarssl/error.h
index 889e4bebc..4c9ef7c47 100644
--- a/include/polarssl/error.h
+++ b/include/polarssl/error.h
@@ -73,19 +73,20 @@
* PBKDF2 1 0x007C-0x007C
*
* High-level module nr (3 bits - 0x1...-0x8...)
- * Name ID Nr of Errors
- * PEM 1 9
- * PKCS#12 1 4 (Started from top)
- * X509 2 25
- * PK 2 3 (Started from top)
- * DHM 3 6
- * PKCS5 3 4 (Started from top)
- * RSA 4 9
- * ECP 4 4 (Started from top)
- * MD 5 4
- * CIPHER 6 5
- * SSL 6 6 (Started from top)
- * SSL 7 31
+ * Name ID Nr of Errors
+ * PEM 1 9
+ * PKCS#12 1 4 (Started from top)
+ * X509 2 25
+ * PK 2 3 (Started from top)
+ * DHM 3 6
+ * PKCS5 3 4 (Started from top)
+ * RSA 4 9
+ * ECP 4 4 (Started from top)
+ * MD 5 4
+ * X509WRITE 5 3 (Started from top)
+ * CIPHER 6 5
+ * SSL 6 6 (Started from top)
+ * SSL 7 31
*
* Module dependent error code (5 bits 0x.08.-0x.F8.)
*/
diff --git a/include/polarssl/oid.h b/include/polarssl/oid.h
index ebb5bad98..025a15f0a 100644
--- a/include/polarssl/oid.h
+++ b/include/polarssl/oid.h
@@ -227,6 +227,11 @@
#define OID_PKCS5_PBE_SHA1_DES_CBC OID_PKCS5 "\x0a" /**< pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10} */
#define OID_PKCS5_PBE_SHA1_RC2_CBC OID_PKCS5 "\x0b" /**< pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} */
+/*
+ * PKCS#8 OIDs
+ */
+#define OID_PKCS9_CSR_EXT_REQ OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */
+
/*
* PKCS#12 PBE OIDs
*/
diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h
index 878586233..e68789ce9 100644
--- a/include/polarssl/x509.h
+++ b/include/polarssl/x509.h
@@ -146,7 +146,7 @@
extern "C" {
#endif
-/**
+/**
* \addtogroup x509_module
* \{ */
@@ -154,8 +154,8 @@ extern "C" {
* \name Structures for parsing X.509 certificates and CRLs
* \{
*/
-
-/**
+
+/**
* Type-length-value structure that allows for ASN1 using DER.
*/
typedef asn1_buf x509_buf;
@@ -166,16 +166,10 @@ typedef asn1_buf x509_buf;
typedef asn1_bitstring x509_bitstring;
/**
- * Container for ASN1 named information objects.
+ * Container for ASN1 named information objects.
* It allows for Relative Distinguished Names (e.g. cn=polarssl,ou=code,etc.).
*/
-typedef struct _x509_name
-{
- x509_buf oid; /**< The object identifier. */
- x509_buf val; /**< The named value. */
- struct _x509_name *next; /**< The next named information object. */
-}
-x509_name;
+typedef asn1_named_data x509_name;
/**
* Container for a sequence of ASN.1 items
@@ -190,7 +184,7 @@ typedef struct _x509_time
}
x509_time;
-/**
+/**
* Container for an X.509 certificate. The certificate may be chained.
*/
typedef struct _x509_cert
@@ -289,42 +283,6 @@ x509_crl;
/** \} name Structures for parsing X.509 certificates and CRLs */
/** \} addtogroup x509_module */
-/**
- * \name Structures for writing X.509 certificates.
- * XvP: commented out as they are not used.
- * - typedef struct _x509_node x509_node;
- * - typedef struct _x509_raw x509_raw;
- */
-/*
-typedef struct _x509_node
-{
- unsigned char *data;
- unsigned char *p;
- unsigned char *end;
-
- size_t len;
-}
-x509_node;
-
-typedef struct _x509_raw
-{
- x509_node raw;
- x509_node tbs;
-
- x509_node version;
- x509_node serial;
- x509_node tbs_signalg;
- x509_node issuer;
- x509_node validity;
- x509_node subject;
- x509_node subpubkey;
-
- x509_node signalg;
- x509_node sign;
-}
-x509_raw;
-*/
-
/**
* \name Functions to read in DHM parameters, a certificate, CRL or private RSA key
* \{
diff --git a/include/polarssl/x509write.h b/include/polarssl/x509write.h
index 0d94f0154..0e443ee8c 100644
--- a/include/polarssl/x509write.h
+++ b/include/polarssl/x509write.h
@@ -29,14 +29,40 @@
#include "config.h"
-#if defined(POLARSSL_X509_WRITE_C)
+#include "x509.h"
-#include "rsa.h"
+/**
+ * \addtogroup x509_module
+ * \{
+ */
+
+/**
+ * \name X509 Write Error codes
+ * \{
+ */
+#define POLARSSL_ERR_X509WRITE_UNKNOWN_OID -0x5F80 /**< Requested OID is unknown. */
+#define POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA -0x5F00 /**< Failed to allocate memory. */
+#define POLARSSL_ERR_X509WRITE_MALLOC_FAILED -0x5E80 /**< Failed to allocate memory. */
+/* \} name */
+/* \} addtogroup x509_module */
#ifdef __cplusplus
extern "C" {
#endif
+/**
+ * \addtogroup x509_module
+ * \{
+ */
+
+/**
+ * \name Structures for writing X.509 CSRs (Certificate Signing Request)
+ * \{
+ */
+
+/**
+ * Container for CSR named objects
+ */
typedef struct _x509_req_name
{
char oid[128];
@@ -46,15 +72,187 @@ typedef struct _x509_req_name
}
x509_req_name;
-int x509_write_pubkey_der( unsigned char *buf, size_t size, rsa_context *rsa );
-int x509_write_key_der( unsigned char *buf, size_t size, rsa_context *rsa );
-int x509_write_cert_req( unsigned char *buf, size_t size, rsa_context *rsa,
- x509_req_name *req_name, md_type_t md_alg );
+/**
+ * Container for a CSR
+ */
+typedef struct _x509_csr
+{
+ rsa_context *rsa;
+ x509_req_name *subject;
+ md_type_t md_alg;
+ asn1_named_data *extensions;
+}
+x509_csr;
+
+/* \} addtogroup x509_module */
+
+/**
+ * \brief Initialize a CSR context
+ *
+ * \param ctx CSR context to initialize
+ */
+void x509write_csr_init( x509_csr *ctx );
+
+/**
+ * \brief Set the subject name for a CSR
+ * Subject names should contain a comma-separated list
+ * of OID types and values:
+ * e.g. "C=NL,O=Offspark,CN=PolarSSL Server 1"
+ *
+ * \param ctx CSR context to use
+ * \param subject_name subject name to set
+ *
+ * \return 0 if subject name was parsed successfully, or
+ * a specific error code
+ */
+int x509write_csr_set_subject_name( x509_csr *ctx, char *subject_name );
+
+/**
+ * \brief Set the RSA key for a CSR (public key will be included,
+ * private key used to sign the CSR when writing it)
+ *
+ * \param ctx CSR context to use
+ * \param rsa RSA key to include
+ */
+void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa );
+
+/**
+ * \brief Set the MD algorithm to use for the signature
+ * (e.g. POLARSSL_MD_SHA1)
+ *
+ * \param ctx CSR context to use
+ * \param md_ald MD algorithm to use
+ */
+void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg );
+
+/**
+ * \brief Set the Key Usage Extension flags
+ * (e.g. KU_DIGITAL_SIGNATURE | KU_KEY_CERT_SIGN)
+ *
+ * \param ctx CSR context to use
+ * \param key_usage key usage flags to set
+ *
+ * \return 0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED
+ */
+int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage );
+
+/**
+ * \brief Set the Netscape Cert Type flags
+ * (e.g. NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_EMAIL)
+ *
+ * \param ctx CSR context to use
+ * \param ns_cert_type Netscape Cert Type flags to set
+ *
+ * \return 0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED
+ */
+int x509write_csr_set_ns_cert_type( x509_csr *ctx, unsigned char ns_cert_type );
+
+/**
+ * \brief Generic function to add to or replace an extension in the CSR
+ *
+ * \param ctx CSR context to use
+ * \param oid OID of the extension
+ * \param oid_len length of the OID
+ * \param val value of the extension OCTET STRING
+ * \param val_len length of the value data
+ *
+ * \return 0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED
+ */
+int x509write_csr_set_extension( x509_csr *ctx,
+ const char *oid, size_t oid_len,
+ const unsigned char *val, size_t val_len );
+
+/**
+ * \brief Free the contents of a CSR context
+ *
+ * \param ctx CSR context to free
+ */
+void x509write_csr_free( x509_csr *ctx );
+
+/**
+ * \brief Write a RSA public key to a PKCS#1 DER structure
+ * Note: data is written at the end of the buffer! Use the
+ * return value to determine where you should start
+ * using the buffer
+ *
+ * \param rsa RSA to write away
+ * \param buf buffer to write to
+ * \param size size of the buffer
+ *
+ * \return length of data written if successful, or a specific
+ * error code
+ */
+int x509write_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size );
+
+/**
+ * \brief Write a RSA key to a PKCS#1 DER structure
+ * Note: data is written at the end of the buffer! Use the
+ * return value to determine where you should start
+ * using the buffer
+ *
+ * \param rsa RSA to write away
+ * \param buf buffer to write to
+ * \param size size of the buffer
+ *
+ * \return length of data written if successful, or a specific
+ * error code
+ */
+int x509write_key_der( rsa_context *rsa, unsigned char *buf, size_t size );
+
+/**
+ * \brief Write a CSR (Certificate Signing Request) to a
+ * DER structure
+ * Note: data is written at the end of the buffer! Use the
+ * return value to determine where you should start
+ * using the buffer
+ *
+ * \param rsa CSR to write away
+ * \param buf buffer to write to
+ * \param size size of the buffer
+ *
+ * \return length of data written if successful, or a specific
+ * error code
+ */
+int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size );
+
+#if defined(POLARSSL_BASE64_C)
+/**
+ * \brief Write a RSA public key to a PKCS#1 PEM string
+ *
+ * \param rsa RSA to write away
+ * \param buf buffer to write to
+ * \param size size of the buffer
+ *
+ * \return 0 successful, or a specific error code
+ */
+int x509write_pubkey_pem( rsa_context *rsa, unsigned char *buf, size_t size );
+
+/**
+ * \brief Write a RSA key to a PKCS#1 PEM string
+ *
+ * \param rsa RSA to write away
+ * \param buf buffer to write to
+ * \param size size of the buffer
+ *
+ * \return 0 successful, or a specific error code
+ */
+int x509write_key_pem( rsa_context *rsa, unsigned char *buf, size_t size );
+
+/**
+ * \brief Write a CSR (Certificate Signing Request) to a
+ * PEM string
+ *
+ * \param rsa CSR to write away
+ * \param buf buffer to write to
+ * \param size size of the buffer
+ *
+ * \return 0 successful, or a specific error code
+ */
+int x509write_csr_pem( x509_csr *ctx, unsigned char *buf, size_t size );
+#endif /* POLARSSL_BASE64_C */
#ifdef __cplusplus
}
#endif
-#endif /* POLARSSL_X509_WRITE_C */
-
#endif /* POLARSSL_X509_WRITE_H */
diff --git a/library/asn1parse.c b/library/asn1parse.c
index ff566c9ce..f6b271ec5 100644
--- a/library/asn1parse.c
+++ b/library/asn1parse.c
@@ -343,4 +343,32 @@ int asn1_get_alg_null( unsigned char **p,
return( 0 );
}
+void asn1_free_named_data( asn1_named_data *cur )
+{
+ if( cur == NULL )
+ return;
+
+ polarssl_free( cur->oid.p );
+ polarssl_free( cur->val.p );
+
+ memset( cur, 0, sizeof( asn1_named_data ) );
+}
+
+asn1_named_data *asn1_find_named_data( asn1_named_data *list,
+ const char *oid, size_t len )
+{
+ while( list != NULL )
+ {
+ if( list->oid.len == len &&
+ memcmp( list->oid.p, oid, len ) == 0 )
+ {
+ break;
+ }
+
+ list = list->next;
+ }
+
+ return( list );
+}
+
#endif
diff --git a/library/asn1write.c b/library/asn1write.c
index b1d68392f..463c730fb 100644
--- a/library/asn1write.c
+++ b/library/asn1write.c
@@ -72,6 +72,21 @@ int asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag )
return( 1 );
}
+int asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
+ const unsigned char *buf, size_t size )
+{
+ size_t len = 0;
+
+ if( *p - start < (int) size )
+ return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+
+ len = size;
+ (*p) -= len;
+ memcpy( *p, buf, len );
+
+ return( len );
+}
+
#if defined(POLARSSL_BIGNUM_C)
int asn1_write_mpi( unsigned char **p, unsigned char *start, mpi *X )
{
@@ -125,15 +140,8 @@ int asn1_write_oid( unsigned char **p, unsigned char *start, const char *oid )
int ret;
size_t len = 0;
- // Write OID
- //
- len = strlen( oid );
-
- if( *p - start < (int) len )
- return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
-
- (*p) -= len;
- memcpy( *p, oid, len );
+ ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
+ (const unsigned char *) oid, strlen( oid ) ) );
ASN1_CHK_ADD( len , asn1_write_len( p, start, len ) );
ASN1_CHK_ADD( len , asn1_write_tag( p, start, ASN1_OID ) );
@@ -142,7 +150,7 @@ int asn1_write_oid( unsigned char **p, unsigned char *start, const char *oid )
}
int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
- const char *algorithm_oid )
+ const char *oid )
{
int ret;
size_t null_len = 0;
@@ -155,7 +163,7 @@ int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
// Write OID
//
- ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, algorithm_oid ) );
+ ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, oid ) );
len = oid_len + null_len;
ASN1_CHK_ADD( len, asn1_write_len( p, start, oid_len + null_len ) );
@@ -201,43 +209,68 @@ int asn1_write_printable_string( unsigned char **p, unsigned char *start,
int ret;
size_t len = 0;
- // Write string
- //
- len = strlen( text );
-
- if( *p - start < (int) len )
- return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
-
- (*p) -= len;
- memcpy( *p, text, len );
+ ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
+ (const unsigned char *) text, strlen( text ) ) );
ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_PRINTABLE_STRING ) );
return( len );
}
-
+
int asn1_write_ia5_string( unsigned char **p, unsigned char *start,
- char *text )
+ char *text )
{
int ret;
size_t len = 0;
- // Write string
- //
- len = strlen( text );
-
- if( *p - start < (int) len )
- return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
-
- (*p) -= len;
- memcpy( *p, text, len );
+ ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start,
+ (const unsigned char *) text, strlen( text ) ) );
ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_IA5_STRING ) );
return( len );
}
-
+int asn1_write_bitstring( unsigned char **p, unsigned char *start,
+ const unsigned char *buf, size_t bits )
+{
+ int ret;
+ size_t len = 0, size;
+
+ size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 );
+
+ // Calculate byte length
+ //
+ if( *p - start < (int) size + 1 )
+ return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+
+ len = size + 1;
+ (*p) -= size;
+ memcpy( *p, buf, size );
+
+ // Write unused bits
+ //
+ *--(*p) = size * 8 - bits;
+
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_BIT_STRING ) );
+
+ return( len );
+}
+
+int asn1_write_octet_string( unsigned char **p, unsigned char *start,
+ const unsigned char *buf, size_t size )
+{
+ int ret;
+ size_t len = 0;
+
+ ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, buf, size ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_OCTET_STRING ) );
+
+ return( len );
+}
#endif
diff --git a/library/error.c b/library/error.c
index 35a4af086..86586dde2 100644
--- a/library/error.c
+++ b/library/error.c
@@ -149,6 +149,10 @@
#include "polarssl/x509.h"
#endif
+#if defined(POLARSSL_X509_WRITE_C)
+#include "polarssl/x509write.h"
+#endif
+
#if defined(POLARSSL_XTEA_C)
#include "polarssl/xtea.h"
#endif
@@ -432,6 +436,15 @@ void polarssl_strerror( int ret, char *buf, size_t buflen )
snprintf( buf, buflen, "X509 - Elliptic curve is unsupported (only NIST curves are supported)" );
#endif /* POLARSSL_X509_PARSE_C */
+#if defined(POLARSSL_X509_WRITE_C)
+ if( use_ret == -(POLARSSL_ERR_X509WRITE_UNKNOWN_OID) )
+ snprintf( buf, buflen, "X509WRITE - Requested OID is unknown" );
+ if( use_ret == -(POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA) )
+ snprintf( buf, buflen, "X509WRITE - Failed to allocate memory" );
+ if( use_ret == -(POLARSSL_ERR_X509WRITE_MALLOC_FAILED) )
+ snprintf( buf, buflen, "X509WRITE - Failed to allocate memory" );
+#endif /* POLARSSL_X509_WRITE_C */
+
if( strlen( buf ) == 0 )
snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret );
}
diff --git a/library/x509write.c b/library/x509write.c
index 7aa65ce37..7e04e1206 100644
--- a/library/x509write.c
+++ b/library/x509write.c
@@ -33,7 +33,231 @@
#include "polarssl/md.h"
#include "polarssl/oid.h"
-int x509_write_pubkey_der( unsigned char *buf, size_t size, rsa_context *rsa )
+#if defined(POLARSSL_BASE64_C)
+#include "polarssl/base64.h"
+#endif
+
+#if defined(POLARSSL_MEMORY_C)
+#include "polarssl/memory.h"
+#else
+#include
+#define polarssl_malloc malloc
+#define polarssl_free free
+#endif
+
+void x509write_csr_init( x509_csr *ctx )
+{
+ memset( ctx, 0, sizeof(x509_csr) );
+}
+
+void x509write_csr_free( x509_csr *ctx )
+{
+ x509_req_name *cur;
+ asn1_named_data *cur_ext;
+
+ while( ( cur = ctx->subject ) != NULL )
+ {
+ ctx->subject = cur->next;
+ polarssl_free( cur );
+ }
+
+ while( ( cur_ext = ctx->extensions ) != NULL )
+ {
+ ctx->extensions = cur_ext->next;
+ asn1_free_named_data( cur_ext );
+ polarssl_free( cur_ext );
+ }
+
+ memset( ctx, 0, sizeof(x509_csr) );
+}
+
+void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg )
+{
+ ctx->md_alg = md_alg;
+}
+
+void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa )
+{
+ ctx->rsa = rsa;
+}
+
+int x509write_csr_set_subject_name( x509_csr *ctx, char *subject_name )
+{
+ int ret = 0;
+ char *s = subject_name, *c = s;
+ char *end = s + strlen( s );
+ char *oid = NULL;
+ int in_tag = 1;
+ x509_req_name *cur;
+
+ while( ctx->subject )
+ {
+ cur = ctx->subject;
+ ctx->subject = ctx->subject->next;
+ polarssl_free( cur );
+ }
+
+ while( c <= end )
+ {
+ if( in_tag && *c == '=' )
+ {
+ if( memcmp( s, "CN", 2 ) == 0 && c - s == 2 )
+ oid = OID_AT_CN;
+ else if( memcmp( s, "C", 1 ) == 0 && c - s == 1 )
+ oid = OID_AT_COUNTRY;
+ else if( memcmp( s, "O", 1 ) == 0 && c - s == 1 )
+ oid = OID_AT_ORGANIZATION;
+ else if( memcmp( s, "L", 1 ) == 0 && c - s == 1 )
+ oid = OID_AT_LOCALITY;
+ else if( memcmp( s, "R", 1 ) == 0 && c - s == 1 )
+ oid = OID_PKCS9_EMAIL;
+ else if( memcmp( s, "OU", 2 ) == 0 && c - s == 2 )
+ oid = OID_AT_ORG_UNIT;
+ else if( memcmp( s, "ST", 2 ) == 0 && c - s == 2 )
+ oid = OID_AT_STATE;
+ else
+ {
+ ret = POLARSSL_ERR_X509WRITE_UNKNOWN_OID;
+ goto exit;
+ }
+
+ s = c + 1;
+ in_tag = 0;
+ }
+
+ if( !in_tag && ( *c == ',' || c == end ) )
+ {
+ if( c - s > 127 )
+ {
+ ret = POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA;
+ goto exit;
+ }
+
+ cur = polarssl_malloc( sizeof(x509_req_name) );
+
+ if( cur == NULL )
+ {
+ ret = POLARSSL_ERR_X509WRITE_MALLOC_FAILED;
+ goto exit;
+ }
+
+ memset( cur, 0, sizeof(x509_req_name) );
+
+ cur->next = ctx->subject;
+ ctx->subject = cur;
+
+ strncpy( cur->oid, oid, strlen( oid ) );
+ strncpy( cur->name, s, c - s );
+
+ s = c + 1;
+ in_tag = 1;
+ }
+ c++;
+ }
+
+exit:
+
+ return( ret );
+}
+
+int x509write_csr_set_extension( x509_csr *ctx,
+ const char *oid, size_t oid_len,
+ const unsigned char *val, size_t val_len )
+{
+ asn1_named_data *cur;
+
+ if( ( cur = asn1_find_named_data( ctx->extensions, oid,
+ oid_len ) ) == NULL )
+ {
+ cur = polarssl_malloc( sizeof(asn1_named_data) );
+ if( cur == NULL )
+ return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
+
+ memset( cur, 0, sizeof(asn1_named_data) );
+
+ cur->oid.len = oid_len;
+ cur->oid.p = polarssl_malloc( oid_len );
+ if( cur->oid.p == NULL )
+ {
+ polarssl_free( cur );
+ return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
+ }
+
+ cur->val.len = val_len;
+ cur->val.p = polarssl_malloc( val_len );
+ if( cur->val.p == NULL )
+ {
+ polarssl_free( cur->oid.p );
+ polarssl_free( cur );
+ return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
+ }
+
+ memcpy( cur->oid.p, oid, oid_len );
+
+ cur->next = ctx->extensions;
+ ctx->extensions = cur;
+ }
+
+ if( cur->val.len != val_len )
+ {
+ polarssl_free( cur->val.p );
+
+ cur->val.len = val_len;
+ cur->val.p = polarssl_malloc( val_len );
+ if( cur->val.p == NULL )
+ {
+ polarssl_free( cur->oid.p );
+ polarssl_free( cur );
+ return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
+ }
+ }
+
+ memcpy( cur->val.p, val, val_len );
+
+ return( 0 );
+}
+
+int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage )
+{
+ unsigned char buf[4];
+ unsigned char *c;
+ int ret;
+
+ c = buf + 4;
+
+ if( ( ret = asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
+ return( ret );
+
+ ret = x509write_csr_set_extension( ctx, OID_KEY_USAGE,
+ OID_SIZE( OID_KEY_USAGE ),
+ buf, 4 );
+ if( ret != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+int x509write_csr_set_ns_cert_type( x509_csr *ctx, unsigned char ns_cert_type )
+{
+ unsigned char buf[4];
+ unsigned char *c;
+ int ret;
+
+ c = buf + 4;
+
+ if( ( ret = asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
+ return( ret );
+
+ ret = x509write_csr_set_extension( ctx, OID_NS_CERT_TYPE,
+ OID_SIZE( OID_NS_CERT_TYPE ),
+ buf, 4 );
+ if( ret != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+int x509write_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size )
{
int ret;
unsigned char *c;
@@ -41,6 +265,12 @@ int x509_write_pubkey_der( unsigned char *buf, size_t size, rsa_context *rsa )
c = buf + size - 1;
+ /*
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER -- e
+ * }
+ */
ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->E ) );
ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->N ) );
@@ -50,6 +280,11 @@ int x509_write_pubkey_der( unsigned char *buf, size_t size, rsa_context *rsa )
if( c - buf < 1 )
return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+ /*
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING }
+ */
*--c = 0;
len += 1;
@@ -64,7 +299,7 @@ int x509_write_pubkey_der( unsigned char *buf, size_t size, rsa_context *rsa )
return( len );
}
-int x509_write_key_der( unsigned char *buf, size_t size, rsa_context *rsa )
+int x509write_key_der( rsa_context *rsa, unsigned char *buf, size_t size )
{
int ret;
unsigned char *c;
@@ -167,8 +402,7 @@ static int x509_write_sig( unsigned char **p, unsigned char *start,
return( len );
}
-int x509_write_cert_req( unsigned char *buf, size_t size, rsa_context *rsa,
- x509_req_name *req_name, md_type_t md_alg )
+int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size )
{
int ret;
const char *sig_oid;
@@ -178,15 +412,52 @@ int x509_write_cert_req( unsigned char *buf, size_t size, rsa_context *rsa,
unsigned char tmp_buf[2048];
size_t sub_len = 0, pub_len = 0, sig_len = 0;
size_t len = 0;
- x509_req_name *cur = req_name;
+ x509_req_name *cur = ctx->subject;
+ asn1_named_data *cur_ext = ctx->extensions;
c = tmp_buf + 2048 - 1;
- ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, 0 ) );
+ while( cur_ext != NULL )
+ {
+ size_t ext_len = 0;
+
+ ASN1_CHK_ADD( ext_len, asn1_write_raw_buffer( &c, tmp_buf, cur_ext->val.p,
+ cur_ext->val.len ) );
+ ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, cur_ext->val.len ) );
+ ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_OCTET_STRING ) );
+
+ ASN1_CHK_ADD( ext_len, asn1_write_raw_buffer( &c, tmp_buf, cur_ext->oid.p,
+ cur_ext->oid.len ) );
+ ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, cur_ext->oid.len ) );
+ ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_OID ) );
+
+ ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, ext_len ) );
+ ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ cur_ext = cur_ext->next;
+
+ len += ext_len;
+ }
+
+ if( len )
+ {
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SET ) );
+
+ ASN1_CHK_ADD( len, asn1_write_oid( &c, tmp_buf, OID_PKCS9_CSR_EXT_REQ ) );
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
+ ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+ }
+
+ ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC ) );
- ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &rsa->E ) );
- ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &rsa->N ) );
+ ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &ctx->rsa->E ) );
+ ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &ctx->rsa->N ) );
ASN1_CHK_ADD( pub_len, asn1_write_len( &c, tmp_buf, pub_len ) );
ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
@@ -194,6 +465,11 @@ int x509_write_cert_req( unsigned char *buf, size_t size, rsa_context *rsa,
if( c - tmp_buf < 1 )
return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL );
+ /*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ */
*--c = 0;
pub_len += 1;
@@ -217,21 +493,24 @@ int x509_write_cert_req( unsigned char *buf, size_t size, rsa_context *rsa,
ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) );
ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
+ /*
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ */
ASN1_CHK_ADD( len, asn1_write_int( &c, tmp_buf, 0 ) );
ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) );
ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) );
- md( md_info_from_type( md_alg ), c, len, hash );
+ md( md_info_from_type( ctx->md_alg ), c, len, hash );
- rsa_pkcs1_sign( rsa, NULL, NULL, RSA_PRIVATE, md_alg, 0, hash, sig );
+ rsa_pkcs1_sign( ctx->rsa, NULL, NULL, RSA_PRIVATE, ctx->md_alg, 0, hash, sig );
// Generate correct OID
//
- ret = oid_get_oid_by_sig_alg( POLARSSL_PK_RSA, md_alg, &sig_oid );
+ ret = oid_get_oid_by_sig_alg( POLARSSL_PK_RSA, ctx->md_alg, &sig_oid );
c2 = buf + size - 1;
- ASN1_CHK_ADD( sig_len, x509_write_sig( &c2, buf, sig_oid, sig, rsa->len ) );
+ ASN1_CHK_ADD( sig_len, x509_write_sig( &c2, buf, sig_oid, sig, ctx->rsa->len ) );
c2 -= len;
memcpy( c2, c, len );
@@ -243,4 +522,117 @@ int x509_write_cert_req( unsigned char *buf, size_t size, rsa_context *rsa,
return( len );
}
+#define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n"
+#define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n"
+
+#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n"
+#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n"
+
+#define PEM_BEGIN_PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----\n"
+#define PEM_END_PRIVATE_KEY "-----END RSA PRIVATE KEY-----\n"
+
+#if defined(POLARSSL_BASE64_C)
+static int x509write_pemify( const char *begin_str, const char *end_str,
+ const unsigned char *der_data, size_t der_len,
+ unsigned char *buf, size_t size )
+{
+ int ret;
+ unsigned char base_buf[4096];
+ unsigned char *c = base_buf, *p = buf;
+ size_t len = 0, olen = sizeof(base_buf);
+
+ if( ( ret = base64_encode( base_buf, &olen, der_data, der_len ) ) != 0 )
+ return( ret );
+
+ if( olen + strlen( begin_str ) + strlen( end_str ) +
+ olen / 64 > size )
+ {
+ return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
+ }
+
+ memcpy( p, begin_str, strlen( begin_str ) );
+ p += strlen( begin_str );
+
+ while( olen )
+ {
+ len = ( olen > 64 ) ? 64 : olen;
+ memcpy( p, c, len );
+ olen -= len;
+ p += len;
+ c += len;
+ *p++ = '\n';
+ }
+
+ memcpy( p, end_str, strlen( end_str ) );
+ p += strlen( end_str );
+
+ *p = '\0';
+
+ return( 0 );
+}
+
+int x509write_pubkey_pem( rsa_context *rsa, unsigned char *buf, size_t size )
+{
+ int ret;
+ unsigned char output_buf[4096];
+
+ if( ( ret = x509write_pubkey_der( rsa, output_buf,
+ sizeof(output_buf) ) ) < 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = x509write_pemify( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
+ output_buf + sizeof(output_buf) - 1 - ret,
+ ret, buf, size ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+}
+
+int x509write_key_pem( rsa_context *rsa, unsigned char *buf, size_t size )
+{
+ int ret;
+ unsigned char output_buf[4096];
+
+ if( ( ret = x509write_key_der( rsa, output_buf,
+ sizeof(output_buf) ) ) < 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = x509write_pemify( PEM_BEGIN_PRIVATE_KEY, PEM_END_PRIVATE_KEY,
+ output_buf + sizeof(output_buf) - 1 - ret,
+ ret, buf, size ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+}
+
+int x509write_csr_pem( x509_csr *ctx, unsigned char *buf, size_t size )
+{
+ int ret;
+ unsigned char output_buf[4096];
+
+ if( ( ret = x509write_csr_der( ctx, output_buf,
+ sizeof(output_buf) ) ) < 0 )
+ {
+ return( ret );
+ }
+
+ if( ( ret = x509write_pemify( PEM_BEGIN_CSR, PEM_END_CSR,
+ output_buf + sizeof(output_buf) - 1 - ret,
+ ret, buf, size ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ return( 0 );
+}
+#endif /* POLARSSL_BASE64_C */
+
#endif
diff --git a/programs/.gitignore b/programs/.gitignore
index e9f4e54ef..2b7510f6e 100644
--- a/programs/.gitignore
+++ b/programs/.gitignore
@@ -35,6 +35,7 @@ test/o_p_test
test/selftest
test/ssl_cert_test
test/ssl_test
+util/pem2der
util/strerror
x509/cert_app
x509/cert_req
diff --git a/programs/Makefile b/programs/Makefile
index 1c2b5fc80..ea024fae6 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -39,7 +39,7 @@ APPS = aes/aescrypt2 aes/crypt_and_hash \
test/ssl_cert_test test/benchmark \
test/selftest test/ssl_test \
test/ecp-bench \
- util/strerror \
+ util/pem2der util/strerror \
x509/cert_app x509/crl_app \
x509/cert_req
@@ -195,6 +195,10 @@ test/o_p_test: test/o_p_test.c ../library/libpolarssl.a
echo " CC test/o_p_test.c"
$(CC) $(CFLAGS) $(OFLAGS) test/o_p_test.c $(LDFLAGS) -o $@ -lssl -lcrypto
+util/pem2der: util/pem2der.c ../library/libpolarssl.a
+ echo " CC util/pem2der.c"
+ $(CC) $(CFLAGS) $(OFLAGS) util/pem2der.c $(LDFLAGS) -o $@
+
util/strerror: util/strerror.c ../library/libpolarssl.a
echo " CC util/strerror.c"
$(CC) $(CFLAGS) $(OFLAGS) util/strerror.c $(LDFLAGS) -o $@
diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c
index 88cb9071c..d9ab45c94 100644
--- a/programs/pkey/key_app_writer.c
+++ b/programs/pkey/key_app_writer.c
@@ -1,5 +1,5 @@
/*
- * Key reading application
+ * Key writing application
*
* Copyright (C) 2006-2013, Brainspark B.V.
*
@@ -60,11 +60,15 @@ int main( int argc, char *argv[] )
#define OUTPUT_MODE_PRIVATE 1
#define OUTPUT_MODE_PUBLIC 2
+#define OUTPUT_FORMAT_PEM 0
+#define OUTPUT_FORMAT_DER 1
+
#define DFL_MODE MODE_NONE
#define DFL_FILENAME "keyfile.key"
#define DFL_DEBUG_LEVEL 0
-#define DFL_OUTPUT_MODE OUTPUT_MODE_NONE
+#define DFL_OUTPUT_MODE OUTPUT_MODE_NONE
#define DFL_OUTPUT_FILENAME "keyfile.pem"
+#define DFL_OUTPUT_FORMAT OUTPUT_FORMAT_PEM
/*
* global options
@@ -75,79 +79,80 @@ struct options
const char *filename; /* filename of the key file */
int output_mode; /* the output mode to use */
const char *output_file; /* where to store the constructed key file */
+ int output_format; /* the output format to use */
} opt;
-static void write_public_key( rsa_context *rsa, const char *output_file )
+static int write_public_key( rsa_context *rsa, const char *output_file )
{
+ int ret;
FILE *f;
unsigned char output_buf[16000];
- unsigned char base_buf[16000];
- unsigned char *c;
- int ret;
- size_t len = 0, olen = 16000;
+ unsigned char *c = output_buf;
+ size_t len = 0;
memset(output_buf, 0, 16000);
- ret = x509_write_pubkey_der( output_buf, 16000, rsa );
- if( ret < 0 )
- return;
-
- len = ret;
- c = output_buf + 15999 - len;
-
- base64_encode( base_buf, &olen, c, len );
-
- c = base_buf;
-
- f = fopen( output_file, "w" );
- fprintf(f, "-----BEGIN PUBLIC KEY-----\n");
- while (olen)
+ if( opt.output_format == OUTPUT_FORMAT_PEM )
{
- int use_len = olen;
- if (use_len > 64) use_len = 64;
- fwrite( c, 1, use_len, f );
- olen -= use_len;
- c += use_len;
- fprintf(f, "\n");
+ if( ( ret = x509write_pubkey_pem( rsa, output_buf, 16000 ) ) != 0 )
+ return( ret );
+
+ len = strlen( (char *) output_buf );
}
- fprintf(f, "-----END PUBLIC KEY-----\n");
+ else
+ {
+ if( ( ret = x509write_pubkey_der( rsa, output_buf, 16000 ) ) < 0 )
+ return( ret );
+
+ len = ret;
+ c = output_buf + sizeof(output_buf) - len - 1;
+ }
+
+ if( ( f = fopen( output_file, "w" ) ) == NULL )
+ return( -1 );
+
+ if( fwrite( c, 1, len, f ) != len )
+ return( -1 );
+
fclose(f);
+
+ return( 0 );
}
-static void write_private_key( rsa_context *rsa, const char *output_file )
+static int write_private_key( rsa_context *rsa, const char *output_file )
{
+ int ret;
FILE *f;
unsigned char output_buf[16000];
- unsigned char base_buf[16000];
- unsigned char *c;
- int ret;
- size_t len = 0, olen = 16000;
+ unsigned char *c = output_buf;
+ size_t len = 0;
memset(output_buf, 0, 16000);
- ret = x509_write_key_der( output_buf, 16000, rsa );
- if( ret < 0 )
- return;
-
- len = ret;
- c = output_buf + 15999 - len;
-
- base64_encode( base_buf, &olen, c, len );
-
- c = base_buf;
-
- f = fopen( output_file, "w" );
- fprintf(f, "-----BEGIN RSA PRIVATE KEY-----\n");
- while (olen)
+ if( opt.output_format == OUTPUT_FORMAT_PEM )
{
- int use_len = olen;
- if (use_len > 64) use_len = 64;
- fwrite( c, 1, use_len, f );
- olen -= use_len;
- c += use_len;
- fprintf(f, "\n");
+ if( ( ret = x509write_key_pem( rsa, output_buf, 16000 ) ) != 0 )
+ return( ret );
+
+ len = strlen( (char *) output_buf );
}
- fprintf(f, "-----END RSA PRIVATE KEY-----\n");
+ else
+ {
+ if( ( ret = x509write_key_der( rsa, output_buf, 16000 ) ) < 0 )
+ return( ret );
+
+ len = ret;
+ c = output_buf + sizeof(output_buf) - len - 1;
+ }
+
+ if( ( f = fopen( output_file, "w" ) ) == NULL )
+ return( -1 );
+
+ if( fwrite( c, 1, len, f ) != len )
+ return( -1 );
+
fclose(f);
+
+ return( 0 );
}
#define USAGE \
@@ -156,7 +161,8 @@ static void write_private_key( rsa_context *rsa, const char *output_file )
" mode=private|public default: none\n" \
" filename=%%s default: keyfile.key\n" \
" output_mode=private|public default: none\n" \
- " output_file=%%s defeult: keyfile.pem\n" \
+ " output_file=%%s default: keyfile.pem\n" \
+ " output_format=pem|der default: pem\n" \
"\n"
int main( int argc, char *argv[] )
@@ -184,6 +190,7 @@ int main( int argc, char *argv[] )
opt.filename = DFL_FILENAME;
opt.output_mode = DFL_OUTPUT_MODE;
opt.output_file = DFL_OUTPUT_FILENAME;
+ opt.output_format = DFL_OUTPUT_FORMAT;
for( i = 1; i < argc; i++ )
{
@@ -210,6 +217,15 @@ int main( int argc, char *argv[] )
else
goto usage;
}
+ else if( strcmp( p, "output_format" ) == 0 )
+ {
+ if( strcmp( q, "pem" ) == 0 )
+ opt.output_format = OUTPUT_FORMAT_PEM;
+ else if( strcmp( q, "der" ) == 0 )
+ opt.output_format = OUTPUT_FORMAT_DER;
+ else
+ goto usage;
+ }
else if( strcmp( p, "filename" ) == 0 )
opt.filename = q;
else if( strcmp( p, "output_file" ) == 0 )
diff --git a/programs/util/CMakeLists.txt b/programs/util/CMakeLists.txt
index c0f2e4cea..aedd94f58 100644
--- a/programs/util/CMakeLists.txt
+++ b/programs/util/CMakeLists.txt
@@ -5,6 +5,9 @@ set(libs
add_executable(strerror strerror.c)
target_link_libraries(strerror ${libs})
-install(TARGETS strerror
+add_executable(pem2der pem2der.c)
+target_link_libraries(pem2der ${libs})
+
+install(TARGETS strerror pem2der
DESTINATION "bin"
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
diff --git a/programs/util/pem2der.c b/programs/util/pem2der.c
new file mode 100644
index 000000000..0315f02ea
--- /dev/null
+++ b/programs/util/pem2der.c
@@ -0,0 +1,288 @@
+/*
+ * Convert PEM to DER
+ *
+ * Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ * This file is part of PolarSSL (http://www.polarssl.org)
+ * Lead Maintainer: Paul Bakker
+ *
+ * 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
+#include
+#include
+
+#include "polarssl/config.h"
+
+#include "polarssl/error.h"
+#include "polarssl/base64.h"
+
+#define DFL_FILENAME "file.pem"
+#define DFL_OUTPUT_FILENAME "file.der"
+
+/*
+ * global options
+ */
+struct options
+{
+ char *filename; /* filename of the input file */
+ char *output_file; /* where to store the output */
+} opt;
+
+int convert_pem_to_der( const unsigned char *input, size_t ilen,
+ unsigned char *output, size_t *olen )
+{
+ int ret;
+ const unsigned char *s1, *s2, *end = input + ilen;
+ size_t len = 0;
+
+ s1 = (unsigned char *) strstr( (char *) input, "-----BEGIN" );
+ if( s1 == NULL )
+ return( -1 );
+
+ s2 = (unsigned char *) strstr( (char *) input, "-----END" );
+ if( s2 == NULL )
+ return( -1 );
+
+ s1 += 10;
+ while( s1 < end && *s1 != '-' )
+ s1++;
+ while( s1 < end && *s1 == '-' )
+ s1++;
+ if( *s1 == '\r' ) s1++;
+ if( *s1 == '\n' ) s1++;
+
+ if( s2 <= s1 || s2 > end )
+ return( -1 );
+
+ ret = base64_decode( NULL, &len, (const unsigned char *) s1, s2 - s1 );
+ if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER )
+ return( ret );
+
+ if( len > *olen )
+ return( -1 );
+
+ if( ( ret = base64_decode( output, &len, (const unsigned char *) s1,
+ s2 - s1 ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ *olen = len;
+
+ return( 0 );
+}
+
+/*
+ * Load all data from a file into a given buffer.
+ */
+static int load_file( const char *path, unsigned char **buf, size_t *n )
+{
+ FILE *f;
+ long size;
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( -1 );
+
+ fseek( f, 0, SEEK_END );
+ if( ( size = ftell( f ) ) == -1 )
+ {
+ fclose( f );
+ return( -1 );
+ }
+ fseek( f, 0, SEEK_SET );
+
+ *n = (size_t) size;
+
+ if( *n + 1 == 0 ||
+ ( *buf = (unsigned char *) malloc( *n + 1 ) ) == NULL )
+ {
+ fclose( f );
+ return( -1 );
+ }
+
+ if( fread( *buf, 1, *n, f ) != *n )
+ {
+ fclose( f );
+ free( *buf );
+ return( -1 );
+ }
+
+ fclose( f );
+
+ (*buf)[*n] = '\0';
+
+ return( 0 );
+}
+
+/*
+ * Write buffer to a file
+ */
+static int write_file( const char *path, unsigned char *buf, size_t n )
+{
+ FILE *f;
+
+ if( ( f = fopen( path, "wb" ) ) == NULL )
+ return( -1 );
+
+ if( fwrite( buf, 1, n, f ) != n )
+ {
+ fclose( f );
+ return( -1 );
+ }
+
+ fclose( f );
+ return( 0 );
+}
+
+#define USAGE \
+ "\n usage: pem2der param=<>...\n" \
+ "\n acceptable parameters:\n" \
+ " filename=%%s default: file.pem\n" \
+ " output_file=%%s default: file.der\n" \
+ "\n"
+
+#if !defined(POLARSSL_BASE64_C) || !defined(POLARSSL_FS_IO)
+int main( int argc, char *argv[] )
+{
+ ((void) argc);
+ ((void) argv);
+
+ printf("POLARSSL_BASE64_C and/or POLARSSL_FS_IO not defined.\n");
+ return( 0 );
+}
+#else
+int main( int argc, char *argv[] )
+{
+ int ret = 0;
+ unsigned char *pem_buffer = NULL;
+ unsigned char der_buffer[4096];
+ char buf[1024];
+ size_t pem_size, der_size = sizeof(der_buffer);
+ int i, j, n;
+ char *p, *q;
+
+ /*
+ * Set to sane values
+ */
+ memset( buf, 0, sizeof(buf) );
+ memset( der_buffer, 0, sizeof(der_buffer) );
+
+ if( argc == 0 )
+ {
+ usage:
+ printf( USAGE );
+ goto exit;
+ }
+
+ opt.filename = DFL_FILENAME;
+ opt.output_file = DFL_OUTPUT_FILENAME;
+
+ for( i = 1; i < argc; i++ )
+ {
+
+ p = argv[i];
+ if( ( q = strchr( p, '=' ) ) == NULL )
+ goto usage;
+ *q++ = '\0';
+
+ n = strlen( p );
+ for( j = 0; j < n; j++ )
+ {
+ if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' )
+ argv[i][j] |= 0x20;
+ }
+
+ if( strcmp( p, "filename" ) == 0 )
+ opt.filename = q;
+ else if( strcmp( p, "output_file" ) == 0 )
+ opt.output_file = q;
+ else
+ goto usage;
+ }
+
+ /*
+ * 1.1. Load the PEM file
+ */
+ printf( "\n . Loading the PEM file ..." );
+ fflush( stdout );
+
+ ret = load_file( opt.filename, &pem_buffer, &pem_size );
+
+ if( ret != 0 )
+ {
+#ifdef POLARSSL_ERROR_C
+ error_strerror( ret, buf, 1024 );
+#endif
+ printf( " failed\n ! load_file returned %d - %s\n\n", ret, buf );
+ goto exit;
+ }
+
+ printf( " ok\n" );
+
+ /*
+ * 1.2. Convert from PEM to DER
+ */
+ printf( " . Converting from PEM to DER ..." );
+ fflush( stdout );
+
+ if( ( ret = convert_pem_to_der( pem_buffer, pem_size, der_buffer, &der_size ) ) != 0 )
+ {
+#ifdef POLARSSL_ERROR_C
+ error_strerror( ret, buf, 1024 );
+#endif
+ printf( " failed\n ! convert_pem_to_der %d - %s\n\n", ret, buf );
+ goto exit;
+ }
+
+ printf( " ok\n" );
+
+ /*
+ * 1.3. Write the DER file
+ */
+ printf( " . Writing the DER file ..." );
+ fflush( stdout );
+
+ ret = write_file( opt.output_file, der_buffer, der_size );
+
+ if( ret != 0 )
+ {
+#ifdef POLARSSL_ERROR_C
+ error_strerror( ret, buf, 1024 );
+#endif
+ printf( " failed\n ! write_file returned %d - %s\n\n", ret, buf );
+ goto exit;
+ }
+
+ printf( " ok\n" );
+
+exit:
+ free( pem_buffer );
+
+#if defined(_WIN32)
+ printf( " + Press Enter to exit this program.\n" );
+ fflush( stdout ); getchar();
+#endif
+
+ return( ret );
+}
+#endif /* POLARSSL_BASE64_C && POLARSSL_FS_IO */
diff --git a/programs/x509/CMakeLists.txt b/programs/x509/CMakeLists.txt
index 08a962aef..d07cff82d 100644
--- a/programs/x509/CMakeLists.txt
+++ b/programs/x509/CMakeLists.txt
@@ -16,6 +16,9 @@ target_link_libraries(cert_app ${libs})
add_executable(crl_app crl_app.c)
target_link_libraries(crl_app ${libs})
-install(TARGETS cert_app crl_app
+add_executable(cert_req cert_req.c)
+target_link_libraries(cert_req ${libs})
+
+install(TARGETS cert_app crl_app cert_req
DESTINATION "bin"
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c
index cbd62521d..384ef08d6 100644
--- a/programs/x509/cert_req.c
+++ b/programs/x509/cert_req.c
@@ -44,6 +44,8 @@
#define DFL_DEBUG_LEVEL 0
#define DFL_OUTPUT_FILENAME "cert.req"
#define DFL_SUBJECT_NAME "CN=Cert,O=PolarSSL,C=NL"
+#define DFL_KEY_USAGE 0
+#define DFL_NS_CERT_TYPE 0
/*
* global options
@@ -54,53 +56,32 @@ struct options
int debug_level; /* level of debugging */
char *output_file; /* where to store the constructed key file */
char *subject_name; /* subject name for certificate request */
+ unsigned char key_usage; /* key usage flags */
+ unsigned char ns_cert_type; /* NS cert type */
} opt;
-void my_debug( void *ctx, int level, const char *str )
-{
- if( level < opt.debug_level )
- {
- fprintf( (FILE *) ctx, "%s", str );
- fflush( (FILE *) ctx );
- }
-}
-
-void write_certificate_request( rsa_context *rsa, x509_req_name *req_name,
- char *output_file )
+int write_certificate_request( x509_csr *req, char *output_file )
{
+ int ret;
FILE *f;
unsigned char output_buf[4096];
- unsigned char base_buf[4096];
- unsigned char *c;
- int ret;
- size_t len = 0, olen = 4096;
+ size_t len = 0;
- memset(output_buf, 0, 4096);
- ret = x509_write_cert_req( output_buf, 4096, rsa, req_name, POLARSSL_MD_SHA1 );
+ memset( output_buf, 0, 4096 );
+ if( ( ret = x509write_csr_pem( req, output_buf, 4096 ) ) < 0 )
+ return( ret );
- if( ret < 0 )
- return;
+ len = strlen( (char *) output_buf );
- len = ret;
- c = output_buf + 4095 - len;
+ if( ( f = fopen( output_file, "w" ) ) == NULL )
+ return( -1 );
- base64_encode( base_buf, &olen, c, len );
+ if( fwrite( output_buf, 1, len, f ) != len )
+ return( -1 );
- c = base_buf;
-
- f = fopen( output_file, "w" );
- fprintf(f, "-----BEGIN CERTIFICATE REQUEST-----\n");
- while (olen)
- {
- int use_len = olen;
- if (use_len > 64) use_len = 64;
- fwrite( c, 1, use_len, f );
- olen -= use_len;
- c += use_len;
- fprintf(f, "\n");
- }
- fprintf(f, "-----END CERTIFICATE REQUEST-----\n");
fclose(f);
+
+ return( 0 );
}
#define USAGE \
@@ -110,6 +91,24 @@ void write_certificate_request( rsa_context *rsa, x509_req_name *req_name,
" debug_level=%%d default: 0 (disabled)\n" \
" output_file=%%s default: cert.req\n" \
" subject_name=%%s default: CN=Cert,O=PolarSSL,C=NL\n" \
+ " key_usage=%%s default: (empty)\n" \
+ " Comma-separated-list of values:\n" \
+ " digital_signature\n" \
+ " non_repudiation\n" \
+ " key_encipherment\n" \
+ " data_encipherment\n" \
+ " key_agreement\n" \
+ " key_certificate_sign\n" \
+ " crl_sign\n" \
+ " ns_cert_type=%%s default: (empty)\n" \
+ " Comma-separated-list of values:\n" \
+ " ssl_client\n" \
+ " ssl_server\n" \
+ " email\n" \
+ " object_signing\n" \
+ " ssl_ca\n" \
+ " email_ca\n" \
+ " object_signing_ca\n" \
"\n"
#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \
@@ -130,16 +129,14 @@ int main( int argc, char *argv[] )
rsa_context rsa;
char buf[1024];
int i, j, n;
- char *p, *q;
- char *s, *c, *end;
- int in_tag;
- char *oid = NULL;
- x509_req_name *req_name = NULL;
- x509_req_name *cur = req_name;
+ char *p, *q, *r;
+ x509_csr req;
/*
* Set to sane values
*/
+ x509write_csr_init( &req );
+ x509write_csr_set_md_alg( &req, POLARSSL_MD_SHA1 );
memset( &rsa, 0, sizeof( rsa_context ) );
memset( buf, 0, 1024 );
@@ -147,6 +144,7 @@ int main( int argc, char *argv[] )
{
usage:
printf( USAGE );
+ ret = 1;
goto exit;
}
@@ -154,6 +152,8 @@ int main( int argc, char *argv[] )
opt.debug_level = DFL_DEBUG_LEVEL;
opt.output_file = DFL_OUTPUT_FILENAME;
opt.subject_name = DFL_SUBJECT_NAME;
+ opt.key_usage = DFL_KEY_USAGE;
+ opt.ns_cert_type = DFL_NS_CERT_TYPE;
for( i = 1; i < argc; i++ )
{
@@ -184,81 +184,80 @@ int main( int argc, char *argv[] )
{
opt.subject_name = q;
}
+ else if( strcmp( p, "key_usage" ) == 0 )
+ {
+ while( q != NULL )
+ {
+ if( ( r = strchr( q, ',' ) ) != NULL )
+ *r++ = '\0';
+
+ if( strcmp( q, "digital_signature" ) == 0 )
+ opt.key_usage |= KU_DIGITAL_SIGNATURE;
+ else if( strcmp( q, "non_repudiation" ) == 0 )
+ opt.key_usage |= KU_NON_REPUDIATION;
+ else if( strcmp( q, "key_encipherment" ) == 0 )
+ opt.key_usage |= KU_KEY_ENCIPHERMENT;
+ else if( strcmp( q, "data_encipherment" ) == 0 )
+ opt.key_usage |= KU_DATA_ENCIPHERMENT;
+ else if( strcmp( q, "key_agreement" ) == 0 )
+ opt.key_usage |= KU_KEY_AGREEMENT;
+ else if( strcmp( q, "key_cert_sign" ) == 0 )
+ opt.key_usage |= KU_KEY_CERT_SIGN;
+ else if( strcmp( q, "crl_sign" ) == 0 )
+ opt.key_usage |= KU_CRL_SIGN;
+ else
+ goto usage;
+
+ q = r;
+ }
+ }
+ else if( strcmp( p, "ns_cert_type" ) == 0 )
+ {
+ while( q != NULL )
+ {
+ if( ( r = strchr( q, ',' ) ) != NULL )
+ *r++ = '\0';
+
+ if( strcmp( q, "ssl_client" ) == 0 )
+ opt.ns_cert_type |= NS_CERT_TYPE_SSL_CLIENT;
+ else if( strcmp( q, "ssl_server" ) == 0 )
+ opt.ns_cert_type |= NS_CERT_TYPE_SSL_SERVER;
+ else if( strcmp( q, "email" ) == 0 )
+ opt.ns_cert_type |= NS_CERT_TYPE_EMAIL;
+ else if( strcmp( q, "object_signing" ) == 0 )
+ opt.ns_cert_type |= NS_CERT_TYPE_OBJECT_SIGNING;
+ else if( strcmp( q, "ssl_ca" ) == 0 )
+ opt.ns_cert_type |= NS_CERT_TYPE_SSL_CA;
+ else if( strcmp( q, "email_ca" ) == 0 )
+ opt.ns_cert_type |= NS_CERT_TYPE_EMAIL_CA;
+ else if( strcmp( q, "object_signing_ca" ) == 0 )
+ opt.ns_cert_type |= NS_CERT_TYPE_OBJECT_SIGNING_CA;
+ else
+ goto usage;
+
+ q = r;
+ }
+ }
else
goto usage;
}
+ if( opt.key_usage )
+ x509write_csr_set_key_usage( &req, opt.key_usage );
+
+ if( opt.ns_cert_type )
+ x509write_csr_set_ns_cert_type( &req, opt.ns_cert_type );
+
/*
* 1.0. Check the subject name for validity
*/
- s = opt.subject_name;
- end = s + strlen( s );
-
- c = s;
-
- in_tag = 1;
- while( c <= end )
+ if( ( ret = x509write_csr_set_subject_name( &req, opt.subject_name ) ) != 0 )
{
- if( in_tag && *c == '=' )
- {
- if( memcmp( s, "CN", 2 ) == 0 && c - s == 2 )
- oid = OID_AT_CN;
- else if( memcmp( s, "C", 1 ) == 0 && c - s == 1 )
- oid = OID_AT_COUNTRY;
- else if( memcmp( s, "O", 1 ) == 0 && c - s == 1 )
- oid = OID_AT_ORGANIZATION;
- else if( memcmp( s, "L", 1 ) == 0 && c - s == 1 )
- oid = OID_AT_LOCALITY;
- else if( memcmp( s, "R", 1 ) == 0 && c - s == 1 )
- oid = OID_PKCS9_EMAIL;
- else if( memcmp( s, "OU", 2 ) == 0 && c - s == 2 )
- oid = OID_AT_ORG_UNIT;
- else if( memcmp( s, "ST", 2 ) == 0 && c - s == 2 )
- oid = OID_AT_STATE;
- else
- {
- printf("Failed to parse subject name.\n");
- goto exit;
- }
-
- s = c + 1;
- in_tag = 0;
- }
-
- if( !in_tag && ( *c == ',' || c == end ) )
- {
- if( c - s > 127 )
- {
- printf("Name too large for buffer.\n");
- goto exit;
- }
-
- if( cur == NULL )
- {
- req_name = malloc( sizeof(x509_req_name) );
- cur = req_name;
- }
- else
- {
- cur->next = malloc( sizeof(x509_req_name) );
- cur = cur->next;
- }
-
- if( cur == NULL )
- {
- printf( "Failed to allocate memory.\n" );
- goto exit;
- }
-
- memset( cur, 0, sizeof(x509_req_name) );
-
- strncpy( cur->oid, oid, strlen( oid ) );
- strncpy( cur->name, s, c - s );
-
- s = c + 1;
- in_tag = 1;
- }
- c++;
+#ifdef POLARSSL_ERROR_C
+ error_strerror( ret, buf, 1024 );
+#endif
+ printf( " failed\n ! x509write_csr_set_subject_name returned %d - %s\n\n", ret, buf );
+ goto exit;
}
/*
@@ -275,16 +274,32 @@ int main( int argc, char *argv[] )
error_strerror( ret, buf, 1024 );
#endif
printf( " failed\n ! x509parse_key_rsa returned %d - %s\n\n", ret, buf );
- rsa_free( &rsa );
+ goto exit;
+ }
+
+ x509write_csr_set_rsa_key( &req, &rsa );
+
+ printf( " ok\n" );
+
+ /*
+ * 1.2. Writing the request
+ */
+ printf( " . Writing the certificate request ..." );
+ fflush( stdout );
+
+ if( ( ret = write_certificate_request( &req, opt.output_file ) ) != 0 )
+ {
+#ifdef POLARSSL_ERROR_C
+ error_strerror( ret, buf, 1024 );
+#endif
+ printf( " failed\n ! write_certifcate_request %d - %s\n\n", ret, buf );
goto exit;
}
printf( " ok\n" );
- write_certificate_request( &rsa, req_name, opt.output_file );
-
exit:
-
+ x509write_csr_free( &req );
rsa_free( &rsa );
#if defined(_WIN32)
diff --git a/scripts/generate_errors.pl b/scripts/generate_errors.pl
index 7257ae670..5b9549402 100755
--- a/scripts/generate_errors.pl
+++ b/scripts/generate_errors.pl
@@ -13,7 +13,7 @@ my @low_level_modules = ( "AES", "ASN1", "BLOWFISH", "CAMELLIA", "BIGNUM",
"PADLOCK", "DES", "NET", "CTR_DRBG", "ENTROPY",
"MD2", "MD4", "MD5", "SHA1", "SHA256", "SHA512", "GCM" );
my @high_level_modules = ( "PEM", "X509", "DHM", "RSA", "ECP", "MD", "CIPHER", "SSL",
- "PK", "PKCS12", "PKCS5" );
+ "PK", "PKCS12", "PKCS5", "X509WRITE" );
my $line_separator = $/;
undef $/;
@@ -49,6 +49,7 @@ while (my $line = )
my $define_name = $module_name;
$define_name = "X509_PARSE" if ($define_name eq "X509");
+ $define_name = "X509_WRITE" if ($define_name eq "X509WRITE");
$define_name = "ASN1_PARSE" if ($define_name eq "ASN1");
$define_name = "SSL_TLS" if ($define_name eq "SSL");
diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data
index c4984360b..7a48440e4 100644
--- a/tests/suites/test_suite_x509write.data
+++ b/tests/suites/test_suite_x509write.data
@@ -1,27 +1,27 @@
Certificate Request check Server1 SHA1
depends_on:POLARSSL_SHA1_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_SHA1:"data_files/server1.req.sha1"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_SHA1:"data_files/server1.req.sha1"
Certificate Request check Server1 SHA224
depends_on:POLARSSL_SHA256_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_SHA224:"data_files/server1.req.sha224"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_SHA224:"data_files/server1.req.sha224"
Certificate Request check Server1 SHA256
depends_on:POLARSSL_SHA256_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_SHA256:"data_files/server1.req.sha256"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_SHA256:"data_files/server1.req.sha256"
Certificate Request check Server1 SHA384
depends_on:POLARSSL_SHA512_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_SHA384:"data_files/server1.req.sha384"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_SHA384:"data_files/server1.req.sha384"
Certificate Request check Server1 SHA512
depends_on:POLARSSL_SHA512_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_SHA512:"data_files/server1.req.sha512"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_SHA512:"data_files/server1.req.sha512"
Certificate Request check Server1 MD4
depends_on:POLARSSL_MD4_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_MD4:"data_files/server1.req.md4"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_MD4:"data_files/server1.req.md4"
Certificate Request check Server1 MD5
depends_on:POLARSSL_MD5_C
-x509_cert_req_check:"data_files/server1.key":POLARSSL_MD_MD5:"data_files/server1.req.md5"
+x509_csr_check:"data_files/server1.key":POLARSSL_MD_MD5:"data_files/server1.req.md5"
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index 680dfb4c4..d3c801a1d 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -11,36 +11,19 @@
*/
/* BEGIN_CASE */
-void x509_cert_req_check( char *key_file, int md_type,
+void x509_csr_check( char *key_file, int md_type,
char *cert_req_check_file )
{
rsa_context rsa;
pem_context pem;
- x509_req_name req_name, *cur;
+ x509_csr req;
unsigned char *c;
unsigned char buf[4000];
unsigned char check_buf[4000];
int ret;
size_t olen = 2000;
FILE *f;
-
- cur = &req_name;
-
- memset( cur, 0, sizeof(x509_req_name) );
- strcpy( cur->oid, OID_AT_CN );
- strcpy( cur->name, "PolarSSL Server 1" );
- cur->next = malloc( sizeof(x509_req_name) );
- cur = cur->next;
-
- memset( cur, 0, sizeof(x509_req_name) );
- strcpy( cur->oid, OID_AT_ORGANIZATION );
- strcpy( cur->name, "PolarSSL" );
- cur->next = malloc( sizeof(x509_req_name) );
- cur = cur->next;
-
- memset( cur, 0, sizeof(x509_req_name) );
- strcpy( cur->oid, OID_AT_COUNTRY );
- strcpy( cur->name, "NL" );
+ char *subject_name = "C=NL,O=PolarSSL,CN=PolarSSL Server 1";
memset( &rsa, 0, sizeof(rsa_context) );
ret = x509parse_keyfile_rsa( &rsa, key_file, NULL );
@@ -48,7 +31,12 @@ void x509_cert_req_check( char *key_file, int md_type,
if( ret != 0 )
return;
- ret = x509_write_cert_req( buf, 4000, &rsa, &req_name, md_type );
+ x509write_csr_init( &req );
+ x509write_csr_set_md_alg( &req, md_type );
+ x509write_csr_set_rsa_key( &req, &rsa );
+ TEST_ASSERT( x509write_csr_set_subject_name( &req, subject_name ) == 0 );
+
+ ret = x509write_csr_der( &req, buf, 4000 );
TEST_ASSERT( ret >= 0 );
c = buf + 3999 - ret;
@@ -64,12 +52,7 @@ void x509_cert_req_check( char *key_file, int md_type,
TEST_ASSERT( memcmp( c, pem.buf, pem.buflen ) == 0 );
TEST_ASSERT( pem.buflen == (size_t) ret );
- while( ( cur = req_name.next ) != NULL )
- {
- req_name.next = cur->next;
- free( cur );
- }
-
+ x509write_csr_free( &req );
rsa_free( &rsa );
pem_free( &pem );
}