- Added reading of DHM context from memory and file

diff --git a/ChangeLog b/ChangeLog
index 4ac9de1..b19bd6c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,7 @@
      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 c793932..af8fcd6 100644
--- a/include/polarssl/certs.h
+++ b/include/polarssl/certs.h
@@ -38,6 +38,7 @@
 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 b23167b..13250dd 100644
--- a/include/polarssl/md.h
+++ b/include/polarssl/md.h
@@ -41,6 +41,8 @@
     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 100c004..715a4e8 100644
--- a/include/polarssl/ssl.h
+++ b/include/polarssl/ssl.h
@@ -454,6 +454,17 @@
 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 cbcb5b0..0df8433 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 @@
 #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_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 37de8c2..9df2eb2 100644
--- a/library/certs.c
+++ b/library/certs.c
@@ -186,4 +186,11 @@
 "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 67eff47..11d50ac 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -1806,6 +1806,25 @@
     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 ea9748c..e48ed94 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 <string.h>
 #include <stdlib.h>
@@ -1819,6 +1820,122 @@
     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 <stdarg.h>
 
@@ -2511,6 +2628,7 @@
     x509_cert cacert;
     x509_cert clicert;
     rsa_context rsa;
+    dhm_context dhm;
 
     if( verbose != 0 )
         printf( "  X.509 certificate load: " );
@@ -2568,11 +2686,26 @@
     }
 
     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