diff --git a/ChangeLog b/ChangeLog index 4ac9de162..b19bd6c2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,7 @@ Features with OpenVPN (donated by Fox-IT) * Added generic cipher wrapper for integration with OpenVPN (donated by Fox-IT) + * Added reading of DHM context from memory and file = Version 0.14.0 released on 2010-08-16 Features diff --git a/include/polarssl/certs.h b/include/polarssl/certs.h index c79393233..af8fcd677 100644 --- a/include/polarssl/certs.h +++ b/include/polarssl/certs.h @@ -38,6 +38,7 @@ extern const char test_srv_crt[]; extern const char test_srv_key[]; extern const char test_cli_crt[]; extern const char test_cli_key[]; +extern const char test_dhm_params[]; #ifdef __cplusplus } diff --git a/include/polarssl/md.h b/include/polarssl/md.h index b23167b2b..13250dd8f 100644 --- a/include/polarssl/md.h +++ b/include/polarssl/md.h @@ -41,6 +41,8 @@ typedef enum { POLARSSL_MD_SHA512, } md_type_t; +#define POLARSSL_MD_MAX_SIZE 64 /* longest known is SHA512 */ + /** * Message digest information. Allows message digest functions to be called * in a generic way. diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index 100c00480..715a4e886 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -453,6 +453,17 @@ void ssl_set_own_cert( ssl_context *ssl, x509_cert *own_cert, */ int ssl_set_dh_param( ssl_context *ssl, const char *dhm_P, const char *dhm_G ); +/** + * \brief Set the Diffie-Hellman public P and G values, + * read from existing context (server-side only) + * + * \param ssl SSL context + * \param dhm_ctx Diffie-Hellman-Merkle context + * + * \return 0 if successful + */ +int ssl_set_dh_param_ctx( ssl_context *ssl, dhm_context *dhm_ctx ); + /** * \brief Set hostname for ServerName TLS Extension * diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h index cbcb5b09e..0df84332f 100644 --- a/include/polarssl/x509.h +++ b/include/polarssl/x509.h @@ -28,6 +28,7 @@ #define POLARSSL_X509_H #include "polarssl/rsa.h" +#include "polarssl/dhm.h" /** * @addtogroup x509_module @@ -322,7 +323,7 @@ extern "C" { #endif /** - * @name Functions to read in a certificate, CRL or private RSA key + * @name Functions to read in DHM parameters, a certificate, CRL or private RSA key * @{ */ @@ -404,7 +405,31 @@ int x509parse_key( rsa_context *rsa, */ int x509parse_keyfile( rsa_context *rsa, const char *path, const char *password ); -/** @} name Functions to read in a certificate, CRL or private RSA key */ + +/** @ingroup x509_module */ +/** + * \brief Parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param dhmin input buffer + * \param dhminlen size of the buffer + * + * \return 0 if successful, or a specific X509 error code + */ +int x509parse_dhm( dhm_context *dhm, const unsigned char *dhmin, int dhminlen ); + +/** @ingroup x509_module */ +/** + * \brief Load and parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param path filename to read the DHM Parameters from + * + * \return 0 if successful, or a specific X509 error code + */ +int x509parse_dhmfile( dhm_context *rsa, const char *path ); + +/** @} name Functions to read in DHM parameters, a certificate, CRL or private RSA key */ diff --git a/library/certs.c b/library/certs.c index 37de8c239..9df2eb250 100644 --- a/library/certs.c +++ b/library/certs.c @@ -186,4 +186,11 @@ const char test_cli_key[] = "3vMGjy6jnBSaKoktW8ikY+4FHq+t5z63UN3RF367Iz0dWzIVocbxAQ==\r\n" "-----END RSA PRIVATE KEY-----\r\n"; +const char test_dhm_params[] = +"-----BEGIN DH PARAMETERS-----\r\n" +"MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n" +"1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n" +"9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n" +"-----END DH PARAMETERS-----\r\n"; + #endif diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 67eff4728..11d50ac99 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -1806,6 +1806,25 @@ int ssl_set_dh_param( ssl_context *ssl, const char *dhm_P, const char *dhm_G ) return( 0 ); } +int ssl_set_dh_param_ctx( ssl_context *ssl, dhm_context *dhm_ctx ) +{ + int ret; + + if( ( ret = mpi_copy(&ssl->dhm_ctx.P, &dhm_ctx->P) ) != 0 ) + { + SSL_DEBUG_RET( 1, "mpi_copy", ret ); + return( ret ); + } + + if( ( ret = mpi_copy(&ssl->dhm_ctx.G, &dhm_ctx->G) ) != 0 ) + { + SSL_DEBUG_RET( 1, "mpi_copy", ret ); + return( ret ); + } + + return( 0 ); +} + int ssl_set_hostname( ssl_context *ssl, const char *hostname ) { if( hostname == NULL ) diff --git a/library/x509parse.c b/library/x509parse.c index ea9748c9f..e48ed949a 100644 --- a/library/x509parse.c +++ b/library/x509parse.c @@ -47,6 +47,7 @@ #include "polarssl/sha1.h" #include "polarssl/sha2.h" #include "polarssl/sha4.h" +#include "polarssl/dhm.h" #include #include @@ -1819,6 +1820,122 @@ int x509parse_keyfile( rsa_context *rsa, const char *path, const char *pwd ) return( ret ); } +/* + * Parse DHM parameters + */ +int x509parse_dhm( dhm_context *dhm, const unsigned char *dhmin, int dhminlen ) +{ + int ret, len; + unsigned char *buf, *s1, *s2; + unsigned char *p, *end; + + s1 = (unsigned char *) strstr( (char *) dhmin, + "-----BEGIN DH PARAMETERS-----" ); + + if( s1 != NULL ) + { + s2 = (unsigned char *) strstr( (char *) dhmin, + "-----END DH PARAMETERS-----" ); + + if( s2 == NULL || s2 <= s1 ) + return( POLARSSL_ERR_X509_KEY_INVALID_PEM ); + + s1 += 29; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( POLARSSL_ERR_X509_KEY_INVALID_PEM ); + + len = 0; + ret = base64_decode( NULL, &len, s1, s2 - s1 ); + + if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER ) + return( ret | POLARSSL_ERR_X509_KEY_INVALID_PEM ); + + if( ( buf = (unsigned char *) malloc( len ) ) == NULL ) + return( 1 ); + + if( ( ret = base64_decode( buf, &len, s1, s2 - s1 ) ) != 0 ) + { + free( buf ); + return( ret | POLARSSL_ERR_X509_KEY_INVALID_PEM ); + } + + dhminlen = len; + } + else + { + buf = NULL; + } + + memset( dhm, 0, sizeof( dhm_context ) ); + + p = ( s1 != NULL ) ? buf : (unsigned char *) dhmin; + end = p + dhminlen; + + /* + * DHParams ::= SEQUENCE { + * prime INTEGER, -- P + * generator INTEGER, -- g + * } + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + if( s1 != NULL ) + free( buf ); + + dhm_free( dhm ); + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT | ret ); + } + + end = p + len; + + if( ( ret = asn1_get_mpi( &p, end, &dhm->P ) ) != 0 || + ( ret = asn1_get_mpi( &p, end, &dhm->G ) ) != 0 ) + { + if( s1 != NULL ) + free( buf ); + + dhm_free( dhm ); + return( ret | POLARSSL_ERR_X509_KEY_INVALID_FORMAT ); + } + + if( p != end ) + { + if( s1 != NULL ) + free( buf ); + + dhm_free( dhm ); + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT | + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + if( s1 != NULL ) + free( buf ); + + return( 0 ); +} + +/* + * Load and parse a private RSA key + */ +int x509parse_dhmfile( dhm_context *dhm, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if ( load_file( path, &buf, &n ) ) + return( 1 ); + + ret = x509parse_dhm( dhm, buf, (int) n); + + memset( buf, 0, n + 1 ); + free( buf ); + + return( ret ); +} + #if defined _MSC_VER && !defined snprintf #include @@ -2511,6 +2628,7 @@ int x509_self_test( int verbose ) x509_cert cacert; x509_cert clicert; rsa_context rsa; + dhm_context dhm; if( verbose != 0 ) printf( " X.509 certificate load: " ); @@ -2567,12 +2685,27 @@ int x509_self_test( int verbose ) return( ret ); } + if( verbose != 0 ) + printf( "passed\n X.509 DHM parameter load: " ); + + i = strlen( test_dhm_params ); + j = strlen( test_ca_pwd ); + + if( ( ret = x509parse_dhm( &dhm, (unsigned char *) test_dhm_params, i ) ) != 0 ) + { + if( verbose != 0 ) + printf( "failed\n" ); + + return( ret ); + } + if( verbose != 0 ) printf( "passed\n\n" ); x509_free( &cacert ); x509_free( &clicert ); rsa_free( &rsa ); + dhm_free( &dhm ); return( 0 ); #else