Coverage Report

Created: 2026-04-30 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/hkdf/hkdf.cc.inc
Line
Count
Source
1
// Copyright 2014 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/hkdf.h>
16
17
#include <assert.h>
18
#include <string.h>
19
20
#include <openssl/err.h>
21
#include <openssl/hmac.h>
22
23
#include "../../internal.h"
24
25
26
using namespace bssl;
27
28
int HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest,
29
         const uint8_t *secret, size_t secret_len, const uint8_t *salt,
30
0
         size_t salt_len, const uint8_t *info, size_t info_len) {
31
  // https://tools.ietf.org/html/rfc5869#section-2
32
0
  uint8_t prk[EVP_MAX_MD_SIZE];
33
0
  size_t prk_len;
34
35
0
  if (!HKDF_extract(prk, &prk_len, digest, secret, secret_len, salt,
36
0
                    salt_len) ||
37
0
      !HKDF_expand(out_key, out_len, digest, prk, prk_len, info, info_len)) {
38
0
    return 0;
39
0
  }
40
41
0
  return 1;
42
0
}
43
44
int HKDF_extract(uint8_t *out_key, size_t *out_len, const EVP_MD *digest,
45
                 const uint8_t *secret, size_t secret_len, const uint8_t *salt,
46
18.4k
                 size_t salt_len) {
47
  // https://tools.ietf.org/html/rfc5869#section-2.2
48
49
  // If salt is not given, HashLength zeros are used. However, HMAC does that
50
  // internally already so we can ignore it.
51
18.4k
  unsigned len;
52
18.4k
  if (HMAC(digest, salt, salt_len, secret, secret_len, out_key, &len) ==
53
18.4k
      nullptr) {
54
0
    OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB);
55
0
    return 0;
56
0
  }
57
18.4k
  *out_len = len;
58
18.4k
  assert(*out_len == EVP_MD_size(digest));
59
18.4k
  return 1;
60
18.4k
}
61
62
int HKDF_expand(uint8_t *out_key, size_t out_len, const EVP_MD *digest,
63
                const uint8_t *prk, size_t prk_len, const uint8_t *info,
64
249k
                size_t info_len) {
65
  // https://tools.ietf.org/html/rfc5869#section-2.3
66
249k
  const size_t digest_len = EVP_MD_size(digest);
67
249k
  uint8_t previous[EVP_MAX_MD_SIZE];
68
249k
  size_t n, done = 0;
69
249k
  unsigned i;
70
249k
  int ret = 0;
71
249k
  HMAC_CTX hmac;
72
73
  // Expand key material to desired length.
74
249k
  n = (out_len + digest_len - 1) / digest_len;
75
249k
  if (out_len + digest_len < out_len || n > 255) {
76
0
    OPENSSL_PUT_ERROR(HKDF, HKDF_R_OUTPUT_TOO_LARGE);
77
0
    return 0;
78
0
  }
79
80
249k
  HMAC_CTX_init(&hmac);
81
249k
  if (!HMAC_Init_ex(&hmac, prk, prk_len, digest, nullptr)) {
82
0
    goto out;
83
0
  }
84
85
454k
  for (i = 0; i < n; i++) {
86
205k
    uint8_t ctr = i + 1;
87
205k
    size_t todo;
88
89
205k
    if (i != 0 && (!HMAC_Init_ex(&hmac, nullptr, 0, nullptr, nullptr) ||
90
4
                   !HMAC_Update(&hmac, previous, digest_len))) {
91
0
      goto out;
92
0
    }
93
205k
    if (!HMAC_Update(&hmac, info, info_len) || !HMAC_Update(&hmac, &ctr, 1) ||
94
205k
        !HMAC_Final(&hmac, previous, nullptr)) {
95
0
      goto out;
96
0
    }
97
98
205k
    todo = digest_len;
99
205k
    if (todo > out_len - done) {
100
94.2k
      todo = out_len - done;
101
94.2k
    }
102
205k
    OPENSSL_memcpy(out_key + done, previous, todo);
103
205k
    done += todo;
104
205k
  }
105
106
249k
  ret = 1;
107
108
249k
out:
109
249k
  HMAC_CTX_cleanup(&hmac);
110
249k
  if (ret != 1) {
111
0
    OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB);
112
0
  }
113
249k
  return ret;
114
249k
}