Exemplo n.º 1
0
int 
main (int argc, char **argv)
{
  gpgme_ctx_t ctx;
  gpgme_error_t err;
  gpgme_data_t sig, text;
  gpgme_verify_result_t result;

  init_gpgme (GPGME_PROTOCOL_CMS);

  err = gpgme_new (&ctx);
  fail_if_err (err);
  gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
  
  /* Checking a valid message.  */
  err = gpgme_data_new_from_mem (&text, test_text1, strlen (test_text1), 0);
  fail_if_err (err);
  err = gpgme_data_new_from_mem (&sig, test_sig1, strlen (test_sig1), 0);
  fail_if_err (err);

  err = gpgme_op_verify (ctx, sig, text, NULL);
  fail_if_err (err);
  result = gpgme_op_verify_result (ctx);
  check_result (result, GPGME_SIGSUM_VALID | GPGME_SIGSUM_GREEN,
		"3CF405464F66ED4A7DF45BBDD1E4282E33BDB76E",
		GPG_ERR_NO_ERROR, GPGME_VALIDITY_FULL);

  show_auditlog (ctx);

  /* Checking a manipulated message.  */
  gpgme_data_release (text);
  err = gpgme_data_new_from_mem (&text, test_text1f, strlen (test_text1f), 0);
  fail_if_err (err);
  gpgme_data_seek (sig, 0, SEEK_SET);
  err = gpgme_op_verify (ctx, sig, text, NULL);
  fail_if_err (err);
  result = gpgme_op_verify_result (ctx);
  check_result (result, GPGME_SIGSUM_RED,
		"3CF405464F66ED4A7DF45BBDD1E4282E33BDB76E",
		GPG_ERR_BAD_SIGNATURE, GPGME_VALIDITY_UNKNOWN);

  show_auditlog (ctx);

  gpgme_data_release (text);
  gpgme_data_release (sig);
  gpgme_release (ctx);  
  return got_errors? 1 : 0;
}
Exemplo n.º 2
0
static gboolean
verify_done (SeahorseToolMode *mode, const gchar *uri, gpgme_data_t uridata,
             SeahorsePGPOperation *pop, GError **err)
{
    const gchar *orig;
    gpgme_verify_result_t status;

    status = gpgme_op_verify_result (pop->gctx);
    if (status && status->signatures) {

        orig = g_object_get_data (G_OBJECT (pop), "original-file");
        if (!orig)
            orig = uri;
        seahorse_notify_signatures (orig, status);

    } else {

        /*
         * TODO: What should happen with multiple files at this point.
         * The last thing we want to do is cascade a big pile of error
         * dialogs at the user.
         */

        g_set_error (err, SEAHORSE_ERROR, -1, _("No valid signatures found"));
        return FALSE;
    }

    return TRUE;
}
Exemplo n.º 3
0
Arquivo: verify.c Projeto: gpg/gpgme
const char *
gpgme_get_sig_string_attr (gpgme_ctx_t ctx, int idx,
                           _gpgme_attr_t what, int whatidx)
{
  gpgme_verify_result_t result;
  gpgme_signature_t sig;

  result = gpgme_op_verify_result (ctx);
  sig = result->signatures;

  while (sig && idx)
    {
      sig = sig->next;
      idx--;
    }
  if (!sig || idx)
    return NULL;

  switch (what)
    {
    case GPGME_ATTR_FPR:
      return sig->fpr;

    case GPGME_ATTR_ERRTOK:
      if (whatidx == 1)
        return sig->wrong_key_usage ? "Wrong_Key_Usage" : "";
      else
	return "";
    default:
      break;
    }

  return NULL;
}
Exemplo n.º 4
0
GPGWrapperDecryptedData GPGWrapper::decrypt(const std::string& message)
{
    init();

    ScopedGPGData clear_text, sign_text, encrypted_text;

    gpgme_error_t error = encrypted_text.init(message.c_str(), message.length());
    fail_if_err(error, L"Nie uda³o siê zainicjowaæ danych do odszyfrowania (encrypted_text).");
    error = sign_text.init();
    fail_if_err(error, L"Nie uda³o siê zainicjowaæ danych do odszyfrowania (sign_text).");

    error = gpgme_op_decrypt(context, encrypted_text.get(), sign_text.get());
    fail_if_err(error, L"Nie uda³o siê odszyfrowaæ wiadomoœci.");

    error = gpgme_data_rewind(sign_text.get());
    fail_if_err(error, L"Nie uda³o siê przewin¹æ na pocz¹tek podpisanego strumienia, aby go póŸniej zweryfikowaæ.");

    error = clear_text.init();
    fail_if_err(error, L"Nie uda³o siê zainicjowaæ danych do odszyfrowania (clear_text).");

    error = gpgme_op_verify(context, sign_text.get(), NULL, clear_text.get());
    fail_if_err(error, L"Nie powiod³a siê próba potwierdzenia podpisu nadawcy.");

    GPGWrapperDecryptedData result;

    gpgme_verify_result_t verifyResult = gpgme_op_verify_result(context);
    if (verifyResult != NULL && verifyResult->signatures != NULL && verifyResult->signatures->summary & GPGME_SIGSUM_VALID)
        result.isSignValid = true;

    result.data = copyData(clear_text.get());

    return result;
}
Exemplo n.º 5
0
/* ------------------
 * verify a signed string with the key found with fingerprint fpr
 * FREE MEMORY AFTER USAGE OF RETURN VALUE!
 * ------------------ */
static char* verify(const char* sig_str)
{
	gpgme_error_t error;
	gpgme_ctx_t ctx;
	gpgme_data_t plain,sig,sig_text;
	gpgme_verify_result_t result;
	char* fpr = NULL;
	char* armored_sig_str = NULL;

	if (sig_str == NULL)
	{
		purple_debug_error(PLUGIN_ID,"verify got null parameter\n");
		return NULL;
	}

	// connect to gpgme
	gpgme_check_version (NULL);
	error = gpgme_new(&ctx);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		return NULL;
	}

	// armor sig_str
	armored_sig_str = str_armor(sig_str);

	// create data containers
	gpgme_data_new_from_mem (&sig, armored_sig_str,strlen(armored_sig_str),1);
	gpgme_data_new(&plain);

	// try to verify
	error = gpgme_op_verify(ctx,sig,NULL,plain);
	if (error)
	{
		purple_debug_error(PLUGIN_ID,"gpgme_op_verify failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error));
		gpgme_release (ctx);
		return NULL;
	}

	// get result
 	result = gpgme_op_verify_result (ctx);
	if (result != NULL)
	{
		if (result->signatures != NULL)
		{
			// return the fingerprint of the key that made the signature
			fpr = g_strdup(result->signatures->fpr);
		}
	}

	// release memory for data containers
	gpgme_data_release(sig);
	gpgme_data_release(plain);

	return fpr;
}
Exemplo n.º 6
0
Arquivo: verify.c Projeto: gpg/gpgme
/* Retrieve the signature status of signature IDX in CTX after a
   successful verify operation in R_STAT (if non-null).  The creation
   time stamp of the signature is returned in R_CREATED (if non-null).
   The function returns a string containing the fingerprint.  */
const char *
gpgme_get_sig_status (gpgme_ctx_t ctx, int idx,
                      _gpgme_sig_stat_t *r_stat, time_t *r_created)
{
  gpgme_verify_result_t result;
  gpgme_signature_t sig;

  result = gpgme_op_verify_result (ctx);
  sig = result->signatures;

  while (sig && idx)
    {
      sig = sig->next;
      idx--;
    }
  if (!sig || idx)
    return NULL;

  if (r_stat)
    {
      switch (gpg_err_code (sig->status))
	{
	case GPG_ERR_NO_ERROR:
	  *r_stat = GPGME_SIG_STAT_GOOD;
	  break;

	case GPG_ERR_BAD_SIGNATURE:
	  *r_stat = GPGME_SIG_STAT_BAD;
	  break;

	case GPG_ERR_NO_PUBKEY:
	  *r_stat = GPGME_SIG_STAT_NOKEY;
	  break;

	case GPG_ERR_NO_DATA:
	  *r_stat = GPGME_SIG_STAT_NOSIG;
	  break;

	case GPG_ERR_SIG_EXPIRED:
	  *r_stat = GPGME_SIG_STAT_GOOD_EXP;
	  break;

	case GPG_ERR_KEY_EXPIRED:
	  *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY;
	  break;

	default:
	  *r_stat = GPGME_SIG_STAT_ERROR;
	  break;
	}
    }
  if (r_created)
    *r_created = sig->timestamp;
  return sig->fpr;
}
Exemplo n.º 7
0
void
p_gpg_verify(const char *const barejid, const char *const sign)
{
    if (!sign) {
        return;
    }

    gpgme_ctx_t ctx;
    gpgme_error_t error = gpgme_new(&ctx);

    if (error) {
        log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        return;
    }

    char *sign_with_header_footer = _add_header_footer(sign, PGP_SIGNATURE_HEADER, PGP_SIGNATURE_FOOTER);
    gpgme_data_t sign_data;
    gpgme_data_new_from_mem(&sign_data, sign_with_header_footer, strlen(sign_with_header_footer), 1);
    free(sign_with_header_footer);

    gpgme_data_t plain_data;
    gpgme_data_new(&plain_data);

    error = gpgme_op_verify(ctx, sign_data, NULL, plain_data);
    gpgme_data_release(sign_data);
    gpgme_data_release(plain_data);

    if (error) {
        log_error("GPG: Failed to verify. %s %s", gpgme_strsource(error), gpgme_strerror(error));
        gpgme_release(ctx);
        return;
    }

    gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
    if (result) {
        if (result->signatures) {
            gpgme_key_t key = NULL;
            error = gpgme_get_key(ctx, result->signatures->fpr, &key, 0);
            if (error) {
                log_debug("Could not find PGP key with ID %s for %s", result->signatures->fpr, barejid);
            } else {
                log_debug("Fingerprint found for %s: %s ", barejid, key->subkeys->fpr);
                ProfPGPPubKeyId *pubkeyid = malloc(sizeof(ProfPGPPubKeyId));
                pubkeyid->id = strdup(key->subkeys->keyid);
                pubkeyid->received = TRUE;
                g_hash_table_replace(pubkeys, strdup(barejid), pubkeyid);
            }

            gpgme_key_unref(key);
        }
    }

    gpgme_release(ctx);
}
Exemplo n.º 8
0
static gboolean
decrypt_done (SeahorseToolMode *mode, const gchar *uri, gpgme_data_t uridata,
              SeahorsePGPOperation *pop, GError **err)
{
    gpgme_verify_result_t status;

    status = gpgme_op_verify_result (pop->gctx);
    if (status && status->signatures)
        seahorse_notify_signatures (uri, status);

    return TRUE;
}
Exemplo n.º 9
0
int 
main (int argc, char *argv[])
{
  gpgme_ctx_t ctx;
  gpgme_error_t err;
  gpgme_data_t in, out;
  gpgme_verify_result_t result;
  char *agent_info;
  int i;

  init_gpgme (GPGME_PROTOCOL_OpenPGP);

  err = gpgme_new (&ctx);
  fail_if_err (err);

  agent_info = getenv ("GPG_AGENT_INFO");
  if (!(agent_info && strchr (agent_info, ':')))
    gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);

  err = gpgme_data_new_from_mem (&in, "Hallo Leute\n", 12, 0);
  fail_if_err (err);
  err = gpgme_data_new (&out);
  fail_if_err (err);

  for (i = 0; i < sizeof (expected_notations) / sizeof (expected_notations[0]);
       i++)
    {
      err = gpgme_sig_notation_add (ctx, expected_notations[i].name,
				    expected_notations[i].value,
				    expected_notations[i].flags);
      fail_if_err (err);
    }
  
  err = gpgme_op_sign (ctx, in, out, GPGME_SIG_MODE_NORMAL);
  fail_if_err (err);

  gpgme_data_release (in);
  err = gpgme_data_new (&in);
  fail_if_err (err);

  gpgme_data_seek (out, 0, SEEK_SET);

  err = gpgme_op_verify (ctx, out, NULL, in);
  fail_if_err (err);
  result = gpgme_op_verify_result (ctx);
  check_result (result);

  gpgme_data_release (in);
  gpgme_data_release (out);
  gpgme_release (ctx);
  return 0;
}
Exemplo n.º 10
0
static inline retvalue verify_signature(const struct signature_requirement *requirements, const char *releasegpg, const char *releasename) {
	gpgme_verify_result_t result;
	int i;
	const struct signature_requirement *req;

	result = gpgme_op_verify_result(context);
	if (result == NULL) {
		fprintf(stderr,
"Internal error communicating with libgpgme: no result record!\n\n");
		return RET_ERROR_GPGME;
	}

	for (req = requirements ; req != NULL ; req = req->next) {
		bool fullfilled = false;

		/* check first for good signatures, and then for good enough
		   signatures, to not pester the user with warnings of one
		   of the alternate keys, if the last one is good enough */

		for (i = 0 ; (size_t)i < req->num_keys ; i++) {

			if (key_good(&req->keys[i], result->signatures)) {
				fullfilled = true;
				break;
			}
		}
		for (i = 0 ; !fullfilled && (size_t)i < req->num_keys ; i++) {

			if (key_good_enough(&req->keys[i], result->signatures,
						releasegpg, releasename)) {
				fullfilled = true;
				break;
			}
		}
		if (!fullfilled) {
			fprintf(stderr,
"ERROR: Condition '%s' not fullfilled for '%s'.\n",
					req->condition, releasegpg);
			print_signatures(stderr, result->signatures,
					releasegpg);
			return RET_ERROR_BADSIG;
		}
		if (verbose > 10) {
			fprintf(stdout, "Condition '%s' fullfilled for '%s'.\n",
					req->condition, releasegpg);
		}
	}
	if (verbose > 20)
		print_signatures(stdout, result->signatures, releasegpg);
	return RET_OK;
}
Exemplo n.º 11
0
/* Not that this closure is called in the context of the
   waiter_thread.  */
static void
verify_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
{
  if (!err)
    {
      gpgme_verify_result_t res;

      res = gpgme_op_verify_result (ctx);
      if (res) 
        verify_dialog_box (gpgme_get_protocol (ctx), res, NULL);
    }
  gpgme_data_release (cld->sigobj);
  engine_private_finished (cld->filter, err);
}
Exemplo n.º 12
0
/*
int main(int argc, char** argv)
{
	gpgme_ctx_t ctx;
	gpgme_error_t err;
	init_gpgme(GPGME_PROTOCOL_OpenPGP);
	err = gpgme_new(&ctx);
	check_errors(err,"error with gpgme_new");
	verify_signature(ctx,"signature.c.sig","signature.c");
	
	return 0;
}
*/
bool verify_signature(gpgme_ctx_t ctx, char* sig_path,char* file_path)
{
	gpgme_error_t err;
	FILE* fp_sig = NULL;
	FILE* fp_msg = NULL;
	gpgme_data_t sig = NULL;
	gpgme_data_t msg = NULL;
	gpgme_verify_result_t result;
	fp_sig = fopen(sig_path,"rb");	//open file with signature
	if(!fp_sig)
	{
		err = gpg_error_from_syserror();
		fprintf (stderr, PGM ": can't open `%s': %s\n", sig_path, gpg_strerror(err));
		return false;
	}
	fp_msg = fopen(file_path,"rb");	//open file which want to check
	if(!fp_msg)
	{
		err = gpg_error_from_syserror();
		fprintf(stderr,PGM ": cant open `%s`: %s\n", file_path, gpg_strerror(err));
		return false;
	}
	err = gpgme_data_new_from_stream(&sig,fp_sig);	//write to gpgme_data object from fp_sig stream(signature)
	if(err)
	{
		fprintf (stderr, PGM ": error allocating data object: %s\n",gpg_strerror (err));
		return false;
	}
	if(fp_msg)
	{
		err = gpgme_data_new_from_stream(&msg,fp_msg);	//write to gpgme_data object from fp_msg(file)
		if(err)
		{
			fprintf(stderr,PGM ": error allocation data object: %s\n",gpg_strerror(err));
			return false;
		}
	}
	err = gpgme_op_verify(ctx,sig,msg,NULL);	//verify signature
	check_errors(err,"error with verify");
	result = gpgme_op_verify_result(ctx);		//get result of checking signature
	if(result)
	{
		print_result_of_checking(result);		//printf checking information
	}
	fclose(fp_sig);
	fclose(fp_msg);
	gpgme_data_release (msg);
	gpgme_data_release (sig);		
	return true;
}
Exemplo n.º 13
0
int
main (int argc, char *argv[])
{
  gpgme_ctx_t ctx;
  gpgme_error_t err;
  gpgme_data_t in, out;
  gpgme_decrypt_result_t decrypt_result;
  gpgme_verify_result_t verify_result;
  char *cipher_2_asc = make_filename ("cipher-2.asc");
  char *agent_info;

  init_gpgme (GPGME_PROTOCOL_OpenPGP);

  err = gpgme_new (&ctx);
  fail_if_err (err);

  agent_info = getenv("GPG_AGENT_INFO");
  if (!(agent_info && strchr (agent_info, ':')))
    gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL);

  err = gpgme_data_new_from_file (&in, cipher_2_asc, 1);
  free (cipher_2_asc);
  fail_if_err (err);
  err = gpgme_data_new (&out);
  fail_if_err (err);

  err = gpgme_op_decrypt_verify (ctx, in, out);
  fail_if_err (err);
  decrypt_result = gpgme_op_decrypt_result (ctx);
  if (decrypt_result->unsupported_algorithm)
    {
      fprintf (stderr, "%s:%i: unsupported algorithm: %s\n",
	       __FILE__, __LINE__, decrypt_result->unsupported_algorithm);
      exit (1);
    }
  print_data (out);
  verify_result = gpgme_op_verify_result (ctx);
  check_verify_result (verify_result, 0,
		       "A0FF4590BB6122EDEF6E3C542D727CC768697734",
		       GPG_ERR_NO_ERROR);

  gpgme_data_release (in);
  gpgme_data_release (out);
  gpgme_release (ctx);
  return 0;
}
Exemplo n.º 14
0
/* Get the key used to create signature IDX in CTX and return it in
   R_KEY.  */
gpgme_error_t
gpgme_get_sig_key (gpgme_ctx_t ctx, int idx, gpgme_key_t *r_key)
{
  gpgme_verify_result_t result;
  gpgme_signature_t sig;

  result = gpgme_op_verify_result (ctx);
  sig = result->signatures;

  while (sig && idx)
    {
      sig = sig->next;
      idx--;
    }
  if (!sig || idx)
    return gpg_error (GPG_ERR_EOF);

  return gpgme_get_key (ctx, sig->fpr, r_key, 0);
}
Exemplo n.º 15
0
gpgme_verify_result_t sgpgme_verify_signature(gpgme_ctx_t ctx, gpgme_data_t sig, 
					gpgme_data_t plain, gpgme_data_t dummy)
{
	gpgme_verify_result_t status = NULL;
	gpgme_error_t err;

	if ((err = gpgme_op_verify(ctx, sig, plain, dummy)) != GPG_ERR_NO_ERROR) {
		debug_print("op_verify err %s\n", gpgme_strerror(err));
		privacy_set_error("%s", gpgme_strerror(err));
		return GINT_TO_POINTER(-GPG_ERR_SYSTEM_ERROR);
	}
	status = gpgme_op_verify_result(ctx);
	if (status && status->signatures == NULL) {
		debug_print("no signature found\n");
		privacy_set_error(_("No signature found"));
		return GINT_TO_POINTER(-GPG_ERR_SYSTEM_ERROR);
	}
	return status;
}
Exemplo n.º 16
0
void geanypg_handle_signatures(encrypt_data * ed)
{
    int verified = 0;
    gpgme_verify_result_t vres = gpgme_op_verify_result(ed->ctx);
    if (vres)
    {
        gpgme_signature_t sig = vres->signatures;
        while (sig)
        {
            geanypg_check_sig(ed, sig);
            sig = sig->next;
            verified = 1;
        }
    }
    if (!verified)
    {
        fprintf(stderr, "GEANYPG: could not find verification results\n");
        dialogs_show_msgbox(GTK_MESSAGE_ERROR, "Error, could not find verification results");
    }
}
Exemplo n.º 17
0
/* Not that this closure is called in the context of the
   waiter_thread.  */
static void
decrypt_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err)
{
  update_passphrase_cache (err, &cld->pw_cb);

  if (!err && !cld->with_verify) 
    ;
  else if (!err) 
    {
      gpgme_verify_result_t res;

      /* Decryption succeeded.  Now check the state of the signatures. */
      res = gpgme_op_verify_result (ctx);
      if (res && res->signatures)
        verify_dialog_box (gpgme_get_protocol (ctx), res, NULL);
    }
  else if (gpg_err_code (err) == GPG_ERR_DECRYPT_FAILED)
    {
      /* The decryption failed.  See whether we can figure out a more
         suitable error code.  */
      gpgme_decrypt_result_t res;

      res = gpgme_op_decrypt_result (ctx);
      if (res && res->recipients 
          && gpgme_err_code (res->recipients->status) == GPG_ERR_NO_SECKEY)
        err = gpg_error (GPG_ERR_NO_SECKEY);
      /* Fixme: return the keyids */
    }
  else
    {
      /* Decryption failed for other reasons. */
    }

  /* If the passphrase callback indicated a cancel operation, change
     the the error code accordingly. */
  if (err && (cld->pw_cb.opts & OPT_FLAG_CANCEL))
    err = gpg_error (GPG_ERR_CANCELED);

  engine_private_finished (cld->filter, err);
}
Exemplo n.º 18
0
    void crypto_asym::fill_signing_result()
    {
	gpgme_verify_result_t inter = gpgme_op_verify_result(context);
	gpgme_signature_t res = NULL;
	signator tmp;

	signing_result.clear();

	if(inter != NULL)
	    res = inter->signatures;
	else
	    res = NULL;

	while(res != NULL)
	{
	    if(res->summary & (GPGME_SIGSUM_VALID|GPGME_SIGSUM_GREEN))
		tmp.result = signator::good;
	    else if(res->summary & GPGME_SIGSUM_RED)
		tmp.result = signator::bad;
	    else if(res->summary & GPGME_SIGSUM_KEY_MISSING)
		tmp.result = signator::unknown_key;
	    else
		tmp.result = signator::error;

	    if(res->summary & GPGME_SIGSUM_KEY_REVOKED)
		tmp.key_validity = signator::revoked;
	    else if(res->summary & GPGME_SIGSUM_KEY_EXPIRED)
		tmp.key_validity = signator::expired;
	    else
		tmp.key_validity = signator::valid;

	    tmp.fingerprint = res->fpr;

	    tmp.signing_date = datetime(res->timestamp);
	    tmp.signature_expiration_date = datetime(res->exp_timestamp);

	    res = res->next;
	    signing_result.push_back(tmp);
	}
    }
Exemplo n.º 19
0
bool c_gpgme::verify_detached_signature ( const std::string &sig_file, const std::string &clear_data_file, const std::string &expected_fpr ) {
	auto sig_file_ptr = load_file(sig_file);
	auto clear_data_file_ptr = load_file(clear_data_file);
	m_error_code = gpgme_op_verify(m_ctx, *sig_file_ptr, *clear_data_file_ptr, nullptr);
	if (m_error_code) return false;
	gpgme_verify_result_t result = gpgme_op_verify_result(m_ctx);
	if (result == nullptr) return false;
	gpgme_signature_t sig = result->signatures;
	if (!sig) return false;

	for (; sig; sig = sig->next) {
		if ((sig->summary & GPGME_SIGSUM_VALID) || (sig->summary & GPGME_SIGSUM_GREEN)) {  // Valid
			if (expected_fpr == sig->fpr) return true;
			else return false;
		}
		else if (sig->summary == 0 && sig->status == GPG_ERR_NO_ERROR) { // Valid but key is not certified with a trusted signature
			if (expected_fpr == sig->fpr) return true;
			else return false;
		}
	}
	return false;
}
Exemplo n.º 20
0
/* Loop through all files in metalink structure and retrieve them.
   Returns RETROK if all files were downloaded.
   Returns last retrieval error (from retrieve_url) if some files
   could not be downloaded.  */
uerr_t
retrieve_from_metalink (const metalink_t* metalink)
{
  metalink_file_t **mfile_ptr;
  uerr_t last_retr_err = RETROK; /* Store last encountered retrieve error.  */

  FILE *_output_stream = output_stream;
  bool _output_stream_regular = output_stream_regular;
  char *_output_document = opt.output_document;

  DEBUGP (("Retrieving from Metalink\n"));

  /* No files to download.  */
  if (!metalink->files)
    return RETROK;

  if (opt.output_document)
    {
      /* We cannot support output_document as we need to compute checksum
         of downloaded file, and to remove it if the checksum is bad.  */
      logputs (LOG_NOTQUIET,
               _("-O not supported for metalink download. Ignoring.\n"));
    }

  for (mfile_ptr = metalink->files; *mfile_ptr; mfile_ptr++)
    {
      metalink_file_t *mfile = *mfile_ptr;
      metalink_resource_t **mres_ptr;
      char *filename = NULL;
      bool hash_ok = false;

      uerr_t retr_err = METALINK_MISSING_RESOURCE;

      /* -1 -> file should be rejected
         0 -> could not verify
         1 -> verified successfully  */
      char sig_status = 0;

      output_stream = NULL;

      DEBUGP (("Processing metalink file %s...\n", quote (mfile->name)));

      /* Resources are sorted by priority.  */
      for (mres_ptr = mfile->resources; *mres_ptr; mres_ptr++)
        {
          metalink_resource_t *mres = *mres_ptr;
          metalink_checksum_t **mchksum_ptr, *mchksum;
          struct iri *iri;
          struct url *url;
          int url_err;

          if (!RES_TYPE_SUPPORTED (mres->type))
            {
              logprintf (LOG_VERBOSE,
                         _("Resource type %s not supported, ignoring...\n"),
                         quote (mres->type));
              continue;
            }

          retr_err = METALINK_RETR_ERROR;

          /* If output_stream is not NULL, then we have failed on
             previous resource and are retrying. Thus, remove the file.  */
          if (output_stream)
            {
              fclose (output_stream);
              output_stream = NULL;
              if (unlink (filename))
                logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
              xfree (filename);
            }

          /* Parse our resource URL.  */
          iri = iri_new ();
          set_uri_encoding (iri, opt.locale, true);
          url = url_parse (mres->url, &url_err, iri, false);

          if (!url)
            {
              char *error = url_error (mres->url, url_err);
              logprintf (LOG_NOTQUIET, "%s: %s.\n", mres->url, error);
              xfree (error);
              inform_exit_status (URLERROR);
              iri_free (iri);
              continue;
            }
          else
            {
              /* Avoid recursive Metalink from HTTP headers.  */
              bool _metalink_http = opt.metalink_over_http;

              /* Assure proper local file name regardless of the URL
                 of particular Metalink resource.
                 To do that we create the local file here and put
                 it as output_stream. We restore the original configuration
                 after we are finished with the file.  */
              output_stream = unique_create (mfile->name, true, &filename);
              output_stream_regular = true;

              /* Store the real file name for displaying in messages.  */
              opt.output_document = filename;

              opt.metalink_over_http = false;
              DEBUGP (("Storing to %s\n", filename));
              retr_err = retrieve_url (url, mres->url, NULL, NULL,
                                       NULL, NULL, opt.recursive, iri, false);
              opt.metalink_over_http = _metalink_http;
            }
          url_free (url);
          iri_free (iri);

          if (retr_err == RETROK)
            {
              FILE *local_file;

              /* Check the digest.  */
              local_file = fopen (filename, "rb");
              if (!local_file)
                {
                  logprintf (LOG_NOTQUIET, _("Could not open downloaded file.\n"));
                  continue;
                }

              for (mchksum_ptr = mfile->checksums; *mchksum_ptr; mchksum_ptr++)
                {
                  char sha256[SHA256_DIGEST_SIZE];
                  char sha256_txt[2 * SHA256_DIGEST_SIZE + 1];

                  mchksum = *mchksum_ptr;

                  /* I have seen both variants...  */
                  if (strcasecmp (mchksum->type, "sha256")
                      && strcasecmp (mchksum->type, "sha-256"))
                    {
                      DEBUGP (("Ignoring unsupported checksum type %s.\n",
                               quote (mchksum->type)));
                      continue;
                    }

                  logprintf (LOG_VERBOSE, _("Computing checksum for %s\n"),
                             quote (mfile->name));

                  sha256_stream (local_file, sha256);
                  wg_hex_to_string (sha256_txt, sha256, SHA256_DIGEST_SIZE);
                  DEBUGP (("Declared hash: %s\n", mchksum->hash));
                  DEBUGP (("Computed hash: %s\n", sha256_txt));
                  if (!strcmp (sha256_txt, mchksum->hash))
                    {
                      logputs (LOG_VERBOSE,
                               _("Checksum matches.\n"));
                      hash_ok = true;
                    }
                  else
                    {
                      logprintf (LOG_NOTQUIET,
                                 _("Checksum mismatch for file %s.\n"),
                                 quote (mfile->name));
                      hash_ok = false;
                    }

                  /* Stop as soon as we checked the supported checksum.  */
                  break;
                } /* Iterate over available checksums.  */
              fclose (local_file);
              local_file = NULL;

              if (!hash_ok)
                continue;

              sig_status = 0; /* Not verified.  */

#ifdef HAVE_GPGME
              /* Check the crypto signature.

                 Note that the signtures from Metalink in XML will not be
                 parsed when using libmetalink version older than 0.1.3.
                 Metalink-over-HTTP is not affected by this problem.  */
              if (mfile->signature)
                {
                  metalink_signature_t *msig = mfile->signature;
                  gpgme_error_t gpgerr;
                  gpgme_ctx_t gpgctx;
                  gpgme_data_t gpgsigdata, gpgdata;
                  gpgme_verify_result_t gpgres;
                  gpgme_signature_t gpgsig;
                  gpgme_protocol_t gpgprot = GPGME_PROTOCOL_UNKNOWN;
                  int fd = -1;

                  /* Initialize the library - as name suggests.  */
                  gpgme_check_version (NULL);

                  /* Open data file.  */
                  fd = open (filename, O_RDONLY);
                  if (fd == -1)
                    {
                      logputs (LOG_NOTQUIET,
                               _("Could not open downloaded file for signature "
                                 "verification.\n"));
                      goto gpg_skip_verification;
                    }

                  /* Assign file descriptor to GPG data structure.  */
                  gpgerr = gpgme_data_new_from_fd (&gpgdata, fd);
                  if (gpgerr != GPG_ERR_NO_ERROR)
                    {
                      logprintf (LOG_NOTQUIET,
                                 "GPGME data_new_from_fd: %s\n",
                                 gpgme_strerror (gpgerr));
                      goto gpg_skip_verification;
                    }

                  /* Prepare new GPGME context.  */
                  gpgerr = gpgme_new (&gpgctx);
                  if (gpgerr != GPG_ERR_NO_ERROR)
                    {
                      logprintf (LOG_NOTQUIET,
                                 "GPGME new: %s\n",
                                 gpgme_strerror (gpgerr));
                      gpgme_data_release (gpgdata);
                      goto gpg_skip_verification;
                    }

                  DEBUGP (("Verifying signature %s:\n%s\n",
                           quote (msig->mediatype),
                           msig->signature));

                  /* Check signature type.  */
                  if (!strcmp (msig->mediatype, "application/pgp-signature"))
                    gpgprot = GPGME_PROTOCOL_OpenPGP;
                  else /* Unsupported signature type.  */
                    {
                      gpgme_release (gpgctx);
                      gpgme_data_release (gpgdata);
                      goto gpg_skip_verification;
                    }

                  gpgerr = gpgme_set_protocol (gpgctx, gpgprot);
                  if (gpgerr != GPG_ERR_NO_ERROR)
                    {
                      logprintf (LOG_NOTQUIET,
                                 "GPGME set_protocol: %s\n",
                                 gpgme_strerror (gpgerr));
                      gpgme_release (gpgctx);
                      gpgme_data_release (gpgdata);
                      goto gpg_skip_verification;
                    }

                  /* Load the signature.  */
                  gpgerr = gpgme_data_new_from_mem (&gpgsigdata,
                                                    msig->signature,
                                                    strlen (msig->signature),
                                                    0);
                  if (gpgerr != GPG_ERR_NO_ERROR)
                    {
                      logprintf (LOG_NOTQUIET,
                                 _("GPGME data_new_from_mem: %s\n"),
                                 gpgme_strerror (gpgerr));
                      gpgme_release (gpgctx);
                      gpgme_data_release (gpgdata);
                      goto gpg_skip_verification;
                    }

                  /* Verify the signature.  */
                  gpgerr = gpgme_op_verify (gpgctx, gpgsigdata, gpgdata, NULL);
                  if (gpgerr != GPG_ERR_NO_ERROR)
                    {
                      logprintf (LOG_NOTQUIET,
                                 _("GPGME op_verify: %s\n"),
                                 gpgme_strerror (gpgerr));
                      gpgme_data_release (gpgsigdata);
                      gpgme_release (gpgctx);
                      gpgme_data_release (gpgdata);
                      goto gpg_skip_verification;
                    }

                  /* Check the results.  */
                  gpgres = gpgme_op_verify_result (gpgctx);
                  if (!gpgres)
                    {
                      logputs (LOG_NOTQUIET,
                               _("GPGME op_verify_result: NULL\n"));
                      gpgme_data_release (gpgsigdata);
                      gpgme_release (gpgctx);
                      gpgme_data_release (gpgdata);
                      goto gpg_skip_verification;
                    }

                  /* The list is null-terminated.  */
                  for (gpgsig = gpgres->signatures; gpgsig; gpgsig = gpgsig->next)
                    {
                      DEBUGP (("Checking signature %s\n", gpgsig->fpr));

                      if (gpgsig->summary
                          & (GPGME_SIGSUM_VALID | GPGME_SIGSUM_GREEN))
                        {
                          logputs (LOG_VERBOSE,
                                   _("Signature validation suceeded.\n"));
                          sig_status = 1;
                          break;
                        }

                      if (gpgsig->summary & GPGME_SIGSUM_RED)
                        {
                          logputs (LOG_NOTQUIET,
                                   _("Invalid signature. Rejecting resource.\n"));
                          sig_status = -1;
                          break;
                        }

                      if (gpgsig->summary == 0
                          && (gpgsig->status & 0xFFFF) == GPG_ERR_NO_ERROR)
                        {
                          logputs (LOG_VERBOSE,
                                   _("Data matches signature, but signature "
                                     "is not trusted.\n"));
                        }

                      if ((gpgsig->status & 0xFFFF) != GPG_ERR_NO_ERROR)
                        {
                          logprintf (LOG_NOTQUIET,
                                     "GPGME: %s\n",
                                     gpgme_strerror (gpgsig->status & 0xFFFF));
                        }
                    }
                  gpgme_data_release (gpgsigdata);
                  gpgme_release (gpgctx);
                  gpgme_data_release (gpgdata);
gpg_skip_verification:
                  if (fd != -1)
                    close (fd);
                } /* endif (mfile->signature) */
#endif
              /* Stop if file was downloaded with success.  */
              if (sig_status >= 0)
                break;
            } /* endif RETR_OK.  */
        } /* Iterate over resources.  */

      if (retr_err != RETROK)
        {
          logprintf (LOG_VERBOSE, _("Failed to download %s. Skipping resource.\n"),
                     quote (mfile->name));
        }
      else if (!hash_ok)
        {
          retr_err = METALINK_CHKSUM_ERROR;
          logprintf (LOG_NOTQUIET,
                     _("File %s retrieved but checksum does not match. "
                       "\n"), quote (mfile->name));
        }
#ifdef HAVE_GPGME
        /* Signature will be only validated if hash check was successful.  */
      else if (sig_status < 0)
        {
          retr_err = METALINK_SIG_ERROR;
          logprintf (LOG_NOTQUIET,
                     _("File %s retrieved but signature does not match. "
                       "\n"), quote (mfile->name));
        }
#endif
      last_retr_err = retr_err == RETROK ? last_retr_err : retr_err;

      /* Remove the file if error encountered or if option specified.
         Note: the file has been downloaded using *_loop. Therefore, it
         is not necessary to keep the file for continuated download.  */
      if ((retr_err != RETROK || opt.delete_after)
           && filename != NULL && file_exists_p (filename))
        {
          logprintf (LOG_VERBOSE, _("Removing %s.\n"), quote (filename));
          if (unlink (filename))
            logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
        }
      if (output_stream)
        {
          fclose (output_stream);
          output_stream = NULL;
        }
      xfree (filename);
    } /* Iterate over files.  */

  /* Restore original values.  */
  opt.output_document = _output_document;
  output_stream_regular = _output_stream_regular;
  output_stream = _output_stream;

  return last_retr_err;
}
Exemplo n.º 21
0
gpgme_data_t sgpgme_decrypt_verify(gpgme_data_t cipher, gpgme_verify_result_t *status, gpgme_ctx_t ctx)
{
	struct passphrase_cb_info_s info;
	gpgme_data_t plain;
	gpgme_error_t err;

	memset (&info, 0, sizeof info);
	
	if ((err = gpgme_data_new(&plain)) != GPG_ERR_NO_ERROR) {
		gpgme_release(ctx);
		privacy_set_error(_("Couldn't initialize data, %s"), gpgme_strerror(err));
		return NULL;
	}
	
	if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
		prefs_gpg_enable_agent(prefs_gpg_get_config()->use_gpg_agent);
    		if (!getenv("GPG_AGENT_INFO") || !prefs_gpg_get_config()->use_gpg_agent) {
        		info.c = ctx;
        		gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info);
    		}
	} else {
		prefs_gpg_enable_agent(TRUE);
        	info.c = ctx;
        	gpgme_set_passphrase_cb (ctx, NULL, &info);
	}
	
	
	if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) {
		err = gpgme_op_decrypt_verify(ctx, cipher, plain);
		if (err != GPG_ERR_NO_ERROR) {
			debug_print("can't decrypt (%s)\n", gpgme_strerror(err));
			privacy_set_error("%s", gpgme_strerror(err));
			gpgmegtk_free_passphrase();
			gpgme_data_release(plain);
			return NULL;
		}

		err = cm_gpgme_data_rewind(plain);
		if (err) {
			debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno));
		}

		debug_print("decrypted.\n");
		*status = gpgme_op_verify_result (ctx);
	} else {
		err = gpgme_op_decrypt(ctx, cipher, plain);
		if (err != GPG_ERR_NO_ERROR) {
			debug_print("can't decrypt (%s)\n", gpgme_strerror(err));
			privacy_set_error("%s", gpgme_strerror(err));
			gpgmegtk_free_passphrase();
			gpgme_data_release(plain);
			return NULL;
		}

		err = cm_gpgme_data_rewind(plain);
		if (err) {
			debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno));
		}

		debug_print("decrypted.\n");
		*status = gpgme_op_verify_result (ctx);
	}
	return plain;
}
Exemplo n.º 22
0
/**
 * Check the PGP signature for the given file path.
 * If base64_sig is provided, it will be used as the signature data after
 * decoding. If base64_sig is NULL, expect a signature file next to path
 * (e.g. "%s.sig").
 *
 * The return value will be 0 if nothing abnormal happened during the signature
 * check, and -1 if an error occurred while checking signatures or if a
 * signature could not be found; pm_errno will be set. Note that "abnormal"
 * does not include a failed signature; the value in siglist should be checked
 * to determine if the signature(s) are good.
 * @param handle the context handle
 * @param path the full path to a file
 * @param base64_sig optional PGP signature data in base64 encoding
 * @param siglist a pointer to storage for signature results
 * @return 0 in normal cases, -1 if the something failed in the check process
 */
int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path,
		const char *base64_sig, alpm_siglist_t *siglist)
{
	int ret = -1, sigcount;
	gpgme_error_t gpg_err = 0;
	gpgme_ctx_t ctx;
	gpgme_data_t filedata, sigdata;
	gpgme_verify_result_t verify_result;
	gpgme_signature_t gpgsig;
	char *sigpath = NULL;
	unsigned char *decoded_sigdata = NULL;
	FILE *file = NULL, *sigfile = NULL;

	if(!path || _alpm_access(handle, NULL, path, R_OK) != 0) {
		RET_ERR(handle, ALPM_ERR_NOT_A_FILE, -1);
	}

	if(!siglist) {
		RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
	}
	siglist->count = 0;

	if(!base64_sig) {
		sigpath = _alpm_sigpath(handle, path);
		if(_alpm_access(handle, NULL, sigpath, R_OK) != 0
				|| (sigfile = fopen(sigpath, "rb")) == NULL) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "sig path %s could not be opened\n",
					sigpath);
			handle->pm_errno = ALPM_ERR_SIG_MISSING;
			goto error;
		}
	}

	/* does the file we are verifying exist? */
	file = fopen(path, "rb");
	if(file == NULL) {
		handle->pm_errno = ALPM_ERR_NOT_A_FILE;
		goto error;
	}

	if(init_gpgme(handle)) {
		/* pm_errno was set in gpgme_init() */
		goto error;
	}

	_alpm_log(handle, ALPM_LOG_DEBUG, "checking signature for %s\n", path);

	memset(&ctx, 0, sizeof(ctx));
	memset(&sigdata, 0, sizeof(sigdata));
	memset(&filedata, 0, sizeof(filedata));

	gpg_err = gpgme_new(&ctx);
	CHECK_ERR();

	/* create our necessary data objects to verify the signature */
	gpg_err = gpgme_data_new_from_stream(&filedata, file);
	CHECK_ERR();

	/* next create data object for the signature */
	if(base64_sig) {
		/* memory-based, we loaded it from a sync DB */
		size_t data_len;
		int decode_ret = alpm_decode_signature(base64_sig,
				&decoded_sigdata, &data_len);
		if(decode_ret) {
			handle->pm_errno = ALPM_ERR_SIG_INVALID;
			goto gpg_error;
		}
		gpg_err = gpgme_data_new_from_mem(&sigdata,
				(char *)decoded_sigdata, data_len, 0);
	} else {
		/* file-based, it is on disk */
		gpg_err = gpgme_data_new_from_stream(&sigdata, sigfile);
	}
	CHECK_ERR();

	/* here's where the magic happens */
	gpg_err = gpgme_op_verify(ctx, sigdata, filedata, NULL);
	CHECK_ERR();
	verify_result = gpgme_op_verify_result(ctx);
	CHECK_ERR();
	if(!verify_result || !verify_result->signatures) {
		_alpm_log(handle, ALPM_LOG_DEBUG, "no signatures returned\n");
		handle->pm_errno = ALPM_ERR_SIG_MISSING;
		goto gpg_error;
	}
	for(gpgsig = verify_result->signatures, sigcount = 0;
			gpgsig; gpgsig = gpgsig->next, sigcount++);
	_alpm_log(handle, ALPM_LOG_DEBUG, "%d signatures returned\n", sigcount);

	CALLOC(siglist->results, sigcount, sizeof(alpm_sigresult_t),
			handle->pm_errno = ALPM_ERR_MEMORY; goto gpg_error);
	siglist->count = sigcount;

	for(gpgsig = verify_result->signatures, sigcount = 0; gpgsig;
			gpgsig = gpgsig->next, sigcount++) {
		alpm_list_t *summary_list, *summary;
		alpm_sigstatus_t status;
		alpm_sigvalidity_t validity;
		gpgme_key_t key;
		alpm_sigresult_t *result;

		_alpm_log(handle, ALPM_LOG_DEBUG, "fingerprint: %s\n", gpgsig->fpr);
		summary_list = list_sigsum(gpgsig->summary);
		for(summary = summary_list; summary; summary = summary->next) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "summary: %s\n", (const char *)summary->data);
		}
		alpm_list_free(summary_list);
		_alpm_log(handle, ALPM_LOG_DEBUG, "status: %s\n", gpgme_strerror(gpgsig->status));
		_alpm_log(handle, ALPM_LOG_DEBUG, "timestamp: %lu\n", gpgsig->timestamp);

		if((time_t)gpgsig->timestamp > time(NULL)) {
			_alpm_log(handle, ALPM_LOG_DEBUG,
					"signature timestamp is greater than system time.\n");
		}

		_alpm_log(handle, ALPM_LOG_DEBUG, "exp_timestamp: %lu\n", gpgsig->exp_timestamp);
		_alpm_log(handle, ALPM_LOG_DEBUG, "validity: %s; reason: %s\n",
				string_validity(gpgsig->validity),
				gpgme_strerror(gpgsig->validity_reason));

		result = siglist->results + sigcount;
		gpg_err = gpgme_get_key(ctx, gpgsig->fpr, &key, 0);
		if(gpg_err_code(gpg_err) == GPG_ERR_EOF) {
			_alpm_log(handle, ALPM_LOG_DEBUG, "key lookup failed, unknown key\n");
			gpg_err = GPG_ERR_NO_ERROR;
			/* we dupe the fpr in this case since we have no key to point at */
			STRDUP(result->key.fingerprint, gpgsig->fpr,
					handle->pm_errno = ALPM_ERR_MEMORY; goto gpg_error);
		} else {
Exemplo n.º 23
0
Arquivo: gpg.c Projeto: zde/librepo
gboolean
lr_gpg_check_signature_fd(int signature_fd,
                          int data_fd,
                          const char *home_dir,
                          GError **err)
{
    gpgme_error_t gpgerr;
    gpgme_ctx_t context;
    gpgme_data_t signature_data;
    gpgme_data_t data_data;
    gpgme_verify_result_t result;
    gpgme_signature_t sig;

    assert(!err || *err == NULL);

    // Initialization
    gpgme_check_version(NULL);
    gpgerr = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
    if (gpgerr != GPG_ERR_NO_ERROR) {
        g_debug("%s: gpgme_engine_check_version: %s",
                 __func__, gpgme_strerror(gpgerr));
        g_set_error(err, LR_GPG_ERROR, LRE_GPGNOTSUPPORTED,
                    "gpgme_engine_check_version() error: %s",
                    gpgme_strerror(gpgerr));
        return FALSE;
    }

    gpgerr = gpgme_new(&context);
    if (gpgerr != GPG_ERR_NO_ERROR) {
        g_debug("%s: gpgme_new: %s", __func__, gpgme_strerror(gpgerr));
        g_set_error(err, LR_GPG_ERROR, LRE_GPGERROR,
                    "gpgme_new() error: %s", gpgme_strerror(gpgerr));
        return FALSE;
    }

    gpgerr = gpgme_set_protocol(context, GPGME_PROTOCOL_OpenPGP);
    if (gpgerr != GPG_ERR_NO_ERROR) {
        g_debug("%s: gpgme_set_protocol: %s", __func__, gpgme_strerror(gpgerr));
        g_set_error(err, LR_GPG_ERROR, LRE_GPGERROR,
                    "gpgme_set_protocol() error: %s", gpgme_strerror(gpgerr));
        gpgme_release(context);
        return FALSE;
    }

    if (home_dir) {
        gpgerr = gpgme_ctx_set_engine_info(context, GPGME_PROTOCOL_OpenPGP,
                                        NULL, home_dir);
        if (gpgerr != GPG_ERR_NO_ERROR) {
            g_debug("%s: gpgme_ctx_set_engine_info: %s", __func__,
                    gpgme_strerror(gpgerr));
            g_set_error(err, LR_GPG_ERROR, LRE_GPGERROR,
                        "gpgme_ctx_set_engine_info() error: %s",
                        gpgme_strerror(gpgerr));
            gpgme_release(context);
            return FALSE;
        }
    }

    gpgme_set_armor(context, 1);

    gpgerr = gpgme_data_new_from_fd(&signature_data, signature_fd);
    if (gpgerr != GPG_ERR_NO_ERROR) {
        g_debug("%s: gpgme_data_new_from_fd: %s",
                 __func__, gpgme_strerror(gpgerr));
        g_set_error(err, LR_GPG_ERROR, LRE_GPGERROR,
                    "gpgme_data_new_from_fd(_, %d) error: %s",
                    signature_fd, gpgme_strerror(gpgerr));
        gpgme_release(context);
        return FALSE;
    }

    gpgerr = gpgme_data_new_from_fd(&data_data, data_fd);
    if (gpgerr != GPG_ERR_NO_ERROR) {
        g_debug("%s: gpgme_data_new_from_fd: %s",
                 __func__, gpgme_strerror(gpgerr));
        g_set_error(err, LR_GPG_ERROR, LRE_GPGERROR,
                    "gpgme_data_new_from_fd(_, %d) error: %s",
                    data_fd, gpgme_strerror(gpgerr));
        gpgme_data_release(signature_data);
        gpgme_release(context);
        return FALSE;
    }

    // Verify
    gpgerr = gpgme_op_verify(context, signature_data, data_data, NULL);
    gpgme_data_release(signature_data);
    gpgme_data_release(data_data);
    if (gpgerr != GPG_ERR_NO_ERROR) {
        g_debug("%s: gpgme_op_verify: %s", __func__, gpgme_strerror(gpgerr));
        g_set_error(err, LR_GPG_ERROR, LRE_GPGERROR,
                    "gpgme_op_verify() error: %s", gpgme_strerror(gpgerr));
        gpgme_release(context);
        return FALSE;
    }

    result = gpgme_op_verify_result(context);
    if (!result) {
        g_debug("%s: gpgme_op_verify_result: error", __func__);
        g_set_error(err, LR_GPG_ERROR, LRE_GPGERROR,
                    "gpgme_op_verify_result() error: %s",
                    gpgme_strerror(gpgerr));
        gpgme_release(context);
        return FALSE;
    }

    // Check result of verification
    sig = result->signatures;
    if(!sig) {
        g_debug("%s: signature verify error (no signatures)", __func__);
        g_set_error(err, LR_GPG_ERROR, LRE_BADGPG,
                    "Signature verify error - no signatures");
        gpgme_release(context);
        return FALSE;
    }

    // Example of signature usage could be found in gpgme git repository
    // in the gpgme/tests/run-verify.c
    for (; sig; sig = sig->next) {
        if ((sig->summary & GPGME_SIGSUM_VALID) ||  // Valid
            (sig->summary & GPGME_SIGSUM_GREEN) ||  // Valid
            (sig->summary == 0 && sig->status == GPG_ERR_NO_ERROR)) // Valid but key is not certified with a trusted signature
        {
            gpgme_release(context);
            return TRUE;
        }
    }

    gpgme_release(context);
    g_debug("%s: Bad GPG signature", __func__);
    g_set_error(err, LR_GPG_ERROR, LRE_BADGPG, "Bad GPG signature");
    return FALSE;
}
Exemplo n.º 24
0
Arquivo: gpg.c Projeto: comotion/cpm
/* #############################################################################
 *
 * Description    encrypt the given buffer and return the encrypted data with
 *                an updated size information
 * Author         Harry Brueckner
 * Date           2005-03-31
 * Arguments      char* buffer      - buffer to encrypt
 *                int size          - size of the buffer
 *                char** newbuffer  - pointer to the new buffer which holds the
 *                                    encrypted data
 *                int* newsize      - size of the returned buffer
 *                PASSPHRASE_FN password_cb   - callback function pointer used
 *                                              to get the current passphrase
 *                SHOWERROR_FN showerror_cb   - callback function pointer used
 *                                              to display errors
 * Return         0 if ok, otherwise 1
 */
int gpgDecrypt(char* buffer, int size, char** newbuffer, int* newsize,
    PASSPHRASE_FN password_cb, SHOWERROR_FN showerror_cb)
  {
    gpgme_ctx_t         context;
    gpgme_error_t       error;
    gpgme_data_t        input,
                        output;
    gpgme_decrypt_result_t  decrypt_result = NULL;
    gpgme_verify_result_t   verify_result;
    int                 showerror = 1;
    char*               agent;
    char*               tmpbuffer = NULL;

    TRACE(99, "gpgDecrypt()", NULL);

    /* we set our passphrase callback function */
    passphrase_callback = password_cb;

    *newbuffer = NULL;
    *newsize = 0;

    error = gpgme_new(&context);
    if (error)
      {
        (showerror_cb)(_("GpgMe context error"), gpgme_strerror(error));
        return 1;
      }
    else
      {   /* we got a context, we set the passphrase callback */
        /* Flawfinder: ignore */
        agent = getenv("GPG_AGENT_INFO");
        if (!(agent && strchr(agent, ':')))
          {
            retries = 0;
            gpgme_set_passphrase_cb(context, gpgRequestPassphrase, NULL);
          }
      }

    if (!error)
      { error = gpgme_data_new_from_mem(&input, buffer, size, 0); }

    if (!error)
      { error = gpgme_data_new(&output); }

    if (!error)
      { error = gpgme_op_decrypt_verify(context, input, output); }

    if (!error)
      { decrypt_result = gpgme_op_decrypt_result(context); }

    if (!error &&
        decrypt_result &&
        decrypt_result -> unsupported_algorithm)
      {
        tmpbuffer = memAlloc(__FILE__, __LINE__, STDBUFFERLENGTH);
        snprintf(tmpbuffer, STDBUFFERLENGTH, _("unsupported algorithm: %s\n"),
            decrypt_result -> unsupported_algorithm);
        (showerror_cb)(_("GpgMe error"), tmpbuffer);
        memFree(__FILE__, __LINE__, tmpbuffer, STDBUFFERLENGTH);

        showerror = 0;
        error = 1;
      }

    if (!error)
      {
        verify_result = gpgme_op_verify_result(context);
        error = gpgCheckVerifyResult(showerror_cb, verify_result,
            GPG_ERR_NO_ERROR);
        showerror = !error;
      }

    /* we don't need the passphrase any longer */
    clearPassphrase(0);

    if (!error)
      { tmpbuffer = gpgData2Char(output, newsize); }

#ifdef GPGME_HAS_RECIPIENT
    /* we get the recipients of the message for the further re-encryption of
     * the file
     */
    if (!error &&
        decrypt_result &&
        decrypt_result -> recipients)
      {
        error = gpgGetRecipients(decrypt_result -> recipients, showerror_cb);
        showerror = 0;
      }
#endif

    gpgme_data_release(input);
    gpgme_data_release(output);
    gpgme_release(context);

    *newbuffer = tmpbuffer;

    if (error)
      {
        if (showerror)
          { (showerror_cb)(_("GpgMe decrypt error"), gpgme_strerror(error)); }
        return 1;
      }
    else
        return 0;
  }
Exemplo n.º 25
0
int
opkg_verify_file (char *text_file, char *sig_file)
{
#if defined HAVE_GPGME
    if (conf->check_signature == 0 )
        return 0;
    int status = -1;
    gpgme_ctx_t ctx;
    gpgme_data_t sig, text, key;
    gpgme_error_t err;
    gpgme_verify_result_t result;
    gpgme_signature_t s;
    char *trusted_path = NULL;

    gpgme_check_version (NULL);

    err = gpgme_new (&ctx);

    if (err)
	return -1;

    sprintf_alloc(&trusted_path, "%s/%s", conf->offline_root, "/etc/opkg/trusted.gpg");
    err = gpgme_data_new_from_file (&key, trusted_path, 1);
    free (trusted_path);
    if (err)
    {
      return -1;
    }
    err = gpgme_op_import (ctx, key);
    if (err)
    {
      gpgme_data_release (key);
      return -1;
    }
    gpgme_data_release (key);

    err = gpgme_data_new_from_file (&sig, sig_file, 1);
    if (err)
    {
	gpgme_release (ctx);
	return -1;
    }

    err = gpgme_data_new_from_file (&text, text_file, 1);
    if (err)
    {
        gpgme_data_release (sig);
	gpgme_release (ctx);
	return -1;
    }

    err = gpgme_op_verify (ctx, sig, text, NULL);

    result = gpgme_op_verify_result (ctx);
    if (!result)
	return -1;

    /* see if any of the signitures matched */
    s = result->signatures;
    while (s)
    {
	status = gpg_err_code (s->status);
	if (status == GPG_ERR_NO_ERROR)
	    break;
	s = s->next;
    }


    gpgme_data_release (sig);
    gpgme_data_release (text);
    gpgme_release (ctx);

    return status;
#elif defined HAVE_OPENSSL
    X509_STORE *store = NULL;
    PKCS7 *p7 = NULL;
    BIO *in = NULL, *indata = NULL;

    // Sig check failed by default !
    int status = -1;

    openssl_init();

    // Set-up the key store
    if(!(store = setup_verify(conf->signature_ca_file, conf->signature_ca_path))){
        opkg_msg(ERROR, "Can't open CA certificates.\n");
        goto verify_file_end;
    }

    // Open a BIO to read the sig file
    if (!(in = BIO_new_file(sig_file, "rb"))){
        opkg_msg(ERROR, "Can't open signature file %s.\n", sig_file);
        goto verify_file_end;
    }

    // Read the PKCS7 block contained in the sig file
    p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
    if(!p7){
        opkg_msg(ERROR, "Can't read signature file %s (Corrupted ?).\n",
		sig_file);
        goto verify_file_end;
    }
#if defined(HAVE_PATHFINDER)
    if(conf->check_x509_path){
	if(!pkcs7_pathfinder_verify_signers(p7)){
	    opkg_msg(ERROR, "pkcs7_pathfinder_verify_signers: "
		    "Path verification failed.\n");
	    goto verify_file_end;
	}
    }
#endif

    // Open the Package file to authenticate
    if (!(indata = BIO_new_file(text_file, "rb"))){
        opkg_msg(ERROR, "Can't open file %s.\n", text_file);
        goto verify_file_end;
    }

    // Let's verify the autenticity !
    if (PKCS7_verify(p7, NULL, store, indata, NULL, PKCS7_BINARY) != 1){
        // Get Off My Lawn!
        opkg_msg(ERROR, "Verification failure.\n");
    }else{
        // Victory !
        status = 0;
    }

verify_file_end:
    BIO_free(in);
    BIO_free(indata);
    PKCS7_free(p7);
    X509_STORE_free(store);

    return status;
#else
    /* mute `unused variable' warnings. */
    (void) sig_file;
    (void) text_file;
    (void) conf;
    return 0;
#endif
}
Exemplo n.º 26
0
retvalue signature_check(const struct signature_requirement *requirements, const char *releasegpg, const char *release) {
	gpg_error_t err;
	int fd, gpgfd;
	gpgme_data_t dh, dh_gpg;
	gpgme_verify_result_t result;
	int i;
	const struct signature_requirement *req;

	assert (requirements != NULL);

	if (FAILEDTOALLOC(release) || FAILEDTOALLOC(releasegpg))
		return RET_ERROR_OOM;

	assert (context != NULL);

	/* Read the file and its signature into memory: */
	gpgfd = open(releasegpg, O_RDONLY|O_NOCTTY);
	if (gpgfd < 0) {
		int e = errno;
		fprintf(stderr, "Error opening '%s': %s\n",
				releasegpg, strerror(e));
		return RET_ERRNO(e);
	}
	fd = open(release, O_RDONLY|O_NOCTTY);
	if (fd < 0) {
		int e = errno;
		(void)close(gpgfd);
		fprintf(stderr, "Error opening '%s': %s\n",
			       release, strerror(e));
		return RET_ERRNO(e);
	}
	err = gpgme_data_new_from_fd(&dh_gpg, gpgfd);
	if (err != 0) {
		(void)close(gpgfd); (void)close(fd);
		fprintf(stderr, "Error reading '%s':\n", releasegpg);
		return gpgerror(err);
	}
	err = gpgme_data_new_from_fd(&dh, fd);
	if (err != 0) {
		gpgme_data_release(dh_gpg);
		(void)close(gpgfd); (void)close(fd);
		fprintf(stderr, "Error reading '%s':\n", release);
		return gpgerror(err);
	}

	/* Verify the signature */

	err = gpgme_op_verify(context, dh_gpg, dh, NULL);
	gpgme_data_release(dh_gpg);
	gpgme_data_release(dh);
	close(gpgfd); close(fd);
	if (err != 0) {
		fprintf(stderr, "Error verifying '%s':\n", releasegpg);
		return gpgerror(err);
	}

	result = gpgme_op_verify_result(context);
	if (result == NULL) {
		fprintf(stderr,
"Internal error communicating with libgpgme: no result record!\n\n");
		return RET_ERROR_GPGME;
	}

	for (req = requirements ; req != NULL ; req = req->next) {
		bool fullfilled = false;

		/* check first for good signatures, and then for good enough
		   signatures, to not pester the user with warnings of one
		   of the alternate keys, if the last one is good enough */

		for (i = 0 ; (size_t)i < req->num_keys ; i++) {

			if (key_good(&req->keys[i], result->signatures)) {
				fullfilled = true;
				break;
			}
		}
		for (i = 0 ; !fullfilled && (size_t)i < req->num_keys ; i++) {

			if (key_good_enough(&req->keys[i], result->signatures,
						releasegpg, release)) {
				fullfilled = true;
				break;
			}
		}
		if (!fullfilled) {
			fprintf(stderr,
"ERROR: Condition '%s' not fullfilled for '%s'.\n",
					req->condition, releasegpg);
			print_signatures(stderr, result->signatures,
					releasegpg);
			return RET_ERROR_BADSIG;
		}
		if (verbose > 10) {
			fprintf(stdout, "Condition '%s' fullfilled for '%s'.\n",
					req->condition, releasegpg);
		}
	}
	if (verbose > 20)
		print_signatures(stdout, result->signatures, releasegpg);
	return RET_OK;
}
Exemplo n.º 27
0
/* The main GPG decryption routine for libfko.
*/
int
gpgme_decrypt(fko_ctx_t fko_ctx, unsigned char *indata,
        size_t in_len, const char *pw, unsigned char **out, size_t *out_len)
{
    char                   *tmp_buf;
    int                     res;

    gpgme_ctx_t             gpg_ctx     = NULL;
    gpgme_data_t            cipher      = NULL;
    gpgme_data_t            plaintext   = NULL;
    gpgme_error_t           err;
    gpgme_decrypt_result_t  decrypt_res;
    gpgme_verify_result_t   verify_res;

    /* Initialize gpgme
    */
    res = init_gpgme(fko_ctx);
    if(res != FKO_SUCCESS)
        return(res);

    gpg_ctx = fko_ctx->gpg_ctx;

    err = gpgme_data_new(&plaintext);
    if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
    {
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        fko_ctx->gpg_err = err;

        return(FKO_ERROR_GPGME_PLAINTEXT_DATA_OBJ);
    }

    /* Initialize the cipher data (place into gpgme_data object)
    */
    err = gpgme_data_new_from_mem(&cipher, (char*)indata, in_len, 0);
    if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
    {
        gpgme_data_release(plaintext);
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        fko_ctx->gpg_err = err;

        return(FKO_ERROR_GPGME_CIPHER_DATA_OBJ);
    }

    /* Set the passphrase callback.
    */
    gpgme_set_passphrase_cb(gpg_ctx, my_passphrase_cb, (void*)pw);

    /* Now decrypt and verify.
    */
    err = gpgme_op_decrypt_verify(gpg_ctx, cipher, plaintext);
    if(gpg_err_code(err) != GPG_ERR_NO_ERROR)
    {
        gpgme_data_release(plaintext);
        gpgme_data_release(cipher);
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        fko_ctx->gpg_err = err;

        return(FKO_ERROR_GPGME_DECRYPT_FAILED);
    }

    /* Done with the cipher text.
    */
    gpgme_data_release(cipher);

    /* We check the "usupported_algorithm" flag in the decrypt result.
    */
    decrypt_res = gpgme_op_decrypt_result(gpg_ctx);

    if(decrypt_res->unsupported_algorithm)
    {
        gpgme_data_release(plaintext);
        gpgme_release(gpg_ctx);
        fko_ctx->gpg_ctx = NULL;

        return(FKO_ERROR_GPGME_DECRYPT_UNSUPPORTED_ALGORITHM);
    }

    /* Now verify the signatures if so configured.
    */
    if(fko_ctx->verify_gpg_sigs)
    {
        verify_res  = gpgme_op_verify_result(gpg_ctx);

        res = process_sigs(fko_ctx, verify_res);

        if(res != FKO_SUCCESS)
        {
            gpgme_data_release(plaintext);
            gpgme_release(gpg_ctx);
            fko_ctx->gpg_ctx = NULL;

            return(res);
        }
    }

    /* Get the encrypted data and its length from the gpgme data object.
    */
    tmp_buf = gpgme_data_release_and_get_mem(plaintext, out_len);

    /* Use calloc here with an extra byte because I am not sure if all systems
     * will include the terminating NULL with the decrypted data (which is
     * expected to be a string).
    */
    *out = calloc(1, *out_len+1); /* This is freed upon fko_ctx destruction. */

    if(*out == NULL)
        res = FKO_ERROR_MEMORY_ALLOCATION;
    else
    {
        memcpy(*out, tmp_buf, *out_len);
        res = FKO_SUCCESS;
    }

    gpgme_free(tmp_buf);

    return(res);
}
Exemplo n.º 28
0
/**
 * seahorse_service_crypto_verify_text:
 * @crypto: #SeahorseServiceCrypto context
 * @ktype: "openpgp"
 * @flags: FLAG_QUIET for no notification
 * @crypttext: the text to decrypt
 * @cleartext: the plaintext after verification (out)
 * @signer: the signer if the text is signed (out)
 * @error: a potential error (out)
 *
 * DBus: VerifyText
 *
 * Decrypts the @crypttext and returns it in @cleartext. If the text
 * was signed, the signed is returned.
 *
 * Returns: TRUE on success
 */
gboolean
seahorse_service_crypto_verify_text (SeahorseServiceCrypto *crypto, 
                                     const gchar *ktype, int flags, 
                                     const gchar *crypttext, gchar **cleartext,
                                     char **signer, GError **error)
{
    gpgme_verify_result_t status;
    gpgme_error_t gerr;
    SeahorseGpgmeOperation *pop; 
    gpgme_data_t plain, cipher;
    gboolean ret = TRUE;
    GQuark keyid;
    
    if (!g_str_equal (ktype, g_quark_to_string (SEAHORSE_PGP))) {
        g_set_error (error, SEAHORSE_DBUS_ERROR, SEAHORSE_DBUS_ERROR_INVALID,
                     _("Invalid key type for verifying: %s"), ktype);
        return FALSE;        
    }

    /* 
     * TODO: Once we support different kinds of keys that support encryption
     * then all this logic will need to change. 
     */

    pop = seahorse_gpgme_operation_new (NULL);
    
    /* new data from text */
    gerr = gpgme_data_new_from_mem (&cipher, crypttext, strlen (crypttext), FALSE);
    g_return_val_if_fail (GPG_IS_OK (gerr), FALSE);
    gerr = gpgme_data_new (&plain);
    g_return_val_if_fail (GPG_IS_OK (gerr), FALSE);
   
    /* encrypt with armor */
    gpgme_set_textmode (pop->gctx, TRUE);
    gpgme_set_armor (pop->gctx, TRUE);

    /* Do the decryption */
    gerr = gpgme_op_verify_start (pop->gctx, cipher, NULL, plain);

    /* Frees plain */
    ret = process_crypto_result (pop, gerr, plain, cleartext, NULL, error);
    
    if (ret) {
        *signer = NULL;
        status = gpgme_op_verify_result (pop->gctx);
    
        if (status->signatures) {
            if (!(flags & FLAG_QUIET))
                notify_signatures (NULL, status);
            if (status->signatures->summary & GPGME_SIGSUM_GREEN ||
                status->signatures->summary & GPGME_SIGSUM_VALID ||
                status->signatures->summary & GPGME_SIGSUM_KEY_MISSING) {
                keyid = seahorse_pgp_key_canonize_id (status->signatures->fpr);
                *signer = seahorse_context_id_to_dbus (SCTX_APP (), keyid);
            }
        }
    }
    
    g_object_unref (pop);
    gpgme_data_release (cipher);
    return TRUE;
}
Exemplo n.º 29
0
Arquivo: verify.c Projeto: gpg/gpgme
/* Retrieve certain attributes of a signature.  IDX is the index
   number of the signature after a successful verify operation.  WHAT
   is an attribute where GPGME_ATTR_EXPIRE is probably the most useful
   one.  WHATIDX is to be passed as 0 for most attributes . */
unsigned long
gpgme_get_sig_ulong_attr (gpgme_ctx_t ctx, int idx,
                          _gpgme_attr_t what, int whatidx)
{
  gpgme_verify_result_t result;
  gpgme_signature_t sig;

  result = gpgme_op_verify_result (ctx);
  sig = result->signatures;

  while (sig && idx)
    {
      sig = sig->next;
      idx--;
    }
  if (!sig || idx)
    return 0;

  switch (what)
    {
    case GPGME_ATTR_CREATED:
      return sig->timestamp;

    case GPGME_ATTR_EXPIRE:
      return sig->exp_timestamp;

    case GPGME_ATTR_VALIDITY:
      return (unsigned long) sig->validity;

    case GPGME_ATTR_SIG_STATUS:
      switch (gpg_err_code (sig->status))
	{
	case GPG_ERR_NO_ERROR:
	  return GPGME_SIG_STAT_GOOD;

	case GPG_ERR_BAD_SIGNATURE:
	  return GPGME_SIG_STAT_BAD;

	case GPG_ERR_NO_PUBKEY:
	  return GPGME_SIG_STAT_NOKEY;

	case GPG_ERR_NO_DATA:
	  return GPGME_SIG_STAT_NOSIG;

	case GPG_ERR_SIG_EXPIRED:
	  return GPGME_SIG_STAT_GOOD_EXP;

	case GPG_ERR_KEY_EXPIRED:
	  return GPGME_SIG_STAT_GOOD_EXPKEY;

	default:
	  return GPGME_SIG_STAT_ERROR;
	}

    case GPGME_ATTR_SIG_SUMMARY:
      return sig->summary;

    default:
      break;
    }
  return 0;
}
Exemplo n.º 30
0
static GMimeSignatureList *
pkcs7_get_signatures (Pkcs7Ctx *pkcs7, gboolean verify)
{
	GMimeSignatureList *signatures;
	GMimeSignature *signature;
	gpgme_verify_result_t result;
	gpgme_subkey_t subkey;
	gpgme_signature_t sig;
	gpgme_user_id_t uid;
	gpgme_key_t key;
	
	/* get the signature verification results from GpgMe */
	if (!(result = gpgme_op_verify_result (pkcs7->ctx)) || !result->signatures)
		return verify ? g_mime_signature_list_new () : NULL;
	
	/* create a new signature list to return */
	signatures = g_mime_signature_list_new ();
	
	sig = result->signatures;
	
	while (sig != NULL) {
		signature = g_mime_signature_new ();
		g_mime_signature_list_add (signatures, signature);
		
		if (sig->status != GPG_ERR_NO_ERROR)
			g_mime_signature_set_status (signature, GMIME_SIGNATURE_STATUS_ERROR);
		else
			g_mime_signature_set_status (signature, GMIME_SIGNATURE_STATUS_GOOD);
		
		g_mime_certificate_set_pubkey_algo (signature->cert, sig->pubkey_algo);
		g_mime_certificate_set_digest_algo (signature->cert, sig->hash_algo);
		g_mime_certificate_set_fingerprint (signature->cert, sig->fpr);
		g_mime_signature_set_expires (signature, sig->exp_timestamp);
		g_mime_signature_set_created (signature, sig->timestamp);
		
		if (sig->exp_timestamp != 0 && sig->exp_timestamp <= time (NULL)) {
			/* signature expired, automatically results in a BAD signature */
			signature->errors |= GMIME_SIGNATURE_ERROR_EXPSIG;
			signature->status = GMIME_SIGNATURE_STATUS_BAD;
		}
		
		if (gpgme_get_key (pkcs7->ctx, sig->fpr, &key, 0) == GPG_ERR_NO_ERROR && key) {
			/* get more signer info from their signing key */
			g_mime_certificate_set_trust (signature->cert, pkcs7_trust (key->owner_trust));
			g_mime_certificate_set_issuer_serial (signature->cert, key->issuer_serial);
			g_mime_certificate_set_issuer_name (signature->cert, key->issuer_name);
			
			/* get the keyid, name, and email address */
			uid = key->uids;
			while (uid) {
				if (uid->name && *uid->name)
					g_mime_certificate_set_name (signature->cert, uid->name);
				
				if (uid->email && *uid->email)
					g_mime_certificate_set_email (signature->cert, uid->email);
				
				if (uid->uid && *uid->uid)
					g_mime_certificate_set_key_id (signature->cert, uid->uid);
				
				if (signature->cert->name && signature->cert->email && signature->cert->keyid)
					break;
				
				uid = uid->next;
			}
			
			/* get the subkey used for signing */
			subkey = key->subkeys;
			while (subkey && !subkey->can_sign)
				subkey = subkey->next;
			
			if (subkey) {
				g_mime_certificate_set_created (signature->cert, subkey->timestamp);
				g_mime_certificate_set_expires (signature->cert, subkey->expires);
				
				if (subkey->revoked) {
					/* signer's key has been revoked, automatic BAD status */
					signature->errors |= GMIME_SIGNATURE_ERROR_REVKEYSIG;
					signature->status = GMIME_SIGNATURE_STATUS_BAD;
				}
				
				if (subkey->expired) {
					/* signer's key has expired, automatic BAD status */
					signature->errors |= GMIME_SIGNATURE_ERROR_EXPKEYSIG;
					signature->status = GMIME_SIGNATURE_STATUS_BAD;
				}
			} else {
				/* If we don't have the subkey used by the signer, then we can't
				 * tell what the status is, so set to ERROR if it hasn't already
				 * been designated as BAD. */
				if (signature->status != GMIME_SIGNATURE_STATUS_BAD)
					signature->status = GMIME_SIGNATURE_STATUS_ERROR;
				signature->errors |= GMIME_SIGNATURE_ERROR_NO_PUBKEY;
			}
			
			gpgme_key_unref (key);
		} else {
			/* If we don't have the signer's public key, then we can't tell what
			 * the status is, so set it to ERROR if it hasn't already been
			 * designated as BAD. */
			g_mime_certificate_set_trust (signature->cert, GMIME_CERTIFICATE_TRUST_UNDEFINED);
			if (signature->status != GMIME_SIGNATURE_STATUS_BAD)
				signature->status = GMIME_SIGNATURE_STATUS_ERROR;
			signature->errors |= GMIME_SIGNATURE_ERROR_NO_PUBKEY;
		}
		
		sig = sig->next;
	}
	
	return signatures;
}