Coverage Report

Created: 2024-11-21 06:47

/src/boringssl/crypto/evp/p_dh.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2006-2019 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 <assert.h>
13
14
#include <openssl/dh.h>
15
#include <openssl/err.h>
16
#include <openssl/mem.h>
17
18
#include "internal.h"
19
20
21
typedef struct dh_pkey_ctx_st {
22
  int pad;
23
} DH_PKEY_CTX;
24
25
0
static int pkey_dh_init(EVP_PKEY_CTX *ctx) {
26
0
  DH_PKEY_CTX *dctx = OPENSSL_zalloc(sizeof(DH_PKEY_CTX));
27
0
  if (dctx == NULL) {
28
0
    return 0;
29
0
  }
30
31
0
  ctx->data = dctx;
32
0
  return 1;
33
0
}
34
35
0
static int pkey_dh_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
36
0
  if (!pkey_dh_init(dst)) {
37
0
    return 0;
38
0
  }
39
40
0
  const DH_PKEY_CTX *sctx = src->data;
41
0
  DH_PKEY_CTX *dctx = dst->data;
42
0
  dctx->pad = sctx->pad;
43
0
  return 1;
44
0
}
45
46
0
static void pkey_dh_cleanup(EVP_PKEY_CTX *ctx) {
47
0
  OPENSSL_free(ctx->data);
48
0
  ctx->data = NULL;
49
0
}
50
51
0
static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
52
0
  DH *dh = DH_new();
53
0
  if (dh == NULL || !EVP_PKEY_assign_DH(pkey, dh)) {
54
0
    DH_free(dh);
55
0
    return 0;
56
0
  }
57
58
0
  if (ctx->pkey != NULL && !EVP_PKEY_copy_parameters(pkey, ctx->pkey)) {
59
0
    return 0;
60
0
  }
61
62
0
  return DH_generate_key(dh);
63
0
}
64
65
0
static int pkey_dh_derive(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len) {
66
0
  DH_PKEY_CTX *dctx = ctx->data;
67
0
  if (ctx->pkey == NULL || ctx->peerkey == NULL) {
68
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
69
0
    return 0;
70
0
  }
71
72
0
  DH *our_key = ctx->pkey->pkey;
73
0
  DH *peer_key = ctx->peerkey->pkey;
74
0
  if (our_key == NULL || peer_key == NULL) {
75
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
76
0
    return 0;
77
0
  }
78
79
0
  const BIGNUM *pub_key = DH_get0_pub_key(peer_key);
80
0
  if (pub_key == NULL) {
81
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
82
0
    return 0;
83
0
  }
84
85
0
  if (out == NULL) {
86
0
    *out_len = DH_size(our_key);
87
0
    return 1;
88
0
  }
89
90
0
  if (*out_len < (size_t)DH_size(our_key)) {
91
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
92
0
    return 0;
93
0
  }
94
95
0
  int ret = dctx->pad ? DH_compute_key_padded(out, pub_key, our_key)
96
0
                      : DH_compute_key(out, pub_key, our_key);
97
0
  if (ret < 0) {
98
0
    return 0;
99
0
  }
100
101
0
  assert(ret <= DH_size(our_key));
102
0
  *out_len = (size_t)ret;
103
0
  return 1;
104
0
}
105
106
0
static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) {
107
0
  DH_PKEY_CTX *dctx = ctx->data;
108
0
  switch (type) {
109
0
    case EVP_PKEY_CTRL_PEER_KEY:
110
      // |EVP_PKEY_derive_set_peer| requires the key implement this command,
111
      // even if it is a no-op.
112
0
      return 1;
113
114
0
    case EVP_PKEY_CTRL_DH_PAD:
115
0
      dctx->pad = p1;
116
0
      return 1;
117
118
0
    default:
119
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
120
0
      return 0;
121
0
  }
122
0
}
123
124
const EVP_PKEY_METHOD dh_pkey_meth = {
125
    .pkey_id = EVP_PKEY_DH,
126
    .init = pkey_dh_init,
127
    .copy = pkey_dh_copy,
128
    .cleanup = pkey_dh_cleanup,
129
    .keygen = pkey_dh_keygen,
130
    .derive = pkey_dh_derive,
131
    .ctrl = pkey_dh_ctrl,
132
};
133
134
0
int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad) {
135
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_DERIVE,
136
0
                           EVP_PKEY_CTRL_DH_PAD, pad, NULL);
137
0
}