webpg-npapi 0.6.1
FB::variant webpgPluginAPI::gpgDecryptVerify ( const std::string &  data,
int  use_agent 
)

Attempts to decrypt and verify the string data. If use_agent is 0, it will attempt to disable the key-agent to prevent the passphrase dialog from displaying. This is useful in cases where you want to verify or decrypt without unlocking the private keyring (i.e. in an automated parsing environment).

Parameters:
dataThe data to decrypt and/or verify.
use_agentAttempt to disable the gpg-agent
Returns:
FB::variant response
response {
    "data":"This is a test of symmetric encrypted data with a signature...\n",
    "error":false,
    "message_type":"signed_message",
    "signatures":{
        "0":{
            "expiration":"0",
            "fingerprint":"0C178DD984F837340075BD76C599711F5E82BB93",
            "status":"GOOD",
            "timestamp":"1346645718",
            "validity":"full"
        }
    }
}
Parameters:
dataThe data to decrypt and/or verify.
use_agentAttempt to disable the gpg-agent

Definition at line 1354 of file webpgPluginAPI.cpp.

References get_gpgme_ctx(), restoreGPGConfig(), and setTempGPGOption().

Referenced by gpgDecrypt().

{
    gpgme_ctx_t ctx;
    gpgme_error_t err;
    gpgme_decrypt_result_t decrypt_result;
    gpgme_verify_result_t verify_result;
    gpgme_signature_t sig;
    gpgme_data_t in, out;
    std::string out_buf;
    std::string envvar;
    FB::VariantMap response;
    int nsigs;
    int tnsigs = 0;
    char buf[513];
    int ret;

    char *agent_info = getenv("GPG_AGENT_INFO");

    if (use_agent == 0) {
        // Set the GPG_AGENT_INFO to null because the user shouldn't be bothered with for
        //  a passphrase if we get a chunk of encrypted data by mistake.
        setTempGPGOption("batch", "");
        // Set the defined password to be "", if anything else is sent to the
        //  agent, this will result in a return error of invalid key when
        //  performing Symmetric decryption (because the passphrase is the
        //  secret key)
        setTempGPGOption("passphrase", "\"\"");
#ifndef HAVE_W32_SYSTEM
#ifndef FB_MACOSX
        // Poison the GPG_AGENT_INFO environment variable
        envvar = "GPG_AGENT_INFO=INVALID";
        putenv(strdup(envvar.c_str()));
#endif
#endif
        // Create our context with the above modifications
        ctx = get_gpgme_ctx();
        // Set the passphrase callback to just send "\n", which will
        //  deal with the case there is no gpg-agent
        gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);
    } else {
        ctx = get_gpgme_ctx();
    }

    err = gpgme_data_new_from_mem (&in, data.c_str(), data.length(), 0);
    if (err != GPG_ERR_NO_ERROR) {
        return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
    }

    err = gpgme_data_new (&out);
    if (err != GPG_ERR_NO_ERROR) {
        return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
    }

    err = gpgme_op_decrypt_verify (ctx, in, out);

    decrypt_result = gpgme_op_decrypt_result (ctx);
    verify_result = gpgme_op_verify_result (ctx);

    if (use_agent == 0) {
        // Restore the gpg.conf options
        restoreGPGConfig();
        // Restore GPG_AGENT_INFO to its original value
#ifndef HAVE_W32_SYSTEM
#ifndef FB_MACOSX
        envvar = "GPG_AGENT_INFO=";
        envvar += agent_info;
        putenv(strdup(envvar.c_str()));
#endif
#endif
    }

    if (err != GPG_ERR_NO_ERROR && !verify_result) {
        // There was an error returned while decrypting;
        //   either bad data, or signed only data
        if (verify_result && verify_result->signatures) {
            if (verify_result->signatures->status != GPG_ERR_NO_ERROR) {
                //No valid GPG data to decrypt or signatures to verify; possibly bad armor.\" }";
                return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
            }
        }
        if (gpg_err_code(err) == GPG_ERR_CANCELED) {
            return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
        }
        if (gpg_err_code(err) == GPG_ERR_BAD_PASSPHRASE) {
            return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
        }
        if (gpg_err_source(err) == GPG_ERR_SOURCE_PINENTRY) {
            return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
        }
        if (gpg_err_source(err) == GPG_ERR_SOURCE_GPGAGENT) {
            return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
        }
    }

    FB::VariantMap signatures;
    if (verify_result && verify_result->signatures) {
        tnsigs = 0;
        for (nsigs=0, sig=verify_result->signatures; sig; sig = sig->next, nsigs++) {
            FB::VariantMap signature;
            signature["fingerprint"] = nonnull (sig->fpr);
            signature["timestamp"] = sig->timestamp;
            signature["expiration"] = sig->exp_timestamp;
            signature["validity"] = sig->validity == GPGME_VALIDITY_UNKNOWN? "unknown":
                    sig->validity == GPGME_VALIDITY_UNDEFINED? "undefined":
                    sig->validity == GPGME_VALIDITY_NEVER? "never":
                    sig->validity == GPGME_VALIDITY_MARGINAL? "marginal":
                    sig->validity == GPGME_VALIDITY_FULL? "full":
                    sig->validity == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]";
            signature["status"] = gpg_err_code (sig->status) == GPG_ERR_NO_ERROR? "GOOD":
                    gpg_err_code (sig->status) == GPG_ERR_BAD_SIGNATURE? "BAD_SIG":
                    gpg_err_code (sig->status) == GPG_ERR_NO_PUBKEY? "NO_PUBKEY":
                    gpg_err_code (sig->status) == GPG_ERR_NO_DATA? "NO_SIGNATURE":
                    gpg_err_code (sig->status) == GPG_ERR_SIG_EXPIRED? "GOOD_EXPSIG":
                    gpg_err_code (sig->status) == GPG_ERR_KEY_EXPIRED? "GOOD_EXPKEY": "INVALID";
            signatures[i_to_str(nsigs)] = signature;
            tnsigs++;
        }
    }

    if (nsigs < 1 || err == 11) {
        response["message_type"] = "encrypted_message";
        if (use_agent == 0) {
            response["message_event"] = "auto";
        } else {
            response["message_event"] = "manual";
        }
    } else {
        response["message_type"] = "signed_message";
    }

    if (err != GPG_ERR_NO_ERROR && tnsigs < 1) {
        return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);
    }

    if (gpgme_err_code (err) == 58 && tnsigs < 1) {
        gpgme_data_release (out);
        response["data"] = data;
        response["message_type"] = "detached_signature";
    } else {
        ret = gpgme_data_seek(out, 0, SEEK_SET);

        if (ret)
            return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);

        while ((ret = gpgme_data_read (out, buf, 512)) > 0)
            out_buf += buf;

        if (ret < 0)
            return get_error_map(__func__, gpgme_err_code (err), gpgme_strerror (err), __LINE__, __FILE__);

        if (out_buf.length() < 1) {
            response["data"] = data;
            response["message_type"] = "detached_signature";
            gpgme_data_release (out);
        } else {
            size_t out_size = 0;
            gpgme_data_seek(out, 0, SEEK_SET);
            out_buf = gpgme_data_release_and_get_mem (out, &out_size);

            /* strip the size_t data out of the output buffer */
            out_buf = out_buf.substr(0, out_size);
            response["data"] = out_buf;
        }

    }

    response["signatures"] = signatures;
    response["error"] = false;
    gpgme_data_release (in);
    gpgme_release (ctx);

    return response;
}

Here is the call graph for this function:

 All Classes Functions