diff --git a/ChangeLog b/ChangeLog index c8ec678d7..b24009b9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,8 @@ Features * Added GCM suites to TLS 1.2 (RFC 5288) * Added commandline error code convertor (util/strerror) * Added support for Hardware Acceleration hooking in SSL/TLS + * Added OpenSSL / PolarSSL compatibility script (tests/compat.sh) and + example application (programs/ssl/o_p_test) (Requires OpenSSL) Changes * Removed redundant POLARSSL_DEBUG_MSG define @@ -34,6 +36,8 @@ Bugfix * Fixed single RSA test that failed on Big Endian systems (Closes ticket #54) * mpi_exp_mod() now correctly handles negative base numbers (Closes ticket #52) + * Handle encryption with private key and decryption with public key as per + RFC 2313 Security * Fixed potential memory corruption on miscrafted client messages (found by diff --git a/library/rsa.c b/library/rsa.c index 72806e17e..215f1aa09 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -386,23 +386,34 @@ int rsa_pkcs1_encrypt( rsa_context *ctx, nb_pad = olen - 3 - ilen; *p++ = 0; - *p++ = RSA_CRYPT; - - while( nb_pad-- > 0 ) + if( mode == RSA_PUBLIC ) { - int rng_dl = 100; + *p++ = RSA_CRYPT; - do { - ret = f_rng( p_rng, p, 1 ); - } while( *p == 0 && --rng_dl && ret == 0 ); + while( nb_pad-- > 0 ) + { + int rng_dl = 100; - // Check if RNG failed to generate data - // - if( rng_dl == 0 || ret != 0) - return POLARSSL_ERR_RSA_RNG_FAILED + ret; + do { + ret = f_rng( p_rng, p, 1 ); + } while( *p == 0 && --rng_dl && ret == 0 ); - p++; + // Check if RNG failed to generate data + // + if( rng_dl == 0 || ret != 0) + return POLARSSL_ERR_RSA_RNG_FAILED + ret; + + p++; + } } + else + { + *p++ = RSA_SIGN; + + while( nb_pad-- > 0 ) + *p++ = 0xFF; + } + *p++ = 0; memcpy( p, input, ilen ); break; @@ -475,6 +486,7 @@ int rsa_pkcs1_decrypt( rsa_context *ctx, int ret; size_t ilen; unsigned char *p; + unsigned char bt; unsigned char buf[1024]; #if defined(POLARSSL_PKCS1_V21) unsigned char lhash[POLARSSL_MD_MAX_SIZE]; @@ -501,16 +513,37 @@ int rsa_pkcs1_decrypt( rsa_context *ctx, { case RSA_PKCS_V15: - if( *p++ != 0 || *p++ != RSA_CRYPT ) + if( *p++ != 0 ) return( POLARSSL_ERR_RSA_INVALID_PADDING ); - - while( *p != 0 ) + + bt = *p++; + if( ( bt != RSA_CRYPT && mode == RSA_PRIVATE ) || + ( bt != RSA_SIGN && mode == RSA_PUBLIC ) ) { - if( p >= buf + ilen - 1 ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + } + + if( bt == RSA_CRYPT ) + { + while( *p != 0 && p < buf + ilen - 1 ) + p++; + + if( *p != 0 || p >= buf + ilen - 1 ) return( POLARSSL_ERR_RSA_INVALID_PADDING ); + p++; } - p++; + else + { + while( *p == 0xFF && p < buf + ilen - 1 ) + p++; + + if( *p != 0 || p >= buf + ilen - 1 ) + return( POLARSSL_ERR_RSA_INVALID_PADDING ); + + p++; + } + break; #if defined(POLARSSL_PKCS1_V21) diff --git a/programs/Makefile b/programs/Makefile index 2f486cd19..d28bc53ce 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -36,6 +36,10 @@ APPS = aes/aescrypt2 aes/crypt_and_hash \ x509/cert_app x509/crl_app \ x509/cert_req +ifdef OPENSSL +APPS += test/o_p_test +endif + .SILENT: all: $(APPS) @@ -168,6 +172,10 @@ test/ssl_test: test/ssl_test.c ../library/libpolarssl.a echo " CC test/ssl_test.c" $(CC) $(CFLAGS) $(OFLAGS) test/ssl_test.c $(LDFLAGS) -o $@ +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/strerror: util/strerror.c ../library/libpolarssl.a echo " CC util/strerror.c" $(CC) $(CFLAGS) $(OFLAGS) util/strerror.c $(LDFLAGS) -o $@ diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt index 5ad436457..f00fc9d60 100644 --- a/programs/test/CMakeLists.txt +++ b/programs/test/CMakeLists.txt @@ -1,3 +1,5 @@ +FIND_PACKAGE(OpenSSL) + set(libs polarssl ) @@ -21,3 +23,13 @@ target_link_libraries(ssl_cert_test ${libs}) install(TARGETS selftest benchmark ssl_test ssl_cert_test DESTINATION "bin" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + +if(OPENSSL_FOUND) + add_executable(o_p_test o_p_test.c) + target_link_libraries(o_p_test ${libs} ${OPENSSL_LIBRARIES}) + + install(TARGETS o_p_test + DESTINATION "bin" + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +endif(OPENSSL_FOUND) + diff --git a/programs/test/o_p_test.c b/programs/test/o_p_test.c new file mode 100644 index 000000000..187372af9 --- /dev/null +++ b/programs/test/o_p_test.c @@ -0,0 +1,243 @@ +/* + * Test application that shows some PolarSSL and OpenSSL compatibility + * + * Copyright (C) 2011-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 _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "polarssl/config.h" + +#include "polarssl/x509.h" +#include "polarssl/rsa.h" +#include "polarssl/entropy.h" +#include "polarssl/ctr_drbg.h" + +int main( int argc, char *argv[] ) +{ + int ret; + FILE *key_file; + size_t olen; + rsa_context p_rsa; + RSA *o_rsa; + entropy_context entropy; + ctr_drbg_context ctr_drbg; + unsigned char input[1024]; + unsigned char p_pub_encrypted[512]; + unsigned char o_pub_encrypted[512]; + unsigned char p_pub_decrypted[512]; + unsigned char o_pub_decrypted[512]; + unsigned char p_priv_encrypted[512]; + unsigned char o_priv_encrypted[512]; + unsigned char p_priv_decrypted[512]; + unsigned char o_priv_decrypted[512]; + char *pers = "o_p_test_example"; + + entropy_init( &entropy ); + if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy, + (unsigned char *) pers, strlen( pers ) ) ) != 0 ) + { + printf( " failed\n ! ctr_drbg_init returned %d\n", ret ); + goto exit; + } + ERR_load_crypto_strings(); + + ret = 1; + + if( argc != 3 ) + { + printf( "usage: o_p_test \n" ); + +#ifdef WIN32 + printf( "\n" ); +#endif + + goto exit; + } + + printf( " . Reading private key from %s into PolarSSL ...", argv[1] ); + fflush( stdout ); + + rsa_init( &p_rsa, RSA_PKCS_V15, 0 ); + if( x509parse_keyfile( &p_rsa, argv[1], NULL ) != 0 ) + { + ret = 1; + printf( " failed\n ! Could not load key.\n\n" ); + goto exit; + } + + printf( " passed\n"); + + printf( " . Reading private key from %s into OpenSSL ...", argv[1] ); + fflush( stdout ); + + key_file = fopen( argv[1], "r" ); + o_rsa = PEM_read_RSAPrivateKey(key_file, 0, 0, 0); + fclose(key_file); + if( o_rsa == NULL ) + { + ret = 1; + printf( " failed\n ! Could not load key.\n\n" ); + goto exit; + } + + printf( " passed\n"); + printf( "\n" ); + + if( strlen( argv[1] ) > 100 ) + { + printf( " Input data larger than 100 characters.\n\n" ); + goto exit; + } + + memcpy( input, argv[2], strlen( argv[2] ) ); + + /* + * Calculate the RSA encryption with public key. + */ + printf( " . Generating the RSA encrypted value with PolarSSL (RSA_PUBLIC) ..." ); + fflush( stdout ); + + if( ( ret = rsa_pkcs1_encrypt( &p_rsa, ctr_drbg_random, &ctr_drbg, RSA_PUBLIC, strlen( argv[1] ), input, p_pub_encrypted ) ) != 0 ) + { + printf( " failed\n ! rsa_pkcs1_encrypt returned %d\n\n", ret ); + goto exit; + } + else + printf( " passed\n"); + + printf( " . Generating the RSA encrypted value with OpenSSL (PUBLIC) ..." ); + fflush( stdout ); + + if( ( ret = RSA_public_encrypt( strlen( argv[1] ), input, o_pub_encrypted, o_rsa, RSA_PKCS1_PADDING ) ) == -1 ) + { + unsigned long code = ERR_get_error(); + printf( " failed\n ! RSA_public_encrypt returned %d %s\n\n", ret, ERR_error_string( code, NULL ) ); + goto exit; + } + else + printf( " passed\n"); + + /* + * Calculate the RSA encryption with private key. + */ + printf( " . Generating the RSA encrypted value with PolarSSL (RSA_PRIVATE) ..." ); + fflush( stdout ); + + if( ( ret = rsa_pkcs1_encrypt( &p_rsa, ctr_drbg_random, &ctr_drbg, RSA_PRIVATE, strlen( argv[1] ), input, p_priv_encrypted ) ) != 0 ) + { + printf( " failed\n ! rsa_pkcs1_encrypt returned %d\n\n", ret ); + goto exit; + } + else + printf( " passed\n"); + + printf( " . Generating the RSA encrypted value with OpenSSL (PRIVATE) ..." ); + fflush( stdout ); + + if( ( ret = RSA_private_encrypt( strlen( argv[1] ), input, o_priv_encrypted, o_rsa, RSA_PKCS1_PADDING ) ) == -1 ) + { + unsigned long code = ERR_get_error(); + printf( " failed\n ! RSA_private_encrypt returned %d %s\n\n", ret, ERR_error_string( code, NULL ) ); + goto exit; + } + else + printf( " passed\n"); + + printf( "\n" ); + + /* + * Calculate the RSA decryption with private key. + */ + printf( " . Generating the RSA decrypted value for OpenSSL (PUBLIC) with PolarSSL (PRIVATE) ..." ); + fflush( stdout ); + + if( ( ret = rsa_pkcs1_decrypt( &p_rsa, RSA_PRIVATE, &olen, o_pub_encrypted, p_pub_decrypted, 1024 ) ) != 0 ) + { + printf( " failed\n ! rsa_pkcs1_decrypt returned %d\n\n", ret ); + } + else + printf( " passed\n"); + + printf( " . Generating the RSA decrypted value for PolarSSL (PUBLIC) with OpenSSL (PRIVATE) ..." ); + fflush( stdout ); + + if( ( ret = RSA_private_decrypt( p_rsa.len, p_pub_encrypted, o_pub_decrypted, o_rsa, RSA_PKCS1_PADDING ) ) == -1 ) + { + unsigned long code = ERR_get_error(); + printf( " failed\n ! RSA_private_decrypt returned %d %s\n\n", ret, ERR_error_string( code, NULL ) ); + } + else + printf( " passed\n"); + + /* + * Calculate the RSA decryption with public key. + */ + printf( " . Generating the RSA decrypted value for OpenSSL (PRIVATE) with PolarSSL (PUBLIC) ..." ); + fflush( stdout ); + + if( ( ret = rsa_pkcs1_decrypt( &p_rsa, RSA_PUBLIC, &olen, o_priv_encrypted, p_priv_decrypted, 1024 ) ) != 0 ) + { + printf( " failed\n ! rsa_pkcs1_decrypt returned %d\n\n", ret ); + } + else + printf( " passed\n"); + + printf( " . Generating the RSA decrypted value for PolarSSL (PRIVATE) with OpenSSL (PUBLIC) ..." ); + fflush( stdout ); + + if( ( ret = RSA_public_decrypt( p_rsa.len, p_priv_encrypted, o_priv_decrypted, o_rsa, RSA_PKCS1_PADDING ) ) == -1 ) + { + unsigned long code = ERR_get_error(); + printf( " failed\n ! RSA_public_decrypt returned %d %s\n\n", ret, ERR_error_string( code, NULL ) ); + } + else + printf( " passed\n"); + + printf( "\n" ); + printf( "String value (OpenSSL Public Encrypt, PolarSSL Private Decrypt): '%s'\n", p_pub_decrypted ); + printf( "String value (PolarSSL Public Encrypt, OpenSSL Private Decrypt): '%s'\n", o_pub_decrypted ); + printf( "String value (OpenSSL Private Encrypt, PolarSSL Public Decrypt): '%s'\n", p_priv_decrypted ); + printf( "String value (PolarSSL Private Encrypt, OpenSSL Public Decrypt): '%s'\n", o_priv_decrypted ); + +exit: + +#ifdef WIN32 + printf( " + Press Enter to exit this program.\n" ); + fflush( stdout ); getchar(); +#endif + + return( ret ); +}