1 /*
2 * Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <openssl/evp.h>
11
12 #include <openssl/bn.h>
13 #include <openssl/dh.h>
14 #include <openssl/err.h>
15
16 #include "internal.h"
17 #include "../internal.h"
18
19
dh_free(EVP_PKEY * pkey)20 static void dh_free(EVP_PKEY *pkey) {
21 DH_free(pkey->pkey);
22 pkey->pkey = NULL;
23 }
24
dh_size(const EVP_PKEY * pkey)25 static int dh_size(const EVP_PKEY *pkey) { return DH_size(pkey->pkey); }
26
dh_bits(const EVP_PKEY * pkey)27 static int dh_bits(const EVP_PKEY *pkey) { return DH_bits(pkey->pkey); }
28
dh_param_missing(const EVP_PKEY * pkey)29 static int dh_param_missing(const EVP_PKEY *pkey) {
30 const DH *dh = pkey->pkey;
31 return dh == NULL || DH_get0_p(dh) == NULL || DH_get0_g(dh) == NULL;
32 }
33
dh_param_copy(EVP_PKEY * to,const EVP_PKEY * from)34 static int dh_param_copy(EVP_PKEY *to, const EVP_PKEY *from) {
35 if (dh_param_missing(from)) {
36 OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
37 return 0;
38 }
39
40 const DH *dh = from->pkey;
41 const BIGNUM *q_old = DH_get0_q(dh);
42 BIGNUM *p = BN_dup(DH_get0_p(dh));
43 BIGNUM *q = q_old == NULL ? NULL : BN_dup(q_old);
44 BIGNUM *g = BN_dup(DH_get0_g(dh));
45 if (p == NULL || (q_old != NULL && q == NULL) || g == NULL ||
46 !DH_set0_pqg(to->pkey, p, q, g)) {
47 BN_free(p);
48 BN_free(q);
49 BN_free(g);
50 return 0;
51 }
52
53 // |DH_set0_pqg| took ownership of |p|, |q|, and |g|.
54 return 1;
55 }
56
dh_param_cmp(const EVP_PKEY * a,const EVP_PKEY * b)57 static int dh_param_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
58 if (dh_param_missing(a) || dh_param_missing(b)) {
59 return -2;
60 }
61
62 // Matching OpenSSL, only compare p and g for PKCS#3-style Diffie-Hellman.
63 // OpenSSL only checks q in X9.42-style Diffie-Hellman ("DHX").
64 const DH *a_dh = a->pkey;
65 const DH *b_dh = b->pkey;
66 return BN_cmp(DH_get0_p(a_dh), DH_get0_p(b_dh)) == 0 &&
67 BN_cmp(DH_get0_g(a_dh), DH_get0_g(b_dh)) == 0;
68 }
69
dh_pub_cmp(const EVP_PKEY * a,const EVP_PKEY * b)70 static int dh_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
71 if (dh_param_cmp(a, b) <= 0) {
72 return 0;
73 }
74
75 const DH *a_dh = a->pkey;
76 const DH *b_dh = b->pkey;
77 return BN_cmp(DH_get0_pub_key(a_dh), DH_get0_pub_key(b_dh)) == 0;
78 }
79
80 const EVP_PKEY_ASN1_METHOD dh_asn1_meth = {
81 .pkey_id = EVP_PKEY_DH,
82 .pkey_method = &dh_pkey_meth,
83 .pub_cmp = dh_pub_cmp,
84 .pkey_size = dh_size,
85 .pkey_bits = dh_bits,
86 .param_missing = dh_param_missing,
87 .param_copy = dh_param_copy,
88 .param_cmp = dh_param_cmp,
89 .pkey_free = dh_free,
90 };
91
EVP_PKEY_set1_DH(EVP_PKEY * pkey,DH * key)92 int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) {
93 if (EVP_PKEY_assign_DH(pkey, key)) {
94 DH_up_ref(key);
95 return 1;
96 }
97 return 0;
98 }
99
EVP_PKEY_assign_DH(EVP_PKEY * pkey,DH * key)100 int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key) {
101 evp_pkey_set_method(pkey, &dh_asn1_meth);
102 pkey->pkey = key;
103 return key != NULL;
104 }
105
EVP_PKEY_get0_DH(const EVP_PKEY * pkey)106 DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey) {
107 if (pkey->type != EVP_PKEY_DH) {
108 OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DH_KEY);
109 return NULL;
110 }
111 return pkey->pkey;
112 }
113
EVP_PKEY_get1_DH(const EVP_PKEY * pkey)114 DH *EVP_PKEY_get1_DH(const EVP_PKEY *pkey) {
115 DH *dh = EVP_PKEY_get0_DH(pkey);
116 if (dh != NULL) {
117 DH_up_ref(dh);
118 }
119 return dh;
120 }
121