/src/gnutls/lib/nettle/int/tls1-prf.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2017 Red Hat, Inc. |
3 | | * |
4 | | * Author: Nikos Mavrogiannopoulos |
5 | | * |
6 | | * This file is part of GnuTLS. |
7 | | * |
8 | | * The GnuTLS is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public License |
10 | | * as published by the Free Software Foundation; either version 2.1 of |
11 | | * the License, or (at your option) any later version. |
12 | | * |
13 | | * This library is distributed in the hope that it will be useful, but |
14 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public License |
19 | | * along with this program. If not, see <https://www.gnu.org/licenses/> |
20 | | * |
21 | | */ |
22 | | |
23 | | /* Functions for the TLS PRF handling. |
24 | | */ |
25 | | |
26 | | #if HAVE_CONFIG_H |
27 | | #include "config.h" |
28 | | #endif |
29 | | |
30 | | #include "gnutls_int.h" |
31 | | #include "fips.h" |
32 | | |
33 | | #include <stdlib.h> |
34 | | #include <string.h> |
35 | | |
36 | | #include <nettle/hmac.h> |
37 | | #include <nettle/memxor.h> |
38 | | #include "int/tls1-prf.h" |
39 | | #include <nettle/sha1.h> |
40 | | #include <nettle/md5.h> |
41 | | |
42 | | /* The RFC2246 P_hash() function. The mac_ctx is expected to |
43 | | * be initialized and key set to be the secret key. |
44 | | */ |
45 | | static void P_hash(void *mac_ctx, nettle_hash_update_func *update, |
46 | | nettle_hash_digest_func *digest, size_t digest_size, |
47 | | size_t seed_size, const uint8_t *seed, size_t label_size, |
48 | | const char *label, size_t dst_length, uint8_t *dst) |
49 | 0 | { |
50 | 0 | uint8_t Atmp[MAX_HASH_SIZE]; |
51 | 0 | ssize_t left; |
52 | 0 | unsigned started = 0; |
53 | | |
54 | | /* round up */ |
55 | 0 | left = dst_length; |
56 | |
|
57 | 0 | while (left > 0) { |
58 | 0 | if (started == 0) { /* A(0) */ |
59 | 0 | update(mac_ctx, label_size, |
60 | 0 | (const uint8_t *)label); /* hash label */ |
61 | 0 | update(mac_ctx, seed_size, seed); |
62 | 0 | started = 1; |
63 | 0 | } else { |
64 | 0 | update(mac_ctx, digest_size, Atmp); |
65 | 0 | } |
66 | 0 | digest(mac_ctx, digest_size, Atmp); /* store A(i) */ |
67 | |
|
68 | 0 | update(mac_ctx, digest_size, Atmp); /* hash A(i) */ |
69 | 0 | update(mac_ctx, label_size, |
70 | 0 | (const uint8_t *)label); /* hash label */ |
71 | 0 | update(mac_ctx, seed_size, seed); /* hash seed */ |
72 | |
|
73 | 0 | if (left < (ssize_t)digest_size) |
74 | 0 | digest_size = left; |
75 | |
|
76 | 0 | digest(mac_ctx, digest_size, dst); |
77 | |
|
78 | 0 | left -= digest_size; |
79 | 0 | dst += digest_size; |
80 | 0 | } |
81 | |
|
82 | 0 | return; |
83 | 0 | } |
84 | | |
85 | | int tls10_prf(size_t secret_size, const uint8_t *secret, size_t label_size, |
86 | | const char *label, size_t seed_size, const uint8_t *seed, |
87 | | size_t length, uint8_t *dst) |
88 | 0 | { |
89 | 0 | int l_s; |
90 | 0 | const uint8_t *s1, *s2; |
91 | 0 | struct hmac_md5_ctx md5_ctx; |
92 | 0 | struct hmac_sha1_ctx sha1_ctx; |
93 | 0 | uint8_t o1[MAX_PRF_BYTES]; |
94 | |
|
95 | 0 | if (length > MAX_PRF_BYTES) |
96 | 0 | return 0; |
97 | | |
98 | 0 | l_s = secret_size / 2; |
99 | 0 | s1 = &secret[0]; |
100 | 0 | s2 = &secret[l_s]; |
101 | 0 | if (secret_size % 2 != 0) { |
102 | 0 | l_s++; |
103 | 0 | } |
104 | |
|
105 | 0 | hmac_md5_set_key(&md5_ctx, l_s, s1); |
106 | |
|
107 | 0 | P_hash(&md5_ctx, (nettle_hash_update_func *)hmac_md5_update, |
108 | 0 | (nettle_hash_digest_func *)hmac_md5_digest, MD5_DIGEST_SIZE, |
109 | 0 | seed_size, seed, label_size, label, length, o1); |
110 | |
|
111 | 0 | hmac_sha1_set_key(&sha1_ctx, l_s, s2); |
112 | |
|
113 | 0 | P_hash(&sha1_ctx, (nettle_hash_update_func *)hmac_sha1_update, |
114 | 0 | (nettle_hash_digest_func *)hmac_sha1_digest, SHA1_DIGEST_SIZE, |
115 | 0 | seed_size, seed, label_size, label, length, dst); |
116 | |
|
117 | 0 | memxor(dst, o1, length); |
118 | |
|
119 | 0 | return 1; |
120 | 0 | } |
121 | | |
122 | | /*- |
123 | | * tls12_prf: |
124 | | * @mac_ctx: a MAC context initialized with key being the secret |
125 | | * @update: a MAC update function |
126 | | * @digest: a MAC digest function |
127 | | * @digest_size: the MAC output size |
128 | | * @label_size: the size of the label |
129 | | * @label: the label to apply |
130 | | * @seed_size: the seed size |
131 | | * @seed: the seed |
132 | | * @length: size of desired PRF output |
133 | | * @dst: the location to store output |
134 | | * |
135 | | * The TLS 1.2 Pseudo-Random-Function (PRF). |
136 | | * |
137 | | * Returns: zero on failure, non zero on success. |
138 | | -*/ |
139 | | int tls12_prf(void *mac_ctx, nettle_hash_update_func *update, |
140 | | nettle_hash_digest_func *digest, size_t digest_size, |
141 | | size_t label_size, const char *label, size_t seed_size, |
142 | | const uint8_t *seed, size_t length, uint8_t *dst) |
143 | 0 | { |
144 | 0 | #define MASTER_SECRET "master secret" |
145 | 0 | #define MASTER_SECRET_SIZE (sizeof(MASTER_SECRET) - 1) |
146 | |
|
147 | 0 | P_hash(mac_ctx, update, digest, digest_size, seed_size, seed, |
148 | 0 | label_size, label, length, dst); |
149 | | |
150 | | /* Since May 16, 2023, the use of extended master secret is |
151 | | * mandatory according to FIPS 140-3 IG D.Q. Instead of |
152 | | * allowing the "extended master secret" label specifically, |
153 | | * we mark the use of non-EMS label, i.e., "master secret" as |
154 | | * non-approved, because it is still useful to call the |
155 | | * gnutls_prf_raw function with arbitrary label, e.g., in |
156 | | * self-tests. |
157 | | */ |
158 | 0 | if (label_size == MASTER_SECRET_SIZE && |
159 | 0 | memcmp(label, MASTER_SECRET, MASTER_SECRET_SIZE) == 0) { |
160 | 0 | _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED); |
161 | 0 | } else { |
162 | 0 | _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED); |
163 | 0 | } |
164 | |
|
165 | 0 | return 1; |
166 | 0 | } |