/src/boringssl/crypto/evp/p_dh.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2006-2019 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/evp.h> |
16 | | |
17 | | #include <assert.h> |
18 | | |
19 | | #include <openssl/dh.h> |
20 | | #include <openssl/err.h> |
21 | | #include <openssl/mem.h> |
22 | | |
23 | | #include "internal.h" |
24 | | |
25 | | |
26 | | namespace { |
27 | | typedef struct dh_pkey_ctx_st { |
28 | | int pad; |
29 | | } DH_PKEY_CTX; |
30 | | } // namespace |
31 | | |
32 | 0 | static int pkey_dh_init(EVP_PKEY_CTX *ctx) { |
33 | 0 | DH_PKEY_CTX *dctx = |
34 | 0 | reinterpret_cast<DH_PKEY_CTX *>(OPENSSL_zalloc(sizeof(DH_PKEY_CTX))); |
35 | 0 | if (dctx == NULL) { |
36 | 0 | return 0; |
37 | 0 | } |
38 | | |
39 | 0 | ctx->data = dctx; |
40 | 0 | return 1; |
41 | 0 | } |
42 | | |
43 | 0 | static int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { |
44 | 0 | if (!pkey_dh_init(dst)) { |
45 | 0 | return 0; |
46 | 0 | } |
47 | | |
48 | 0 | const DH_PKEY_CTX *sctx = reinterpret_cast<DH_PKEY_CTX *>(src->data); |
49 | 0 | DH_PKEY_CTX *dctx = reinterpret_cast<DH_PKEY_CTX *>(dst->data); |
50 | 0 | dctx->pad = sctx->pad; |
51 | 0 | return 1; |
52 | 0 | } |
53 | | |
54 | 0 | static void pkey_dh_cleanup(EVP_PKEY_CTX *ctx) { |
55 | 0 | OPENSSL_free(ctx->data); |
56 | 0 | ctx->data = NULL; |
57 | 0 | } |
58 | | |
59 | 0 | static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { |
60 | 0 | DH *dh = DH_new(); |
61 | 0 | if (dh == NULL || !EVP_PKEY_assign_DH(pkey, dh)) { |
62 | 0 | DH_free(dh); |
63 | 0 | return 0; |
64 | 0 | } |
65 | | |
66 | 0 | if (ctx->pkey != NULL && !EVP_PKEY_copy_parameters(pkey, ctx->pkey.get())) { |
67 | 0 | return 0; |
68 | 0 | } |
69 | | |
70 | 0 | return DH_generate_key(dh); |
71 | 0 | } |
72 | | |
73 | 0 | static int pkey_dh_derive(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len) { |
74 | 0 | DH_PKEY_CTX *dctx = reinterpret_cast<DH_PKEY_CTX *>(ctx->data); |
75 | 0 | if (ctx->pkey == NULL || ctx->peerkey == NULL) { |
76 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET); |
77 | 0 | return 0; |
78 | 0 | } |
79 | | |
80 | 0 | DH *our_key = reinterpret_cast<DH *>(ctx->pkey->pkey); |
81 | 0 | DH *peer_key = reinterpret_cast<DH *>(ctx->peerkey->pkey); |
82 | 0 | if (our_key == NULL || peer_key == NULL) { |
83 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET); |
84 | 0 | return 0; |
85 | 0 | } |
86 | | |
87 | 0 | const BIGNUM *pub_key = DH_get0_pub_key(peer_key); |
88 | 0 | if (pub_key == NULL) { |
89 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET); |
90 | 0 | return 0; |
91 | 0 | } |
92 | | |
93 | 0 | if (out == NULL) { |
94 | 0 | *out_len = DH_size(our_key); |
95 | 0 | return 1; |
96 | 0 | } |
97 | | |
98 | 0 | if (*out_len < (size_t)DH_size(our_key)) { |
99 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); |
100 | 0 | return 0; |
101 | 0 | } |
102 | | |
103 | 0 | int ret = dctx->pad ? DH_compute_key_padded(out, pub_key, our_key) |
104 | 0 | : DH_compute_key(out, pub_key, our_key); |
105 | 0 | if (ret < 0) { |
106 | 0 | return 0; |
107 | 0 | } |
108 | | |
109 | 0 | assert(ret <= DH_size(our_key)); |
110 | 0 | *out_len = (size_t)ret; |
111 | 0 | return 1; |
112 | 0 | } |
113 | | |
114 | 0 | static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { |
115 | 0 | DH_PKEY_CTX *dctx = reinterpret_cast<DH_PKEY_CTX *>(ctx->data); |
116 | 0 | switch (type) { |
117 | 0 | case EVP_PKEY_CTRL_PEER_KEY: |
118 | | // |EVP_PKEY_derive_set_peer| requires the key implement this command, |
119 | | // even if it is a no-op. |
120 | 0 | return 1; |
121 | | |
122 | 0 | case EVP_PKEY_CTRL_DH_PAD: |
123 | 0 | dctx->pad = p1; |
124 | 0 | return 1; |
125 | | |
126 | 0 | default: |
127 | 0 | OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); |
128 | 0 | return 0; |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | | const EVP_PKEY_CTX_METHOD dh_pkey_meth = { |
133 | | /*pkey_id=*/EVP_PKEY_DH, |
134 | | /*init=*/pkey_dh_init, |
135 | | /*copy=*/pkey_dh_copy, |
136 | | /*cleanup=*/pkey_dh_cleanup, |
137 | | /*keygen=*/pkey_dh_keygen, |
138 | | /*sign=*/nullptr, |
139 | | /*sign_message=*/nullptr, |
140 | | /*verify=*/nullptr, |
141 | | /*verify_message=*/nullptr, |
142 | | /*verify_recover=*/nullptr, |
143 | | /*encrypt=*/nullptr, |
144 | | /*decrypt=*/nullptr, |
145 | | /*derive=*/pkey_dh_derive, |
146 | | /*paramgen=*/nullptr, |
147 | | /*ctrl=*/pkey_dh_ctrl, |
148 | | }; |
149 | | |
150 | 0 | int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad) { |
151 | 0 | return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_DERIVE, |
152 | 0 | EVP_PKEY_CTRL_DH_PAD, pad, NULL); |
153 | 0 | } |