diff --git a/programs/.gitignore b/programs/.gitignore index e9f4e54ef..2b7510f6e 100644 --- a/programs/.gitignore +++ b/programs/.gitignore @@ -35,6 +35,7 @@ test/o_p_test test/selftest test/ssl_cert_test test/ssl_test +util/pem2der util/strerror x509/cert_app x509/cert_req diff --git a/programs/Makefile b/programs/Makefile index 1c2b5fc80..ea024fae6 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -39,7 +39,7 @@ APPS = aes/aescrypt2 aes/crypt_and_hash \ test/ssl_cert_test test/benchmark \ test/selftest test/ssl_test \ test/ecp-bench \ - util/strerror \ + util/pem2der util/strerror \ x509/cert_app x509/crl_app \ x509/cert_req @@ -195,6 +195,10 @@ test/o_p_test: test/o_p_test.c ../library/libpolarssl.a echo " CC test/o_p_test.c" $(CC) $(CFLAGS) $(OFLAGS) test/o_p_test.c $(LDFLAGS) -o $@ -lssl -lcrypto +util/pem2der: util/pem2der.c ../library/libpolarssl.a + echo " CC util/pem2der.c" + $(CC) $(CFLAGS) $(OFLAGS) util/pem2der.c $(LDFLAGS) -o $@ + util/strerror: util/strerror.c ../library/libpolarssl.a echo " CC util/strerror.c" $(CC) $(CFLAGS) $(OFLAGS) util/strerror.c $(LDFLAGS) -o $@ diff --git a/programs/util/CMakeLists.txt b/programs/util/CMakeLists.txt index c0f2e4cea..aedd94f58 100644 --- a/programs/util/CMakeLists.txt +++ b/programs/util/CMakeLists.txt @@ -5,6 +5,9 @@ set(libs add_executable(strerror strerror.c) target_link_libraries(strerror ${libs}) -install(TARGETS strerror +add_executable(pem2der pem2der.c) +target_link_libraries(pem2der ${libs}) + +install(TARGETS strerror pem2der DESTINATION "bin" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) diff --git a/programs/util/pem2der.c b/programs/util/pem2der.c new file mode 100644 index 000000000..0315f02ea --- /dev/null +++ b/programs/util/pem2der.c @@ -0,0 +1,288 @@ +/* + * Convert PEM to DER + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include + +#include "polarssl/config.h" + +#include "polarssl/error.h" +#include "polarssl/base64.h" + +#define DFL_FILENAME "file.pem" +#define DFL_OUTPUT_FILENAME "file.der" + +/* + * global options + */ +struct options +{ + char *filename; /* filename of the input file */ + char *output_file; /* where to store the output */ +} opt; + +int convert_pem_to_der( const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ) +{ + int ret; + const unsigned char *s1, *s2, *end = input + ilen; + size_t len = 0; + + s1 = (unsigned char *) strstr( (char *) input, "-----BEGIN" ); + if( s1 == NULL ) + return( -1 ); + + s2 = (unsigned char *) strstr( (char *) input, "-----END" ); + if( s2 == NULL ) + return( -1 ); + + s1 += 10; + while( s1 < end && *s1 != '-' ) + s1++; + while( s1 < end && *s1 == '-' ) + s1++; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + + if( s2 <= s1 || s2 > end ) + return( -1 ); + + ret = base64_decode( NULL, &len, (const unsigned char *) s1, s2 - s1 ); + if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER ) + return( ret ); + + if( len > *olen ) + return( -1 ); + + if( ( ret = base64_decode( output, &len, (const unsigned char *) s1, + s2 - s1 ) ) != 0 ) + { + return( ret ); + } + + *olen = len; + + return( 0 ); +} + +/* + * Load all data from a file into a given buffer. + */ +static int load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + long size; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( -1 ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( -1 ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = (unsigned char *) malloc( *n + 1 ) ) == NULL ) + { + fclose( f ); + return( -1 ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + free( *buf ); + return( -1 ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + return( 0 ); +} + +/* + * Write buffer to a file + */ +static int write_file( const char *path, unsigned char *buf, size_t n ) +{ + FILE *f; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( -1 ); + + if( fwrite( buf, 1, n, f ) != n ) + { + fclose( f ); + return( -1 ); + } + + fclose( f ); + return( 0 ); +} + +#define USAGE \ + "\n usage: pem2der param=<>...\n" \ + "\n acceptable parameters:\n" \ + " filename=%%s default: file.pem\n" \ + " output_file=%%s default: file.der\n" \ + "\n" + +#if !defined(POLARSSL_BASE64_C) || !defined(POLARSSL_FS_IO) +int main( int argc, char *argv[] ) +{ + ((void) argc); + ((void) argv); + + printf("POLARSSL_BASE64_C and/or POLARSSL_FS_IO not defined.\n"); + return( 0 ); +} +#else +int main( int argc, char *argv[] ) +{ + int ret = 0; + unsigned char *pem_buffer = NULL; + unsigned char der_buffer[4096]; + char buf[1024]; + size_t pem_size, der_size = sizeof(der_buffer); + int i, j, n; + char *p, *q; + + /* + * Set to sane values + */ + memset( buf, 0, sizeof(buf) ); + memset( der_buffer, 0, sizeof(der_buffer) ); + + if( argc == 0 ) + { + usage: + printf( USAGE ); + goto exit; + } + + opt.filename = DFL_FILENAME; + opt.output_file = DFL_OUTPUT_FILENAME; + + for( i = 1; i < argc; i++ ) + { + + p = argv[i]; + if( ( q = strchr( p, '=' ) ) == NULL ) + goto usage; + *q++ = '\0'; + + n = strlen( p ); + for( j = 0; j < n; j++ ) + { + if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' ) + argv[i][j] |= 0x20; + } + + if( strcmp( p, "filename" ) == 0 ) + opt.filename = q; + else if( strcmp( p, "output_file" ) == 0 ) + opt.output_file = q; + else + goto usage; + } + + /* + * 1.1. Load the PEM file + */ + printf( "\n . Loading the PEM file ..." ); + fflush( stdout ); + + ret = load_file( opt.filename, &pem_buffer, &pem_size ); + + if( ret != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! load_file returned %d - %s\n\n", ret, buf ); + goto exit; + } + + printf( " ok\n" ); + + /* + * 1.2. Convert from PEM to DER + */ + printf( " . Converting from PEM to DER ..." ); + fflush( stdout ); + + if( ( ret = convert_pem_to_der( pem_buffer, pem_size, der_buffer, &der_size ) ) != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! convert_pem_to_der %d - %s\n\n", ret, buf ); + goto exit; + } + + printf( " ok\n" ); + + /* + * 1.3. Write the DER file + */ + printf( " . Writing the DER file ..." ); + fflush( stdout ); + + ret = write_file( opt.output_file, der_buffer, der_size ); + + if( ret != 0 ) + { +#ifdef POLARSSL_ERROR_C + error_strerror( ret, buf, 1024 ); +#endif + printf( " failed\n ! write_file returned %d - %s\n\n", ret, buf ); + goto exit; + } + + printf( " ok\n" ); + +exit: + free( pem_buffer ); + +#if defined(_WIN32) + printf( " + Press Enter to exit this program.\n" ); + fflush( stdout ); getchar(); +#endif + + return( ret ); +} +#endif /* POLARSSL_BASE64_C && POLARSSL_FS_IO */