-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Add support for getting/setting GCM authentication tag (fixes #115) #201
Conversation
|
||
luaL_buffinit(L, &tag); | ||
|
||
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_size, (void*)luaL_prepbuffsize(&tag, tag_size))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When was EVP_CIPHER_CTX_ctrl
introduced? luaossl still tries to be compatible with old openssl versions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it's been around a "long time". I don't know if it was in 0.9.8 (I can dig if really necessary), but it's certainly in 1.0.2. It's due to be retired post-3.0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's due to be retired post-3.0.
What is it going to be replaced with?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A new OSSL_PARAM
API they've introduced. I haven't looked too much into it so far, as I haven't been working on any code that can be 3.0.x-only just yet.
@@ -11975,6 +11975,47 @@ static int cipher_final(lua_State *L) { | |||
} /* cipher_final() */ | |||
|
|||
|
|||
static int cipher_get_tag(lua_State *L) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be cipher_gcm_get_tag
or similar to follow the naming of the option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly. It's actually not unique to GCM, but to the family of AEAD modes - in OpenSSL this includes CCM. In 1.1.x there is now therefore an alias for EVP_CTRL_AEAD_GET_TAG
but this constant is not defined in 1.0.x. The current code should work with both GCM and CCM.
If we change the name, we could call it e.g. :get_aead_tag()
, but I don't know whether this level of disambiguation is necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be sensible to use EVP_CIPHER_type
to get the type of the cipher and then use the relevant constant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. As I mentioned, modern versions of OpenSSL have both CCM_GET_TAG and GCM_GET_TAG aliased to AEAD_GET_TAG
. The latter was added in 1.1, but before this the CCM variant was an alias of GCM_GET_TAG anyway.
In summary: in old versions, GCM_GET_TAG
and CCM_GET_TAG
are interchangeable identifiers for the same operation. In newer versions (1.1+) AEAD_GET_TAG
was added as a generic identifier for this operation.
References:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a comment saying as much?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added in 4a8b770
The following code snippet can be used to test GCM encryption (it's based on the code originally posted as broken in #115): local cipher = require "openssl.cipher"
local key = "abcdefghijklmnopabcdefghijklmnop"
local iv = "123456123456"
local message = "My secret message"
local c = cipher.new("aes-256-gcm"):encrypt(key, iv);
local encrypted = c:update(message)
assert(c:final());
local tag = assert(c:getTag(16));
print("Encrypted to "..#encrypted.." bytes with "..#tag.."-byte tag");
-- Now for the decryption
local aes = cipher.new("aes-256-gcm"):decrypt(key, iv)
-- Provide the expected authentication tag to OpenSSL
aes:setTag(tag);
local decrypted = aes:update(encrypted)
print(decrypted)
print(aes:final()) CCM can be tested by changing |
Could you add this as a regression test? |
Regression test added in e402818 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of nits; otherwise LGTM.
src/openssl.c
Outdated
{ "getTag", &cipher_get_tag }, | ||
{ "setTag", &cipher_set_tag }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These need whitespace for alignment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 0dad2b3
src/openssl.c
Outdated
auxL_pusherror(L, auxL_EOPENSSL, NULL); | ||
|
||
return 2; | ||
} /* cipher_get_tag() */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} /* cipher_get_tag() */ | |
} /* cipher_set_tag() */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 0dad2b3
Merged with bed73b6 |
@mwild1 I'm only running your regression tests now, and I get:
|
Well that's interesting. The test passes fine for me as-is. If I change the IV length to 7, I get:
This is with OpenSSL 1.1.1. Although I can't find it now, I vaguely recall some documentation that indicated the iv_length() function was not reliable for ciphers that accept IVs of variable/multiple lengths. My guess is that maybe the default IV length has changed between versions. Out of curiosity, what version was your result with? Some further reading:
So in 1.1.1+ if we explicitly set the IV length (which might be sensible anyway if the default varies between versions) then this issue should go away. But if we want backwards-compatibility with pre-1.1.1, I guess we need to skip this check for these ciphers. |
Me too:
I'm running new enough that the fix you mentioned should be in. I guess it's something else... |
oh; I only just noticed the line number in the stack trace: the error moves from 36 to 31 when the IV changes length. So I guess for |
Yeah, I made these changes for testing:
|
See #115 (comment) for context.