Merged refactored x509write module into development

This commit is contained in:
Paul Bakker 2013-08-28 16:31:30 +02:00
commit ca174fef80
21 changed files with 1442 additions and 321 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.)
*/

View file

@ -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
*/

View file

@ -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.
* - <tt>typedef struct _x509_node x509_node;</tt>
* - <tt>typedef struct _x509_raw x509_raw;</tt>
*/
/*
typedef struct _x509_node
{
unsigned char *data;
unsigned char *p;
unsigned char *end;
size_t len;
}
x509_node;
typedef struct _x509_raw
{
x509_node raw;
x509_node tbs;
x509_node version;
x509_node serial;
x509_node tbs_signalg;
x509_node issuer;
x509_node validity;
x509_node subject;
x509_node subpubkey;
x509_node signalg;
x509_node sign;
}
x509_raw;
*/
/**
* \name Functions to read in DHM parameters, a certificate, CRL or private RSA key
* \{

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -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 );
}

View file

@ -33,7 +33,231 @@
#include "polarssl/md.h"
#include "polarssl/oid.h"
int x509_write_pubkey_der( unsigned char *buf, size_t size, rsa_context *rsa )
#if defined(POLARSSL_BASE64_C)
#include "polarssl/base64.h"
#endif
#if defined(POLARSSL_MEMORY_C)
#include "polarssl/memory.h"
#else
#include <stdlib.h>
#define polarssl_malloc malloc
#define polarssl_free free
#endif
void x509write_csr_init( x509_csr *ctx )
{
memset( ctx, 0, sizeof(x509_csr) );
}
void x509write_csr_free( x509_csr *ctx )
{
x509_req_name *cur;
asn1_named_data *cur_ext;
while( ( cur = ctx->subject ) != NULL )
{
ctx->subject = cur->next;
polarssl_free( cur );
}
while( ( cur_ext = ctx->extensions ) != NULL )
{
ctx->extensions = cur_ext->next;
asn1_free_named_data( cur_ext );
polarssl_free( cur_ext );
}
memset( ctx, 0, sizeof(x509_csr) );
}
void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg )
{
ctx->md_alg = md_alg;
}
void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa )
{
ctx->rsa = rsa;
}
int x509write_csr_set_subject_name( x509_csr *ctx, char *subject_name )
{
int ret = 0;
char *s = subject_name, *c = s;
char *end = s + strlen( s );
char *oid = NULL;
int in_tag = 1;
x509_req_name *cur;
while( ctx->subject )
{
cur = ctx->subject;
ctx->subject = ctx->subject->next;
polarssl_free( cur );
}
while( c <= end )
{
if( in_tag && *c == '=' )
{
if( memcmp( s, "CN", 2 ) == 0 && c - s == 2 )
oid = OID_AT_CN;
else if( memcmp( s, "C", 1 ) == 0 && c - s == 1 )
oid = OID_AT_COUNTRY;
else if( memcmp( s, "O", 1 ) == 0 && c - s == 1 )
oid = OID_AT_ORGANIZATION;
else if( memcmp( s, "L", 1 ) == 0 && c - s == 1 )
oid = OID_AT_LOCALITY;
else if( memcmp( s, "R", 1 ) == 0 && c - s == 1 )
oid = OID_PKCS9_EMAIL;
else if( memcmp( s, "OU", 2 ) == 0 && c - s == 2 )
oid = OID_AT_ORG_UNIT;
else if( memcmp( s, "ST", 2 ) == 0 && c - s == 2 )
oid = OID_AT_STATE;
else
{
ret = POLARSSL_ERR_X509WRITE_UNKNOWN_OID;
goto exit;
}
s = c + 1;
in_tag = 0;
}
if( !in_tag && ( *c == ',' || c == end ) )
{
if( c - s > 127 )
{
ret = POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA;
goto exit;
}
cur = polarssl_malloc( sizeof(x509_req_name) );
if( cur == NULL )
{
ret = POLARSSL_ERR_X509WRITE_MALLOC_FAILED;
goto exit;
}
memset( cur, 0, sizeof(x509_req_name) );
cur->next = ctx->subject;
ctx->subject = cur;
strncpy( cur->oid, oid, strlen( oid ) );
strncpy( cur->name, s, c - s );
s = c + 1;
in_tag = 1;
}
c++;
}
exit:
return( ret );
}
int x509write_csr_set_extension( x509_csr *ctx,
const char *oid, size_t oid_len,
const unsigned char *val, size_t val_len )
{
asn1_named_data *cur;
if( ( cur = asn1_find_named_data( ctx->extensions, oid,
oid_len ) ) == NULL )
{
cur = polarssl_malloc( sizeof(asn1_named_data) );
if( cur == NULL )
return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
memset( cur, 0, sizeof(asn1_named_data) );
cur->oid.len = oid_len;
cur->oid.p = polarssl_malloc( oid_len );
if( cur->oid.p == NULL )
{
polarssl_free( cur );
return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
}
cur->val.len = val_len;
cur->val.p = polarssl_malloc( val_len );
if( cur->val.p == NULL )
{
polarssl_free( cur->oid.p );
polarssl_free( cur );
return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
}
memcpy( cur->oid.p, oid, oid_len );
cur->next = ctx->extensions;
ctx->extensions = cur;
}
if( cur->val.len != val_len )
{
polarssl_free( cur->val.p );
cur->val.len = val_len;
cur->val.p = polarssl_malloc( val_len );
if( cur->val.p == NULL )
{
polarssl_free( cur->oid.p );
polarssl_free( cur );
return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED );
}
}
memcpy( cur->val.p, val, val_len );
return( 0 );
}
int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage )
{
unsigned char buf[4];
unsigned char *c;
int ret;
c = buf + 4;
if( ( ret = asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
return( ret );
ret = x509write_csr_set_extension( ctx, OID_KEY_USAGE,
OID_SIZE( OID_KEY_USAGE ),
buf, 4 );
if( ret != 0 )
return( ret );
return( 0 );
}
int x509write_csr_set_ns_cert_type( x509_csr *ctx, unsigned char ns_cert_type )
{
unsigned char buf[4];
unsigned char *c;
int ret;
c = buf + 4;
if( ( ret = asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
return( ret );
ret = x509write_csr_set_extension( ctx, OID_NS_CERT_TYPE,
OID_SIZE( OID_NS_CERT_TYPE ),
buf, 4 );
if( ret != 0 )
return( ret );
return( 0 );
}
int x509write_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size )
{
int ret;
unsigned char *c;
@ -41,6 +265,12 @@ 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

1
programs/.gitignore vendored
View file

@ -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

View file

@ -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 $@

View file

@ -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 )

View file

@ -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)

288
programs/util/pem2der.c Normal file
View file

@ -0,0 +1,288 @@
/*
* Convert PEM to DER
*
* Copyright (C) 2006-2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE 1
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "polarssl/config.h"
#include "polarssl/error.h"
#include "polarssl/base64.h"
#define DFL_FILENAME "file.pem"
#define DFL_OUTPUT_FILENAME "file.der"
/*
* global options
*/
struct options
{
char *filename; /* filename of the input file */
char *output_file; /* where to store the output */
} opt;
int convert_pem_to_der( const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen )
{
int ret;
const unsigned char *s1, *s2, *end = input + ilen;
size_t len = 0;
s1 = (unsigned char *) strstr( (char *) input, "-----BEGIN" );
if( s1 == NULL )
return( -1 );
s2 = (unsigned char *) strstr( (char *) input, "-----END" );
if( s2 == NULL )
return( -1 );
s1 += 10;
while( s1 < end && *s1 != '-' )
s1++;
while( s1 < end && *s1 == '-' )
s1++;
if( *s1 == '\r' ) s1++;
if( *s1 == '\n' ) s1++;
if( s2 <= s1 || s2 > end )
return( -1 );
ret = base64_decode( NULL, &len, (const unsigned char *) s1, s2 - s1 );
if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER )
return( ret );
if( len > *olen )
return( -1 );
if( ( ret = base64_decode( output, &len, (const unsigned char *) s1,
s2 - s1 ) ) != 0 )
{
return( ret );
}
*olen = len;
return( 0 );
}
/*
* Load all data from a file into a given buffer.
*/
static int load_file( const char *path, unsigned char **buf, size_t *n )
{
FILE *f;
long size;
if( ( f = fopen( path, "rb" ) ) == NULL )
return( -1 );
fseek( f, 0, SEEK_END );
if( ( size = ftell( f ) ) == -1 )
{
fclose( f );
return( -1 );
}
fseek( f, 0, SEEK_SET );
*n = (size_t) size;
if( *n + 1 == 0 ||
( *buf = (unsigned char *) malloc( *n + 1 ) ) == NULL )
{
fclose( f );
return( -1 );
}
if( fread( *buf, 1, *n, f ) != *n )
{
fclose( f );
free( *buf );
return( -1 );
}
fclose( f );
(*buf)[*n] = '\0';
return( 0 );
}
/*
* Write buffer to a file
*/
static int write_file( const char *path, unsigned char *buf, size_t n )
{
FILE *f;
if( ( f = fopen( path, "wb" ) ) == NULL )
return( -1 );
if( fwrite( buf, 1, n, f ) != n )
{
fclose( f );
return( -1 );
}
fclose( f );
return( 0 );
}
#define USAGE \
"\n usage: pem2der param=<>...\n" \
"\n acceptable parameters:\n" \
" filename=%%s default: file.pem\n" \
" output_file=%%s default: file.der\n" \
"\n"
#if !defined(POLARSSL_BASE64_C) || !defined(POLARSSL_FS_IO)
int main( int argc, char *argv[] )
{
((void) argc);
((void) argv);
printf("POLARSSL_BASE64_C and/or POLARSSL_FS_IO not defined.\n");
return( 0 );
}
#else
int main( int argc, char *argv[] )
{
int ret = 0;
unsigned char *pem_buffer = NULL;
unsigned char der_buffer[4096];
char buf[1024];
size_t pem_size, der_size = sizeof(der_buffer);
int i, j, n;
char *p, *q;
/*
* Set to sane values
*/
memset( buf, 0, sizeof(buf) );
memset( der_buffer, 0, sizeof(der_buffer) );
if( argc == 0 )
{
usage:
printf( USAGE );
goto exit;
}
opt.filename = DFL_FILENAME;
opt.output_file = DFL_OUTPUT_FILENAME;
for( i = 1; i < argc; i++ )
{
p = argv[i];
if( ( q = strchr( p, '=' ) ) == NULL )
goto usage;
*q++ = '\0';
n = strlen( p );
for( j = 0; j < n; j++ )
{
if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' )
argv[i][j] |= 0x20;
}
if( strcmp( p, "filename" ) == 0 )
opt.filename = q;
else if( strcmp( p, "output_file" ) == 0 )
opt.output_file = q;
else
goto usage;
}
/*
* 1.1. Load the PEM file
*/
printf( "\n . Loading the PEM file ..." );
fflush( stdout );
ret = load_file( opt.filename, &pem_buffer, &pem_size );
if( ret != 0 )
{
#ifdef POLARSSL_ERROR_C
error_strerror( ret, buf, 1024 );
#endif
printf( " failed\n ! load_file returned %d - %s\n\n", ret, buf );
goto exit;
}
printf( " ok\n" );
/*
* 1.2. Convert from PEM to DER
*/
printf( " . Converting from PEM to DER ..." );
fflush( stdout );
if( ( ret = convert_pem_to_der( pem_buffer, pem_size, der_buffer, &der_size ) ) != 0 )
{
#ifdef POLARSSL_ERROR_C
error_strerror( ret, buf, 1024 );
#endif
printf( " failed\n ! convert_pem_to_der %d - %s\n\n", ret, buf );
goto exit;
}
printf( " ok\n" );
/*
* 1.3. Write the DER file
*/
printf( " . Writing the DER file ..." );
fflush( stdout );
ret = write_file( opt.output_file, der_buffer, der_size );
if( ret != 0 )
{
#ifdef POLARSSL_ERROR_C
error_strerror( ret, buf, 1024 );
#endif
printf( " failed\n ! write_file returned %d - %s\n\n", ret, buf );
goto exit;
}
printf( " ok\n" );
exit:
free( pem_buffer );
#if defined(_WIN32)
printf( " + Press Enter to exit this program.\n" );
fflush( stdout ); getchar();
#endif
return( ret );
}
#endif /* POLARSSL_BASE64_C && POLARSSL_FS_IO */

View file

@ -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)

View file

@ -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)

View file

@ -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 = <GREP>)
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");

View file

@ -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"

View file

@ -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 );
}