Key generation with GPGME and GnuPG hangs at gpgme_op_genkey

Robert J. Hansen rjh at sixdemonbag.org
Wed Jan 27 15:42:54 CET 2016


> Yes, that was the problem. I installed haveged and it worked. But it seems
> that the key generation in my C++ application will not work, if a custom passphrase 
> callback is set. The key generation code is unchanged, but with the callback I get an 
> GPG_ERR_GENERAL error. The init and callback code is as follows:

I cleaned your code up a bit and it works fine.

Compile with:

$ g++ foo.cc -O2 -o foo -std=c++11 `gpgme-config --cflags --libs`

or

$ clang++ foo.cc -O2 -o foo -std=c++11 `gpgme-config --cflags --libs`




#include <string>
#include <iostream>
#include <gpgme.h>
#include <clocale>

using std::string;
using std::cin;
using std::cout;
using std::cerr;
using std::getline;

static gpgme_error_t passphrase_cb(void *hook,
                                   const char *uid_hint,
                                   const char *passphrase_info,
                                   int prev_was_bad,
                                   int fd)
{
    string passphrase { "" };
    size_t written { 0 };

    cout << "Enter your passphrase: ";
    getline(cin, passphrase);

    if (passphrase.empty())
        return GPG_ERR_CANCELED;

    while (written < passphrase.size())
    {
        ssize_t bytesWritten = gpgme_io_write(fd,
            &passphrase[0] + written,
            passphrase.size() - written);
        if (bytesWritten == 0)
            break;
        written += bytesWritten;
    }
    gpgme_io_write(fd, "\n", 1);
    return GPG_ERR_NO_ERROR;
}

int main()
{
    int rv = -1;
    gpgme_ctx_t mContext;
    gpgme_engine_info_t info;
    gpgme_error_t error;
    bool contextInitialized { false };
    const char* def = "<GnupgKeyParms format=\"internal\"> \n"
        " Key-Type: default \n"
        " Subkey-Type: default \n"
        " Name-Real: Joe Tester3 \n"
        " Name-Comment: with stupid passphrase \n"
        " Name-Email: joe3 at foo.bar \n"
        " Expire-Date: 0 \n"
        " Passphrase: abc \n"
        " </GnupgKeyParms> \n";

    gpgme_check_version(nullptr);
    error = gpgme_new(&mContext);
    if (GPG_ERR_NO_ERROR != gpgme_err_code(error))
    {
        cerr << "Couldn't create new context.\n";
        goto BAIL_OUT;
    }
    contextInitialized = true;

    error = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
    if (GPG_ERR_NO_ERROR != gpgme_err_code(error))
    {
        cerr << "GPGME doesn't support OpenPGP.\n";
        goto BAIL_OUT;
    }
    error = gpgme_get_engine_info(&info);
    if (GPG_ERR_NO_ERROR != gpgme_err_code(error))
    {
        cerr << "Couldn't get engine information.\n";
        goto BAIL_OUT;
    }
    error = gpgme_ctx_set_engine_info(mContext,
                                      GPGME_PROTOCOL_OpenPGP,
                                      nullptr,
                                      nullptr);
    if (GPG_ERR_NO_ERROR != gpgme_err_code(error))
    {
        cerr << "Couldn't set engine to OpenPGP.\n";
        goto BAIL_OUT;
    }

    gpgme_set_passphrase_cb(mContext, passphrase_cb, nullptr);
    error = gpgme_op_genkey(mContext, def, nullptr, nullptr);

    if (GPG_ERR_INV_VALUE  == gpgme_err_code(error))
        cerr << "Value error\n";
    else if (GPG_ERR_NOT_SUPPORTED == gpgme_err_code(error))
        cerr << "Not supported error\n";
    else if (GPG_ERR_GENERAL  ==  gpgme_err_code(error))
        cerr << "general error\n";
    else if (GPG_ERR_NO_ERROR == gpgme_err_code(error))
    {
        gpgme_genkey_result_t res = gpgme_op_genkey_result(mContext);
        if (res->primary && res->sub)
        {
            rv = 0;
        }
    }
BAIL_OUT:
    if (contextInitialized) gpgme_release(mContext);
    return rv;
}



More information about the Gnupg-users mailing list