Skip to content

Commit 90b287c

Browse files
committed
Fix AES-GCM decryption on OpenSSL 1.0.2-fips
Signed-off-by: Cory Snider <[email protected]>
1 parent 340f98f commit 90b287c

File tree

1 file changed

+29
-4
lines changed

1 file changed

+29
-4
lines changed

goopenssl.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,22 +144,47 @@ go_openssl_EVP_CIPHER_CTX_open_wrapper(const GO_EVP_CIPHER_CTX_PTR ctx,
144144
const unsigned char *aad, int aad_len,
145145
const unsigned char *tag)
146146
{
147-
if (in_len == 0) in = "";
147+
if (in_len == 0) {
148+
in = "";
149+
// When the caller only wants to verify authenticated additional data
150+
// (AAD), no output buffer is technically needed as there is no data to
151+
// decrypt. Unfortunately, AAD is specified by calling EVP_DecryptUpdate
152+
// with out set to NULL, so decrypting a zero-length input with a NULL
153+
// output buffer looks to OpenSSL like specifying an additional
154+
// (zero-length) chunk of AAD. This is effectively a no-op and
155+
// verification will proceed as expected, except for OpenSSL 1.0.2 in
156+
// FIPS mode. It will fail to verify unless EVP_DecryptUpdate is called
157+
// at least once with a non-NULL output buffer. OpenSSL will not
158+
// dereference the output buffer when the input length is zero, so set
159+
// it to an arbitrary non-NULL pointer to satisfy OpenSSL.
160+
//
161+
// While a stack-allocated buffer could be used, that would risk a
162+
// buffer overflow which would then smash the stack if OpenSSL
163+
// unexpectedly dereferenced it. Instead pass a value which would
164+
// trigger a segfault if dereferenced on any modern platform where a
165+
// NULL-pointer dereference would also segfault.
166+
if (out == NULL) out = (unsigned char *)1;
167+
}
148168
if (aad_len == 0) aad = "";
149169

150170
if (go_openssl_EVP_CipherInit_ex(ctx, NULL, NULL, NULL, nonce, GO_AES_DECRYPT) != 1)
151171
return 0;
152172

173+
// OpenSSL 1.0.x FIPS Object Module 2.0 versions below 2.0.5 require that
174+
// the tag be set before the ciphertext, otherwise EVP_DecryptUpdate returns
175+
// an error. At least one extant commercially-supported, FIPS validated
176+
// build of OpenSSL 1.0.2 uses FIPS module version 2.0.1. Set the tag first
177+
// to maximize compatibility with all OpenSSL version combinations.
178+
if (go_openssl_EVP_CIPHER_CTX_ctrl(ctx, GO_EVP_CTRL_GCM_SET_TAG, 16, (unsigned char *)(tag)) != 1)
179+
return 0;
180+
153181
int discard_len, out_len;
154182
if (go_openssl_EVP_DecryptUpdate(ctx, NULL, &discard_len, aad, aad_len) != 1
155183
|| go_openssl_EVP_DecryptUpdate(ctx, out, &out_len, in, in_len) != 1)
156184
{
157185
return 0;
158186
}
159187

160-
if (go_openssl_EVP_CIPHER_CTX_ctrl(ctx, GO_EVP_CTRL_GCM_SET_TAG, 16, (unsigned char *)(tag)) != 1)
161-
return 0;
162-
163188
if (go_openssl_EVP_DecryptFinal_ex(ctx, out + out_len, &discard_len) != 1)
164189
return 0;
165190

0 commit comments

Comments
 (0)