diff options
| author | tb <> | 2026-08-27 07:13:34 +0000 |
|---|---|---|
| committer | tb <> | 2026-08-27 07:13:34 +0000 |
| commit | 448d7a6a510aab5c772d736a43fb5dcec9dfbd73 (patch) | |
| tree | f67eb62142f9922c5c57ea2a3c58dadbee783beb /src | |
| parent | 85f442b9807a72de444e8a0c8670310031ffd5e8 (diff) | |
| download | openbsd-448d7a6a510aab5c772d736a43fb5dcec9dfbd73.tar.gz openbsd-448d7a6a510aab5c772d736a43fb5dcec9dfbd73.tar.bz2 openbsd-448d7a6a510aab5c772d736a43fb5dcec9dfbd73.zip | |
libcrypto: harden cms_kek_cipher() a bit
When AES key unwrap with padding is in use, the EVP interface breaks its
contract and writes more than the outlen it initially reports to the output
buffer. This is an old, sneaky trap that the muppet set eons ago and many
victims walked right into it, including the muppet himself.
If inlen is larger than outlen, allocate inlen bytes to unwrap with padding
to avoid a buffer overwrite. This is a variant of OpenSSL's fix. Since we
do not support AES keywrap with padding no actual bufer overwrite occurs
here at the moment, but if we ever chose to do so (unlikely) this trap
would be avoided. There's plenty more traps that the next round of scas
will surely find in this absolute trashfire of CMS support code.
ok kenjiro
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/cms/cms_kari.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/src/lib/libcrypto/cms/cms_kari.c b/src/lib/libcrypto/cms/cms_kari.c index c23da18058..a16f51a569 100644 --- a/src/lib/libcrypto/cms/cms_kari.c +++ b/src/lib/libcrypto/cms/cms_kari.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: cms_kari.c,v 1.18 2025/05/10 05:54:38 tb Exp $ */ | 1 | /* $OpenBSD: cms_kari.c,v 1.19 2026/08/27 07:13:34 tb Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 3 | * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
| 4 | * project. | 4 | * project. |
| @@ -250,6 +250,7 @@ cms_kek_cipher(unsigned char **pout, size_t *poutlen, const unsigned char *in, | |||
| 250 | size_t keklen; | 250 | size_t keklen; |
| 251 | int rv = 0; | 251 | int rv = 0; |
| 252 | unsigned char *out = NULL; | 252 | unsigned char *out = NULL; |
| 253 | size_t outsize = 0; | ||
| 253 | int outlen; | 254 | int outlen; |
| 254 | 255 | ||
| 255 | keklen = EVP_CIPHER_CTX_key_length(kari->ctx); | 256 | keklen = EVP_CIPHER_CTX_key_length(kari->ctx); |
| @@ -264,7 +265,11 @@ cms_kek_cipher(unsigned char **pout, size_t *poutlen, const unsigned char *in, | |||
| 264 | /* obtain output length of ciphered key */ | 265 | /* obtain output length of ciphered key */ |
| 265 | if (!EVP_CipherUpdate(kari->ctx, NULL, &outlen, in, inlen)) | 266 | if (!EVP_CipherUpdate(kari->ctx, NULL, &outlen, in, inlen)) |
| 266 | goto err; | 267 | goto err; |
| 267 | out = malloc(outlen); | 268 | |
| 269 | outsize = outlen; | ||
| 270 | if (outsize < inlen) | ||
| 271 | outsize = inlen; | ||
| 272 | out = malloc(outsize); | ||
| 268 | if (out == NULL) | 273 | if (out == NULL) |
| 269 | goto err; | 274 | goto err; |
| 270 | if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, inlen)) | 275 | if (!EVP_CipherUpdate(kari->ctx, out, &outlen, in, inlen)) |
| @@ -276,7 +281,7 @@ cms_kek_cipher(unsigned char **pout, size_t *poutlen, const unsigned char *in, | |||
| 276 | err: | 281 | err: |
| 277 | explicit_bzero(kek, keklen); | 282 | explicit_bzero(kek, keklen); |
| 278 | if (!rv) | 283 | if (!rv) |
| 279 | free(out); | 284 | freezero(out, outsize); |
| 280 | (void)EVP_CIPHER_CTX_reset(kari->ctx); | 285 | (void)EVP_CIPHER_CTX_reset(kari->ctx); |
| 281 | /* FIXME: WHY IS kari->pctx freed here? /RL */ | 286 | /* FIXME: WHY IS kari->pctx freed here? /RL */ |
| 282 | EVP_PKEY_CTX_free(kari->pctx); | 287 | EVP_PKEY_CTX_free(kari->pctx); |
