diff options
| author | tb <> | 2026-01-01 13:36:09 +0000 |
|---|---|---|
| committer | tb <> | 2026-01-01 13:36:09 +0000 |
| commit | 2f3ff374dcb9558a8165a6b1cf17cc024522a212 (patch) | |
| tree | 2e89d7bda538c32322ff1fabe1804b21093d0439 /src | |
| parent | 10bebbca92ef87af97bc15c6337afbbe050bb96e (diff) | |
| download | openbsd-2f3ff374dcb9558a8165a6b1cf17cc024522a212.tar.gz openbsd-2f3ff374dcb9558a8165a6b1cf17cc024522a212.tar.bz2 openbsd-2f3ff374dcb9558a8165a6b1cf17cc024522a212.zip | |
mlkem: clear a few (pointers to) secrets
The ML-KEM code is doing a pretty poor job at cleaning up secrets it no
longer needs. This commit clears a few stack-based arrays containing
secrets or not obviously public information and stack-based structs
containing pointers to secrets.
ok jsing kenjiro
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/mlkem/mlkem.c | 14 | ||||
| -rw-r--r-- | src/lib/libcrypto/mlkem/mlkem_internal.c | 46 |
2 files changed, 47 insertions, 13 deletions
diff --git a/src/lib/libcrypto/mlkem/mlkem.c b/src/lib/libcrypto/mlkem/mlkem.c index 006937c39d..2f3f3c23e4 100644 --- a/src/lib/libcrypto/mlkem/mlkem.c +++ b/src/lib/libcrypto/mlkem/mlkem.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: mlkem.c,v 1.5 2026/01/01 12:47:52 tb Exp $ */ | 1 | /* $OpenBSD: mlkem.c,v 1.6 2026/01/01 13:36:09 tb Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2025, Bob Beck <beck@obtuse.com> | 3 | * Copyright (c) 2025, Bob Beck <beck@obtuse.com> |
| 4 | * | 4 | * |
| @@ -14,9 +14,12 @@ | |||
| 14 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | 14 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 15 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 15 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 16 | */ | 16 | */ |
| 17 | |||
| 17 | #include <stdlib.h> | 18 | #include <stdlib.h> |
| 19 | #include <string.h> | ||
| 18 | 20 | ||
| 19 | #include <openssl/mlkem.h> | 21 | #include <openssl/mlkem.h> |
| 22 | |||
| 20 | #include "mlkem_internal.h" | 23 | #include "mlkem_internal.h" |
| 21 | 24 | ||
| 22 | static inline int | 25 | static inline int |
| @@ -229,11 +232,14 @@ MLKEM_encap(const MLKEM_public_key *public_key, | |||
| 229 | uint8_t **out_shared_secret, size_t *out_shared_secret_len) | 232 | uint8_t **out_shared_secret, size_t *out_shared_secret_len) |
| 230 | { | 233 | { |
| 231 | uint8_t entropy[MLKEM_ENCAP_ENTROPY]; | 234 | uint8_t entropy[MLKEM_ENCAP_ENTROPY]; |
| 235 | int ret; | ||
| 232 | 236 | ||
| 233 | arc4random_buf(entropy, MLKEM_ENCAP_ENTROPY); | 237 | arc4random_buf(entropy, sizeof(entropy)); |
| 234 | 238 | ret = MLKEM_encap_external_entropy(public_key, entropy, out_ciphertext, | |
| 235 | return MLKEM_encap_external_entropy(public_key, entropy, out_ciphertext, | ||
| 236 | out_ciphertext_len, out_shared_secret, out_shared_secret_len); | 239 | out_ciphertext_len, out_shared_secret, out_shared_secret_len); |
| 240 | explicit_bzero(entropy, sizeof(entropy)); | ||
| 241 | |||
| 242 | return ret; | ||
| 237 | } | 243 | } |
| 238 | LCRYPTO_ALIAS(MLKEM_encap); | 244 | LCRYPTO_ALIAS(MLKEM_encap); |
| 239 | 245 | ||
diff --git a/src/lib/libcrypto/mlkem/mlkem_internal.c b/src/lib/libcrypto/mlkem/mlkem_internal.c index 903b1ea2a3..c8305bb0d9 100644 --- a/src/lib/libcrypto/mlkem/mlkem_internal.c +++ b/src/lib/libcrypto/mlkem/mlkem_internal.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: mlkem_internal.c,v 1.4 2026/01/01 12:47:52 tb Exp $ */ | 1 | /* $OpenBSD: mlkem_internal.c,v 1.5 2026/01/01 13:36:09 tb Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2024, Google Inc. | 3 | * Copyright (c) 2024, Google Inc. |
| 4 | * Copyright (c) 2024, 2025 Bob Beck <beck@obtuse.com> | 4 | * Copyright (c) 2024, 2025 Bob Beck <beck@obtuse.com> |
| @@ -887,10 +887,14 @@ mlkem_generate_key(uint8_t *out_encoded_public_key, | |||
| 887 | uint8_t entropy_buf[MLKEM_SEED_LENGTH]; | 887 | uint8_t entropy_buf[MLKEM_SEED_LENGTH]; |
| 888 | uint8_t *entropy = optional_out_seed != NULL ? optional_out_seed : | 888 | uint8_t *entropy = optional_out_seed != NULL ? optional_out_seed : |
| 889 | entropy_buf; | 889 | entropy_buf; |
| 890 | int ret; | ||
| 890 | 891 | ||
| 891 | arc4random_buf(entropy, MLKEM_SEED_LENGTH); | 892 | arc4random_buf(entropy, MLKEM_SEED_LENGTH); |
| 892 | return mlkem_generate_key_external_entropy(out_encoded_public_key, | 893 | ret = mlkem_generate_key_external_entropy(out_encoded_public_key, |
| 893 | out_private_key, entropy); | 894 | out_private_key, entropy); |
| 895 | explicit_bzero(entropy_buf, sizeof(entropy_buf)); | ||
| 896 | |||
| 897 | return ret; | ||
| 894 | } | 898 | } |
| 895 | 899 | ||
| 896 | int | 900 | int |
| @@ -978,6 +982,10 @@ mlkem_generate_key_external_entropy(uint8_t *out_encoded_public_key, | |||
| 978 | 982 | ||
| 979 | err: | 983 | err: |
| 980 | CBB_cleanup(&cbb); | 984 | CBB_cleanup(&cbb); |
| 985 | explicit_bzero(&priv, sizeof(priv)); | ||
| 986 | explicit_bzero(augmented_seed, sizeof(augmented_seed)); | ||
| 987 | explicit_bzero(error, sizeof(error)); | ||
| 988 | explicit_bzero(hashed, sizeof(hashed)); | ||
| 981 | 989 | ||
| 982 | return ret; | 990 | return ret; |
| 983 | } | 991 | } |
| @@ -1042,6 +1050,11 @@ encrypt_cpa(uint8_t *out, const struct public_key *pub, | |||
| 1042 | vector_encode(out, &u[0], u_bits, rank); | 1050 | vector_encode(out, &u[0], u_bits, rank); |
| 1043 | scalar_compress(&v, v_bits); | 1051 | scalar_compress(&v, v_bits); |
| 1044 | scalar_encode(out + compressed_vector_size(rank), &v, v_bits); | 1052 | scalar_encode(out + compressed_vector_size(rank), &v, v_bits); |
| 1053 | |||
| 1054 | explicit_bzero(secret, sizeof(secret)); | ||
| 1055 | explicit_bzero(error, sizeof(error)); | ||
| 1056 | explicit_bzero(u, sizeof(u)); | ||
| 1057 | explicit_bzero(input, sizeof(input)); | ||
| 1045 | } | 1058 | } |
| 1046 | 1059 | ||
| 1047 | /* Calls mlkem_encap_external_entropy| with random bytes */ | 1060 | /* Calls mlkem_encap_external_entropy| with random bytes */ |
| @@ -1055,6 +1068,7 @@ mlkem_encap(const MLKEM_public_key *public_key, | |||
| 1055 | arc4random_buf(entropy, MLKEM_ENCAP_ENTROPY); | 1068 | arc4random_buf(entropy, MLKEM_ENCAP_ENTROPY); |
| 1056 | mlkem_encap_external_entropy(out_ciphertext, | 1069 | mlkem_encap_external_entropy(out_ciphertext, |
| 1057 | out_shared_secret, public_key, entropy); | 1070 | out_shared_secret, public_key, entropy); |
| 1071 | explicit_bzero(entropy, sizeof(entropy)); | ||
| 1058 | } | 1072 | } |
| 1059 | 1073 | ||
| 1060 | /* See section 6.2 of the spec. */ | 1074 | /* See section 6.2 of the spec. */ |
| @@ -1076,6 +1090,9 @@ mlkem_encap_external_entropy(uint8_t *out_ciphertext, | |||
| 1076 | encrypt_cpa(out_ciphertext, &pub, entropy, key_and_randomness + 32, | 1090 | encrypt_cpa(out_ciphertext, &pub, entropy, key_and_randomness + 32, |
| 1077 | public_key->rank); | 1091 | public_key->rank); |
| 1078 | memcpy(out_shared_secret, key_and_randomness, 32); | 1092 | memcpy(out_shared_secret, key_and_randomness, 32); |
| 1093 | |||
| 1094 | explicit_bzero(key_and_randomness, sizeof(key_and_randomness)); | ||
| 1095 | explicit_bzero(input, sizeof(input)); | ||
| 1079 | } | 1096 | } |
| 1080 | 1097 | ||
| 1081 | static void | 1098 | static void |
| @@ -1101,6 +1118,8 @@ decrypt_cpa(uint8_t out[32], const struct private_key *priv, | |||
| 1101 | scalar_sub(&v, &mask); | 1118 | scalar_sub(&v, &mask); |
| 1102 | scalar_compress(&v, 1); | 1119 | scalar_compress(&v, 1); |
| 1103 | scalar_encode_1(out, &v); | 1120 | scalar_encode_1(out, &v); |
| 1121 | |||
| 1122 | explicit_bzero(u, sizeof(u)); | ||
| 1104 | } | 1123 | } |
| 1105 | 1124 | ||
| 1106 | /* See section 6.3 */ | 1125 | /* See section 6.3 */ |
| @@ -1149,6 +1168,8 @@ mlkem_decap(const MLKEM_private_key *private_key, const uint8_t *ciphertext, | |||
| 1149 | 1168 | ||
| 1150 | err: | 1169 | err: |
| 1151 | freezero(expected_ciphertext, expected_ciphertext_length); | 1170 | freezero(expected_ciphertext, expected_ciphertext_length); |
| 1171 | explicit_bzero(key_and_randomness, sizeof(key_and_randomness)); | ||
| 1172 | explicit_bzero(decrypted, sizeof(decrypted)); | ||
| 1152 | 1173 | ||
| 1153 | return ret; | 1174 | return ret; |
| 1154 | } | 1175 | } |
| @@ -1249,6 +1270,7 @@ mlkem_marshal_private_key(const MLKEM_private_key *private_key, | |||
| 1249 | 1270 | ||
| 1250 | err: | 1271 | err: |
| 1251 | CBB_cleanup(&cbb); | 1272 | CBB_cleanup(&cbb); |
| 1273 | explicit_bzero(&priv, sizeof(priv)); | ||
| 1252 | 1274 | ||
| 1253 | return ret; | 1275 | return ret; |
| 1254 | } | 1276 | } |
| @@ -1259,28 +1281,34 @@ mlkem_parse_private_key(const uint8_t *input, size_t input_len, | |||
| 1259 | { | 1281 | { |
| 1260 | struct private_key priv; | 1282 | struct private_key priv; |
| 1261 | CBS cbs, s_bytes; | 1283 | CBS cbs, s_bytes; |
| 1284 | int ret = 0; | ||
| 1262 | 1285 | ||
| 1263 | private_key_from_external(out_private_key, &priv); | 1286 | private_key_from_external(out_private_key, &priv); |
| 1264 | CBS_init(&cbs, input, input_len); | 1287 | CBS_init(&cbs, input, input_len); |
| 1265 | 1288 | ||
| 1266 | if (!CBS_get_bytes(&cbs, &s_bytes, | 1289 | if (!CBS_get_bytes(&cbs, &s_bytes, |
| 1267 | encoded_vector_size(out_private_key->rank))) | 1290 | encoded_vector_size(out_private_key->rank))) |
| 1268 | return 0; | 1291 | goto err; |
| 1269 | if (!vector_decode(priv.s, CBS_data(&s_bytes), kLog2Prime, | 1292 | if (!vector_decode(priv.s, CBS_data(&s_bytes), kLog2Prime, |
| 1270 | out_private_key->rank)) | 1293 | out_private_key->rank)) |
| 1271 | return 0; | 1294 | goto err; |
| 1272 | if (!mlkem_parse_public_key_no_hash(&priv.pub, &cbs, | 1295 | if (!mlkem_parse_public_key_no_hash(&priv.pub, &cbs, |
| 1273 | out_private_key->rank)) | 1296 | out_private_key->rank)) |
| 1274 | return 0; | 1297 | goto err; |
| 1275 | 1298 | ||
| 1276 | memcpy(priv.pub.public_key_hash, CBS_data(&cbs), 32); | 1299 | memcpy(priv.pub.public_key_hash, CBS_data(&cbs), 32); |
| 1277 | if (!CBS_skip(&cbs, 32)) | 1300 | if (!CBS_skip(&cbs, 32)) |
| 1278 | return 0; | 1301 | goto err; |
| 1279 | memcpy(priv.fo_failure_secret, CBS_data(&cbs), 32); | 1302 | memcpy(priv.fo_failure_secret, CBS_data(&cbs), 32); |
| 1280 | if (!CBS_skip(&cbs, 32)) | 1303 | if (!CBS_skip(&cbs, 32)) |
| 1281 | return 0; | 1304 | goto err; |
| 1282 | if (CBS_len(&cbs) != 0) | 1305 | if (CBS_len(&cbs) != 0) |
| 1283 | return 0; | 1306 | goto err; |
| 1284 | 1307 | ||
| 1285 | return 1; | 1308 | ret = 1; |
| 1309 | |||
| 1310 | err: | ||
| 1311 | explicit_bzero(&priv, sizeof(priv)); | ||
| 1312 | |||
| 1313 | return ret; | ||
| 1286 | } | 1314 | } |
