mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-21 14:47:03 +01:00
Implemented PKA trust model
This commit is contained in:
parent
a1cdf3c75f
commit
986a137c58
@ -1,3 +1,7 @@
|
||||
2005-07-28 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac (USE_DNS_PKA): Define in addition to USE_DNS_SRV.
|
||||
|
||||
2005-07-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
Replaced in all directories all calls to m_free, m_alloc,
|
||||
|
6
NEWS
6
NEWS
@ -10,6 +10,12 @@ Noteworthy changes in version 1.4.3
|
||||
--enable-old-keyserver-helpers. Note that none of this affects
|
||||
finger or LDAP support, which are unchanged.
|
||||
|
||||
* Implemented Public Key Association (PKA) trust model option.
|
||||
This is an optional trust model on top of the standard ones. It
|
||||
make use of of special DNS records and notation data to
|
||||
associate a mail address with an OpenPGP key. See: XXXX for a
|
||||
description.
|
||||
|
||||
|
||||
Noteworthy changes in version 1.4.2 (2005-07-26)
|
||||
------------------------------------------------
|
||||
|
@ -563,7 +563,8 @@ AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, gethostbyname,
|
||||
AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt,
|
||||
[NETLIBS="-lsocket $NETLIBS"]))
|
||||
|
||||
dnl Now try for the resolver functions so we can use DNS SRV
|
||||
dnl Now try for the resolver functions so we can use DNS SRV and our
|
||||
dnl PKA feature.
|
||||
|
||||
AC_ARG_ENABLE(dns-srv,
|
||||
AC_HELP_STRING([--disable-dns-srv],
|
||||
@ -597,6 +598,7 @@ if (test x"$try_hkp" = xyes || test x"$try_http" = xyes) && test x"$use_dns_srv"
|
||||
if test x"$use_dns_srv" = xyes ; then
|
||||
AC_DEFINE(USE_DNS_SRV,1,[define to use DNS SRV])
|
||||
SRVLIBS=$LIBS
|
||||
AC_DEFINE(USE_DNS_PKA,1,[define to use our experimental DNS PKA])
|
||||
fi
|
||||
|
||||
LIBS=$_srv_save_libs
|
||||
|
@ -1,3 +1,23 @@
|
||||
2005-07-28 Werner Koch <wk@g10code.com>
|
||||
|
||||
* Makefile.am (other_libs): Add SRVLIBS.
|
||||
|
||||
* parse-packet.c (can_handle_critical_notation): We know about
|
||||
pka-address@gnupg.org.
|
||||
* 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 <wk@g10code.com>
|
||||
|
||||
* export.c (do_export_stream): Make two strings translatable.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
21
g10/keygen.c
21
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 )
|
||||
|
@ -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);
|
||||
|
||||
|
115
g10/mainproc.c
115
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, "pka-address@gnupg.org", 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)
|
||||
{
|
||||
|
25
g10/misc.c
25
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
|
||||
|
80
g10/packet.h
80
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
|
||||
|
@ -1042,6 +1042,8 @@ can_handle_critical_notation(const byte *name,size_t len)
|
||||
{
|
||||
if(len==32 && memcmp(name,"preferred-email-encoding@pgp.com",32)==0)
|
||||
return 1;
|
||||
if(len==21 && memcmp(name,"pka-address@gnupg.org",21)==0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -253,6 +253,10 @@ int vasprintf (char **result, const char *format, va_list args);
|
||||
int asprintf (char **buf, const char *fmt, ...);
|
||||
#endif /*_WIN32*/
|
||||
|
||||
/*-- pka.c --*/
|
||||
char *get_pka_info (const char *address, unsigned char *fpr);
|
||||
|
||||
|
||||
|
||||
/**** other missing stuff ****/
|
||||
#ifndef HAVE_ATEXIT /* For SunOS */
|
||||
|
@ -1,3 +1,8 @@
|
||||
2005-07-28 Werner Koch <wk@g10code.com>
|
||||
|
||||
* pka.c: New.
|
||||
* Makefile.am (pka-test): new.
|
||||
|
||||
2005-07-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
* memory.c (FNAMEX, FNAMEXM): New macros to cope with the now used
|
||||
|
@ -38,7 +38,7 @@ endif
|
||||
#libutil_a_LDFLAGS =
|
||||
libutil_a_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \
|
||||
ttyio.c argparse.c memory.c secmem.c errors.c iobuf.c \
|
||||
dotlock.c http.c srv.h srv.c simple-gettext.c \
|
||||
dotlock.c http.c srv.h srv.c pka.c simple-gettext.c \
|
||||
membuf.c w32reg.c $(assuan_source)
|
||||
|
||||
libutil_a_DEPENDENCIES = @LIBOBJS@ @REGEX_O@
|
||||
@ -46,9 +46,14 @@ libutil_a_DEPENDENCIES = @LIBOBJS@ @REGEX_O@
|
||||
libutil_a_LIBADD = @LIBOBJS@ @REGEX_O@
|
||||
|
||||
http-test: http.c
|
||||
gcc -DHAVE_CONFIG_H -I. -I. -I.. $(INCLUDES) $(LDFLAGS) -g -Wall \
|
||||
cc -DHAVE_CONFIG_H -I. -I. -I.. $(INCLUDES) $(LDFLAGS) -g -Wall \
|
||||
-DTEST -o http-test http.c libutil.a @LIBINTL@ @SRVLIBS@ @CAPLIBS@
|
||||
|
||||
srv-test: srv.c
|
||||
gcc -DHAVE_CONFIG_H -I. -I. -I.. $(INCLUDES) $(LDFLAGS) -g -Wall \
|
||||
cc -DHAVE_CONFIG_H -I. -I. -I.. $(INCLUDES) $(LDFLAGS) -g -Wall \
|
||||
-DTEST -o srv-test srv.c libutil.a @LIBINTL@ @SRVLIBS@ @CAPLIBS@
|
||||
|
||||
pka-test: pka.c
|
||||
cc -DHAVE_CONFIG_H -I. -I. -I.. $(INCLUDES) $(LDFLAGS) -g -Wall \
|
||||
-DTEST -o pka-test pka.c libutil.a @LIBINTL@ @SRVLIBS@ @CAPLIBS@
|
||||
|
||||
|
254
util/pka.c
Normal file
254
util/pka.c
Normal file
@ -0,0 +1,254 @@
|
||||
/* pka.c - DNS Public Key Association RR access
|
||||
* Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef USE_DNS_PKA
|
||||
#include <sys/types.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h>
|
||||
#endif
|
||||
#endif /* USE_DNS_PKA */
|
||||
|
||||
#include "memory.h"
|
||||
#include "types.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
#ifdef USE_DNS_PKA
|
||||
/* Parse the TXT resource record. Format is:
|
||||
|
||||
v=1;fpr=a4d94e92b0986ab5ee9dcd755de249965b0358a2;uri=string
|
||||
|
||||
For simplicity white spaces are not allowed. Because we expect to
|
||||
use a new RRTYPE for this in the future we define the TXT really
|
||||
strict for simplicity: No white spaces, case sensitivity of the
|
||||
names, order must be as given above. Only URI is optional.
|
||||
|
||||
This function modifies BUFFER. On success 0 is returned, the 20
|
||||
byte fingerprint stored at FPR and BUFFER contains the URI or an
|
||||
empty string.
|
||||
*/
|
||||
static int
|
||||
parse_txt_record (char *buffer, unsigned char *fpr)
|
||||
{
|
||||
char *p, *pend;
|
||||
int i;
|
||||
|
||||
p = buffer;
|
||||
pend = strchr (p, ';');
|
||||
if (!pend)
|
||||
return -1;
|
||||
*pend++ = 0;
|
||||
if (strcmp (p, "v=1"))
|
||||
return -1; /* Wrong or missing version. */
|
||||
|
||||
p = pend;
|
||||
pend = strchr (p, ';');
|
||||
if (pend)
|
||||
*pend++ = 0;
|
||||
if (strncmp (p, "fpr=", 4))
|
||||
return -1; /* Missing fingerprint part. */
|
||||
p += 4;
|
||||
for (i=0; i < 20 && hexdigitp (p) && hexdigitp (p+1); i++, p += 2)
|
||||
fpr[i] = xtoi_2 (p);
|
||||
if (i != 20)
|
||||
return -1; /* Fingerprint consists not of exactly 40 hexbytes. */
|
||||
|
||||
p = pend;
|
||||
if (!p || !*p)
|
||||
{
|
||||
*buffer = 0;
|
||||
return 0; /* Success (no URI given). */
|
||||
}
|
||||
if (strncmp (p, "uri=", 4))
|
||||
return -1; /* Unknown part. */
|
||||
p += 4;
|
||||
/* There is an URI, copy it to the start of the buffer. */
|
||||
while (*p)
|
||||
*buffer++ = *p++;
|
||||
*buffer = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* For the given email ADDRESS lookup the PKA information in the DNS.
|
||||
|
||||
On success the 20 byte SHA-1 fingerprint is stored at FPR and the
|
||||
URI will be returned in an allocated buffer. Note that the URI
|
||||
might be an zero length string as this information is optiobnal.
|
||||
Caller must xfree the returned string.
|
||||
|
||||
On error NULL is returned and the 20 bytes at FPR are not
|
||||
defined. */
|
||||
char *
|
||||
get_pka_info (const char *address, unsigned char *fpr)
|
||||
{
|
||||
unsigned char answer[PACKETSZ];
|
||||
int anslen;
|
||||
int qdcount, ancount, nscount, arcount;
|
||||
int rc;
|
||||
unsigned char *p, *pend;
|
||||
const char *domain;
|
||||
char *name;
|
||||
|
||||
|
||||
domain = strrchr (address, '@');
|
||||
if (!domain || domain == address || !domain[1])
|
||||
return NULL; /* invalid mail address given. */
|
||||
|
||||
name = malloc (strlen (address) + 5 + 1);
|
||||
memcpy (name, address, domain - address);
|
||||
strcpy (stpcpy (name + (domain-address), "._pka."), domain+1);
|
||||
|
||||
anslen = res_query (name, C_IN, T_TXT, answer, PACKETSZ);
|
||||
xfree (name);
|
||||
if (anslen < sizeof(HEADER))
|
||||
return NULL; /* DNS resolver returned a too short answer. */
|
||||
if ( (rc=((HEADER*)answer)->rcode) != NOERROR )
|
||||
return NULL; /* DNS resolver returned an error. */
|
||||
|
||||
/* We assume that PACKETSZ is large enough and don't do dynmically
|
||||
expansion of the buffer. */
|
||||
if (anslen > PACKETSZ)
|
||||
return NULL; /* DNS resolver returned a too long answer */
|
||||
|
||||
qdcount = ntohs (((HEADER*)answer)->qdcount);
|
||||
ancount = ntohs (((HEADER*)answer)->ancount);
|
||||
nscount = ntohs (((HEADER*)answer)->nscount);
|
||||
arcount = ntohs (((HEADER*)answer)->arcount);
|
||||
|
||||
if (!ancount)
|
||||
return NULL; /* Got no answer. */
|
||||
|
||||
p = answer + sizeof (HEADER);
|
||||
pend = answer + anslen; /* Actually points directly behind the buffer. */
|
||||
|
||||
while (qdcount-- && p < pend)
|
||||
{
|
||||
rc = dn_skipname (p, pend);
|
||||
if (rc == -1)
|
||||
return NULL;
|
||||
p += rc + QFIXEDSZ;
|
||||
}
|
||||
|
||||
if (ancount > 1)
|
||||
return NULL; /* more than one possible gpg trustdns record - none used. */
|
||||
|
||||
while (ancount-- && p <= pend)
|
||||
{
|
||||
unsigned int type, class, txtlen, n;
|
||||
char *buffer, *bufp;
|
||||
|
||||
rc = dn_skipname (p, pend);
|
||||
if (rc == -1)
|
||||
return NULL;
|
||||
p += rc;
|
||||
if (p >= pend - 10)
|
||||
return NULL; /* RR too short. */
|
||||
|
||||
type = *p++ << 8;
|
||||
type |= *p++;
|
||||
class = *p++ << 8;
|
||||
class |= *p++;
|
||||
p += 4;
|
||||
txtlen = *p++ << 8;
|
||||
txtlen |= *p++;
|
||||
if (type != T_TXT || class != C_IN)
|
||||
return NULL; /* Answer does not match the query. */
|
||||
|
||||
buffer = bufp = xmalloc (txtlen + 1);
|
||||
while (txtlen && p < pend)
|
||||
{
|
||||
for (n = *p++, txtlen--; txtlen && n && p < pend; txtlen--, n--)
|
||||
*bufp++ = *p++;
|
||||
}
|
||||
*bufp = 0;
|
||||
if (parse_txt_record (buffer, fpr))
|
||||
{
|
||||
xfree (buffer);
|
||||
return NULL; /* Not a valid gpg trustdns RR. */
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#else /* !USE_DNS_PKA */
|
||||
|
||||
/* Dummy version of the function if we can't use the resolver
|
||||
functions. */
|
||||
char *
|
||||
get_pka_info (const char *address, unsigned char *fpr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* !USE_DNS_PKA */
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
int
|
||||
main(int argc,char *argv[])
|
||||
{
|
||||
unsigned char fpr[20];
|
||||
char *uri;
|
||||
int i;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf (stderr, "usage: pka mail-addresses\n");
|
||||
return 1;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
for (; argc; argc--, argv++)
|
||||
{
|
||||
uri = get_pka_info ( *argv, fpr );
|
||||
printf ("%s", *argv);
|
||||
if (uri)
|
||||
{
|
||||
putchar (' ');
|
||||
for (i=0; i < 20; i++)
|
||||
printf ("%02X", fpr[i]);
|
||||
if (*uri)
|
||||
printf (" %s", uri);
|
||||
xfree (uri);
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST */
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
compile-command: "cc -DUSE_DNS_PKA -DTEST -I.. -I../include -Wall -g -o pka pka.c -lresolv libutil.a"
|
||||
End:
|
||||
*/
|
@ -251,3 +251,9 @@ main(int argc,char *argv[])
|
||||
return 0;
|
||||
}
|
||||
#endif /* TEST */
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
compile-command: "cc -DTEST -I.. -I../include -Wall -g -o srv srv.c -lresolv libutil.a"
|
||||
End:
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user