diff --git a/include/polarssl/x509write.h b/include/polarssl/x509write.h index 0e443ee8c..8600b428f 100644 --- a/include/polarssl/x509write.h +++ b/include/polarssl/x509write.h @@ -84,6 +84,31 @@ typedef struct _x509_csr } x509_csr; +#define X509_CRT_VERSION_1 0 +#define X509_CRT_VERSION_2 1 +#define X509_CRT_VERSION_3 2 + +#define X509_RFC5280_MAX_SERIAL_LEN 32 +#define X509_RFC5280_UTC_TIME_LEN 15 + +/** + * Container for writing a certificate (CRT) + */ +typedef struct _x509write_cert +{ + int version; + mpi serial; + rsa_context *subject_key; + rsa_context *issuer_key; + x509_req_name *subject; + x509_req_name *issuer; + md_type_t md_alg; + char not_before[X509_RFC5280_UTC_TIME_LEN + 1]; + char not_after[X509_RFC5280_UTC_TIME_LEN + 1]; + asn1_named_data *extensions; +} +x509write_cert; + /* \} addtogroup x509_module */ /** @@ -169,6 +194,125 @@ int x509write_csr_set_extension( x509_csr *ctx, */ void x509write_csr_free( x509_csr *ctx ); +/** + * \brief Initialize a CRT writing context + * + * \param ctx CRT context to initialize + */ +void x509write_crt_init( x509write_cert *ctx ); + +/** + * \brief Set the verion for a Certificate + * Default: X509_CRT_VERSION_3 + * + * \param ctx CRT context to use + * \param version version to set (X509_CRT_VERSION_1, X509_CRT_VERSION_2 or + * X509_CRT_VERSION_3) + */ +void x509write_crt_set_version( x509write_cert *ctx, int version ); + +/** + * \brief Set the serial number for a Certificate. + * + * \param ctx CRT context to use + * \param serial serial number to set + * + * \return 0 if successful + */ +int x509write_crt_set_serial( x509write_cert *ctx, const mpi *serial ); + +/** + * \brief Set the validity period for a Certificate + * Timestamps should be in string format for UTC timezone + * i.e. "YYYYMMDDhhmmss" + * e.g. "20131231235959" for December 31st 2013 + * at 23:59:59 + * + * \param ctx CRT context to use + * \param not_before not_before timestamp + * \param not_after not_after timestamp + * + * \return 0 if timestamp was parsed successfully, or + * a specific error code + */ +int x509write_crt_set_validity( x509write_cert *ctx, char *not_before, + char *not_after ); + +/** + * \brief Set the issuer name for a Certificate + * Issuer names should contain a comma-separated list + * of OID types and values: + * e.g. "C=NL,O=Offspark,CN=PolarSSL CA" + * + * \param ctx CRT context to use + * \param issuer_name issuer name to set + * + * \return 0 if issuer name was parsed successfully, or + * a specific error code + */ +int x509write_crt_set_issuer_name( x509write_cert *ctx, char *issuer_name ); + +/** + * \brief Set the subject name for a Certificate + * Subject names should contain a comma-separated list + * of OID types and values: + * e.g. "C=NL,O=Offspark,CN=PolarSSL Server 1" + * + * \param ctx CRT context to use + * \param subject_name subject name to set + * + * \return 0 if subject name was parsed successfully, or + * a specific error code + */ +int x509write_crt_set_subject_name( x509write_cert *ctx, char *subject_name ); + +/** + * \brief Set the subject public key for the certificate + * + * \param ctx CRT context to use + * \param rsa RSA public key to include + */ +void x509write_crt_set_subject_key( x509write_cert *ctx, rsa_context *rsa ); + +/** + * \brief Set the issuer key used for signing the certificate + * + * \param ctx CRT context to use + * \param rsa RSA key to sign with + */ +void x509write_crt_set_issuer_key( x509write_cert *ctx, rsa_context *rsa ); + +/** + * \brief Set the MD algorithm to use for the signature + * (e.g. POLARSSL_MD_SHA1) + * + * \param ctx CRT context to use + * \param md_ald MD algorithm to use + */ +void x509write_crt_set_md_alg( x509write_cert *ctx, md_type_t md_alg ); + +/** + * \brief Free the contents of a CRT write context + * + * \param ctx CRT context to free + */ +void x509write_crt_free( x509write_cert *ctx ); + +/** + * \brief Write a built up certificate to a X509 DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param crt certificate 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_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size ); + /** * \brief Write a RSA public key to a PKCS#1 DER structure * Note: data is written at the end of the buffer! Use the @@ -216,6 +360,17 @@ int x509write_key_der( rsa_context *rsa, unsigned char *buf, size_t size ); int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size ); #if defined(POLARSSL_BASE64_C) +/** + * \brief Write a built up certificate to a X509 PEM string + * + * \param crt certificate 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_crt_pem( x509write_cert *ctx, unsigned char *buf, size_t size ); + /** * \brief Write a RSA public key to a PKCS#1 PEM string * diff --git a/library/x509write.c b/library/x509write.c index 7e04e1206..1428c67cb 100644 --- a/library/x509write.c +++ b/library/x509write.c @@ -45,55 +45,19 @@ #define polarssl_free free #endif -void x509write_csr_init( x509_csr *ctx ) -{ - memset( ctx, 0, sizeof(x509_csr) ); -} - -void x509write_csr_free( x509_csr *ctx ) -{ - x509_req_name *cur; - asn1_named_data *cur_ext; - - while( ( cur = ctx->subject ) != NULL ) - { - ctx->subject = cur->next; - polarssl_free( cur ); - } - - while( ( cur_ext = ctx->extensions ) != NULL ) - { - ctx->extensions = cur_ext->next; - asn1_free_named_data( cur_ext ); - polarssl_free( cur_ext ); - } - - memset( ctx, 0, sizeof(x509_csr) ); -} - -void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg ) -{ - ctx->md_alg = md_alg; -} - -void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa ) -{ - ctx->rsa = rsa; -} - -int x509write_csr_set_subject_name( x509_csr *ctx, char *subject_name ) +static int x509write_string_to_names( x509_req_name **head, char *name ) { int ret = 0; - char *s = subject_name, *c = s; + char *s = name, *c = s; char *end = s + strlen( s ); char *oid = NULL; int in_tag = 1; x509_req_name *cur; - while( ctx->subject ) + while( *head != NULL ) { - cur = ctx->subject; - ctx->subject = ctx->subject->next; + cur = *head; + *head = cur->next; polarssl_free( cur ); } @@ -143,8 +107,8 @@ int x509write_csr_set_subject_name( x509_csr *ctx, char *subject_name ) memset( cur, 0, sizeof(x509_req_name) ); - cur->next = ctx->subject; - ctx->subject = cur; + cur->next = *head; + *head = cur; strncpy( cur->oid, oid, strlen( oid ) ); strncpy( cur->name, s, c - s ); @@ -160,6 +124,47 @@ exit: return( ret ); } +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 ) +{ + return x509write_string_to_names( &ctx->subject, subject_name ); +} + int x509write_csr_set_extension( x509_csr *ctx, const char *oid, size_t oid_len, const unsigned char *val, size_t val_len ) @@ -257,6 +262,94 @@ int x509write_csr_set_ns_cert_type( x509_csr *ctx, unsigned char ns_cert_type ) return( 0 ); } +void x509write_crt_init( x509write_cert *ctx ) +{ + memset( ctx, 0, sizeof(x509write_cert) ); + + mpi_init( &ctx->serial ); + ctx->version = X509_CRT_VERSION_3; +} + +void x509write_crt_free( x509write_cert *ctx ) +{ + x509_req_name *cur; + asn1_named_data *cur_ext; + + mpi_free( &ctx->serial ); + + while( ( cur = ctx->subject ) != NULL ) + { + ctx->subject = cur->next; + polarssl_free( cur ); + } + + while( ( cur = ctx->issuer ) != NULL ) + { + ctx->issuer = 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_crt_set_md_alg( x509write_cert *ctx, md_type_t md_alg ) +{ + ctx->md_alg = md_alg; +} + +void x509write_crt_set_subject_key( x509write_cert *ctx, rsa_context *rsa ) +{ + ctx->subject_key = rsa; +} + +void x509write_crt_set_issuer_key( x509write_cert *ctx, rsa_context *rsa ) +{ + ctx->issuer_key = rsa; +} + +int x509write_crt_set_subject_name( x509write_cert *ctx, char *subject_name ) +{ + return x509write_string_to_names( &ctx->subject, subject_name ); +} + +int x509write_crt_set_issuer_name( x509write_cert *ctx, char *issuer_name ) +{ + return x509write_string_to_names( &ctx->issuer, issuer_name ); +} + +int x509write_crt_set_serial( x509write_cert *ctx, const mpi *serial ) +{ + int ret; + + if( ( ret = mpi_copy( &ctx->serial, serial ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int x509write_crt_set_validity( x509write_cert *ctx, char *not_before, + char *not_after ) +{ + if( strlen(not_before) != X509_RFC5280_UTC_TIME_LEN - 1 || + strlen(not_after) != X509_RFC5280_UTC_TIME_LEN - 1 ) + { + return( POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA ); + } + strncpy( ctx->not_before, not_before, X509_RFC5280_UTC_TIME_LEN ); + strncpy( ctx->not_after , not_after , X509_RFC5280_UTC_TIME_LEN ); + ctx->not_before[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z'; + ctx->not_after[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z'; + + return( 0 ); +} + int x509write_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size ) { int ret; @@ -344,6 +437,18 @@ int x509write_key_der( rsa_context *rsa, unsigned char *buf, size_t size ) return( len ); } +/* + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ static int x509_write_name( unsigned char **p, unsigned char *start, char *oid, char *name ) { @@ -376,6 +481,25 @@ static int x509_write_name( unsigned char **p, unsigned char *start, char *oid, return( len ); } +static int x509_write_names( unsigned char **p, unsigned char *start, + x509_req_name *first ) +{ + int ret; + size_t len = 0; + x509_req_name *cur = first; + + while( cur != NULL ) + { + ASN1_CHK_ADD( len, x509_write_name( p, start, cur->oid, cur->name ) ); + cur = cur->next; + } + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + return( len ); +} + static int x509_write_sig( unsigned char **p, unsigned char *start, const char *oid, unsigned char *sig, size_t size ) { @@ -402,6 +526,21 @@ static int x509_write_sig( unsigned char **p, unsigned char *start, return( len ); } +static int x509_write_time( unsigned char **p, unsigned char *start, + const char *time, size_t size ) +{ + int ret; + size_t len = 0; + + ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, + (const unsigned char *) time, + size ) ); + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_GENERALIZED_TIME ) ); + + return( len ); +} + int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size ) { int ret; @@ -410,9 +549,8 @@ int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size ) unsigned char hash[64]; unsigned char sig[POLARSSL_MPI_MAX_SIZE]; unsigned char tmp_buf[2048]; - size_t sub_len = 0, pub_len = 0, sig_len = 0; + size_t pub_len = 0, sig_len = 0; size_t len = 0; - x509_req_name *cur = ctx->subject; asn1_named_data *cur_ext = ctx->extensions; c = tmp_buf + 2048 - 1; @@ -482,16 +620,10 @@ int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size ) ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, pub_len ) ); ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); - while( cur != NULL ) - { - ASN1_CHK_ADD( sub_len, x509_write_name( &c, tmp_buf, cur->oid, cur->name ) ); - - cur = cur->next; - } - - len += sub_len; - ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) ); - ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + /* + * Subject ::= Name + */ + ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) ); /* * Version ::= INTEGER { v1(0), v2(1), v3(2) } @@ -522,6 +654,123 @@ int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size ) return( len ); } +int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size ) +{ + int ret; + const char *sig_oid; + unsigned char *c, *c2; + unsigned char hash[64]; + unsigned char sig[POLARSSL_MPI_MAX_SIZE]; + unsigned char tmp_buf[2048]; + size_t sub_len = 0, pub_len = 0, sig_len = 0; + size_t len = 0; + asn1_named_data *cur_ext = ctx->extensions; + + c = tmp_buf + 2048 - 1; + + // Generate correct OID + // + ret = oid_get_oid_by_sig_alg( POLARSSL_PK_RSA, ctx->md_alg, &sig_oid ); + if( ret != 0 ) + return( ret ); + + + /* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ + ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &ctx->subject_key->E ) ); + ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &ctx->subject_key->N ) ); + + ASN1_CHK_ADD( pub_len, asn1_write_len( &c, tmp_buf, pub_len ) ); + ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + if( c - tmp_buf < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--c = 0; + pub_len += 1; + + ASN1_CHK_ADD( pub_len, asn1_write_len( &c, tmp_buf, pub_len ) ); + ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, tmp_buf, ASN1_BIT_STRING ) ); + + ASN1_CHK_ADD( pub_len, asn1_write_algorithm_identifier( &c, tmp_buf, OID_PKCS1_RSA ) ); + + len += pub_len; + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, pub_len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + /* + * Subject ::= Name + */ + ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) ); + + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ + sub_len = 0; + + ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after, + X509_RFC5280_UTC_TIME_LEN ) ); + + ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before, + X509_RFC5280_UTC_TIME_LEN ) ); + + len += sub_len; + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + /* + * Issuer ::= Name + */ + ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->issuer ) ); + + /* + * Signature ::= AlgorithmIdentifier + */ + ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, tmp_buf, + sig_oid ) ); + + /* + * Serial ::= INTEGER + */ + ASN1_CHK_ADD( len, asn1_write_mpi( &c, tmp_buf, &ctx->serial ) ); + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + sub_len = 0; + ASN1_CHK_ADD( sub_len, asn1_write_int( &c, tmp_buf, ctx->version ) ); + len += sub_len; + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ); + + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + md( md_info_from_type( ctx->md_alg ), c, len, hash ); + + rsa_pkcs1_sign( ctx->issuer_key, NULL, NULL, RSA_PRIVATE, ctx->md_alg, 0, hash, sig ); + + c2 = buf + size - 1; + ASN1_CHK_ADD( sig_len, x509_write_sig( &c2, buf, sig_oid, sig, ctx->issuer_key->len ) ); + + c2 -= len; + memcpy( c2, c, len ); + + len += sig_len; + ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + return( len ); +} + +#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n" +#define PEM_END_CRT "-----END CERTIFICATE-----\n" + #define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n" #define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n" @@ -571,6 +820,27 @@ static int x509write_pemify( const char *begin_str, const char *end_str, return( 0 ); } +int x509write_crt_pem( x509write_cert *crt, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[4096]; + + if( ( ret = x509write_crt_der( crt, output_buf, + sizeof(output_buf) ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = x509write_pemify( PEM_BEGIN_CRT, PEM_END_CRT, + output_buf + sizeof(output_buf) - 1 - ret, + ret, buf, size ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + int x509write_pubkey_pem( rsa_context *rsa, unsigned char *buf, size_t size ) { int ret; diff --git a/programs/.gitignore b/programs/.gitignore index 2b7510f6e..b349cd44c 100644 --- a/programs/.gitignore +++ b/programs/.gitignore @@ -40,3 +40,4 @@ util/strerror x509/cert_app x509/cert_req x509/crl_app +x509/cert_write diff --git a/programs/x509/CMakeLists.txt b/programs/x509/CMakeLists.txt index d07cff82d..8aaa4ac24 100644 --- a/programs/x509/CMakeLists.txt +++ b/programs/x509/CMakeLists.txt @@ -19,6 +19,9 @@ target_link_libraries(crl_app ${libs}) add_executable(cert_req cert_req.c) target_link_libraries(cert_req ${libs}) -install(TARGETS cert_app crl_app cert_req +add_executable(cert_write cert_write.c) +target_link_libraries(cert_write ${libs}) + +install(TARGETS cert_app crl_app cert_req cert_write DESTINATION "bin" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c new file mode 100644 index 000000000..59c49b2fe --- /dev/null +++ b/programs/x509/cert_write.c @@ -0,0 +1,423 @@ +/* + * Certificate generation and signing + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * 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/rsa.h" +#include "polarssl/x509.h" +#include "polarssl/base64.h" +#include "polarssl/x509write.h" +#include "polarssl/oid.h" + +#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \ + !defined(POLARSSL_X509_WRITE_C) || !defined(POLARSSL_FS_IO) +int main( int argc, char *argv[] ) +{ + ((void) argc); + ((void) argv); + + printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or " + "POLARSSL_X509_WRITE_C and/or POLARSSL_FS_IO not defined.\n"); + return( 0 ); +} +#else + +#define DFL_SUBJECT_KEY "subject.key" +#define DFL_ISSUER_KEY "ca.key" +#define DFL_SUBJECT_PWD "" +#define DFL_ISSUER_PWD "" +#define DFL_OUTPUT_FILENAME "cert.crt" +#define DFL_SUBJECT_NAME "CN=Cert,O=PolarSSL,C=NL" +#define DFL_ISSUER_NAME "CN=CA,O=PolarSSL,C=NL" +#define DFL_NOT_BEFORE "20010101000000" +#define DFL_NOT_AFTER "20301231235959" +#define DFL_SERIAL "1" +#define DFL_KEY_USAGE 0 +#define DFL_NS_CERT_TYPE 0 + +/* + * global options + */ +struct options +{ + char *subject_key; /* filename of the subject key file */ + char *issuer_key; /* filename of the issuer key file */ + char *subject_pwd; /* password for the subject key file */ + char *issuer_pwd; /* password for the issuer key file */ + char *output_file; /* where to store the constructed key file */ + char *subject_name; /* subject name for certificate */ + char *issuer_name; /* issuer name for certificate */ + char *not_before; /* validity period not before */ + char *not_after; /* validity period not after */ + char *serial; /* serial number string */ + unsigned char key_usage; /* key usage flags */ + unsigned char ns_cert_type; /* NS cert type */ +} opt; + +int write_certificate( x509write_cert *crt, char *output_file ) +{ + int ret; + FILE *f; + unsigned char output_buf[4096]; + size_t len = 0; + + memset( output_buf, 0, 4096 ); + if( ( ret = x509write_crt_pem( crt, output_buf, 4096 ) ) < 0 ) + return( ret ); + + len = strlen( (char *) output_buf ); + + if( ( f = fopen( output_file, "w" ) ) == NULL ) + return( -1 ); + + if( fwrite( output_buf, 1, len, f ) != len ) + return( -1 ); + + fclose(f); + + return( 0 ); +} + +#define USAGE \ + "\n usage: cert_write param=<>...\n" \ + "\n acceptable parameters:\n" \ + " subject_key=%%s default: subject.key\n" \ + " subject_pwd=%%s default: (empty)\n" \ + " issuer_key=%%s default: ca.key\n" \ + " issuer_pwd=%%s default: (empty)\n" \ + " output_file=%%s default: cert.crt\n" \ + " subject_name=%%s default: CN=Cert,O=PolarSSL,C=NL\n" \ + " issuer_name=%%s default: CN=CA,O=PolarSSL,C=NL\n" \ + " serial=%%s default: 1\n" \ + " not_before=%%s default: 20010101000000\n"\ + " not_after=%%s default: 20301231235959\n"\ + " key_usage=%%s default: (empty)\n" \ + " Comma-separated-list of values:\n" \ + " digital_signature\n" \ + " non_repudiation\n" \ + " key_encipherment\n" \ + " data_encipherment\n" \ + " key_agreement\n" \ + " key_certificate_sign\n" \ + " crl_sign\n" \ + " ns_cert_type=%%s default: (empty)\n" \ + " Comma-separated-list of values:\n" \ + " ssl_client\n" \ + " ssl_server\n" \ + " email\n" \ + " object_signing\n" \ + " ssl_ca\n" \ + " email_ca\n" \ + " object_signing_ca\n" \ + "\n" + +int main( int argc, char *argv[] ) +{ + int ret = 0; + rsa_context issuer_rsa, subject_rsa; + char buf[1024]; + int i, j, n; + char *p, *q, *r; + x509write_cert crt; + mpi serial; + + /* + * Set to sane values + */ + x509write_crt_init( &crt ); + x509write_crt_set_md_alg( &crt, POLARSSL_MD_SHA1 ); + rsa_init( &issuer_rsa, RSA_PKCS_V15, 0 ); + rsa_init( &subject_rsa, RSA_PKCS_V15, 0 ); + mpi_init( &serial ); + memset( buf, 0, 1024 ); + + if( argc == 0 ) + { + usage: + printf( USAGE ); + ret = 1; + goto exit; + } + + opt.subject_key = DFL_SUBJECT_KEY; + opt.issuer_key = DFL_ISSUER_KEY; + opt.subject_pwd = DFL_SUBJECT_PWD; + opt.issuer_pwd = DFL_ISSUER_PWD; + opt.output_file = DFL_OUTPUT_FILENAME; + opt.subject_name = DFL_SUBJECT_NAME; + opt.issuer_name = DFL_ISSUER_NAME; + opt.not_before = DFL_NOT_BEFORE; + opt.not_after = DFL_NOT_AFTER; + opt.serial = DFL_SERIAL; + opt.key_usage = DFL_KEY_USAGE; + opt.ns_cert_type = DFL_NS_CERT_TYPE; + + for( i = 1; i < argc; i++ ) + { + + p = argv[i]; + if( ( q = strchr( p, '=' ) ) == NULL ) + goto usage; + *q++ = '\0'; + + n = strlen( p ); + for( j = 0; j < n; j++ ) + { + if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' ) + argv[i][j] |= 0x20; + } + + if( strcmp( p, "subject_key" ) == 0 ) + opt.subject_key = q; + else if( strcmp( p, "issuer_key" ) == 0 ) + opt.issuer_key = q; + else if( strcmp( p, "subject_pwd" ) == 0 ) + opt.subject_pwd = q; + else if( strcmp( p, "issuer_pwd" ) == 0 ) + opt.issuer_pwd = q; + else if( strcmp( p, "output_file" ) == 0 ) + opt.output_file = q; + else if( strcmp( p, "subject_name" ) == 0 ) + { + opt.subject_name = q; + } + else if( strcmp( p, "issuer_name" ) == 0 ) + { + opt.issuer_name = q; + } + else if( strcmp( p, "not_before" ) == 0 ) + { + opt.not_before = q; + } + else if( strcmp( p, "not_after" ) == 0 ) + { + opt.not_after = q; + } + else if( strcmp( p, "serial" ) == 0 ) + { + opt.serial = q; + } + else if( strcmp( p, "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; + } + + // Parse serial to MPI + // + if( ( ret = mpi_read_string( &serial, 10, opt.serial ) ) != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! mpi_read_string returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + +/* + 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 names for validity + */ + if( ( ret = x509write_crt_set_subject_name( &crt, opt.subject_name ) ) != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! x509write_crt_set_subject_name returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + if( ( ret = x509write_crt_set_issuer_name( &crt, opt.issuer_name ) ) != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! x509write_crt_set_issuer_name returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + /* + * 1.1. Load the keys + */ + printf( "\n . Loading the subject key ..." ); + fflush( stdout ); + + ret = x509parse_keyfile_rsa( &subject_rsa, opt.subject_key, opt.subject_pwd ); + + if( ret != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! x509parse_keyfile_rsa returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + x509write_crt_set_subject_key( &crt, &subject_rsa ); + + printf( " ok\n" ); + + printf( " . Loading the issuer key ..." ); + fflush( stdout ); + + ret = x509parse_keyfile_rsa( &issuer_rsa, opt.issuer_key, opt.issuer_pwd ); + + if( ret != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! x509parse_keyfile_rsa returned -x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + x509write_crt_set_issuer_key( &crt, &issuer_rsa ); + + printf( " ok\n" ); + + printf( " . Setting certificate values ..." ); + fflush( stdout ); + + ret = x509write_crt_set_serial( &crt, &serial ); + if( ret != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! x509write_crt_set_serial returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + ret = x509write_crt_set_validity( &crt, opt.not_before, opt.not_after ); + if( ret != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! x509write_crt_set_validity returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + + /* + * 1.2. Writing the request + */ + printf( " . Writing the certificate..." ); + fflush( stdout ); + + if( ( ret = write_certificate( &crt, opt.output_file ) ) != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! write_certifcate -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + +exit: + x509write_crt_free( &crt ); + rsa_free( &subject_rsa ); + rsa_free( &issuer_rsa ); + mpi_free( &serial ); + +#if defined(_WIN32) + printf( " + Press Enter to exit this program.\n" ); + fflush( stdout ); getchar(); +#endif + + return( ret ); +} +#endif /* POLARSSL_BIGNUM_C && POLARSSL_RSA_C && + POLARSSet_serial_X509_WRITE_C && POLARSSL_FS_IO */