Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ignore_mdc_error flag setter and getter #180

Merged
merged 2 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ coverage
Gemfile.lock
/tmp/*
/ports/*
.byebug_history
84 changes: 84 additions & 0 deletions ext/gpgme/gpgme_n.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,46 @@ rb_s_gpgme_release (VALUE dummy, VALUE vctx)
return Qnil;
}

static VALUE
rb_s_gpgme_set_ctx_flag (VALUE dummy, VALUE vctx, VALUE vname, VALUE vstr)
{
gpgme_ctx_t ctx;
gpgme_error_t err;
char* name;
char* str;

name = StringValueCStr(vname);
str = StringValueCStr(vstr);

UNWRAP_GPGME_CTX(vctx, ctx);
if (!ctx)
rb_raise (rb_eArgError, "released ctx");

err = gpgme_set_ctx_flag(ctx, name, str);
return LONG2NUM(err);
}

static VALUE
rb_s_gpgme_get_ctx_flag (VALUE dummy, VALUE vctx, VALUE vname)
{
gpgme_ctx_t ctx;
const char* name;
int yes;

name = StringValueCStr(vname);

UNWRAP_GPGME_CTX(vctx, ctx);
if (!ctx)
rb_raise (rb_eArgError, "released ctx");

const char* result;
result = gpgme_get_ctx_flag(ctx, name);
if (result == NULL)
rb_raise (rb_eArgError, "incorrect ctx flag name");

return rb_str_new_cstr(result);
}

static VALUE
rb_s_gpgme_set_protocol (VALUE dummy, VALUE vctx, VALUE vproto)
{
Expand Down Expand Up @@ -566,6 +606,42 @@ rb_s_gpgme_get_armor (VALUE dummy, VALUE vctx)
return INT2FIX(yes);
}

static VALUE
rb_s_gpgme_set_ignore_mdc_error (VALUE dummy, VALUE vctx, VALUE vyes)
{
gpgme_ctx_t ctx;
gpgme_error_t err;
int yes;

yes = NUM2INT(vyes);

UNWRAP_GPGME_CTX(vctx, ctx);
if (!ctx)
rb_raise (rb_eArgError, "released ctx");

err = gpgme_set_ctx_flag(ctx, "ignore-mdc-error", yes ? "1" : "");
return LONG2NUM(err);
}

static VALUE
rb_s_gpgme_get_ignore_mdc_error (VALUE dummy, VALUE vctx)
{
gpgme_ctx_t ctx;
int yes;

UNWRAP_GPGME_CTX(vctx, ctx);
if (!ctx)
rb_raise (rb_eArgError, "released ctx");

const char* result;
result = gpgme_get_ctx_flag(ctx, "ignore-mdc-error");
if (result == NULL)
rb_raise (rb_eArgError, "incorrect ctx flag name");

yes = (result && *result)? !!atoi (result) : 0;
return INT2FIX(yes);
}

static VALUE
rb_s_gpgme_set_textmode (VALUE dummy, VALUE vctx, VALUE vyes)
{
Expand Down Expand Up @@ -2373,6 +2449,10 @@ Init_gpgme_n (void)
rb_s_gpgme_release, 1);

/* Context Attributes */
rb_define_module_function (mGPGME, "gpgme_set_ctx_flag",
rb_s_gpgme_set_ctx_flag, 3);
rb_define_module_function (mGPGME, "gpgme_get_ctx_flag",
rb_s_gpgme_get_ctx_flag, 2);
rb_define_module_function (mGPGME, "gpgme_set_protocol",
rb_s_gpgme_set_protocol, 2);
rb_define_module_function (mGPGME, "gpgme_get_protocol",
Expand All @@ -2381,6 +2461,10 @@ Init_gpgme_n (void)
rb_s_gpgme_set_armor, 2);
rb_define_module_function (mGPGME, "gpgme_get_armor",
rb_s_gpgme_get_armor, 1);
rb_define_module_function (mGPGME, "gpgme_set_ignore_mdc_error",
rb_s_gpgme_set_ignore_mdc_error, 2);
rb_define_module_function (mGPGME, "gpgme_get_ignore_mdc_error",
rb_s_gpgme_get_ignore_mdc_error, 1);
rb_define_module_function (mGPGME, "gpgme_set_textmode",
rb_s_gpgme_set_textmode, 2);
rb_define_module_function (mGPGME, "gpgme_get_textmode",
Expand Down
66 changes: 60 additions & 6 deletions lib/gpgme/ctx.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ def self.new(options = {})
raise exc if exc
ctx = rctx[0]

ctx.protocol = options[:protocol] if options[:protocol]
ctx.armor = options[:armor] if options[:armor]
ctx.textmode = options[:textmode] if options[:textmode]
ctx.keylist_mode = options[:keylist_mode] if options[:keylist_mode]
ctx.pinentry_mode = options[:pinentry_mode] if options[:pinentry_mode]
ctx.offline = options[:offline] if options[:offline]
ctx.protocol = options[:protocol] if options[:protocol]
ctx.armor = options[:armor] if options[:armor]
ctx.textmode = options[:textmode] if options[:textmode]
ctx.keylist_mode = options[:keylist_mode] if options[:keylist_mode]
ctx.pinentry_mode = options[:pinentry_mode] if options[:pinentry_mode]
ctx.offline = options[:offline] if options[:offline]
ctx.ignore_mdc_error = options[:ignore_mdc_error] if options[:ignore_mdc_error]

if options[:password]
ctx.set_passphrase_callback GPGME::Ctx.method(:pass_function),
Expand Down Expand Up @@ -103,6 +104,43 @@ def release
# Getters and setters
##

# Get the value of the Ctx flag with the given name.
#
# Allowed flag names may include:
# - 'redraw'
# - 'full-status'
# - 'raw-description'
# - 'export-session-key'
# - 'override-session-key'
# - 'include-key-block'
# - 'auto-key-import'
# - 'auto-key-retrieve'
# - 'request-origin'
# - 'no-symkey-cache'
# - 'ignore-mdc-error'
# - 'auto-key-locate'
# - 'trust-model'
# - 'extended-edit'
# - 'cert-expire'
# - 'key-origin'
# - 'import-filter'
# - 'no-auto-check-trustdb'
#
# Please consult the GPGPME documentation for more details
#
def get_ctx_flag(flag_name)
GPGME::gpgme_get_ctx_flag(self, flag_name.to_s)
end

# Set the Ctx flag with the given name
# to the given value.
def set_ctx_flag(flag_name, val)
err = GPGME::gpgme_set_ctx_flag(self, flag_name.to_s, val.to_s)
exc = GPGME::error_to_exception(err)
raise exc if exc
val
end

# Set the +protocol+ used within this context. See {GPGME::Ctx.new} for
# possible values.
def protocol=(proto)
Expand All @@ -128,6 +166,22 @@ def armor
GPGME::gpgme_get_armor(self) == 1 ? true : false
end

# This option ignores a MDC integrity protection failure.
# It is required to decrypt old messages which did not use an MDC.
# It may also be useful if a message is partially garbled,
# but it is necessary to get as much data as possible out of that garbled message.
# Be aware that a missing or failed MDC can be an indication of an attack.
# Use with great caution.
def ignore_mdc_error=(yes)
GPGME::gpgme_set_ignore_mdc_error(self, yes ? 1 : 0)
yes
end

# Return true if the MDC integrity protection is disabled.
def ignore_mdc_error
GPGME::gpgme_get_ignore_mdc_error(self) == 1 ? true : false
end

# Tell whether canonical text mode should be used.
def textmode=(yes)
GPGME::gpgme_set_textmode(self, yes ? 1 : 0)
Expand Down
94 changes: 94 additions & 0 deletions test/ctx_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,70 @@
end
end

describe :get_ctx_flag do
it "reads flags with getters and setters" do
ctx = GPGME::Ctx.new

refute ctx.ignore_mdc_error
assert_equal "", ctx.get_ctx_flag("ignore-mdc-error")

ctx.ignore_mdc_error = true

assert ctx.ignore_mdc_error
assert_equal "1", ctx.get_ctx_flag("ignore-mdc-error")
end

it "can get flags without getters and setters" do
ctx = GPGME::Ctx.new

assert_equal "", ctx.get_ctx_flag("auto-key-locate")
ctx.set_ctx_flag("auto-key-locate", "cert")
assert_equal "cert", ctx.get_ctx_flag("auto-key-locate")
end

it "raises an error when a flag doesn't exist" do
ctx = GPGME::Ctx.new

assert_raises ArgumentError do
ctx.get_ctx_flag("foo")
end
end
end

describe :set_ctx_flag do
it "sets the value for a flag with a getter" do
ctx = GPGME::Ctx.new
refute ctx.ignore_mdc_error

ctx.set_ctx_flag("ignore-mdc-error", "1")
assert ctx.ignore_mdc_error
end

it "unsets the value for a flag with a getter" do
ctx = GPGME::Ctx.new(ignore_mdc_error: true)
assert ctx.ignore_mdc_error

ctx.set_ctx_flag("ignore-mdc-error", "0")
refute ctx.ignore_mdc_error
end

it "can set flags without getters and setters" do
ctx = GPGME::Ctx.new

assert_equal "", ctx.get_ctx_flag("auto-key-locate")
ctx.set_ctx_flag("auto-key-locate", "cert")
assert_equal "cert", ctx.get_ctx_flag("auto-key-locate")
end

it "raises an error when a flag doesn't exist" do
ctx = GPGME::Ctx.new

assert_raises GPGME::Error do
ctx.set_ctx_flag("foo", "bar")
end
end
end

describe :armor do
it "sets false by default" do
ctx = GPGME::Ctx.new
Expand All @@ -101,6 +165,36 @@
end
end

describe :ignore_mdc_error do
it "sets false by default" do
ctx = GPGME::Ctx.new
refute ctx.ignore_mdc_error
end

it "can set" do
ctx = GPGME::Ctx.new

ctx.ignore_mdc_error = true
assert ctx.ignore_mdc_error
end

it "can unset" do
ctx = GPGME::Ctx.new(ignore_mdc_error: true)
assert ctx.ignore_mdc_error

ctx.ignore_mdc_error = false
refute ctx.ignore_mdc_error
end

it "can set and get in constructor" do
ctx = GPGME::Ctx.new(:ignore_mdc_error => false)
refute ctx.ignore_mdc_error

ctx = GPGME::Ctx.new(:ignore_mdc_error => true)
assert ctx.ignore_mdc_error
end
end

describe :protocol do
it "sets 0 by default" do
ctx = GPGME::Ctx.new
Expand Down