Coverage Report

Created: 2026-06-15 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/evp/p_hkdf.cc
Line
Count
Source
1
// Copyright 2022 The BoringSSL Authors
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 <openssl/err.h>
18
#include <openssl/hkdf.h>
19
#include <openssl/kdf.h>
20
#include <openssl/mem.h>
21
#include <openssl/span.h>
22
23
#include "../internal.h"
24
#include "../mem_internal.h"
25
#include "internal.h"
26
27
28
using namespace bssl;
29
30
namespace {
31
32
struct HKDF_PKEY_CTX {
33
  int mode = 0;
34
  const EVP_MD *md = nullptr;
35
  Array<uint8_t> key;
36
  Array<uint8_t> salt;
37
  Vector<uint8_t> info;
38
};
39
40
0
static int pkey_hkdf_init(EvpPkeyCtx *ctx, const EVP_PKEY_ALG *) {
41
0
  ctx->data = New<HKDF_PKEY_CTX>();
42
0
  return 1;
43
0
}
44
45
0
static int pkey_hkdf_copy(EvpPkeyCtx *dst, EvpPkeyCtx *src) {
46
0
  if (!pkey_hkdf_init(dst, nullptr)) {
47
0
    return 0;
48
0
  }
49
50
0
  HKDF_PKEY_CTX *hctx_dst = reinterpret_cast<HKDF_PKEY_CTX *>(dst->data);
51
0
  const HKDF_PKEY_CTX *hctx_src =
52
0
      reinterpret_cast<const HKDF_PKEY_CTX *>(src->data);
53
0
  hctx_dst->mode = hctx_src->mode;
54
0
  hctx_dst->md = hctx_src->md;
55
56
0
  if (!hctx_dst->key.CopyFrom(hctx_src->key) ||
57
0
      !hctx_dst->salt.CopyFrom(hctx_src->salt) ||
58
0
      !hctx_dst->info.CopyFrom(hctx_src->info)) {
59
0
    return 0;
60
0
  }
61
62
0
  return 1;
63
0
}
64
65
0
static void pkey_hkdf_cleanup(EvpPkeyCtx *ctx) {
66
0
  Delete(reinterpret_cast<HKDF_PKEY_CTX *>(ctx->data));
67
0
}
68
69
0
static int pkey_hkdf_derive(EvpPkeyCtx *ctx, uint8_t *out, size_t *out_len) {
70
0
  HKDF_PKEY_CTX *hctx = reinterpret_cast<HKDF_PKEY_CTX *>(ctx->data);
71
0
  if (hctx->md == nullptr) {
72
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
73
0
    return 0;
74
0
  }
75
0
  if (hctx->key.empty()) {
76
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
77
0
    return 0;
78
0
  }
79
80
0
  if (out == nullptr) {
81
0
    if (hctx->mode == EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) {
82
0
      *out_len = EVP_MD_size(hctx->md);
83
0
    }
84
    // HKDF-Expand is variable-length and returns `*out_len` bytes. "Output" the
85
    // input length by leaving it alone.
86
0
    return 1;
87
0
  }
88
89
0
  switch (hctx->mode) {
90
0
    case EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND:
91
0
      return HKDF(out, *out_len, hctx->md, hctx->key.data(), hctx->key.size(),
92
0
                  hctx->salt.data(), hctx->salt.size(), hctx->info.data(),
93
0
                  hctx->info.size());
94
95
0
    case EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY:
96
0
      if (*out_len < EVP_MD_size(hctx->md)) {
97
0
        OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
98
0
        return 0;
99
0
      }
100
0
      return HKDF_extract(out, out_len, hctx->md, hctx->key.data(),
101
0
                          hctx->key.size(), hctx->salt.data(),
102
0
                          hctx->salt.size());
103
104
0
    case EVP_PKEY_HKDEF_MODE_EXPAND_ONLY:
105
0
      return HKDF_expand(out, *out_len, hctx->md, hctx->key.data(),
106
0
                         hctx->key.size(), hctx->info.data(),
107
0
                         hctx->info.size());
108
0
  }
109
0
  OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
110
0
  return 0;
111
0
}
112
113
0
static int pkey_hkdf_ctrl(EvpPkeyCtx *ctx, int type, int p1, void *p2) {
114
0
  HKDF_PKEY_CTX *hctx = reinterpret_cast<HKDF_PKEY_CTX *>(ctx->data);
115
0
  switch (type) {
116
0
    case EVP_PKEY_CTRL_HKDF_MODE:
117
0
      if (p1 != EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND &&
118
0
          p1 != EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY &&
119
0
          p1 != EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) {
120
0
        OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
121
0
        return 0;
122
0
      }
123
0
      hctx->mode = p1;
124
0
      return 1;
125
0
    case EVP_PKEY_CTRL_HKDF_MD:
126
0
      hctx->md = reinterpret_cast<const EVP_MD *>(p2);
127
0
      return 1;
128
0
    case EVP_PKEY_CTRL_HKDF_KEY: {
129
0
      const auto *key = reinterpret_cast<const Span<const uint8_t> *>(p2);
130
0
      return hctx->key.CopyFrom(*key);
131
0
    }
132
0
    case EVP_PKEY_CTRL_HKDF_SALT: {
133
0
      const auto *salt = reinterpret_cast<const Span<const uint8_t> *>(p2);
134
0
      return hctx->salt.CopyFrom(*salt);
135
0
    }
136
0
    case EVP_PKEY_CTRL_HKDF_INFO: {
137
0
      const auto *info = reinterpret_cast<const Span<const uint8_t> *>(p2);
138
      // `EVP_PKEY_CTX_add1_hkdf_info` appends to the info string, rather than
139
      // replacing it.
140
0
      return hctx->info.Append(*info);
141
0
    }
142
0
    default:
143
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
144
0
      return 0;
145
0
  }
146
0
}
147
148
const EVP_PKEY_CTX_METHOD hkdf_pkey_meth = {
149
    EVP_PKEY_HKDF,
150
    pkey_hkdf_init,
151
    pkey_hkdf_copy,
152
    pkey_hkdf_cleanup,
153
    /*keygen=*/nullptr,
154
    /*sign=*/nullptr,
155
    /*sign_message=*/nullptr,
156
    /*verify=*/nullptr,
157
    /*verify_message=*/nullptr,
158
    /*verify_recover=*/nullptr,
159
    /*encrypt=*/nullptr,
160
    /*decrypt=*/nullptr,
161
    pkey_hkdf_derive,
162
    /*paramgen=*/nullptr,
163
    /*encap=*/nullptr,
164
    /*decap=*/nullptr,
165
    pkey_hkdf_ctrl,
166
};
167
168
}  // namespace
169
170
0
const EVP_PKEY_ALG *bssl::evp_pkey_hkdf() {
171
0
  static const EVP_PKEY_ALG kAlg = {nullptr, &hkdf_pkey_meth};
172
0
  return &kAlg;
173
0
}
174
175
0
int EVP_PKEY_CTX_hkdf_mode(EVP_PKEY_CTX *ctx, int mode) {
176
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
177
0
                           EVP_PKEY_CTRL_HKDF_MODE, mode, nullptr);
178
0
}
179
180
0
int EVP_PKEY_CTX_set_hkdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
181
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
182
0
                           EVP_PKEY_CTRL_HKDF_MD, 0, (void *)md);
183
0
}
184
185
int EVP_PKEY_CTX_set1_hkdf_key(EVP_PKEY_CTX *ctx, const uint8_t *key,
186
0
                               size_t key_len) {
187
0
  Span<const uint8_t> span(key, key_len);
188
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
189
0
                           EVP_PKEY_CTRL_HKDF_KEY, 0, &span);
190
0
}
191
192
int EVP_PKEY_CTX_set1_hkdf_salt(EVP_PKEY_CTX *ctx, const uint8_t *salt,
193
0
                                size_t salt_len) {
194
0
  Span<const uint8_t> span(salt, salt_len);
195
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
196
0
                           EVP_PKEY_CTRL_HKDF_SALT, 0, &span);
197
0
}
198
199
int EVP_PKEY_CTX_add1_hkdf_info(EVP_PKEY_CTX *ctx, const uint8_t *info,
200
0
                                size_t info_len) {
201
0
  Span<const uint8_t> span(info, info_len);
202
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
203
0
                           EVP_PKEY_CTRL_HKDF_INFO, 0, &span);
204
0
}