Coverage Report

Created: 2025-09-05 06:13

/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
}