Coverage Report

Created: 2026-02-14 06:34

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/bytestring.h>
18
#include <openssl/err.h>
19
#include <openssl/hkdf.h>
20
#include <openssl/kdf.h>
21
#include <openssl/mem.h>
22
23
#include "../internal.h"
24
#include "../mem_internal.h"
25
#include "internal.h"
26
27
28
using namespace bssl;
29
30
typedef struct {
31
  int mode;
32
  const EVP_MD *md;
33
  uint8_t *key;
34
  size_t key_len;
35
  uint8_t *salt;
36
  size_t salt_len;
37
  CBB info;
38
} HKDF_PKEY_CTX;
39
40
0
static int pkey_hkdf_init(EvpPkeyCtx *ctx) {
41
0
  HKDF_PKEY_CTX *hctx = NewZeroed<HKDF_PKEY_CTX>();
42
0
  if (hctx == nullptr) {
43
0
    return 0;
44
0
  }
45
46
0
  if (!CBB_init(&hctx->info, 0)) {
47
0
    Delete(hctx);
48
0
    return 0;
49
0
  }
50
51
0
  ctx->data = hctx;
52
0
  return 1;
53
0
}
54
55
0
static int pkey_hkdf_copy(EvpPkeyCtx *dst, EvpPkeyCtx *src) {
56
0
  if (!pkey_hkdf_init(dst)) {
57
0
    return 0;
58
0
  }
59
60
0
  HKDF_PKEY_CTX *hctx_dst = reinterpret_cast<HKDF_PKEY_CTX *>(dst->data);
61
0
  const HKDF_PKEY_CTX *hctx_src =
62
0
      reinterpret_cast<const HKDF_PKEY_CTX *>(src->data);
63
0
  hctx_dst->mode = hctx_src->mode;
64
0
  hctx_dst->md = hctx_src->md;
65
66
0
  if (hctx_src->key_len != 0) {
67
0
    hctx_dst->key = reinterpret_cast<uint8_t *>(
68
0
        OPENSSL_memdup(hctx_src->key, hctx_src->key_len));
69
0
    if (hctx_dst->key == nullptr) {
70
0
      return 0;
71
0
    }
72
0
    hctx_dst->key_len = hctx_src->key_len;
73
0
  }
74
75
0
  if (hctx_src->salt_len != 0) {
76
0
    hctx_dst->salt = reinterpret_cast<uint8_t *>(
77
0
        OPENSSL_memdup(hctx_src->salt, hctx_src->salt_len));
78
0
    if (hctx_dst->salt == nullptr) {
79
0
      return 0;
80
0
    }
81
0
    hctx_dst->salt_len = hctx_src->salt_len;
82
0
  }
83
84
0
  if (!CBB_add_bytes(&hctx_dst->info, CBB_data(&hctx_src->info),
85
0
                     CBB_len(&hctx_src->info))) {
86
0
    return 0;
87
0
  }
88
89
0
  return 1;
90
0
}
91
92
0
static void pkey_hkdf_cleanup(EvpPkeyCtx *ctx) {
93
0
  HKDF_PKEY_CTX *hctx = reinterpret_cast<HKDF_PKEY_CTX *>(ctx->data);
94
0
  if (hctx != nullptr) {
95
0
    OPENSSL_free(hctx->key);
96
0
    OPENSSL_free(hctx->salt);
97
0
    CBB_cleanup(&hctx->info);
98
0
    Delete(hctx);
99
0
    ctx->data = nullptr;
100
0
  }
101
0
}
102
103
0
static int pkey_hkdf_derive(EvpPkeyCtx *ctx, uint8_t *out, size_t *out_len) {
104
0
  HKDF_PKEY_CTX *hctx = reinterpret_cast<HKDF_PKEY_CTX *>(ctx->data);
105
0
  if (hctx->md == nullptr) {
106
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
107
0
    return 0;
108
0
  }
109
0
  if (hctx->key_len == 0) {
110
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
111
0
    return 0;
112
0
  }
113
114
0
  if (out == nullptr) {
115
0
    if (hctx->mode == EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) {
116
0
      *out_len = EVP_MD_size(hctx->md);
117
0
    }
118
    // HKDF-Expand is variable-length and returns |*out_len| bytes. "Output" the
119
    // input length by leaving it alone.
120
0
    return 1;
121
0
  }
122
123
0
  switch (hctx->mode) {
124
0
    case EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND:
125
0
      return HKDF(out, *out_len, hctx->md, hctx->key, hctx->key_len, hctx->salt,
126
0
                  hctx->salt_len, CBB_data(&hctx->info), CBB_len(&hctx->info));
127
128
0
    case EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY:
129
0
      if (*out_len < EVP_MD_size(hctx->md)) {
130
0
        OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
131
0
        return 0;
132
0
      }
133
0
      return HKDF_extract(out, out_len, hctx->md, hctx->key, hctx->key_len,
134
0
                          hctx->salt, hctx->salt_len);
135
136
0
    case EVP_PKEY_HKDEF_MODE_EXPAND_ONLY:
137
0
      return HKDF_expand(out, *out_len, hctx->md, hctx->key, hctx->key_len,
138
0
                         CBB_data(&hctx->info), CBB_len(&hctx->info));
139
0
  }
140
0
  OPENSSL_PUT_ERROR(EVP, ERR_R_INTERNAL_ERROR);
141
0
  return 0;
142
0
}
143
144
0
static int pkey_hkdf_ctrl(EvpPkeyCtx *ctx, int type, int p1, void *p2) {
145
0
  HKDF_PKEY_CTX *hctx = reinterpret_cast<HKDF_PKEY_CTX *>(ctx->data);
146
0
  switch (type) {
147
0
    case EVP_PKEY_CTRL_HKDF_MODE:
148
0
      if (p1 != EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND &&
149
0
          p1 != EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY &&
150
0
          p1 != EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) {
151
0
        OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION);
152
0
        return 0;
153
0
      }
154
0
      hctx->mode = p1;
155
0
      return 1;
156
0
    case EVP_PKEY_CTRL_HKDF_MD:
157
0
      hctx->md = reinterpret_cast<const EVP_MD *>(p2);
158
0
      return 1;
159
0
    case EVP_PKEY_CTRL_HKDF_KEY: {
160
0
      const CBS *key = reinterpret_cast<const CBS *>(p2);
161
0
      if (!CBS_stow(key, &hctx->key, &hctx->key_len)) {
162
0
        return 0;
163
0
      }
164
0
      return 1;
165
0
    }
166
0
    case EVP_PKEY_CTRL_HKDF_SALT: {
167
0
      const CBS *salt = reinterpret_cast<const CBS *>(p2);
168
0
      if (!CBS_stow(salt, &hctx->salt, &hctx->salt_len)) {
169
0
        return 0;
170
0
      }
171
0
      return 1;
172
0
    }
173
0
    case EVP_PKEY_CTRL_HKDF_INFO: {
174
0
      const CBS *info = reinterpret_cast<const CBS *>(p2);
175
      // |EVP_PKEY_CTX_add1_hkdf_info| appends to the info string, rather than
176
      // replacing it.
177
0
      if (!CBB_add_bytes(&hctx->info, CBS_data(info), CBS_len(info))) {
178
0
        return 0;
179
0
      }
180
0
      return 1;
181
0
    }
182
0
    default:
183
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
184
0
      return 0;
185
0
  }
186
0
}
187
188
const EVP_PKEY_CTX_METHOD bssl::hkdf_pkey_meth = {
189
    /*pkey_id=*/EVP_PKEY_HKDF,  pkey_hkdf_init,   pkey_hkdf_copy,
190
    pkey_hkdf_cleanup,
191
    /*keygen=*/nullptr,
192
    /*sign=*/nullptr,
193
    /*sign_message=*/nullptr,
194
    /*verify=*/nullptr,
195
    /*verify_message=*/nullptr,
196
    /*verify_recover=*/nullptr,
197
    /*encrypt=*/nullptr,
198
    /*decrypt=*/nullptr,        pkey_hkdf_derive,
199
    /*paramgen=*/nullptr,       pkey_hkdf_ctrl,
200
};
201
202
0
int EVP_PKEY_CTX_hkdf_mode(EVP_PKEY_CTX *ctx, int mode) {
203
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
204
0
                           EVP_PKEY_CTRL_HKDF_MODE, mode, nullptr);
205
0
}
206
207
0
int EVP_PKEY_CTX_set_hkdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) {
208
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
209
0
                           EVP_PKEY_CTRL_HKDF_MD, 0, (void *)md);
210
0
}
211
212
int EVP_PKEY_CTX_set1_hkdf_key(EVP_PKEY_CTX *ctx, const uint8_t *key,
213
0
                               size_t key_len) {
214
0
  CBS cbs;
215
0
  CBS_init(&cbs, key, key_len);
216
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
217
0
                           EVP_PKEY_CTRL_HKDF_KEY, 0, &cbs);
218
0
}
219
220
int EVP_PKEY_CTX_set1_hkdf_salt(EVP_PKEY_CTX *ctx, const uint8_t *salt,
221
0
                                size_t salt_len) {
222
0
  CBS cbs;
223
0
  CBS_init(&cbs, salt, salt_len);
224
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
225
0
                           EVP_PKEY_CTRL_HKDF_SALT, 0, &cbs);
226
0
}
227
228
int EVP_PKEY_CTX_add1_hkdf_info(EVP_PKEY_CTX *ctx, const uint8_t *info,
229
0
                                size_t info_len) {
230
0
  CBS cbs;
231
0
  CBS_init(&cbs, info, info_len);
232
0
  return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_HKDF, EVP_PKEY_OP_DERIVE,
233
0
                           EVP_PKEY_CTRL_HKDF_INFO, 0, &cbs);
234
0
}