diff --git a/ChangeLog b/ChangeLog index 979437566..9649780a7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,10 @@ Features * Added support for wildcard certificates * Added support for multi-domain certificates through the X509 Subject Alternative Name extension + * Added preliminary ASN.1 buffer writing support + * Added preliminary X509 Certificate Request writing support + * Added key_app_writer example application + * Added cert_req example application Changes * Removed redundant POLARSSL_DEBUG_MSG define diff --git a/include/polarssl/asn1.h b/include/polarssl/asn1.h index bc7b6bba9..dc3f2fef7 100644 --- a/include/polarssl/asn1.h +++ b/include/polarssl/asn1.h @@ -47,12 +47,12 @@ * ASN1 is a standard to specify data structures. * \{ */ -#define POLARSSL_ERR_ASN1_OUT_OF_DATA -0x0014 /**< Out of data when parsing an ASN1 data structure. */ -#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG -0x0016 /**< ASN1 tag was of an unexpected value. */ -#define POLARSSL_ERR_ASN1_INVALID_LENGTH -0x0018 /**< Error when trying to determine the length or invalid length. */ -#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH -0x001A /**< Actual length differs from expected length. */ -#define POLARSSL_ERR_ASN1_INVALID_DATA -0x001C /**< Data is invalid. (not used) */ -#define POLARSSL_ERR_ASN1_MALLOC_FAILED -0x001E /**< Memory allocation failed */ +#define POLARSSL_ERR_ASN1_OUT_OF_DATA -0x0060 /**< Out of data when parsing an ASN1 data structure. */ +#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG -0x0062 /**< ASN1 tag was of an unexpected value. */ +#define POLARSSL_ERR_ASN1_INVALID_LENGTH -0x0064 /**< Error when trying to determine the length or invalid length. */ +#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH -0x0066 /**< Actual length differs from expected length. */ +#define POLARSSL_ERR_ASN1_INVALID_DATA -0x0068 /**< Data is invalid. (not used) */ +#define POLARSSL_ERR_ASN1_MALLOC_FAILED -0x006A /**< Memory allocation failed */ /* \} name */ /** diff --git a/include/polarssl/asn1write.h b/include/polarssl/asn1write.h new file mode 100644 index 000000000..38f6eeae3 --- /dev/null +++ b/include/polarssl/asn1write.h @@ -0,0 +1,46 @@ +/** + * \file asn1write.h + * + * \brief ASN.1 buffer writing functionality + * + * Copyright (C) 2006-2012, 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 POLARSSL_ASN1_WRITE_H +#define POLARSSL_ASN1_WRITE_H + +#include "asn1.h" + +#define POLARSSL_ERR_ASN1_BUF_TOO_SMALL -0x006C /**< Buffer too small when writing ASN.1 data structure. */ + +#define ASN1_CHK_ADD(g, f) if( ( ret = f ) < 0 ) return( ret ); else g += ret + +int asn1_write_len( unsigned char **p, unsigned char *start, size_t len ); +int asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag ); +int asn1_write_mpi( unsigned char **p, unsigned char *start, mpi *X ); +int asn1_write_null( unsigned char **p, unsigned char *start ); +int asn1_write_oid( unsigned char **p, unsigned char *start, char *oid ); +int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, char *algorithm_oid ); +int asn1_write_int( unsigned char **p, unsigned char *start, int val ); +int asn1_write_printable_string( unsigned char **p, unsigned char *start, + char *text ); + +#endif /* POLARSSL_ASN1_WRITE_H */ diff --git a/include/polarssl/config.h b/include/polarssl/config.h index bb9e6806d..62663ced6 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -288,6 +288,15 @@ */ #define POLARSSL_ASN1_PARSE_C +/** + * \def POLARSSL_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + */ +#define POLARSSL_ASN1_WRITE_C + /** * \def POLARSSL_BASE64_C * @@ -697,6 +706,19 @@ */ #define POLARSSL_X509_PARSE_C +/** + * \def POLARSSL_X509_WRITE_C + * + * Enable X.509 buffer writing. + * + * Module: library/x509write.c + * + * Requires: POLARSSL_BIGNUM_C, POLARSSL_RSA_C + * + * This module is required for X.509 certificate request writing. + */ +#define POLARSSL_X509_WRITE_C + /** * \def POLARSSL_XTEA_C * diff --git a/include/polarssl/error.h b/include/polarssl/error.h index 9c1707105..e2e91f9db 100644 --- a/include/polarssl/error.h +++ b/include/polarssl/error.h @@ -49,16 +49,16 @@ * * Module Nr Codes assigned * MPI 7 0x0002-0x0010 - * ASN1 6 0x0014-0x001E * AES 2 0x0020-0x0022 * CAMELLIA 2 0x0024-0x0026 * XTEA 1 0x0028-0x0028 * BASE64 2 0x002A-0x002C * PADLOCK 1 0x0030-0x0030 * DES 1 0x0032-0x0032 - * NET 11 0x0040-0x0054 * CTR_DBRG 3 0x0034-0x003A * ENTROPY 3 0x003C-0x0040 + * NET 11 0x0042-0x0056 + * ASN1 7 0x0060-0x006C * MD2 1 0x0070-0x0070 * MD4 1 0x0072-0x0072 * MD5 1 0x0074-0x0074 diff --git a/include/polarssl/net.h b/include/polarssl/net.h index 89e3a00bb..88302ac0a 100644 --- a/include/polarssl/net.h +++ b/include/polarssl/net.h @@ -29,7 +29,7 @@ #include -#define POLARSSL_ERR_NET_UNKNOWN_HOST -0x0040 /**< Failed to get an IP address for the given hostname. */ +#define POLARSSL_ERR_NET_UNKNOWN_HOST -0x0056 /**< Failed to get an IP address for the given hostname. */ #define POLARSSL_ERR_NET_SOCKET_FAILED -0x0042 /**< Failed to open a socket. */ #define POLARSSL_ERR_NET_CONNECT_FAILED -0x0044 /**< The connection to the given server / port failed. */ #define POLARSSL_ERR_NET_BIND_FAILED -0x0046 /**< Binding of the socket failed. */ diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h index 385c8b562..2cd883fb4 100644 --- a/include/polarssl/x509.h +++ b/include/polarssl/x509.h @@ -99,9 +99,15 @@ #define OID_X520 "\x55\x04" #define OID_CN OID_X520 "\x03" +#define OID_COUNTRY OID_X520 "\x06" +#define OID_LOCALITY OID_X520 "\x07" +#define OID_STATE OID_X520 "\x08" +#define OID_ORGANIZATION OID_X520 "\x0A" +#define OID_ORG_UNIT OID_X520 "\x0B" #define OID_PKCS1 "\x2A\x86\x48\x86\xF7\x0D\x01\x01" #define OID_PKCS1_RSA OID_PKCS1 "\x01" +#define OID_PKCS1_SHA1 OID_PKCS1 "\x05" #define OID_RSA_SHA_OBS "\x2B\x0E\x03\x02\x1D" diff --git a/include/polarssl/x509write.h b/include/polarssl/x509write.h new file mode 100644 index 000000000..c24f3e1fa --- /dev/null +++ b/include/polarssl/x509write.h @@ -0,0 +1,46 @@ +/** + * \file x509write.h + * + * \brief X509 buffer writing functionality + * + * Copyright (C) 2006-2012, 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 POLARSSL_X509_WRITE_H +#define POLARSSL_X509_WRITE_H + +#include "rsa.h" + +typedef struct _x509_req_name +{ + char oid[128]; + char name[128]; + + struct _x509_req_name *next; +} +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 ); + +#endif /* POLARSSL_X509_WRITE_H */ diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index de7273571..bb600d403 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -4,6 +4,7 @@ set(src aes.c arc4.c asn1parse.c + asn1write.c base64.c bignum.c camellia.c diff --git a/library/Makefile b/library/Makefile index 26de4d785..968ca31f7 100644 --- a/library/Makefile +++ b/library/Makefile @@ -23,6 +23,7 @@ DLEXT=so # DLEXT=dll OBJS= aes.o arc4.o asn1parse.o \ + asn1write.o \ base64.o bignum.o camellia.o \ certs.o cipher.o cipher_wrap.o \ ctr_drbg.o debug.o des.o \ @@ -34,7 +35,7 @@ OBJS= aes.o arc4.o asn1parse.o \ rsa.o sha1.o sha2.o \ sha4.o ssl_cli.o ssl_srv.o \ ssl_tls.o timing.o version.o \ - x509parse.o xtea.o + x509parse.o x509write.o xtea.o .SILENT: diff --git a/library/asn1write.c b/library/asn1write.c new file mode 100644 index 000000000..0c1d18b6e --- /dev/null +++ b/library/asn1write.c @@ -0,0 +1,218 @@ +/* + * ASN.1 buffer writing functionality + * + * Copyright (C) 2006-2012, 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. + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_ASN1_WRITE_C) + +#include "polarssl/asn1write.h" + +int asn1_write_len( unsigned char **p, unsigned char *start, size_t len ) +{ + if( len < 0x80 ) + { + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = len; + return( 1 ); + } + + if( len <= 0xFF ) + { + if( *p - start < 2 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = len; + *--(*p) = 0x81; + return( 2 ); + } + + if( *p - start < 3 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + // We assume we never have lengths larger than 65535 bytes + // + *--(*p) = len % 256; + *--(*p) = ( len / 256 ) % 256; + *--(*p) = 0x82; + + return( 3 ); +} + +int asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag ) +{ + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = tag; + + return( 1 ); +} + +int asn1_write_mpi( unsigned char **p, unsigned char *start, mpi *X ) +{ + int ret; + size_t len = 0; + + // Write the MPI + // + len = mpi_size( X ); + + if( *p - start < (int) len ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + (*p) -= len; + mpi_write_binary( X, *p, len ); + + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if ( X->s ==1 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_INTEGER ) ); + + return( len ); +} + +int asn1_write_null( unsigned char **p, unsigned char *start ) +{ + int ret; + size_t len = 0; + + // Write NULL + // + ASN1_CHK_ADD( len, asn1_write_len( p, start, 0) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_NULL ) ); + + return( len ); +} + +int asn1_write_oid( unsigned char **p, unsigned char *start, 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_len( p, start, len ) ); + ASN1_CHK_ADD( len , asn1_write_tag( p, start, ASN1_OID ) ); + + return( len ); +} + +int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, + char *algorithm_oid ) +{ + int ret; + size_t null_len = 0; + size_t oid_len = 0; + size_t len = 0; + + // Write NULL + // + ASN1_CHK_ADD( null_len, asn1_write_null( p, start ) ); + + // Write OID + // + ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, algorithm_oid ) ); + + len = oid_len + null_len; + ASN1_CHK_ADD( len, asn1_write_len( p, start, oid_len + null_len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + return( len ); +} + +int asn1_write_int( unsigned char **p, unsigned char *start, int val ) +{ + int ret; + size_t len = 0; + + // TODO negative values and values larger than 128 + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + len += 1; + *--(*p) = val; + + if ( val > 0 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_INTEGER ) ); + + return( len ); +} + +int asn1_write_printable_string( unsigned char **p, unsigned char *start, + 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_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_PRINTABLE_STRING ) ); + + return( len ); +} + +#endif diff --git a/library/error.c b/library/error.c index 9bc503429..195ae2056 100644 --- a/library/error.c +++ b/library/error.c @@ -378,6 +378,8 @@ void error_strerror( int ret, char *buf, size_t buflen ) snprintf( buf, buflen, "ASN1 - Data is invalid. (not used)" ); if( use_ret == -(POLARSSL_ERR_ASN1_MALLOC_FAILED) ) snprintf( buf, buflen, "ASN1 - Memory allocation failed" ); + if( use_ret == -(POLARSSL_ERR_ASN1_BUF_TOO_SMALL) ) + snprintf( buf, buflen, "ASN1 - Buffer too small when writing ASN.1 data structure" ); #endif /* POLARSSL_ASN1_PARSE_C */ #if defined(POLARSSL_BASE64_C) diff --git a/library/x509write.c b/library/x509write.c new file mode 100644 index 000000000..b114e700e --- /dev/null +++ b/library/x509write.c @@ -0,0 +1,233 @@ +/* + * X509 buffer writing functionality + * + * Copyright (C) 2006-2012, 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. + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_X509_WRITE_C) + +#include "polarssl/asn1write.h" +#include "polarssl/x509write.h" +#include "polarssl/x509.h" +#include "polarssl/sha1.h" + +int x509_write_pubkey_der( unsigned char *buf, size_t size, rsa_context *rsa ) +{ + int ret; + unsigned char *c; + size_t len = 0; + + c = buf + size - 1; + + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->E ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->N ) ); + + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + if( c - buf < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--c = 0; + len += 1; + + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_BIT_STRING ) ); + + ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, buf, OID_PKCS1_RSA ) ); + + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + return( len ); +} + +int x509_write_key_der( unsigned char *buf, size_t size, rsa_context *rsa ) +{ + int ret; + unsigned char *c; + size_t len = 0; + + c = buf + size - 1; + + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->QP ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DQ ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DP ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->Q ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->P ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->D ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->E ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->N ) ); + ASN1_CHK_ADD( len, asn1_write_int( &c, buf, 0 ) ); + + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + // TODO: Make NON RSA Specific variant later on +/* *--c = 0; + len += 1; + + len += asn1_write_len( &c, len); + len += asn1_write_tag( &c, ASN1_BIT_STRING ); + + len += asn1_write_oid( &c, OID_PKCS1_RSA ); + + len += asn1_write_int( &c, 0 ); + + len += asn1_write_len( &c, len); + len += asn1_write_tag( &c, ASN1_CONSTRUCTED | ASN1_SEQUENCE );*/ + +/* for(i = 0; i < len; ++i) + { + if (i % 16 == 0 ) printf("\n"); + printf("%02x ", c[i]); + } + printf("\n");*/ + + return( len ); +} + +int x509_write_name( unsigned char **p, unsigned char *start, char *oid, + char *name ) +{ + int ret; + size_t string_len = 0; + size_t oid_len = 0; + size_t len = 0; + + // Write PrintableString + // + ASN1_CHK_ADD( string_len, asn1_write_printable_string( p, start, name ) ); + + // Write OID + // + ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, oid ) ); + + len = oid_len + string_len; + ASN1_CHK_ADD( len, asn1_write_len( p, start, oid_len + string_len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SET ) ); + + return( len ); +} + +int x509_write_sig( unsigned char **p, unsigned char *start, char *oid, + unsigned char *sig, size_t size ) +{ + int ret; + size_t len = 0; + + if( *p - start < (int) size + 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + len = size; + (*p) -= len; + memcpy( *p, sig, len ); + + *--(*p) = 0; + len += 1; + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_BIT_STRING ) ); + + // Write OID + // + ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( p, start, oid ) ); + + return( len ); +} + +int x509_write_cert_req( unsigned char *buf, size_t size, rsa_context *rsa, + x509_req_name *req_name ) +{ + int ret; + unsigned char *c, *c2; + unsigned char hash[20]; + unsigned char sig[512]; + 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; + + c = tmp_buf + 2048 - 1; + + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, 0 ) ); + 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_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 ) ); + + while( cur != NULL ) + { + ASN1_CHK_ADD( sub_len, x509_write_name( &c, tmp_buf, cur->oid, cur->name ) ); + + cur = cur->next; + } + + len += sub_len; + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + ASN1_CHK_ADD( len, 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 ) ); + + sha1( c, len, hash ); + rsa_pkcs1_sign( rsa, NULL, NULL, RSA_PRIVATE, SIG_RSA_SHA1, 0, hash, sig ); + + c2 = buf + size - 1; + ASN1_CHK_ADD( sig_len, x509_write_sig( &c2, buf, OID_PKCS1_SHA1, sig, rsa->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 ); +} + +#endif diff --git a/programs/Makefile b/programs/Makefile index c8b6def33..7027743db 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -12,7 +12,7 @@ APPS = aes/aescrypt2 aes/crypt_and_hash \ hash/md5sum hash/sha1sum \ hash/sha2sum pkey/dh_client \ pkey/dh_genprime pkey/dh_server \ - pkey/key_app \ + pkey/key_app pkey/key_app_writer \ pkey/mpi_demo pkey/rsa_genkey \ pkey/rsa_decrypt pkey/rsa_encrypt \ pkey/rsa_sign pkey/rsa_verify \ @@ -24,7 +24,8 @@ APPS = aes/aescrypt2 aes/crypt_and_hash \ random/gen_random_ctr_drbg \ test/ssl_cert_test test/benchmark \ test/selftest test/ssl_test \ - x509/cert_app x509/crl_app + x509/cert_app x509/crl_app \ + x509/cert_req .SILENT: @@ -74,6 +75,10 @@ pkey/key_app: pkey/key_app.c ../library/libpolarssl.a echo " CC pkey/key_app.c" $(CC) $(CFLAGS) $(OFLAGS) pkey/key_app.c $(LDFLAGS) -o $@ +pkey/key_app_writer: pkey/key_app_writer.c ../library/libpolarssl.a + echo " CC pkey/key_app_writer.c" + $(CC) $(CFLAGS) $(OFLAGS) pkey/key_app_writer.c $(LDFLAGS) -o $@ + pkey/mpi_demo: pkey/mpi_demo.c ../library/libpolarssl.a echo " CC pkey/mpi_demo.c" $(CC) $(CFLAGS) $(OFLAGS) pkey/mpi_demo.c $(LDFLAGS) -o $@ @@ -162,6 +167,10 @@ x509/crl_app: x509/crl_app.c ../library/libpolarssl.a echo " CC x509/crl_app.c" $(CC) $(CFLAGS) $(OFLAGS) x509/crl_app.c $(LDFLAGS) -o $@ +x509/cert_req: x509/cert_req.c ../library/libpolarssl.a + echo " CC x509/cert_req.c" + $(CC) $(CFLAGS) $(OFLAGS) x509/cert_req.c $(LDFLAGS) -o $@ + clean: rm -f $(APPS) diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c new file mode 100644 index 000000000..af508d2b0 --- /dev/null +++ b/programs/pkey/key_app_writer.c @@ -0,0 +1,347 @@ +/* + * Key reading application + * + * Copyright (C) 2006-2011, 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" + +#define MODE_NONE 0 +#define MODE_PRIVATE 1 +#define MODE_PUBLIC 2 + +#define OUTPUT_MODE_NONE 0 +#define OUTPUT_MODE_PRIVATE 1 +#define OUTPUT_MODE_PUBLIC 2 + +#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_FILENAME "keyfile.pem" + +/* + * global options + */ +struct options +{ + int mode; /* the mode to run the application in */ + char *filename; /* filename of the key file */ + int debug_level; /* level of debugging */ + int output_mode; /* the output mode to use */ + char *output_file; /* where to store the constructed key file */ +} 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_public_key( rsa_context *rsa, char *output_file ) +{ + FILE *f; + unsigned char output_buf[4096]; + unsigned char base_buf[4096]; + unsigned char *c; + int ret; + size_t len = 0, olen = 4096; + + memset(output_buf, 0, 4096); + ret = x509_write_pubkey_der( output_buf, 4096, rsa ); + + if( ret < 0 ) + return; + + len = ret; + c = output_buf + 4095 - len; + + base64_encode( base_buf, &olen, c, len ); + + c = base_buf; + + f = fopen( output_file, "w" ); + fprintf(f, "-----BEGIN PUBLIC KEY-----\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 PUBLIC KEY-----\n"); + fclose(f); +} + +void write_private_key( rsa_context *rsa, char *output_file ) +{ + FILE *f; + unsigned char output_buf[4096]; + unsigned char base_buf[4096]; + unsigned char *c; + int ret; + size_t len = 0, olen = 4096; + + memset(output_buf, 0, 4096); + ret = x509_write_key_der( output_buf, 4096, rsa ); + if( ret < 0 ) + return; + + len = ret; + c = output_buf + 4095 - 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) + { + 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 RSA PRIVATE KEY-----\n"); + fclose(f); +} + +#define USAGE \ + "\n usage: key_app param=<>...\n" \ + "\n acceptable parameters:\n" \ + " mode=private|public default: none\n" \ + " filename=%%s default: keyfile.key\n" \ + " debug_level=%%d default: 0 (disabled)\n" \ + " output_mode=private|public default: none\n" \ + " output_file=%%s defeult: keyfile.pem\n" \ + "\n" + +#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \ + !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) +int main( int argc, char *argv[] ) +{ + ((void) argc); + ((void) argv); + + printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or " + "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO not defined.\n"); + return( 0 ); +} +#else +int main( int argc, char *argv[] ) +{ + int ret = 0; + rsa_context rsa; + char buf[1024]; + int i, j, n; + char *p, *q; + + /* + * Set to sane values + */ + memset( &rsa, 0, sizeof( rsa_context ) ); + memset( buf, 0, 1024 ); + + if( argc == 0 ) + { + usage: + printf( USAGE ); + goto exit; + } + + opt.mode = DFL_MODE; + opt.filename = DFL_FILENAME; + opt.debug_level = DFL_DEBUG_LEVEL; + opt.output_mode = DFL_OUTPUT_MODE; + opt.output_file = DFL_OUTPUT_FILENAME; + + for( i = 1; i < argc; i++ ) + { + n = strlen( argv[i] ); + + for( j = 0; j < n; j++ ) + { + if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' ) + argv[i][j] |= 0x20; + } + + p = argv[i]; + if( ( q = strchr( p, '=' ) ) == NULL ) + goto usage; + *q++ = '\0'; + + if( strcmp( p, "mode" ) == 0 ) + { + if( strcmp( q, "private" ) == 0 ) + opt.mode = MODE_PRIVATE; + else if( strcmp( q, "public" ) == 0 ) + opt.mode = MODE_PUBLIC; + else + goto usage; + } + else if( strcmp( p, "output_mode" ) == 0 ) + { + if( strcmp( q, "private" ) == 0 ) + opt.output_mode = OUTPUT_MODE_PRIVATE; + else if( strcmp( q, "public" ) == 0 ) + opt.output_mode = OUTPUT_MODE_PUBLIC; + else + goto usage; + } + else if( strcmp( p, "filename" ) == 0 ) + opt.filename = q; + else if( strcmp( p, "output_file" ) == 0 ) + opt.output_file = q; + else if( strcmp( p, "debug_level" ) == 0 ) + { + opt.debug_level = atoi( q ); + if( opt.debug_level < 0 || opt.debug_level > 65535 ) + goto usage; + } + else + goto usage; + } + + if( opt.mode == MODE_NONE && opt.output_mode != OUTPUT_MODE_NONE ) + { + printf( "\nCannot output a key without reading one.\n"); + goto exit; + } + + if( opt.mode == MODE_PUBLIC && opt.output_mode == OUTPUT_MODE_PRIVATE ) + { + printf( "\nCannot output a private key from a public key.\n"); + goto exit; + } + + if( opt.mode == MODE_PRIVATE ) + { + /* + * 1.1. Load the key + */ + printf( "\n . Loading the private key ..." ); + fflush( stdout ); + + ret = x509parse_keyfile( &rsa, opt.filename, NULL ); + + if( ret != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! x509parse_key returned %d - %s\n\n", ret, buf ); + rsa_free( &rsa ); + goto exit; + } + + printf( " ok\n" ); + + /* + * 1.2 Print the key + */ + printf( " . Key information ...\n" ); + mpi_write_file( "N: ", &rsa.N, 16, NULL ); + mpi_write_file( "E: ", &rsa.E, 16, NULL ); + mpi_write_file( "D: ", &rsa.D, 16, NULL ); + mpi_write_file( "P: ", &rsa.P, 16, NULL ); + mpi_write_file( "Q: ", &rsa.Q, 16, NULL ); + mpi_write_file( "DP: ", &rsa.DP, 16, NULL ); + mpi_write_file( "DQ: ", &rsa.DQ, 16, NULL ); + mpi_write_file( "QP: ", &rsa.QP, 16, NULL ); + + } + else if( opt.mode == MODE_PUBLIC ) + { + /* + * 1.1. Load the key + */ + printf( "\n . Loading the public key ..." ); + fflush( stdout ); + + ret = x509parse_public_keyfile( &rsa, opt.filename ); + + if( ret != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! x509parse_public_key returned %d - %s\n\n", ret, buf ); + rsa_free( &rsa ); + goto exit; + } + + printf( " ok\n" ); + + /* + * 1.2 Print the key + */ + printf( " . Key information ...\n" ); + mpi_write_file( "N: ", &rsa.N, 16, NULL ); + mpi_write_file( "E: ", &rsa.E, 16, NULL ); + } + else + goto usage; + + if( opt.output_mode == OUTPUT_MODE_PUBLIC ) + { + write_public_key( &rsa, opt.output_file ); + } + if( opt.output_mode == OUTPUT_MODE_PRIVATE ) + { + write_private_key( &rsa, opt.output_file ); + } + +exit: + + rsa_free( &rsa ); + +#if defined(_WIN32) + printf( " + Press Enter to exit this program.\n" ); + fflush( stdout ); getchar(); +#endif + + return( ret ); +} +#endif /* POLARSSL_BIGNUM_C && POLARSSL_RSA_C && + POLARSSL_X509_PARSE_C && POLARSSL_FS_IO */ diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c new file mode 100644 index 000000000..4bcfbbeee --- /dev/null +++ b/programs/x509/cert_req.c @@ -0,0 +1,298 @@ +/* + * Certificate request generation + * + * Copyright (C) 2006-2011, 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" + +#define DFL_FILENAME "keyfile.key" +#define DFL_DEBUG_LEVEL 0 +#define DFL_OUTPUT_FILENAME "cert.req" +#define DFL_SUBJECT_NAME "CN=Cert,O=PolarSSL,C=NL" + +/* + * global options + */ +struct options +{ + char *filename; /* filename of the key file */ + int debug_level; /* level of debugging */ + char *output_file; /* where to store the constructed key file */ + char *subject_name; /* subject name for certificate request */ +} 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 ) +{ + FILE *f; + unsigned char output_buf[4096]; + unsigned char base_buf[4096]; + unsigned char *c; + int ret; + size_t len = 0, olen = 4096; + + memset(output_buf, 0, 4096); + ret = x509_write_cert_req( output_buf, 4096, rsa, req_name ); + + if( ret < 0 ) + return; + + len = ret; + c = output_buf + 4095 - len; + + base64_encode( base_buf, &olen, c, len ); + + 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); +} + +#define USAGE \ + "\n usage: key_app param=<>...\n" \ + "\n acceptable parameters:\n" \ + " filename=%%s default: keyfile.key\n" \ + " 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" \ + "\n" + +#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \ + !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) +int main( int argc, char *argv[] ) +{ + ((void) argc); + ((void) argv); + + printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or " + "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO not defined.\n"); + return( 0 ); +} +#else +int main( int argc, char *argv[] ) +{ + int ret = 0; + rsa_context rsa; + 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; + + /* + * Set to sane values + */ + memset( &rsa, 0, sizeof( rsa_context ) ); + memset( buf, 0, 1024 ); + + if( argc == 0 ) + { + usage: + printf( USAGE ); + goto exit; + } + + opt.filename = DFL_FILENAME; + opt.debug_level = DFL_DEBUG_LEVEL; + opt.output_file = DFL_OUTPUT_FILENAME; + opt.subject_name = DFL_SUBJECT_NAME; + + 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 if( strcmp( p, "debug_level" ) == 0 ) + { + opt.debug_level = atoi( q ); + if( opt.debug_level < 0 || opt.debug_level > 65535 ) + goto usage; + } + else if( strcmp( p, "subject_name" ) == 0 ) + { + printf("p: '%s', q: '%s'\n", p, q); + opt.subject_name = q; + } + else + goto usage; + } + + /* + * 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( in_tag && *c == '=' ) + { + if( memcmp( s, "CN", 2 ) == 0 && c - s == 2 ) + oid = OID_CN; + else if( memcmp( s, "C", 1 ) == 0 && c - s == 1 ) + oid = OID_COUNTRY; + else if( memcmp( s, "O", 1 ) == 0 && c - s == 1 ) + oid = OID_ORGANIZATION; + else if( memcmp( s, "L", 1 ) == 0 && c - s == 1 ) + oid = OID_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_ORG_UNIT; + else if( memcmp( s, "ST", 2 ) == 0 && c - s == 2 ) + oid = OID_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++; + } + + /* + * 1.1. Load the key + */ + printf( "\n . Loading the private key ..." ); + fflush( stdout ); + + ret = x509parse_keyfile( &rsa, opt.filename, NULL ); + + if( ret != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! x509parse_key returned %d - %s\n\n", ret, buf ); + rsa_free( &rsa ); + goto exit; + } + + printf( " ok\n" ); + + write_certificate_request( &rsa, req_name, opt.output_file ); + +exit: + + rsa_free( &rsa ); + +#if defined(_WIN32) + printf( " + Press Enter to exit this program.\n" ); + fflush( stdout ); getchar(); +#endif + + return( ret ); +} +#endif /* POLARSSL_BIGNUM_C && POLARSSL_RSA_C && + POLARSSL_X509_PARSE_C && POLARSSL_FS_IO */