While trying to verify corrupted file signature, I used this code :
gpgme_ctx_t ctx;
gpgme_error_t err;
gpgme_data_t input_signed = NULL;
gpgme_data_t output_data = NULL;
gpgme_verify_result_t vresult;
ssize_t chars_read;
error = renson::error::kNoError;
try
{
// set the locale
setlocale(LC_ALL, "");
// check the GPG version
gpgme_check_version(NULL);
gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
// verify if OpenPGP is supported
err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
if (err)
{
LOG_ERROR("Error during gpgme_engine_check_version: " + std::string(gpgme_strerror(err)));
throw renson::error::kBadConfiguration;
}
// create the context for the GPGME operations
err = gpgme_new(&ctx);
if (err)
{
LOG_ERROR("Error during gpgme_new: " + std::string(gpgme_strerror(err)));
throw renson::error::kInvalidOperation;
}
// check if the input path is valid
if (!exists(input_file_path_))
{
LOG_ERROR("Given input file does not exist: " + input_file_path_.string());
throw renson::error::kWrongInputParam;
}
if (!is_regular_file(input_file_path_))
{
LOG_ERROR("Given input path is a directory, not a file: " + input_file_path_.string());
throw renson::error::kWrongInputParam;
}
if (!exists(output_path.parent_path()))
{
LOG_ERROR("Output directory does not exist for: " + output_path.parent_path().string());
throw renson::error::kWrongInputParam;
}
// open signed input file
err = gpgme_data_new_from_file(&input_signed, input_file_path_.string().c_str(), 1);
if (err)
{
LOG_ERROR("Error during gpgme_data_new_from_file on " + input_file_path_.string() + ": " + std::string(gpgme_strerror(err)));
throw renson::error::kWrongInputParam;
}
// create output data
err = gpgme_data_new(&output_data);
if (err)
{
LOG_ERROR("Error during gpgme_data_new: " + std::string(gpgme_strerror(err)));
throw renson::error::kInvalidOperation;
}
// call the actual verify call: "gpg --verify xxx.gpg"
err = gpgme_op_verify(ctx, input_signed, NULL, output_data);
if (err)
{
LOG_ERROR("Error during gpgme_op_verify: " + std::string(gpgme_strerror(err)));
throw renson::error::kFileSignatureError;
}
// interpret the result from gpg
vresult = gpgme_op_verify_result(ctx);
if (gpgme_err_code(vresult->signatures->status) != GPG_ERR_NO_ERROR)
{
LOG_ERROR("unexpected signature status: " + std::string(gpgme_strerror(vresult->signatures->status)));
throw renson::error::kFileSignatureError;
}
else if (vresult->signatures->next)
{
LOG_ERROR("unexpected number of signatures");
throw renson::error::kFileSignatureError;
}
else if (vresult->signatures->summary == GPGME_SIGSUM_RED)
{
LOG_ERROR("unexpected signature summary " + std::to_string(vresult->signatures->summary));
throw renson::error::kFileSignatureError;
}
else if (vresult->signatures->wrong_key_usage)
{
LOG_ERROR("unexpected wrong key usage");
throw renson::error::kFileSignatureError;
}
else if (gpgme_err_code(vresult->signatures->validity_reason) != GPG_ERR_NO_ERROR)
{
LOG_ERROR("unexpected validity reason: " + std::string(gpgme_strerror(vresult->signatures->validity_reason)));
throw renson::error::kFileSignatureError;
}
// Open the output file
std::ofstream output_fs = std::ofstream(output_path.string(), std::ofstream::binary);
if (!output_fs.good())
{
LOG_ERROR("Error opening file: " + output_path.string());
throw renson::error::kFileWriteError;
}
// Rewind the "output_data" data object
err = gpgme_data_seek(output_data, 0, SEEK_SET);
if (err)
{
LOG_ERROR("Error during gpgme_data_seek: " + std::string(gpgme_strerror(err)));
throw renson::error::kInvalidOperation;
}
// Read the contents of output_data and place it into "contents"
const int buffer_size = 256 * 1024;
char contents[buffer_size];
while ((chars_read = gpgme_data_read(output_data, contents, buffer_size)) > 0)
{
// Write the contents of contents to "output_fs"
output_fs.write(contents, chars_read);
if (!output_fs.good())
{
LOG_ERROR("Error writing file: " + output_path.string());
throw renson::error::kFileWriteError;
}
}
}
catch (renson::error::Error& e)
{
error = e;
}
// cleanup
if (input_signed)
gpgme_data_release(input_signed);
if (output_data)
gpgme_data_release(output_data);
// when no exception was thrown, return true, otherwise false
return error == renson::error::kNoError;}
I works fine with a regular gpg file, however, passing a corrupted file, it got stuck at gpgme_op_verify and never return anything.
however using gpgme command works fine and returns that file is corrupted.
Any help ?