/**************** * Show the revocation reason as it is stored with the given signature */ static void do_show_revocation_reason( PKT_signature *sig ) { size_t n, nn; const byte *p, *pp; int seq = 0; const char *text; while( (p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON, &n, &seq, NULL )) ) { if( !n ) continue; /* invalid - just skip it */ if( *p == 0 ) text = _("No reason specified"); else if( *p == 0x01 ) text = _("Key is superseded"); else if( *p == 0x02 ) text = _("Key has been compromised"); else if( *p == 0x03 ) text = _("Key is no longer used"); else if( *p == 0x20 ) text = _("User ID is no longer valid"); else text = NULL; log_info ( _("reason for revocation: ")); if (text) log_printf ("%s\n", text); else log_printf ("code=%02x\n", *p ); n--; p++; pp = NULL; do { /* We don't want any empty lines, so skip them */ while( n && *p == '\n' ) { p++; n--; } if( n ) { pp = memchr( p, '\n', n ); nn = pp? pp - p : n; log_info ( _("revocation comment: ") ); es_write_sanitized (log_get_stream(), p, nn, NULL, NULL); log_printf ("\n"); p += nn; n -= nn; } } while( pp ); } }
/* This is a variant of gpgsm_print_name sending it output to an estream. */ void gpgsm_es_print_name2 (estream_t fp, const char *name, int translate) { const unsigned char *s = (const unsigned char *)name; int i; if (!s) { es_fputs (_("[Error - No name]"), fp); } else if (*s == '<') { const char *s2 = strchr ( (char*)s+1, '>'); if (s2) { if (translate) es_write_sanitized_utf8_buffer (fp, s + 1, s2 - (char*)s - 1, NULL, NULL); else es_write_sanitized (fp, s + 1, s2 - (char*)s - 1, NULL, NULL); } } else if (*s == '(') { pretty_es_print_sexp (fp, s, gcry_sexp_canon_len (s, 0, NULL, NULL)); } else if (!((*s >= '0' && *s < '9') || (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z'))) es_fputs (_("[Error - invalid encoding]"), fp); else { struct dn_array_s *dn = parse_dn (s); if (!dn) es_fputs (_("[Error - invalid DN]"), fp); else { print_dn_parts (NULL, fp, dn, translate); for (i=0; dn[i].key; i++) { xfree (dn[i].key); xfree (dn[i].value); } xfree (dn); } } }
/* Print a DN part to STREAM or if STREAM is NULL to FP. */ static void print_dn_part (FILE *fp, estream_t stream, struct dn_array_s *dn, const char *key, int translate) { struct dn_array_s *first_dn = dn; for (; dn->key; dn++) { if (!dn->done && !strcmp (dn->key, key)) { /* Forward to the last multi-valued RDN, so that we can print them all in reverse in the correct order. Note that this overrides the the standard sequence but that seems to a reasonable thing to do with multi-valued RDNs. */ while (dn->multivalued && dn[1].key) dn++; next: if (!dn->done && dn->value && *dn->value) { if (stream) { es_fprintf (stream, "/%s=", dn->key); if (translate) es_write_sanitized_utf8_buffer (stream, dn->value, strlen (dn->value), "/", NULL); else es_write_sanitized (stream, dn->value, strlen (dn->value), "/", NULL); } else { fprintf (fp, "/%s=", dn->key); if (translate) print_sanitized_utf8_string (fp, dn->value, '/'); else print_sanitized_string (fp, dn->value, '/'); } } dn->done = 1; if (dn > first_dn && dn[-1].multivalued) { dn--; goto next; } } } }
void dump_kbnode (KBNODE node) { for (; node; node = node->next ) { const char *s; switch (node->pkt->pkttype) { case 0: s="empty"; break; case PKT_PUBLIC_KEY: s="public-key"; break; case PKT_SECRET_KEY: s="secret-key"; break; case PKT_SECRET_SUBKEY: s= "secret-subkey"; break; case PKT_PUBKEY_ENC: s="public-enc"; break; case PKT_SIGNATURE: s="signature"; break; case PKT_ONEPASS_SIG: s="onepass-sig"; break; case PKT_USER_ID: s="user-id"; break; case PKT_PUBLIC_SUBKEY: s="public-subkey"; break; case PKT_COMMENT: s="comment"; break; case PKT_RING_TRUST: s="trust"; break; case PKT_PLAINTEXT: s="plaintext"; break; case PKT_COMPRESSED: s="compressed"; break; case PKT_ENCRYPTED: s="encrypted"; break; case PKT_GPG_CONTROL: s="gpg-control"; break; default: s="unknown"; break; } log_debug ("node %p %02x/%02x type=%s", node, node->flag, node->private_flag, s); if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; log_printf (" \""); es_write_sanitized (log_get_stream (), uid->name, uid->len, NULL, NULL); log_printf ("\" %c%c%c%c\n", uid->is_expired? 'e':'.', uid->is_revoked? 'r':'.', uid->created? 'v':'.', uid->is_primary? 'p':'.' ); } else if (node->pkt->pkttype == PKT_SIGNATURE) { log_printf (" class=%02x keyid=%08lX ts=%lu\n", node->pkt->pkt.signature->sig_class, (ulong)node->pkt->pkt.signature->keyid[1], (ulong)node->pkt->pkt.signature->timestamp); } else if (node->pkt->pkttype == PKT_GPG_CONTROL) { log_printf (" ctrl=%d len=%u\n", node->pkt->pkt.gpg_control->control, (unsigned int)node->pkt->pkt.gpg_control->datalen); } else if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { PKT_public_key *pk = node->pkt->pkt.public_key; log_printf (" keyid=%08lX a=%d u=%d %c%c%c%c\n", (ulong)keyid_from_pk( pk, NULL ), pk->pubkey_algo, pk->pubkey_usage, pk->has_expired? 'e':'.', pk->flags.revoked? 'r':'.', pk->flags.valid? 'v':'.', pk->flags.mdc? 'm':'.'); } log_flush (); } }
/* Insert the given fpr into our trustdb. We expect FPR to be an all uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'. This function does first check whether that key has already been put into the trustdb and returns success in this case. Before a FPR actually gets inserted, the user is asked by means of the Pinentry whether this is actual want he wants to do. */ gpg_error_t agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag) { gpg_error_t err = 0; char *desc; char *fname; estream_t fp; char *fprformatted; char *nameformatted; int is_disabled; int yes_i_trust; /* Check whether we are at all allowed to modify the trustlist. This is useful so that the trustlist may be a symlink to a global trustlist with only admin priviliges to modify it. Of course this is not a secure way of denying access, but it avoids the usual clicking on an Okay button most users are used to. */ fname = make_filename (opt.homedir, "trustlist.txt", NULL); if ( access (fname, W_OK) && errno != ENOENT) { xfree (fname); return gpg_error (GPG_ERR_EPERM); } xfree (fname); if (!agent_istrusted (ctrl, fpr, &is_disabled)) { return 0; /* We already got this fingerprint. Silently return success. */ } /* This feature must explicitly been enabled. */ if (!opt.allow_mark_trusted) return gpg_error (GPG_ERR_NOT_SUPPORTED); if (is_disabled) { /* There is an disabled entry in the trustlist. Return an error so that the user won't be asked again for that one. Changing this flag with the integrated marktrusted feature is and will not be made possible. */ return gpg_error (GPG_ERR_NOT_TRUSTED); } /* Insert a new one. */ nameformatted = reformat_name (name, "%0A "); if (!nameformatted) return gpg_error_from_syserror (); /* First a general question whether this is trusted. */ desc = xtryasprintf ( /* TRANSLATORS: This prompt is shown by the Pinentry and has one special property: A "%%0A" is used by Pinentry to insert a line break. The double percent sign is actually needed because it is also a printf format string. If you need to insert a plain % sign, you need to encode it as "%%25". The "%s" gets replaced by the name as stored in the certificate. */ _("Do you ultimately trust%%0A" " \"%s\"%%0A" "to correctly certify user certificates?"), nameformatted); if (!desc) { xfree (nameformatted); return out_of_core (); } err = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"), 1); xfree (desc); if (!err) yes_i_trust = 1; else if (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED) yes_i_trust = 0; else { xfree (nameformatted); return err; } fprformatted = insert_colons (fpr); if (!fprformatted) { xfree (nameformatted); return out_of_core (); } /* If the user trusts this certificate he has to verify the fingerprint of course. */ if (yes_i_trust) { desc = xtryasprintf ( /* TRANSLATORS: This prompt is shown by the Pinentry and has one special property: A "%%0A" is used by Pinentry to insert a line break. The double percent sign is actually needed because it is also a printf format string. If you need to insert a plain % sign, you need to encode it as "%%25". The second "%s" gets replaced by a hexdecimal fingerprint string whereas the first one receives the name as stored in the certificate. */ _("Please verify that the certificate identified as:%%0A" " \"%s\"%%0A" "has the fingerprint:%%0A" " %s"), nameformatted, fprformatted); if (!desc) { xfree (fprformatted); xfree (nameformatted); return out_of_core (); } /* TRANSLATORS: "Correct" is the label of a button and intended to be hit if the fingerprint matches the one of the CA. The other button is "the default "Cancel" of the Pinentry. */ err = agent_get_confirmation (ctrl, desc, _("Correct"), _("Wrong"), 1); xfree (desc); if (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED) yes_i_trust = 0; else if (err) { xfree (fprformatted); xfree (nameformatted); return err; } } /* Now check again to avoid duplicates. We take the lock to make sure that nobody else plays with our file and force a reread. */ lock_trusttable (); agent_reload_trustlist (); if (!agent_istrusted (ctrl, fpr, &is_disabled) || is_disabled) { unlock_trusttable (); xfree (fprformatted); xfree (nameformatted); return is_disabled? gpg_error (GPG_ERR_NOT_TRUSTED) : 0; } fname = make_filename (opt.homedir, "trustlist.txt", NULL); if ( access (fname, F_OK) && errno == ENOENT) { fp = es_fopen (fname, "wx,mode=-rw-r"); if (!fp) { err = gpg_error_from_syserror (); log_error ("can't create `%s': %s\n", fname, gpg_strerror (err)); xfree (fname); unlock_trusttable (); xfree (fprformatted); xfree (nameformatted); return err; } es_fputs (headerblurb, fp); es_fclose (fp); } fp = es_fopen (fname, "a+,mode=-rw-r"); if (!fp) { err = gpg_error_from_syserror (); log_error ("can't open `%s': %s\n", fname, gpg_strerror (err)); xfree (fname); unlock_trusttable (); xfree (fprformatted); xfree (nameformatted); return err; } /* Append the key. */ es_fputs ("\n# ", fp); xfree (nameformatted); nameformatted = reformat_name (name, "\n# "); if (!nameformatted || strchr (name, '\n')) { /* Note that there should never be a LF in NAME but we better play safe and print a sanitized version in this case. */ es_write_sanitized (fp, name, strlen (name), NULL, NULL); } else es_fputs (nameformatted, fp); es_fprintf (fp, "\n%s%s %c\n", yes_i_trust?"":"!", fprformatted, flag); if (es_ferror (fp)) err = gpg_error_from_syserror (); if (es_fclose (fp)) err = gpg_error_from_syserror (); agent_reload_trustlist (); xfree (fname); unlock_trusttable (); xfree (fprformatted); xfree (nameformatted); return err; }