aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/ChangeLog20
-rw-r--r--g10/Makefile.am2
-rw-r--r--g10/free-packet.c29
-rw-r--r--g10/gpgv.c7
-rw-r--r--g10/keygen.c21
-rw-r--r--g10/main.h1
-rw-r--r--g10/mainproc.c115
-rw-r--r--g10/misc.c25
-rw-r--r--g10/packet.h80
-rw-r--r--g10/parse-packet.c2
-rw-r--r--g10/pkclist.c42
11 files changed, 286 insertions, 58 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 9c1acbca6..f9fab2bea 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,23 @@
+2005-07-28 Werner Koch <[email protected]>
+
+ * Makefile.am (other_libs): Add SRVLIBS.
+
+ * parse-packet.c (can_handle_critical_notation): We know about
+ * packet.h (PKT_signature): New fields PKA_INFO and PKA_TRIED.
+ (pka_info_t): New.
+ * free-packet.c (cp_pka_info): New.
+ (free_seckey_enc, copy_signature): Support new fields.
+ * mainproc.c (get_pka_address, pka_uri_from_sig): New.
+ (check_sig_and_print): Try to get the keyserver from the PKA
+ record.
+ * pkclist.c (check_signatures_trust): Adjust the trust based on
+ the PKA.
+ * gpgv.c (parse_keyserver_uri): New stub.
+
+ * keygen.c (has_invalid_email_chars): Moved to ..
+ * misc.c (has_invalid_email_chars): .. here and made global.
+
2005-07-27 Werner Koch <[email protected]>
* export.c (do_export_stream): Make two strings translatable.
diff --git a/g10/Makefile.am b/g10/Makefile.am
index 9e50eeb9a..3c1ba7a76 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -28,7 +28,7 @@ if ! HAVE_DOSISH_SYSTEM
AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)/@PACKAGE@\""
endif
needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a
-other_libs = $(LIBICONV) $(LIBINTL) $(CAPLIBS)
+other_libs = $(LIBICONV) $(SRVLIBS) $(LIBINTL) $(CAPLIBS)
bin_PROGRAMS = gpg gpgv
diff --git a/g10/free-packet.c b/g10/free-packet.c
index 3ede4db9f..01ab543dd 100644
--- a/g10/free-packet.c
+++ b/g10/free-packet.c
@@ -1,6 +1,6 @@
/* free-packet.c - cleanup stuff for packets
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
- * Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
+ * 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -62,10 +62,17 @@ free_seckey_enc( PKT_signature *sig )
mpi_free(sig->data[0]);
for(i=0; i < n; i++ )
mpi_free( sig->data[i] );
-
+
xfree(sig->revkey);
xfree(sig->hashed);
xfree(sig->unhashed);
+
+ if (sig->pka_info)
+ {
+ xfree (sig->pka_info->uri);
+ xfree (sig->pka_info);
+ }
+
xfree(sig);
}
@@ -195,6 +202,21 @@ copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
sk->keyid[1] = pk->keyid[1];
}
+
+static pka_info_t *
+cp_pka_info (const pka_info_t *s)
+{
+ pka_info_t *d = xmalloc (sizeof *s + strlen (s->email));
+
+ d->valid = s->valid;
+ d->checked = s->checked;
+ d->uri = s->uri? xstrdup (s->uri):NULL;
+ memcpy (d->fpr, s->fpr, sizeof s->fpr);
+ strcpy (d->email, s->email);
+ return d;
+}
+
+
PKT_signature *
copy_signature( PKT_signature *d, PKT_signature *s )
{
@@ -210,6 +232,7 @@ copy_signature( PKT_signature *d, PKT_signature *s )
for(i=0; i < n; i++ )
d->data[i] = mpi_copy( s->data[i] );
}
+ d->pka_info = s->pka_info? cp_pka_info (s->pka_info) : NULL;
d->hashed = cp_subpktarea (s->hashed);
d->unhashed = cp_subpktarea (s->unhashed);
if(s->numrevkeys)
diff --git a/g10/gpgv.c b/g10/gpgv.c
index 29211075f..1f2687605 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -333,6 +333,13 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo,
}
struct keyserver_spec *parse_preferred_keyserver(PKT_signature *sig) {return NULL;}
+struct keyserver_spec *parse_keyserver_uri(const char *uri,int require_scheme,
+ const char *configname,
+ unsigned int configlineno)
+{
+ return NULL;
+}
+
void free_keyserver_spec(struct keyserver_spec *keyserver) {}
/* Stubs to avoid linking to photoid.c */
diff --git a/g10/keygen.c b/g10/keygen.c
index ca20ed8e8..a657c13c9 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -1609,27 +1609,6 @@ ask_expiredate()
return x? make_timestamp() + x : 0;
}
-static int
-has_invalid_email_chars( const char *s )
-{
- int at_seen=0;
- static char valid_chars[] = "01234567890_-."
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
- for( ; *s; s++ ) {
- if( *s & 0x80 )
- return 1;
- if( *s == '@' )
- at_seen=1;
- else if( !at_seen && !( !!strchr( valid_chars, *s ) || *s == '+' ) )
- return 1;
- else if( at_seen && !strchr( valid_chars, *s ) )
- return 1;
- }
- return 0;
-}
-
static char *
ask_user_id( int mode )
diff --git a/g10/main.h b/g10/main.h
index 8ffefbb5b..787b58add 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -125,6 +125,7 @@ char *argsplit(char *string);
int parse_options(char *str,unsigned int *options,
struct parse_options *opts,int noisy);
char *unescape_percent_string (const unsigned char *s);
+int has_invalid_email_chars (const char *s);
char *default_homedir (void);
const char *get_libexecdir (void);
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 5913f9304..afd347cfc 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -1296,6 +1296,86 @@ do_proc_packets( CTX c, IOBUF a )
}
+/* Helper for pka_uri_from_sig to parse the to-be-verified address out
+ of the notation data. */
+static pka_info_t *
+get_pka_address (PKT_signature *sig)
+{
+ const unsigned char *p;
+ size_t len, n1, n2;
+ int seq = 0;
+ pka_info_t *pka = NULL;
+
+ while ((p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION,
+ &len, &seq, NULL)))
+ {
+ if (len < 8)
+ continue; /* Notation packet is too short. */
+ n1 = (p[4]<<8)|p[5];
+ n2 = (p[6]<<8)|p[7];
+ if (8 + n1 + n2 != len)
+ continue; /* Length fields of notation packet are inconsistent. */
+ p += 8;
+ if (n1 != 21 || memcmp (p, "[email protected]", 21))
+ continue; /* Not the notation we want. */
+ p += n1;
+ if (n2 < 3)
+ continue; /* Impossible email address. */
+
+ if (pka)
+ break; /* For now we only use the first valid PKA notation. In
+ future we might want to keep additional PKA
+ notations in a linked list. */
+
+ pka = xmalloc (sizeof *pka + n2);
+ pka->valid = 0;
+ pka->checked = 0;
+ pka->uri = NULL;
+ memcpy (pka->email, p, n2);
+ pka->email[n2] = 0;
+
+ if (has_invalid_email_chars (pka->email))
+ {
+ /* We don't accept invalid mail addresses. */
+ xfree (pka);
+ pka = NULL;
+ }
+ }
+
+ return pka;
+}
+
+
+/* Return the URI from a DNS PKA record. If this record has already
+ be retrieved for the signature we merely return it; if not we go
+ out and try to get that DNS record. */
+static const char *
+pka_uri_from_sig (PKT_signature *sig)
+{
+ if (!sig->flags.pka_tried)
+ {
+ assert (!sig->pka_info);
+ sig->flags.pka_tried = 1;
+ sig->pka_info = get_pka_address (sig);
+ if (sig->pka_info)
+ {
+ char *uri;
+
+ uri = get_pka_info (sig->pka_info->email, sig->pka_info->fpr);
+ if (uri)
+ {
+ sig->pka_info->valid = 1;
+ if (!*uri)
+ xfree (uri);
+ else
+ sig->pka_info->uri = uri;
+ }
+ }
+ }
+ return sig->pka_info? sig->pka_info->uri : NULL;
+}
+
+
static int
check_sig_and_print( CTX c, KBNODE node )
{
@@ -1419,8 +1499,34 @@ check_sig_and_print( CTX c, KBNODE node )
}
}
- /* If the preferred keyserver thing above didn't work, this is a
- second try. */
+
+ /* If the preferred keyserver thing above didn't work, our second
+ try is to use the URI from a DNS PKA record. */
+ if ( rc == G10ERR_NO_PUBKEY )
+ {
+ const char *uri = pka_uri_from_sig (sig);
+
+ if (uri)
+ {
+ int res;
+ struct keyserver_spec *spec;
+
+ spec = parse_keyserver_uri (uri, 0, NULL, 0);
+ if (spec)
+ {
+ glo_ctrl.in_auto_key_retrieve++;
+ res = keyserver_import_keyid (sig->keyid, spec);
+ glo_ctrl.in_auto_key_retrieve--;
+ free_keyserver_spec (spec);
+ if (!res)
+ rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey );
+ }
+ }
+ }
+
+
+ /* If the preferred keyserver thing above didn't work and we got
+ no information from the DNS PKA, this is a third try. */
if( rc == G10ERR_NO_PUBKEY && opt.keyserver
&& (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE))
@@ -1673,8 +1779,11 @@ check_sig_and_print( CTX c, KBNODE node )
free_public_key( vpk );
}
- if( !rc )
+ if (!rc)
+ {
+ pka_uri_from_sig (sig); /* Make sure PKA info is available. */
rc = check_signatures_trust( sig );
+ }
if(sig->flags.expired)
{
diff --git a/g10/misc.c b/g10/misc.c
index 380172f09..88b7b2bb1 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -1065,6 +1065,31 @@ unescape_percent_string (const unsigned char *s)
+int
+has_invalid_email_chars (const char *s)
+{
+ int at_seen=0;
+ static char valid_chars[] = ("01234567890_-."
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+ for ( ; *s; s++ )
+ {
+ if ( *s & 0x80 )
+ return 1;
+ if ( *s == '@' )
+ at_seen=1;
+ else if ( !at_seen && !( !!strchr( valid_chars, *s ) || *s == '+' ) )
+ return 1;
+ else if ( at_seen && !strchr( valid_chars, *s ) )
+ return 1;
+ }
+ return 0;
+}
+
+
+
+
/* This is a helper function to load a Windows function from either of
one DLLs. */
#ifdef HAVE_W32_SYSTEM
diff --git a/g10/packet.h b/g10/packet.h
index cbbc0d7b6..0fe87f7ce 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -122,36 +122,56 @@ struct revocation_key {
byte fpr[MAX_FINGERPRINT_LEN];
};
-typedef struct {
- struct {
- unsigned checked:1; /* signature has been checked */
- unsigned valid:1; /* signature is good (if checked is set) */
- unsigned chosen_selfsig:1; /* a selfsig that is the chosen one */
- unsigned unknown_critical:1;
- unsigned exportable:1;
- unsigned revocable:1;
- unsigned policy_url:1; /* At least one policy URL is present */
- unsigned notation:1; /* At least one notation is present */
- unsigned pref_ks:1; /* At least one preferred keyserver is present */
- unsigned expired:1;
- } flags;
- u32 keyid[2]; /* 64 bit keyid */
- u32 timestamp; /* signature made */
- u32 expiredate; /* expires at this date or 0 if not at all */
- byte version;
- byte sig_class; /* sig classification, append for MD calculation*/
- byte pubkey_algo; /* algorithm used for public key scheme */
- /* (PUBKEY_ALGO_xxx) */
- byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */
- byte trust_depth;
- byte trust_value;
- const byte *trust_regexp;
- struct revocation_key **revkey;
- int numrevkeys;
- subpktarea_t *hashed; /* all subpackets with hashed data (v4 only) */
- subpktarea_t *unhashed; /* ditto for unhashed data */
- byte digest_start[2]; /* first 2 bytes of the digest */
- MPI data[PUBKEY_MAX_NSIG];
+
+/* Object to keep information about a PKA DNS record. */
+typedef struct
+{
+ int valid; /* An actual PKA record exists for EMAIL. */
+ int checked; /* Set to true if the FPR has been checked against the
+ actual key. */
+ char *uri; /* Malloced string with the URI. NULL if the URI is
+ not available.*/
+ unsigned char fpr[20]; /* The fingerprint as stored in the PKA RR. */
+ char email[1];/* The email address from the notation data. */
+} pka_info_t;
+
+
+/* Object to keep information pertaining to a signature. */
+typedef struct
+{
+ struct
+ {
+ unsigned checked:1; /* Signature has been checked. */
+ unsigned valid:1; /* Signature is good (if checked is set). */
+ unsigned chosen_selfsig:1; /* A selfsig that is the chosen one. */
+ unsigned unknown_critical:1;
+ unsigned exportable:1;
+ unsigned revocable:1;
+ unsigned policy_url:1; /* At least one policy URL is present */
+ unsigned notation:1; /* At least one notation is present */
+ unsigned pref_ks:1; /* At least one preferred keyserver is present */
+ unsigned expired:1;
+ unsigned pka_tried:1; /* Set if we tried to retrieve the PKA record. */
+ } flags;
+ u32 keyid[2]; /* 64 bit keyid */
+ u32 timestamp; /* Signature made (seconds since Epoch). */
+ u32 expiredate; /* Expires at this date or 0 if not at all. */
+ byte version;
+ byte sig_class; /* Sig classification, append for MD calculation. */
+ byte pubkey_algo; /* Algorithm used for public key scheme */
+ /* (PUBKEY_ALGO_xxx) */
+ byte digest_algo; /* Algorithm used for digest (DIGEST_ALGO_xxxx). */
+ byte trust_depth;
+ byte trust_value;
+ const byte *trust_regexp;
+ struct revocation_key **revkey;
+ int numrevkeys;
+ pka_info_t *pka_info; /* Malloced PKA data or NULL if not
+ available. See also flags.pka_tried. */
+ subpktarea_t *hashed; /* All subpackets with hashed data (v4 only). */
+ subpktarea_t *unhashed; /* Ditto for unhashed data. */
+ byte digest_start[2]; /* First 2 bytes of the digest. */
+ MPI data[PUBKEY_MAX_NSIG];
} PKT_signature;
#define ATTRIB_IMAGE 1
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 068ffbffe..80ebd0d5d 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -1042,6 +1042,8 @@ can_handle_critical_notation(const byte *name,size_t len)
{
if(len==32 && memcmp(name,"[email protected]",32)==0)
return 1;
+ if(len==21 && memcmp(name,"[email protected]",21)==0)
+ return 1;
return 0;
}
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 3967b59ec..1b3238926 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -532,6 +532,48 @@ check_signatures_trust( PKT_signature *sig )
if ((trustlevel & TRUST_FLAG_DISABLED))
log_info (_("Note: This key has been disabled.\n"));
+ /* If we have PKA information adjust the trustlevel. */
+ if (sig->pka_info && sig->pka_info->valid)
+ {
+ unsigned char fpr[MAX_FINGERPRINT_LEN];
+ PKT_public_key *primary_pk;
+ size_t fprlen;
+ int okay;
+
+ log_info (_("Note: Verified address is `%s'\n"), sig->pka_info->email);
+
+ primary_pk = xmalloc_clear (sizeof *primary_pk);
+ get_pubkey (primary_pk, pk->main_keyid);
+ fingerprint_from_pk (primary_pk, fpr, &fprlen);
+ free_public_key (primary_pk);
+
+ if ( fprlen == 20 && !memcmp (sig->pka_info->fpr, fpr, 20) )
+ okay = 1;
+ else
+ okay = 0;
+
+ switch ( (trustlevel & TRUST_MASK) )
+ {
+ case TRUST_UNKNOWN:
+ case TRUST_UNDEFINED:
+ case TRUST_MARGINAL:
+ if (okay)
+ {
+ trustlevel = ((trustlevel & ~TRUST_MASK) | TRUST_FULLY);
+ log_info ("trustlevel adjusted to FULL due to valid PKA info\n");
+ }
+ /* (fall through) */
+ case TRUST_FULLY:
+ if (!okay)
+ {
+ trustlevel = ((trustlevel & ~TRUST_MASK) | TRUST_NEVER);
+ log_info ("trustlevel adjusted to NEVER due to bad PKA info\n");
+ }
+ break;
+ }
+ }
+
+ /* Now let the user know what up with the trustlevel. */
switch ( (trustlevel & TRUST_MASK) )
{
case TRUST_EXPIRED: