[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Sat Apr 9 09:12:59 UTC 2016


The branch master has been updated
       via  6a47c39175c6f5329fa3734c798abd6250560653 (commit)
       via  0263b992881a03bd98bfd6b76ca54626205e9229 (commit)
       via  998f2cb8c4d354ef0a5ebf22f1b2ee48cda97664 (commit)
       via  cf430d059304200e2eac8c02f6ebfbfff3bbdf16 (commit)
       via  17e01abbb0fcba33b896dc3a1d0127dbb7321818 (commit)
       via  32bf92f9c87ae4a2a6a9ba3b93fbcb9e5be0a82b (commit)
       via  0aeddcfa61250a6c474c4f8b3533772a63192f1b (commit)
      from  b9aec69ace2ae84b2b4494cc49725945805d5a29 (commit)


- Log -----------------------------------------------------------------
commit 6a47c39175c6f5329fa3734c798abd6250560653
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 7 15:47:28 2016 +0100

    Add CHANGES entry for DH and DH_METHOD opacity
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 0263b992881a03bd98bfd6b76ca54626205e9229
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 7 15:24:23 2016 +0100

    Add documentation for following DH and DH_METHOD opacity
    
    A number of new functions have been added following the DH and DH_METHOD
    opacity commits. This commit provides documentation for those functions.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 998f2cb8c4d354ef0a5ebf22f1b2ee48cda97664
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 7 14:08:52 2016 +0100

    Fix double free bug in error path
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit cf430d059304200e2eac8c02f6ebfbfff3bbdf16
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 7 13:48:03 2016 +0100

    make update
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 17e01abbb0fcba33b896dc3a1d0127dbb7321818
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 7 13:47:20 2016 +0100

    Make DH_METHOD opaque
    
    Move the dh_method structure into an internal header file and provide
    relevant accessors for the internal fields.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 32bf92f9c87ae4a2a6a9ba3b93fbcb9e5be0a82b
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Apr 6 17:50:22 2016 +0100

    make update
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

commit 0aeddcfa61250a6c474c4f8b3533772a63192f1b
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Apr 6 17:49:48 2016 +0100

    Make DH opaque
    
    Move the dh_st structure into an internal header file and provide
    relevant accessors for the internal fields.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>

-----------------------------------------------------------------------

Summary of changes:
 CHANGES                      |   5 ++
 apps/dhparam.c               |  36 ++++++----
 apps/s_cb.c                  |   2 +-
 crypto/dh/Makefile.in        |   4 +-
 crypto/dh/build.info         |   2 +-
 crypto/dh/dh_ameth.c         |   2 +-
 crypto/dh/dh_asn1.c          |   2 +-
 crypto/dh/dh_check.c         |   2 +-
 crypto/dh/dh_gen.c           |   2 +-
 crypto/dh/dh_key.c           |   2 +-
 crypto/dh/dh_lib.c           |  85 ++++++++++++++++++++++-
 crypto/dh/dh_locl.h          |  57 ++++++++++++++++
 crypto/dh/dh_meth.c          | 158 +++++++++++++++++++++++++++++++++++++++++++
 crypto/dh/dh_pmeth.c         |   2 +-
 crypto/dh/dh_rfc5114.c       |   2 +-
 crypto/dsa/dsa_lib.c         |  41 +++++++----
 doc/crypto/DH_get0_pqg.pod   |  92 +++++++++++++++++++++++++
 doc/crypto/DH_meth_new.pod   | 148 ++++++++++++++++++++++++++++++++++++++++
 doc/crypto/DH_set_method.pod |  33 +--------
 doc/crypto/dh.pod            |  20 ++----
 include/openssl/dh.h         |  87 ++++++++++++------------
 ssl/statem/statem_clnt.c     |  42 +++++++++---
 ssl/statem/statem_srvr.c     |  15 ++--
 ssl/t1_lib.c                 |  15 ++--
 test/dhtest.c                |  65 ++++++++++++------
 test/ssltest_old.c           |  29 +++++---
 util/libcrypto.num           |  31 +++++++++
 27 files changed, 800 insertions(+), 181 deletions(-)
 create mode 100644 crypto/dh/dh_locl.h
 create mode 100644 crypto/dh/dh_meth.c
 create mode 100644 doc/crypto/DH_get0_pqg.pod
 create mode 100644 doc/crypto/DH_meth_new.pod

diff --git a/CHANGES b/CHANGES
index 8ea1330..f404994 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,11 @@
 
  Changes between 1.0.2g and 1.1.0  [xx XXX xxxx]
 
+  *) Made DH and DH_METHOD opaque. The structures for managing DH objects
+     have been moved out of the public header files. New functions for managing
+     these have been added.
+     [Matt Caswell]
+
   *) Made RSA and RSA_METHOD opaque. The structures for managing RSA
      objects have been moved out of the public header files. New
      functions for managing these have been added.
diff --git a/apps/dhparam.c b/apps/dhparam.c
index 58baff8..9ad80ed 100644
--- a/apps/dhparam.c
+++ b/apps/dhparam.c
@@ -384,40 +384,50 @@ int dhparam_main(int argc, char **argv)
     if (C) {
         unsigned char *data;
         int len, bits;
+        BIGNUM *pbn, *gbn;
 
-        len = BN_num_bytes(dh->p);
-        bits = BN_num_bits(dh->p);
+        len = DH_size(dh);
+        bits = DH_bits(dh);
+        DH_get0_pqg(dh, &pbn, NULL, &gbn);
         data = app_malloc(len, "print a BN");
         BIO_printf(out, "#ifndef HEADER_DH_H\n"
                         "# include <openssl/dh.h>\n"
                         "#endif\n"
                         "\n");
         BIO_printf(out, "DH *get_dh%d()\n{\n", bits);
-        print_bignum_var(out, dh->p, "dhp", bits, data);
-        print_bignum_var(out, dh->g, "dhg", bits, data);
-        BIO_printf(out, "    DH *dh = DN_new();\n"
+        print_bignum_var(out, pbn, "dhp", bits, data);
+        print_bignum_var(out, gbn, "dhg", bits, data);
+        BIO_printf(out, "    DH *dh = DH_new();\n"
+                        "    BIGNUM *dhp_bn, *dhg_bn;\n"
                         "\n"
                         "    if (dh == NULL)\n"
                         "        return NULL;\n");
-        BIO_printf(out, "    dh->p = BN_bin2bn(dhp_%d, sizeof (dhp_%d), NULL);\n",
-               bits, bits);
-        BIO_printf(out, "    dh->g = BN_bin2bn(dhg_%d, sizeof (dhg_%d), NULL);\n",
-               bits, bits);
-        BIO_printf(out, "    if (!dh->p || !dh->g) {\n"
+        BIO_printf(out, "    dhp_bn = BN_bin2bn(dhp_%d, sizeof (dhp_%d), NULL);\n",
+                   bits, bits);
+        BIO_printf(out, "    dhg_bn = BN_bin2bn(dhg_%d, sizeof (dhg_%d), NULL);\n",
+                   bits, bits);
+        BIO_printf(out, "    if (dhp_bn == NULL || dhg_bn == NULL\n"
+                        "            || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) {\n"
                         "        DH_free(dh);\n"
+                        "        BN_free(dhp_bn);\n"
+                        "        BN_free(dhg_bn);\n"
                         "        return NULL;\n"
                         "    }\n");
-        if (dh->length)
+        if (DH_get_length(dh) > 0)
             BIO_printf(out,
-                        "    dh->length = %ld;\n", dh->length);
+                        "    if (!DH_set_length(dh, %ld)) {\n"
+                        "        DH_free(dh);\n"
+                        "    }\n", DH_get_length(dh));
         BIO_printf(out, "    return dh;\n}\n");
         OPENSSL_free(data);
     }
 
     if (!noout) {
+        BIGNUM *q;
+        DH_get0_pqg(dh, NULL, &q, NULL);
         if (outformat == FORMAT_ASN1)
             i = i2d_DHparams_bio(out, dh);
-        else if (dh->q)
+        else if (q != NULL)
             i = PEM_write_bio_DHxparams(out, dh);
         else
             i = PEM_write_bio_DHparams(out, dh);
diff --git a/apps/s_cb.c b/apps/s_cb.c
index b75ff31..49f3acd 100644
--- a/apps/s_cb.c
+++ b/apps/s_cb.c
@@ -1371,7 +1371,7 @@ static int security_callback_debug(const SSL *s, const SSL_CTX *ctx,
     case SSL_SECOP_OTHER_DH:
         {
             DH *dh = other;
-            BIO_printf(sdb->out, "%d", BN_num_bits(dh->p));
+            BIO_printf(sdb->out, "%d", DH_bits(dh));
             break;
         }
 #endif
diff --git a/crypto/dh/Makefile.in b/crypto/dh/Makefile.in
index fa2d769..205909a 100644
--- a/crypto/dh/Makefile.in
+++ b/crypto/dh/Makefile.in
@@ -16,9 +16,9 @@ GENERAL=Makefile
 
 LIB=$(TOP)/libcrypto.a
 LIBSRC= dh_asn1.c dh_gen.c dh_key.c dh_lib.c dh_check.c dh_err.c dh_depr.c \
-	dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_kdf.c
+	dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_kdf.c dh_meth.c
 LIBOBJ= dh_asn1.o dh_gen.o dh_key.o dh_lib.o dh_check.o dh_err.o dh_depr.o \
-	dh_ameth.o dh_pmeth.o dh_prn.o dh_rfc5114.o dh_kdf.o
+	dh_ameth.o dh_pmeth.o dh_prn.o dh_rfc5114.o dh_kdf.o dh_meth.o
 
 SRC= $(LIBSRC)
 
diff --git a/crypto/dh/build.info b/crypto/dh/build.info
index 878910d..dba9306 100644
--- a/crypto/dh/build.info
+++ b/crypto/dh/build.info
@@ -1,4 +1,4 @@
 LIBS=../../libcrypto
 SOURCE[../../libcrypto]=\
         dh_asn1.c dh_gen.c dh_key.c dh_lib.c dh_check.c dh_err.c dh_depr.c \
-        dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_kdf.c
+        dh_ameth.c dh_pmeth.c dh_prn.c dh_rfc5114.c dh_kdf.c dh_meth.c
diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c
index fc03d8f..54d5ba5 100644
--- a/crypto/dh/dh_ameth.c
+++ b/crypto/dh/dh_ameth.c
@@ -60,7 +60,7 @@
 #include "internal/cryptlib.h"
 #include <openssl/x509.h>
 #include <openssl/asn1.h>
-#include <openssl/dh.h>
+#include "dh_locl.h"
 #include <openssl/bn.h>
 #include "internal/asn1_int.h"
 #include "internal/evp_int.h"
diff --git a/crypto/dh/dh_asn1.c b/crypto/dh/dh_asn1.c
index 8ea9550..aa80291 100644
--- a/crypto/dh/dh_asn1.c
+++ b/crypto/dh/dh_asn1.c
@@ -59,7 +59,7 @@
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include <openssl/bn.h>
-#include <openssl/dh.h>
+#include "dh_locl.h"
 #include <openssl/objects.h>
 #include <openssl/asn1t.h>
 
diff --git a/crypto/dh/dh_check.c b/crypto/dh/dh_check.c
index 2cc218d..5d14265 100644
--- a/crypto/dh/dh_check.c
+++ b/crypto/dh/dh_check.c
@@ -58,7 +58,7 @@
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include <openssl/bn.h>
-#include <openssl/dh.h>
+#include "dh_locl.h"
 
 /*-
  * Check that p is a safe prime and
diff --git a/crypto/dh/dh_gen.c b/crypto/dh/dh_gen.c
index bfa2376..5c96dac 100644
--- a/crypto/dh/dh_gen.c
+++ b/crypto/dh/dh_gen.c
@@ -63,7 +63,7 @@
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include <openssl/bn.h>
-#include <openssl/dh.h>
+#include "dh_locl.h"
 
 static int dh_builtin_genparams(DH *ret, int prime_len, int generator,
                                 BN_GENCB *cb);
diff --git a/crypto/dh/dh_key.c b/crypto/dh/dh_key.c
index 558ec8c..d957550 100644
--- a/crypto/dh/dh_key.c
+++ b/crypto/dh/dh_key.c
@@ -58,7 +58,7 @@
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include <openssl/rand.h>
-#include <openssl/dh.h>
+#include "dh_locl.h"
 #include "internal/bn_int.h"
 
 static int generate_key(DH *dh);
diff --git a/crypto/dh/dh_lib.c b/crypto/dh/dh_lib.c
index 1a0c054..bf9f8d3 100644
--- a/crypto/dh/dh_lib.c
+++ b/crypto/dh/dh_lib.c
@@ -58,7 +58,7 @@
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include <openssl/bn.h>
-#include <openssl/dh.h>
+#include "dh_locl.h"
 #include <openssl/engine.h>
 
 static const DH_METHOD *default_DH_method = NULL;
@@ -231,3 +231,86 @@ int DH_security_bits(const DH *dh)
         N = -1;
     return BN_security_bits(BN_num_bits(dh->p), N);
 }
+
+
+void DH_get0_pqg(const DH *dh, BIGNUM **p, BIGNUM **q, BIGNUM **g)
+{
+    if (p != NULL)
+        *p = dh->p;
+    if (q != NULL)
+        *q = dh->q;
+    if (g != NULL)
+        *g = dh->g;
+}
+
+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+    /* q is optional */
+    if (p == NULL || g == NULL)
+        return 0;
+    BN_free(dh->p);
+    BN_free(dh->q);
+    BN_free(dh->g);
+    dh->p = p;
+    dh->q = q;
+    dh->g = g;
+
+    if (q != NULL) {
+        dh->length = BN_num_bits(q);
+    }
+
+    return 1;
+}
+
+long DH_get_length(const DH *dh)
+{
+    return dh->length;
+}
+
+int DH_set_length(DH *dh, long length)
+{
+    dh->length = length;
+    return 1;
+}
+
+void DH_get0_key(const DH *dh, BIGNUM **pub_key, BIGNUM **priv_key)
+{
+    if (pub_key != NULL)
+        *pub_key = dh->pub_key;
+    if (priv_key != NULL)
+        *priv_key = dh->priv_key;
+}
+
+int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+    /* Note that it is valid for priv_key to be NULL */
+    if (pub_key == NULL)
+        return 0;
+
+    BN_free(dh->pub_key);
+    BN_free(dh->priv_key);
+    dh->pub_key = pub_key;
+    dh->priv_key = priv_key;
+
+    return 1;
+}
+
+void DH_clear_flags(DH *dh, int flags)
+{
+    dh->flags &= ~flags;
+}
+
+int DH_test_flags(const DH *dh, int flags)
+{
+    return dh->flags & flags;
+}
+
+void DH_set_flags(DH *dh, int flags)
+{
+    dh->flags |= flags;
+}
+
+ENGINE *DH_get0_engine(DH *dh)
+{
+    return dh->engine;
+}
diff --git a/crypto/dh/dh_locl.h b/crypto/dh/dh_locl.h
new file mode 100644
index 0000000..46e4bc7
--- /dev/null
+++ b/crypto/dh/dh_locl.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL licenses, (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * https://www.openssl.org/source/license.html
+ * or in the file LICENSE in the source distribution.
+ */
+
+#include <openssl/dh.h>
+
+struct dh_st {
+    /*
+     * This first argument is used to pick up errors when a DH is passed
+     * instead of a EVP_PKEY
+     */
+    int pad;
+    int version;
+    BIGNUM *p;
+    BIGNUM *g;
+    long length;                /* optional */
+    BIGNUM *pub_key;            /* g^x % p */
+    BIGNUM *priv_key;           /* x */
+    int flags;
+    BN_MONT_CTX *method_mont_p;
+    /* Place holders if we want to do X9.42 DH */
+    BIGNUM *q;
+    BIGNUM *j;
+    unsigned char *seed;
+    int seedlen;
+    BIGNUM *counter;
+    int references;
+    CRYPTO_EX_DATA ex_data;
+    const DH_METHOD *meth;
+    ENGINE *engine;
+    CRYPTO_RWLOCK *lock;
+};
+
+struct dh_method {
+    char *name;
+    /* Methods here */
+    int (*generate_key) (DH *dh);
+    int (*compute_key) (unsigned char *key, const BIGNUM *pub_key, DH *dh);
+
+    /* Can be null */
+    int (*bn_mod_exp) (const DH *dh, BIGNUM *r, const BIGNUM *a,
+                       const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
+                       BN_MONT_CTX *m_ctx);
+    int (*init) (DH *dh);
+    int (*finish) (DH *dh);
+    int flags;
+    char *app_data;
+    /* If this is non-NULL, it will be used to generate parameters */
+    int (*generate_params) (DH *dh, int prime_len, int generator,
+                            BN_GENCB *cb);
+};
diff --git a/crypto/dh/dh_meth.c b/crypto/dh/dh_meth.c
new file mode 100644
index 0000000..0bc5e53
--- /dev/null
+++ b/crypto/dh/dh_meth.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL licenses, (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * https://www.openssl.org/source/license.html
+ * or in the file LICENSE in the source distribution.
+ */
+
+
+#include "dh_locl.h"
+#include <string.h>
+
+DH_METHOD *DH_meth_new(const char *name, int flags)
+{
+    DH_METHOD *dhm = OPENSSL_zalloc(sizeof(DH_METHOD));
+
+    if (dhm != NULL) {
+        dhm->name = OPENSSL_strdup(name);
+        dhm->flags = flags;
+    }
+
+    return dhm;
+}
+
+void DH_meth_free(DH_METHOD *dhm)
+{
+    if (dhm != NULL) {
+        if (dhm->name != NULL)
+            OPENSSL_free(dhm->name);
+        OPENSSL_free(dhm);
+    }
+}
+
+DH_METHOD *DH_meth_dup(const DH_METHOD *dhm)
+{
+    DH_METHOD *ret;
+
+    ret = OPENSSL_malloc(sizeof(DH_METHOD));
+
+    if (ret != NULL) {
+        memcpy(ret, dhm, sizeof(*dhm));
+        ret->name = OPENSSL_strdup(dhm->name);
+    }
+
+    return ret;
+}
+
+const char *DH_meth_get0_name(const DH_METHOD *dhm)
+{
+    return dhm->name;
+}
+
+int DH_meth_set1_name(DH_METHOD *dhm, const char *name)
+{
+    OPENSSL_free(dhm->name);
+    dhm->name = OPENSSL_strdup(name);
+
+    return dhm->name != NULL;
+}
+
+int DH_meth_get_flags(DH_METHOD *dhm)
+{
+    return dhm->flags;
+}
+
+int DH_meth_set_flags(DH_METHOD *dhm, int flags)
+{
+    dhm->flags = flags;
+    return 1;
+}
+
+void *DH_meth_get0_app_data(const DH_METHOD *dhm)
+{
+    return dhm->app_data;
+}
+
+int DH_meth_set0_app_data(DH_METHOD *dhm, void *app_data)
+{
+    dhm->app_data = app_data;
+    return 1;
+}
+
+int (*DH_meth_get_generate_key(const DH_METHOD *dhm)) (DH *)
+{
+    return dhm->generate_key;
+}
+
+int DH_meth_set_generate_key(DH_METHOD *dhm, int (*generate_key) (DH *))
+{
+    dhm->generate_key = generate_key;
+    return 1;
+}
+
+int (*DH_meth_get_compute_key(const DH_METHOD *dhm))
+        (unsigned char *key, const BIGNUM *pub_key, DH *dh)
+{
+    return dhm->compute_key;
+}
+
+int DH_meth_set_compute_key(DH_METHOD *dhm,
+        int (*compute_key) (unsigned char *key, const BIGNUM *pub_key, DH *dh))
+{
+    dhm->compute_key = compute_key;
+    return 1;
+}
+
+
+int (*DH_meth_get_bn_mod_exp(const DH_METHOD *dhm))
+    (const DH *, BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
+     BN_CTX *, BN_MONT_CTX *)
+{
+    return dhm->bn_mod_exp;
+}
+
+int DH_meth_set_bn_mod_exp(DH_METHOD *dhm,
+    int (*bn_mod_exp) (const DH *, BIGNUM *, const BIGNUM *, const BIGNUM *,
+                       const BIGNUM *, BN_CTX *, BN_MONT_CTX *))
+{
+    dhm->bn_mod_exp = bn_mod_exp;
+    return 1;
+}
+
+int (*DH_meth_get_init(const DH_METHOD *dhm))(DH *)
+{
+    return dhm->init;
+}
+
+int DH_meth_set_init(DH_METHOD *dhm, int (*init)(DH *))
+{
+    dhm->init = init;
+    return 1;
+}
+
+int (*DH_meth_get_finish(const DH_METHOD *dhm)) (DH *)
+{
+    return dhm->finish;
+}
+
+int DH_meth_set_finish(DH_METHOD *dhm, int (*finish) (DH *))
+{
+    dhm->finish = finish;
+    return 1;
+}
+
+int (*DH_meth_get_generate_params(const DH_METHOD *dhm))
+        (DH *, int, int, BN_GENCB *)
+{
+    return dhm->generate_params;
+}
+
+int DH_meth_set_generate_params(DH_METHOD *dhm,
+        int (*generate_params) (DH *, int, int, BN_GENCB *))
+{
+    dhm->generate_params = generate_params;
+    return 1;
+}
diff --git a/crypto/dh/dh_pmeth.c b/crypto/dh/dh_pmeth.c
index 93bada0..5d357a3 100644
--- a/crypto/dh/dh_pmeth.c
+++ b/crypto/dh/dh_pmeth.c
@@ -61,7 +61,7 @@
 #include <openssl/asn1t.h>
 #include <openssl/x509.h>
 #include <openssl/evp.h>
-#include <openssl/dh.h>
+#include "dh_locl.h"
 #include <openssl/bn.h>
 #include <openssl/dsa.h>
 #include <openssl/objects.h>
diff --git a/crypto/dh/dh_rfc5114.c b/crypto/dh/dh_rfc5114.c
index da998f5..48b199d 100644
--- a/crypto/dh/dh_rfc5114.c
+++ b/crypto/dh/dh_rfc5114.c
@@ -58,7 +58,7 @@
 
 #include <stdio.h>
 #include "internal/cryptlib.h"
-#include <openssl/dh.h>
+#include "dh_locl.h"
 #include <openssl/bn.h>
 #include "internal/bn_dh.h"
 
diff --git a/crypto/dsa/dsa_lib.c b/crypto/dsa/dsa_lib.c
index 4d5281a..facb97f 100644
--- a/crypto/dsa/dsa_lib.c
+++ b/crypto/dsa/dsa_lib.c
@@ -254,33 +254,50 @@ DH *DSA_dup_DH(const DSA *r)
      */
 
     DH *ret = NULL;
+    BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub_key = NULL, *priv_key = NULL;
 
     if (r == NULL)
         goto err;
     ret = DH_new();
     if (ret == NULL)
         goto err;
-    if (r->p != NULL)
-        if ((ret->p = BN_dup(r->p)) == NULL)
+    if (r->p != NULL || r->g != NULL || r->q != NULL) {
+        if (r->p == NULL || r->g == NULL || r->q == NULL) {
+            /* Shouldn't happen */
             goto err;
-    if (r->q != NULL) {
-        ret->length = BN_num_bits(r->q);
-        if ((ret->q = BN_dup(r->q)) == NULL)
+        }
+        p = BN_dup(r->p);
+        g = BN_dup(r->g);
+        q = BN_dup(r->q);
+        if (p == NULL || g == NULL || q == NULL || !DH_set0_pqg(ret, p, q, g))
             goto err;
+        p = g = q = NULL;
     }
-    if (r->g != NULL)
-        if ((ret->g = BN_dup(r->g)) == NULL)
-            goto err;
-    if (r->pub_key != NULL)
-        if ((ret->pub_key = BN_dup(r->pub_key)) == NULL)
+
+    if (r->pub_key != NULL) {
+        pub_key = BN_dup(r->pub_key);
+        if (pub_key == NULL)
             goto err;
-    if (r->priv_key != NULL)
-        if ((ret->priv_key = BN_dup(r->priv_key)) == NULL)
+        if (r->priv_key != NULL) {
+            priv_key = BN_dup(r->priv_key);
+            if (priv_key == NULL)
+                goto err;
+        }
+        if (!DH_set0_key(ret, pub_key, priv_key))
             goto err;
+    } else if (r->priv_key != NULL) {
+        /* Shouldn't happen */
+        goto err;
+    }
 
     return ret;
 
  err:
+    BN_free(p);
+    BN_free(g);
+    BN_free(q);
+    BN_free(pub_key);
+    BN_free(priv_key);
     DH_free(ret);
     return NULL;
 }
diff --git a/doc/crypto/DH_get0_pqg.pod b/doc/crypto/DH_get0_pqg.pod
new file mode 100644
index 0000000..bcbecf3
--- /dev/null
+++ b/doc/crypto/DH_get0_pqg.pod
@@ -0,0 +1,92 @@
+=pod
+
+=head1 NAME
+
+DH_get0_pqg, DH_set0_pqg, DH_get0_key, DH_set0_key, DH_clear_flags,
+DH_test_flags, DH_set_flags, DH_get0_engine, DH_get_length,
+DH_set_length - Routines for getting and setting data in a DH object
+
+=head1 SYNOPSIS
+
+ #include <openssl/dh.h>
+
+ void DH_get0_pqg(const DH *dh, BIGNUM **p, BIGNUM **q, BIGNUM **g);
+ int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+ void DH_get0_key(const DH *dh, BIGNUM **pub_key, BIGNUM **priv_key);
+ int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
+ void DH_clear_flags(DH *dh, int flags);
+ int DH_test_flags(const DH *dh, int flags);
+ void DH_set_flags(DH *dh, int flags);
+ ENGINE *DH_get0_engine(DH *d);
+ long DH_get_length(const DH *dh);
+ int DH_set_length(DH *dh, long length);
+
+=head1 DESCRIPTION
+
+A DH object contains the parameters B<p>, B<q> and B<g>. Note that the B<q>
+parameter is optional. It also contains a public key (B<pub_key>) and
+(optionally) a private key (B<priv_key>).
+
+The B<p>, B<q> and B<g> parameters can be obtained by calling DH_get0_pqg().
+If the parameters have not yet been set then B<*p>, B<*q> and B<*g> will be set
+to NULL. Otherwise they are set to pointers to their respective values. These
+point directly to the internal representations of the values and therefore
+should not be freed directly.
+
+The B<p>, B<q> and B<g> values can be set by calling DH_set0_pqg() and passing
+the new values for B<p>, B<q> and B<g> as parameters to the function. Calling
+this function transfers the memory management of the values to the DH object,
+and therefore the values that have been passed in should not be freed directly
+after this function has been called. The B<q> parameter may be NULL.
+
+To get the public and private key values use the DH_get0_key() function. A
+pointer to the public key will be stored in B<*pub_key>, and a pointer to the
+private key will be stored in B<*priv_key>. Either may be NULL if they have not
+been set yet, although if the private key has been set then the public key must
+be. The values point to the internal representation of the public key and
+private key values. This memory should not be freed directly.
+
+The public and private key values can be set using DH_set0_key(). The public
+key must always be non-NULL. The private key may be NULL. As for DH_set0_pqg()
+this function transfers the memory management of the key values to the DH
+object, and therefore they should not be freed directly after this function has
+been called.
+
+DH_set_flags() sets the flags in the B<flags> parameter on the DH object.
+Multiple flags can be passed in one go (bitwise ORed together). Any flags that
+are already set are left set. DH_test_flags() tests to see whether the flags
+passed in the B<flags> parameter are currently set in the DH object. Multiple
+flags can be tested in one go. All flags that are currently set are returned, or
+zero if none of the flags are set. DH_clear_flags() clears the specified flags
+within the DH object.
+
+DH_get0_engine() returns a handle to the ENGINE that has been set for this DH
+object, or NULL if no such ENGINE has been set.
+
+The DH_get_length() and DH_set_length() functions get and set the optional
+length parameter associated with this DH object. If the length is non-zero then
+it is used, otherwise it is ignored. The B<length> parameter indicates the
+length of the secret exponent (private key) in bits.
+
+=head1 RETURN VALUES
+
+DH_set0_pqg() and DH_set0_key() return 1 on success or 0 on failure.
+
+DH_test_flags() returns the current state of the flags in the DH object.
+
+DH_get0_engine() returns the ENGINE set for the DH object or NULL if no ENGINE
+has been set.
+
+DH_get_length() returns the length of the secret exponent (private key) in bits,
+or zero if no such length has been explicitly set.
+
+=head1 SEE ALSO
+
+L<dh(3)>, L<DH_new(3)>, L<DH_generate_parameters(3)>, L<DH_generate_key(3)>,
+L<DH_set_method(3)>, L<DH_size(3)>, L<DH_meth_new(3)>
+
+=head1 HISTORY
+
+The functions described here were added in OpenSSL version 1.1.0.
+
+=cut
diff --git a/doc/crypto/DH_meth_new.pod b/doc/crypto/DH_meth_new.pod
new file mode 100644
index 0000000..73222be
--- /dev/null
+++ b/doc/crypto/DH_meth_new.pod
@@ -0,0 +1,148 @@
+=pod
+
+=head1 NAME
+
+DH_meth_new, DH_meth_free, DH_meth_dup, DH_meth_get0_name, DH_meth_set1_name,
+DH_meth_get_flags, DH_meth_set_flags, DH_meth_get0_app_data,
+DH_meth_set0_app_data, DH_meth_get_generate_key, DH_meth_set_generate_key,
+DH_meth_get_compute_key, DH_meth_set_compute_key, DH_meth_get_bn_mod_exp,
+DH_meth_set_bn_mod_exp, DH_meth_get_init, DH_meth_set_init, DH_meth_get_finish,
+DH_meth_set_finish, DH_meth_get_generate_params,
+DH_meth_set_generate_params - Routines to build up DH methods
+
+=head1 SYNOPSIS
+
+ #include <openssl/dh.h>
+
+ DH_METHOD *DH_meth_new(const char *name, int flags);
+ void DH_meth_free(DH_METHOD *dhm);
+ DH_METHOD *DH_meth_dup(const DH_METHOD *dhm);
+ const char *DH_meth_get0_name(const DH_METHOD *dhm);
+ int DH_meth_set1_name(DH_METHOD *dhm, const char *name);
+ int DH_meth_get_flags(DH_METHOD *dhm);
+ int DH_meth_set_flags(DH_METHOD *dhm, int flags);
+ void *DH_meth_get0_app_data(const DH_METHOD *dhm);
+ int DH_meth_set0_app_data(DH_METHOD *dhm, void *app_data);
+ int (*DH_meth_get_generate_key(const DH_METHOD *dhm)) (DH *);
+ int DH_meth_set_generate_key(DH_METHOD *dhm, int (*generate_key) (DH *));
+ int (*DH_meth_get_compute_key(const DH_METHOD *dhm))
+         (unsigned char *key, const BIGNUM *pub_key, DH *dh);
+ int DH_meth_set_compute_key(DH_METHOD *dhm,
+         int (*compute_key) (unsigned char *key, const BIGNUM *pub_key, DH *dh));
+ int (*DH_meth_get_bn_mod_exp(const DH_METHOD *dhm))
+     (const DH *dh, BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+      const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+ int DH_meth_set_bn_mod_exp(DH_METHOD *dhm,
+     int (*bn_mod_exp) (const DH *dh, BIGNUM *r, const BIGNUM *a,
+                        const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
+                        BN_MONT_CTX *m_ctx));
+ int (*DH_meth_get_init(const DH_METHOD *dhm))(DH *);
+ int DH_meth_set_init(DH_METHOD *dhm, int (*init)(DH *));
+ int (*DH_meth_get_finish(const DH_METHOD *dhm)) (DH *);
+ int DH_meth_set_finish(DH_METHOD *dhm, int (*finish) (DH *));
+ int (*DH_meth_get_generate_params(const DH_METHOD *dhm))
+         (DH *, int, int, BN_GENCB *);
+ int DH_meth_set_generate_params(DH_METHOD *dhm,
+         int (*generate_params) (DH *, int, int, BN_GENCB *));
+
+=head1 DESCRIPTION
+
+The B<DH_METHOD> type is a structure used for the provision of custom DH
+implementations. It provides a set of of functions used by OpenSSL for the
+implementation of the various DH capabilities. See the L<dh(3)> page for more
+information.
+
+DH_meth_new() creates a new B<DH_METHOD> structure. It should be given a
+unique B<name> and a set of B<flags>. The B<name> should be a NULL terminated
+string, which will be duplicated and stored in the B<DH_METHOD> object. It is
+the callers responsibility to free the original string. The flags will be used
+during the construction of a new B<DH> object based on this B<DH_METHOD>. Any
+new B<DH> object will have those flags set by default.
+
+DH_meth_dup() creates a duplicate copy of the B<DH_METHOD> object passed as a
+parameter. This might be useful for creating a new B<DH_METHOD> based on an
+existing one, but with some differences.
+
+DH_meth_free() destroys a B<DH_METHOD> structure and frees up any memory
+associated with it.
+
+DH_meth_get0_name() will return a pointer to the name of this DH_METHOD. This
+is a pointer to the internal name string and so should not be freed by the
+caller. DH_meth_set1_name() sets the name of the DH_METHOD to B<name>. The
+string is duplicated and the copy is stored in the DH_METHOD structure, so the
+caller remains responsible for freeing the memory associated with the name.
+
+DH_meth_get_flags() returns the current value of the flags associated with this
+DH_METHOD. DH_meth_set_flags() provides the ability to set these flags.
+
+The functions DH_meth_get0_app_data() and DH_meth_set0_app_data() provide the
+ability to associate implementation specific data with the DH_METHOD. It is
+the application's responsibility to free this data before the DH_METHOD is
+freed via a call to DH_meth_free().
+
+DH_meth_get_generate_key() and DH_meth_set_generate_key() get and set the
+function used for generating a new DH key pair respectively. This function will
+be called in response to the application calling DH_generate_key(). The
+parameter for the function has the same meaning as for DH_generate_key().
+
+DH_meth_get_compute_key() and DH_meth_set_compute_key() get and set the
+function used for computing a new DH shared secret respectively. This function
+will be called in response to the application calling DH_compute_key(). The
+parameters for the function have the same meaning as for DH_compute_key().
+
+DH_meth_get_bn_mod_exp() and DH_meth_set_bn_mod_exp() get and set the function
+used for computing the following value:
+
+ r = a ^ p mod m
+
+This function will be called by the default OpenSSL function for
+DH_generate_key(). The result is stored in the B<r> parameter. This function
+may be NULL unless using the default generate key function, in which case it
+must be present.
+
+DH_meth_get_init() and DH_meth_set_init() get and set the function used
+for creating a new DH instance respectively. This function will be
+called in response to the application calling DH_new() (if the current default
+DH_METHOD is this one) or DH_new_method(). The DH_new() and DH_new_method()
+functions will allocate the memory for the new DH object, and a pointer to this
+newly allocated structure will be passed as a parameter to the function. This
+function may be NULL.
+
+DH_meth_get_finish() and DH_meth_set_finish() get and set the function used
+for destroying an instance of a DH object respectively. This function will be
+called in response to the application calling DH_free(). A pointer to the DH
+to be destroyed is passed as a parameter. The destroy function should be used
+for DH implementation specific clean up. The memory for the DH itself should
+not be freed by this function. This function may be NULL.
+
+DH_meth_get_generate_params() and DH_meth_set_generate_params() get and set the
+function used for generating DH parameters respectively. This function will be
+called in response to the application calling DH_generate_parameters_ex() (or
+DH_generate_parameters()). The parameters for the function have the same
+meaning as for DH_generate_parameters_ex(). This function may be NULL.
+
+=head1 RETURN VALUES
+
+DH_meth_new() and DH_meth_dup() return the newly allocated DH_METHOD object
+or NULL on failure.
+
+DH_meth_get0_name() and DH_meth_get_flags() return the name and flags
+associated with the DH_METHOD respectively.
+
+All other DH_meth_get_*() functions return the appropriate function pointer
+that has been set in the DH_METHOD, or NULL if no such pointer has yet been
+set.
+
+DH_meth_set1_name() and all DH_meth_set_*() functions return 1 on success or
+0 on failure.
+
+=head1 SEE ALSO
+
+L<dh(3)>, L<DH_new(3)>, L<DH_generate_parameters(3)>, L<DH_generate_key(3)>,
+L<DH_set_method(3)>, L<DH_size(3)>, L<DH_get0_pqg(3)>
+
+=head1 HISTORY
+
+The functions described here were added in OpenSSL version 1.1.0.
+
+=cut
diff --git a/doc/crypto/DH_set_method.pod b/doc/crypto/DH_set_method.pod
index 62d1ee1..fe26b01 100644
--- a/doc/crypto/DH_set_method.pod
+++ b/doc/crypto/DH_set_method.pod
@@ -52,35 +52,8 @@ be used for the DH operations. If B<engine> is NULL, the default ENGINE for DH
 operations is used, and if no default ENGINE is set, the DH_METHOD controlled by
 DH_set_default_method() is used.
 
-=head1 THE DH_METHOD STRUCTURE
-
- typedef struct dh_meth_st
- {
-     /* name of the implementation */
-	const char *name;
-
-     /* generate private and public DH values for key agreement */
-        int (*generate_key)(DH *dh);
-
-     /* compute shared secret */
-        int (*compute_key)(unsigned char *key, BIGNUM *pub_key, DH *dh);
-
-     /* compute r = a ^ p mod m (May be NULL for some implementations) */
-        int (*bn_mod_exp)(DH *dh, BIGNUM *r, BIGNUM *a, const BIGNUM *p,
-                                const BIGNUM *m, BN_CTX *ctx,
-                                BN_MONT_CTX *m_ctx);
-
-     /* called at DH_new */
-        int (*init)(DH *dh);
-
-     /* called at DH_free */
-        int (*finish)(DH *dh);
-
-        int flags;
-
-        char *app_data; /* ?? */
-
- } DH_METHOD;
+A new DH_METHOD object may be constructed using DH_meth_new() (see
+L<DH_meth_new(3)>).
 
 =head1 RETURN VALUES
 
@@ -99,6 +72,6 @@ returns a pointer to the newly allocated structure.
 
 =head1 SEE ALSO
 
-L<dh(3)>, L<DH_new(3)>
+L<dh(3)>, L<DH_new(3)>, L<DH_meth_new(3)>
 
 =cut
diff --git a/doc/crypto/dh.pod b/doc/crypto/dh.pod
index ce6a110..b1eaa48 100644
--- a/doc/crypto/dh.pod
+++ b/doc/crypto/dh.pod
@@ -38,25 +38,15 @@ The generation of shared DH parameters is described in
 L<DH_generate_parameters(3)>; L<DH_generate_key(3)> describes how
 to perform a key agreement.
 
-The B<DH> structure consists of several BIGNUM components.
-
- struct
-        {
-        BIGNUM *p;		// prime number (shared)
-        BIGNUM *g;		// generator of Z_p (shared)
-        BIGNUM *priv_key;	// private DH value x
-        BIGNUM *pub_key;	// public DH value g^x
-        // ...
-        };
- DH
+The B<DH> structure consists of several BIGNUM components. The prime B<p>, the
+generate B<g>, the Private key B<priv_key> and the public key B<pub_key>.
+Optionally there may also be an additional parameter B<q>.
 
 Note that DH keys may use non-standard B<DH_METHOD> implementations,
 either directly or by the use of B<ENGINE> modules. In some cases (eg. an
 ENGINE providing support for hardware-embedded keys), these BIGNUM values
 will not be used by the implementation or may be used for alternative data
-storage. For this reason, applications should generally avoid using DH
-structure elements directly and instead use API functions to query or
-modify keys.
+storage.
 
 =head1 SEE ALSO
 
@@ -65,7 +55,7 @@ L<rand(3)>, L<rsa(3)>, L<engine(3)>,
 L<DH_set_method(3)>, L<DH_new(3)>,
 L<DH_get_ex_new_index(3)>,
 L<DH_generate_parameters(3)>,
-L<DH_compute_key(3)>, L<d2i_DHparams(3)>,
+L<DH_compute_key(3)>, L<DH_get0_pqg(3)>, L<DH_meth_new(3)>, L<d2i_DHparams(3)>,
 L<RSA_print(3)> 
 
 =cut
diff --git a/include/openssl/dh.h b/include/openssl/dh.h
index 2e021e2..d78bac9 100644
--- a/include/openssl/dh.h
+++ b/include/openssl/dh.h
@@ -103,51 +103,6 @@ extern "C" {
 /* typedef struct dh_st DH; */
 /* typedef struct dh_method DH_METHOD; */
 
-struct dh_method {
-    const char *name;
-    /* Methods here */
-    int (*generate_key) (DH *dh);
-    int (*compute_key) (unsigned char *key, const BIGNUM *pub_key, DH *dh);
-    /* Can be null */
-    int (*bn_mod_exp) (const DH *dh, BIGNUM *r, const BIGNUM *a,
-                       const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
-                       BN_MONT_CTX *m_ctx);
-    int (*init) (DH *dh);
-    int (*finish) (DH *dh);
-    int flags;
-    char *app_data;
-    /* If this is non-NULL, it will be used to generate parameters */
-    int (*generate_params) (DH *dh, int prime_len, int generator,
-                            BN_GENCB *cb);
-};
-
-struct dh_st {
-    /*
-     * This first argument is used to pick up errors when a DH is passed
-     * instead of a EVP_PKEY
-     */
-    int pad;
-    int version;
-    BIGNUM *p;
-    BIGNUM *g;
-    long length;                /* optional */
-    BIGNUM *pub_key;            /* g^x % p */
-    BIGNUM *priv_key;           /* x */
-    int flags;
-    BN_MONT_CTX *method_mont_p;
-    /* Place holders if we want to do X9.42 DH */
-    BIGNUM *q;
-    BIGNUM *j;
-    unsigned char *seed;
-    int seedlen;
-    BIGNUM *counter;
-    int references;
-    CRYPTO_EX_DATA ex_data;
-    const DH_METHOD *meth;
-    ENGINE *engine;
-    CRYPTO_RWLOCK *lock;
-};
-
 DECLARE_ASN1_ITEM(DHparams)
 
 # define DH_GENERATOR_2          2
@@ -238,6 +193,48 @@ int DH_KDF_X9_42(unsigned char *out, size_t outlen,
                  const unsigned char *ukm, size_t ukmlen, const EVP_MD *md);
 # endif
 
+void DH_get0_pqg(const DH *dh, BIGNUM **p, BIGNUM **q, BIGNUM **g);
+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+void DH_get0_key(const DH *dh, BIGNUM **pub_key, BIGNUM **priv_key);
+int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
+void DH_clear_flags(DH *dh, int flags);
+int DH_test_flags(const DH *dh, int flags);
+void DH_set_flags(DH *dh, int flags);
+ENGINE *DH_get0_engine(DH *d);
+long DH_get_length(const DH *dh);
+int DH_set_length(DH *dh, long length);
+
+DH_METHOD *DH_meth_new(const char *name, int flags);
+void DH_meth_free(DH_METHOD *dhm);
+DH_METHOD *DH_meth_dup(const DH_METHOD *dhm);
+const char *DH_meth_get0_name(const DH_METHOD *dhm);
+int DH_meth_set1_name(DH_METHOD *dhm, const char *name);
+int DH_meth_get_flags(DH_METHOD *dhm);
+int DH_meth_set_flags(DH_METHOD *dhm, int flags);
+void *DH_meth_get0_app_data(const DH_METHOD *dhm);
+int DH_meth_set0_app_data(DH_METHOD *dhm, void *app_data);
+int (*DH_meth_get_generate_key(const DH_METHOD *dhm)) (DH *);
+int DH_meth_set_generate_key(DH_METHOD *dhm, int (*generate_key) (DH *));
+int (*DH_meth_get_compute_key(const DH_METHOD *dhm))
+        (unsigned char *key, const BIGNUM *pub_key, DH *dh);
+int DH_meth_set_compute_key(DH_METHOD *dhm,
+        int (*compute_key) (unsigned char *key, const BIGNUM *pub_key, DH *dh));
+int (*DH_meth_get_bn_mod_exp(const DH_METHOD *dhm))
+    (const DH *, BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
+     BN_CTX *, BN_MONT_CTX *);
+int DH_meth_set_bn_mod_exp(DH_METHOD *dhm,
+    int (*bn_mod_exp) (const DH *, BIGNUM *, const BIGNUM *, const BIGNUM *,
+                       const BIGNUM *, BN_CTX *, BN_MONT_CTX *));
+int (*DH_meth_get_init(const DH_METHOD *dhm))(DH *);
+int DH_meth_set_init(DH_METHOD *dhm, int (*init)(DH *));
+int (*DH_meth_get_finish(const DH_METHOD *dhm)) (DH *);
+int DH_meth_set_finish(DH_METHOD *dhm, int (*finish) (DH *));
+int (*DH_meth_get_generate_params(const DH_METHOD *dhm))
+        (DH *, int, int, BN_GENCB *);
+int DH_meth_set_generate_params(DH_METHOD *dhm,
+        int (*generate_params) (DH *, int, int, BN_GENCB *));
+
+
 # define EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len) \
         EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, \
                         EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN, len, NULL)
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index fe1cde6..5b53b86 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1527,6 +1527,7 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
         PACKET prime, generator, pub_key;
 
         DH *dh;
+        BIGNUM *p, *g, *bnpub_key;
 
         if (!PACKET_get_length_prefixed_2(pkt, &prime)
             || !PACKET_get_length_prefixed_2(pkt, &generator)
@@ -1550,22 +1551,41 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
             goto err;
         }
 
-        if ((dh->p = BN_bin2bn(PACKET_data(&prime),
-                               PACKET_remaining(&prime), NULL)) == NULL
-            || (dh->g = BN_bin2bn(PACKET_data(&generator),
-                                  PACKET_remaining(&generator), NULL)) == NULL
-            || (dh->pub_key =
-                BN_bin2bn(PACKET_data(&pub_key),
-                          PACKET_remaining(&pub_key), NULL)) == NULL) {
+        p = BN_bin2bn(PACKET_data(&prime), PACKET_remaining(&prime), NULL);
+        g = BN_bin2bn(PACKET_data(&generator), PACKET_remaining(&generator),
+                      NULL);
+        bnpub_key = BN_bin2bn(PACKET_data(&pub_key), PACKET_remaining(&pub_key),
+                              NULL);
+        if (p == NULL || g == NULL || bnpub_key == NULL) {
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_BN_LIB);
+            BN_free(p);
+            BN_free(g);
+            BN_free(bnpub_key);
             goto err;
         }
 
-        if (BN_is_zero(dh->p) || BN_is_zero(dh->g) || BN_is_zero(dh->pub_key)) {
+        if (BN_is_zero(p) || BN_is_zero(g) || BN_is_zero(bnpub_key)) {
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_DH_VALUE);
+            BN_free(p);
+            BN_free(g);
+            BN_free(bnpub_key);
             goto f_err;
         }
 
+        if (!DH_set0_pqg(dh, p, NULL, g)) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_BN_LIB);
+            BN_free(p);
+            BN_free(g);
+            BN_free(bnpub_key);
+            goto err;
+        }
+
+        if (!DH_set0_key(dh, bnpub_key, NULL)) {
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_BN_LIB);
+            BN_free(bnpub_key);
+            goto err;
+        }
+
         if (!ssl_security(s, SSL_SECOP_TMP_DH, DH_security_bits(dh), 0, dh)) {
             al = SSL_AD_HANDSHAKE_FAILURE;
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_DH_KEY_TOO_SMALL);
@@ -2254,6 +2274,7 @@ psk_err:
 #ifndef OPENSSL_NO_DH
     else if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
         DH *dh_clnt = NULL;
+        BIGNUM *pub_key;
         skey = s->s3->peer_tmp;
         if (skey == NULL) {
             SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
@@ -2271,9 +2292,10 @@ psk_err:
 
 
         /* send off the data */
-        n = BN_num_bytes(dh_clnt->pub_key);
+        DH_get0_key(dh_clnt, &pub_key, NULL);
+        n = BN_num_bytes(pub_key);
         s2n(n, p);
-        BN_bn2bin(dh_clnt->pub_key, p);
+        BN_bn2bin(pub_key, p);
         n += 2;
         EVP_PKEY_free(ckey);
         ckey = NULL;
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 23e7903..38fa945 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1772,9 +1772,8 @@ int tls_construct_server_key_exchange(SSL *s)
         EVP_PKEY_free(pkdh);
         pkdh = NULL;
 
-        r[0] = dh->p;
-        r[1] = dh->g;
-        r[2] = dh->pub_key;
+        DH_get0_pqg(dh, &r[0], NULL, &r[1]);
+        DH_get0_key(dh, &r[2], NULL);
     } else
 #endif
 #ifndef OPENSSL_NO_EC
@@ -2301,6 +2300,7 @@ MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
         EVP_PKEY *skey = NULL;
         DH *cdh;
         unsigned int i;
+        BIGNUM *pub_key;
 
         if (!PACKET_get_net_2(pkt, &i)) {
             if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
@@ -2343,9 +2343,12 @@ MSG_PROCESS_RETURN tls_process_client_key_exchange(SSL *s, PACKET *pkt)
             goto err;
         }
         cdh = EVP_PKEY_get0_DH(ckey);
-        cdh->pub_key = BN_bin2bn(data, i, NULL);
-        if (cdh->pub_key == NULL) {
-            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, SSL_R_BN_LIB);
+        pub_key = BN_bin2bn(data, i, NULL);
+
+        if (pub_key == NULL || !DH_set0_key(cdh, pub_key, NULL)) {
+            SSLerr(SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            if (pub_key != NULL)
+                BN_free(pub_key);
             goto err;
         }
 
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 6e7b5ed..a4cd23a 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -4091,17 +4091,20 @@ DH *ssl_get_auto_dh(SSL *s)
 
     if (dh_secbits >= 128) {
         DH *dhp = DH_new();
+        BIGNUM *p, *g;
         if (dhp == NULL)
             return NULL;
-        dhp->g = BN_new();
-        if (dhp->g != NULL)
-            BN_set_word(dhp->g, 2);
+        g = BN_new();
+        if (g != NULL)
+            BN_set_word(g, 2);
         if (dh_secbits >= 192)
-            dhp->p = get_rfc3526_prime_8192(NULL);
+            p = get_rfc3526_prime_8192(NULL);
         else
-            dhp->p = get_rfc3526_prime_3072(NULL);
-        if (dhp->p == NULL || dhp->g == NULL) {
+            p = get_rfc3526_prime_3072(NULL);
+        if (p == NULL || g == NULL || !DH_set0_pqg(dhp, p, NULL, g)) {
             DH_free(dhp);
+            BN_free(p);
+            BN_free(g);
             return NULL;
         }
         return dhp;
diff --git a/test/dhtest.c b/test/dhtest.c
index 8fad6da..fb1c2df 100644
--- a/test/dhtest.c
+++ b/test/dhtest.c
@@ -88,6 +88,8 @@ int main(int argc, char *argv[])
     BN_GENCB *_cb = NULL;
     DH *a = NULL;
     DH *b = NULL;
+    BIGNUM *ap = NULL, *ag = NULL, *bp = NULL, *bg = NULL, *apub_key = NULL;
+    BIGNUM *bpub_key = NULL, *priv_key = NULL;
     char buf[12] = {0};
     unsigned char *abuf = NULL;
     unsigned char *bbuf = NULL;
@@ -124,39 +126,43 @@ int main(int argc, char *argv[])
     if (i & DH_NOT_SUITABLE_GENERATOR)
         BIO_puts(out, "the g value is not a generator\n");
 
+    DH_get0_pqg(a, &ap, NULL, &ag);
     BIO_puts(out, "\np    =");
-    BN_print(out, a->p);
+    BN_print(out, ap);
     BIO_puts(out, "\ng    =");
-    BN_print(out, a->g);
+    BN_print(out, ag);
     BIO_puts(out, "\n");
 
     b = DH_new();
     if (b == NULL)
         goto err;
 
-    b->p = BN_dup(a->p);
-    b->g = BN_dup(a->g);
-    if ((b->p == NULL) || (b->g == NULL))
+    bp = BN_dup(ap);
+    bg = BN_dup(ag);
+    if ((bp == NULL) || (bg == NULL) || !DH_set0_pqg(b, bp, NULL, bg))
         goto err;
+    bp = bg = NULL;
 
     /* Set a to run with normal modexp and b to use constant time */
-    a->flags &= ~DH_FLAG_NO_EXP_CONSTTIME;
-    b->flags |= DH_FLAG_NO_EXP_CONSTTIME;
+    DH_clear_flags(a, DH_FLAG_NO_EXP_CONSTTIME);
+    DH_set_flags(b, DH_FLAG_NO_EXP_CONSTTIME);
 
     if (!DH_generate_key(a))
         goto err;
+    DH_get0_key(a, &apub_key, &priv_key);
     BIO_puts(out, "pri 1=");
-    BN_print(out, a->priv_key);
+    BN_print(out, priv_key);
     BIO_puts(out, "\npub 1=");
-    BN_print(out, a->pub_key);
+    BN_print(out, apub_key);
     BIO_puts(out, "\n");
 
     if (!DH_generate_key(b))
         goto err;
+    DH_get0_key(b, &bpub_key, &priv_key);
     BIO_puts(out, "pri 2=");
-    BN_print(out, b->priv_key);
+    BN_print(out, priv_key);
     BIO_puts(out, "\npub 2=");
-    BN_print(out, b->pub_key);
+    BN_print(out, bpub_key);
     BIO_puts(out, "\n");
 
     alen = DH_size(a);
@@ -164,7 +170,7 @@ int main(int argc, char *argv[])
     if (abuf == NULL)
         goto err;
 
-    aout = DH_compute_key(abuf, b->pub_key, a);
+    aout = DH_compute_key(abuf, bpub_key, a);
 
     BIO_puts(out, "key1 =");
     for (i = 0; i < aout; i++) {
@@ -178,7 +184,7 @@ int main(int argc, char *argv[])
     if (bbuf == NULL)
         goto err;
 
-    bout = DH_compute_key(bbuf, a->pub_key, b);
+    bout = DH_compute_key(bbuf, apub_key, b);
 
     BIO_puts(out, "key2 =");
     for (i = 0; i < bout; i++) {
@@ -201,6 +207,8 @@ int main(int argc, char *argv[])
     OPENSSL_free(bbuf);
     DH_free(b);
     DH_free(a);
+    BN_free(bp);
+    BN_free(bg);
     BN_GENCB_free(_cb);
     BIO_free(out);
 
@@ -519,7 +527,7 @@ static int run_rfc5114_tests(void)
     unsigned char *Z1 = NULL;
     unsigned char *Z2 = NULL;
     const rfc5114_td *td = NULL;
-    BIGNUM *bady = NULL;
+    BIGNUM *bady = NULL, *priv_key = NULL, *pub_key = NULL;
 
     for (i = 0; i < (int)OSSL_NELEM(rfctd); i++) {
         td = rfctd + i;
@@ -529,15 +537,19 @@ static int run_rfc5114_tests(void)
         if ((dhA == NULL) || (dhB == NULL))
             goto bad_err;
 
-        dhA->priv_key = BN_bin2bn(td->xA, td->xA_len, NULL);
-        dhA->pub_key = BN_bin2bn(td->yA, td->yA_len, NULL);
+        priv_key = BN_bin2bn(td->xA, td->xA_len, NULL);
+        pub_key = BN_bin2bn(td->yA, td->yA_len, NULL);
+        if (priv_key == NULL || pub_key == NULL
+                || !DH_set0_key(dhA, pub_key, priv_key))
+            goto bad_err;
 
-        dhB->priv_key = BN_bin2bn(td->xB, td->xB_len, NULL);
-        dhB->pub_key = BN_bin2bn(td->yB, td->yB_len, NULL);
+        priv_key = BN_bin2bn(td->xB, td->xB_len, NULL);
+        pub_key = BN_bin2bn(td->yB, td->yB_len, NULL);
 
-        if ((dhA->priv_key == NULL) || (dhA->pub_key == NULL)
-            || (dhB->priv_key == NULL) || (dhB->pub_key == NULL))
+        if (priv_key == NULL || pub_key == NULL
+                || !DH_set0_key(dhB, pub_key, priv_key))
             goto bad_err;
+        priv_key = pub_key = NULL;
 
         if ((td->Z_len != (size_t)DH_size(dhA))
             || (td->Z_len != (size_t)DH_size(dhB)))
@@ -551,10 +563,17 @@ static int run_rfc5114_tests(void)
          * Work out shared secrets using both sides and compare with expected
          * values.
          */
-        if (DH_compute_key(Z1, dhB->pub_key, dhA) == -1)
+        DH_get0_key(dhB, &pub_key, NULL);
+        if (DH_compute_key(Z1, pub_key, dhA) == -1) {
+            pub_key = NULL;
             goto bad_err;
-        if (DH_compute_key(Z2, dhA->pub_key, dhB) == -1)
+        }
+        DH_get0_key(dhA, &pub_key, NULL);
+        if (DH_compute_key(Z2, pub_key, dhB) == -1) {
+            pub_key = NULL;
             goto bad_err;
+        }
+        pub_key = NULL;
 
         if (memcmp(Z1, td->Z, td->Z_len))
             goto err;
@@ -611,6 +630,8 @@ static int run_rfc5114_tests(void)
     BN_free(bady);
     DH_free(dhA);
     DH_free(dhB);
+    BN_free(pub_key);
+    BN_free(priv_key);
     OPENSSL_free(Z1);
     OPENSSL_free(Z2);
 
diff --git a/test/ssltest_old.c b/test/ssltest_old.c
index e3f8d77..2cc25db 100644
--- a/test/ssltest_old.c
+++ b/test/ssltest_old.c
@@ -3527,13 +3527,16 @@ static DH *get_dh512()
         0x02,
     };
     DH *dh;
+    BIGNUM *p, *g;
 
     if ((dh = DH_new()) == NULL)
         return (NULL);
-    dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
-    dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
-    if ((dh->p == NULL) || (dh->g == NULL)) {
+    p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
+    g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
+    if ((p == NULL) || (g == NULL) || !DH_set0_pqg(dh, p, NULL, g)) {
         DH_free(dh);
+        BN_free(p);
+        BN_free(g);
         return (NULL);
     }
     return (dh);
@@ -3568,13 +3571,16 @@ static DH *get_dh1024()
         0x02,
     };
     DH *dh;
+    BIGNUM *p, *g;
 
     if ((dh = DH_new()) == NULL)
         return (NULL);
-    dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
-    dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
-    if ((dh->p == NULL) || (dh->g == NULL)) {
+    p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
+    g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
+    if ((p == NULL) || (g == NULL) || !DH_set0_pqg(dh, p, NULL, g)) {
         DH_free(dh);
+        BN_free(p);
+        BN_free(g);
         return (NULL);
     }
     return (dh);
@@ -3629,16 +3635,19 @@ static DH *get_dh1024dsa()
         0x07, 0xE7, 0x68, 0x1A, 0x82, 0x5D, 0x32, 0xA2,
     };
     DH *dh;
+    BIGNUM *p, *g;
 
     if ((dh = DH_new()) == NULL)
         return (NULL);
-    dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
-    dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
-    if ((dh->p == NULL) || (dh->g == NULL)) {
+    p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
+    g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
+    if ((p == NULL) || (g == NULL) || !DH_set0_pqg(dh, p, NULL, g)) {
         DH_free(dh);
+        BN_free(p);
+        BN_free(g);
         return (NULL);
     }
-    dh->length = 160;
+    DH_set_length(dh, 160);
     return (dh);
 }
 #endif
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 2d4c0e6..af6762f 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4165,3 +4165,34 @@ RSA_meth_set_init                       4031	1_1_0	EXIST::FUNCTION:RSA
 RSA_meth_get_priv_enc                   4032	1_1_0	EXIST::FUNCTION:RSA
 RSA_set0_crt_params                     4037	1_1_0	EXIST::FUNCTION:RSA
 RSA_get0_crt_params                     4038	1_1_0	EXIST::FUNCTION:RSA
+DH_set0_pqg                             4039	1_1_0	EXIST::FUNCTION:DH
+DH_set_flags                            4040	1_1_0	EXIST::FUNCTION:DH
+DH_clear_flags                          4041	1_1_0	EXIST::FUNCTION:DH
+DH_get0_key                             4042	1_1_0	EXIST::FUNCTION:DH
+DH_get0_engine                          4043	1_1_0	EXIST::FUNCTION:DH
+DH_set0_key                             4044	1_1_0	EXIST::FUNCTION:DH
+DH_set_length                           4045	1_1_0	EXIST::FUNCTION:DH
+DH_test_flags                           4046	1_1_0	EXIST::FUNCTION:DH
+DH_get_length                           4047	1_1_0	EXIST::FUNCTION:DH
+DH_get0_pqg                             4048	1_1_0	EXIST::FUNCTION:DH
+DH_meth_get_compute_key                 4049	1_1_0	EXIST::FUNCTION:DH
+DH_meth_set1_name                       4050	1_1_0	EXIST::FUNCTION:DH
+DH_meth_set_init                        4051	1_1_0	EXIST::FUNCTION:DH
+DH_meth_get_finish                      4052	1_1_0	EXIST::FUNCTION:DH
+DH_meth_get0_name                       4053	1_1_0	EXIST::FUNCTION:DH
+DH_meth_set_generate_params             4054	1_1_0	EXIST::FUNCTION:DH
+DH_meth_set_compute_key                 4055	1_1_0	EXIST::FUNCTION:DH
+DH_meth_set_flags                       4056	1_1_0	EXIST::FUNCTION:DH
+DH_meth_get_generate_params             4057	1_1_0	EXIST::FUNCTION:DH
+DH_meth_get_flags                       4058	1_1_0	EXIST::FUNCTION:DH
+DH_meth_set_finish                      4059	1_1_0	EXIST::FUNCTION:DH
+DH_meth_get0_app_data                   4060	1_1_0	EXIST::FUNCTION:DH
+DH_meth_set0_app_data                   4061	1_1_0	EXIST::FUNCTION:DH
+DH_meth_get_init                        4062	1_1_0	EXIST::FUNCTION:DH
+DH_meth_get_bn_mod_exp                  4063	1_1_0	EXIST::FUNCTION:DH
+DH_meth_new                             4064	1_1_0	EXIST::FUNCTION:DH
+DH_meth_dup                             4065	1_1_0	EXIST::FUNCTION:DH
+DH_meth_set_bn_mod_exp                  4066	1_1_0	EXIST::FUNCTION:DH
+DH_meth_set_generate_key                4067	1_1_0	EXIST::FUNCTION:DH
+DH_meth_free                            4068	1_1_0	EXIST::FUNCTION:DH
+DH_meth_get_generate_key                4069	1_1_0	EXIST::FUNCTION:DH


More information about the openssl-commits mailing list