aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2004-10-11 08:44:35 +0000
committerWerner Koch <[email protected]>2004-10-11 08:44:35 +0000
commit5bdb1710268531eb657197f9fab3b1409db97777 (patch)
tree7c0b0e7f451428b01590a59e808b540711d06b49
parent* card-util.c, keyedit.c, openfile.c, pkclist.c, delkey.c, keygen.c, (diff)
downloadgnupg-5bdb1710268531eb657197f9fab3b1409db97777.tar.gz
gnupg-5bdb1710268531eb657197f9fab3b1409db97777.zip
* configure.ac: New option --disable-finger.
* keyserver.c (keyserver_spawn): Print an empty string in log_info if the host is not set (e.g. finger). * gpgkeys_finger.c: New.
-rw-r--r--ChangeLog4
-rw-r--r--configure.ac11
-rw-r--r--g10/ChangeLog12
-rw-r--r--g10/ccid-driver.c380
-rw-r--r--g10/ccid-driver.h5
-rw-r--r--g10/iso7816.h2
-rw-r--r--g10/keyserver.c6
-rw-r--r--keyserver/ChangeLog4
-rw-r--r--keyserver/Makefile.am5
-rwxr-xr-xkeyserver/gpgkeys_fingerbin0 -> 140825 bytes
10 files changed, 398 insertions, 31 deletions
diff --git a/ChangeLog b/ChangeLog
index 42b961b5c..fc63de9ca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2004-10-11 Werner Koch <[email protected]>
+
+ * configure.ac: New option --disable-finger.
+
2004-09-17 Werner Koch <[email protected]>
* configure.ac: Don't check for usb_create_match or
diff --git a/configure.ac b/configure.ac
index 7404ae375..12bc382cc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -303,6 +303,13 @@ if test "$use_exec" = yes ; then
try_http=$enableval, try_http=yes)
AC_MSG_RESULT($try_http)
+ AC_MSG_CHECKING([whether Finger key fetching support is requested])
+ AC_ARG_ENABLE(http,
+ AC_HELP_STRING([--disable-finger],
+ [disable Finger key fetching interface]),
+ try_finger=$enableval, try_finger=yes)
+ AC_MSG_RESULT($try_finger)
+
AC_MSG_CHECKING([whether email keyserver support is requested])
AC_ARG_ENABLE(mailto,
[ --disable-mailto disable email keyserver interface],
@@ -492,6 +499,10 @@ if test x"$try_http" = xyes ; then
AC_SUBST(GPGKEYS_HTTP,"gpgkeys_http$EXEEXT")
fi
+if test x"$try_finger" = xyes ; then
+ AC_SUBST(GPGKEYS_FINGER,"gpgkeys_finger$EXEEXT")
+fi
+
dnl Must check for network library requirements before doing link tests
dnl for ldap, for example. If ldap libs are static (or dynamic and without
dnl ELF runtime link paths), then link will fail and LDAP support won't
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 6af768e4d..b98a377f4 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,8 @@
+2004-10-11 Werner Koch <[email protected]>
+
+ * keyserver.c (keyserver_spawn): Print an empty string in log_info
+ if the host is not set (e.g. finger).
+
2004-10-10 David Shaw <[email protected]>
* card-util.c, keyedit.c, openfile.c, pkclist.c, delkey.c,
@@ -51,6 +56,13 @@
revoked/expired/expires string change of 2004-09-29 was too
simple. Use two styles for each tag.
+2004-10-06 Werner Koch <[email protected]>
+
+ * ccid-driver.c (ccid_open_reader): Store the vendor ID.
+ (ccid_transceive_secure): New.
+ (parse_ccid_descriptor): Workaround for an SCM reader problem.
+ (send_escape_cmd): New.
+
2004-10-05 David Shaw <[email protected]>
* passphrase.c (agent_get_passphrase): Use keystrs for agent
diff --git a/g10/ccid-driver.c b/g10/ccid-driver.c
index 77fea944b..287a8d87d 100644
--- a/g10/ccid-driver.c
+++ b/g10/ccid-driver.c
@@ -154,8 +154,6 @@
-
-
enum {
RDR_to_PC_NotifySlotChange= 0x50,
RDR_to_PC_HardwareError = 0x51,
@@ -183,12 +181,21 @@ enum {
};
+/* We need to know the vendor to do some hacks. */
+enum {
+ VENDOR_SCM = 0x04e6
+};
+
+
/* Store information on the driver's state. A pointer to such a
structure is used as handle for most functions. */
struct ccid_driver_s
{
usb_dev_handle *idev;
char *rid;
+ unsigned short id_vendor;
+ unsigned short id_product;
+ unsigned short bcd_device;
int seqno;
unsigned char t1_ns;
unsigned char t1_nr;
@@ -251,6 +258,8 @@ parse_ccid_descriptor (ccid_driver_t handle,
handle->max_ifsd = 32;
handle->ifsd = 0;
handle->has_pinpad = 0;
+ DEBUGOUT_3 ("idVendor: %04X idProduct: %04X bcdDevice: %04X\n",
+ handle->id_vendor, handle->id_product, handle->bcd_device);
if (buflen < 54 || buf[0] < 54)
{
DEBUGOUT ("CCID device descriptor is too short\n");
@@ -417,8 +426,25 @@ parse_ccid_descriptor (ccid_driver_t handle,
"this is not available\n");
return -1;
}
- else
- return 0;
+
+
+ /* SCM drivers get stuck in their internal USB stack if they try to
+ send a frame of n*wMaxPacketSize back to us. Given that
+ wMaxPacketSize is 64 for these readers we set the IFSD to a value
+ lower than that:
+ 64 - 10 CCID header - 4 T1frame - 2 reserved = 48 */
+ if (handle->id_vendor == VENDOR_SCM
+ /* FIXME: check whether it is the same
+ firmware version for all drivers. */
+ && handle->bcd_device < 0x0513
+ && handle->max_ifsd > 48)
+ {
+ DEBUGOUT ("enabling workaround for buggy SCM readers\n");
+ handle->max_ifsd = 48;
+ }
+
+
+ return 0;
}
@@ -436,7 +462,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
if (!idx)
return NULL;
- /* Fixme: The next line for the current Valgrid without support
+ /* Fixme: The next line is for the current Valgrid without support
for USB IOCTLs. */
memset (buf, 0, sizeof buf);
@@ -825,6 +851,9 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
}
(*handle)->idev = idev;
(*handle)->rid = rid;
+ (*handle)->id_vendor = dev->descriptor.idVendor;
+ (*handle)->id_product = dev->descriptor.idProduct;
+ (*handle)->bcd_device = dev->descriptor.bcdDevice;
DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n", readerno, rid );
@@ -1082,6 +1111,43 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
}
+/* Note that this fucntion won't return the error codes NO_CARD or
+ CARD_INACTIVE */
+static int
+send_escape_cmd (ccid_driver_t handle,
+ const unsigned char *data, size_t datalen)
+{
+ int i, rc;
+ unsigned char msg[100];
+ size_t msglen;
+ unsigned char seqno;
+
+ if (datalen > sizeof msg - 10)
+ return CCID_DRIVER_ERR_INV_VALUE; /* Escape data too large. */
+
+ msg[0] = PC_to_RDR_Escape;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 0; /* RFU */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ memcpy (msg+10, data, datalen);
+ msglen = 10 + datalen;
+ set_msg_len (msg, datalen);
+
+ DEBUGOUT ("sending");
+ for (i=0; i < msglen; i++)
+ DEBUGOUT_CONT_1 (" %02X", msg[i]);
+ DEBUGOUT_LF ();
+ rc = bulk_out (handle, msg, msglen);
+ if (rc)
+ return rc;
+ rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, seqno);
+
+ return rc;
+}
+
+
/* experimental */
int
ccid_poll (ccid_driver_t handle)
@@ -1617,10 +1683,232 @@ ccid_transceive (ccid_driver_t handle,
}
+/* Send the CCID Secure command to the reader. APDU_BUF should contain the APDU template. PIN_MODE defines now the pin gets formatted:
+
+ 1 := The PIN is ASCII encoded and of variable length. The
+ length of the PIN entered will be put into Lc by the reader.
+ The APDU should me made up of 4 bytes without Lc.
+
+ PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0
+ may be used t enable usbale defaults. PIN_PADLEN should be 0
+
+ When called with RESP and NRESP set to NULL, the function will
+ merely check whether the reader supports the secure command for the
+ given APDU and PIN_MODE. */
+int
+ccid_transceive_secure (ccid_driver_t handle,
+ const unsigned char *apdu_buf, size_t apdu_buflen,
+ int pin_mode, int pinlen_min, int pinlen_max,
+ int pin_padlen,
+ unsigned char *resp, size_t maxresplen, size_t *nresp)
+{
+ int rc;
+ unsigned char send_buffer[10+259], recv_buffer[10+259];
+ unsigned char *msg, *tpdu, *p;
+ size_t msglen, tpdulen, n;
+ unsigned char seqno;
+ int i;
+ size_t dummy_nresp;
+ int testmode;
+
+ testmode = !resp && !nresp;
+
+ if (!nresp)
+ nresp = &dummy_nresp;
+ *nresp = 0;
+
+ if (apdu_buflen >= 4 && apdu_buf[1] == 0x20 && (handle->has_pinpad & 1))
+ ;
+ else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2))
+ return CCID_DRIVER_ERR_NOT_SUPPORTED; /* Not yet by our code. */
+ else
+ return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
+ if (pin_mode != 1)
+ return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
+ if (pin_padlen != 0)
+ return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
+ if (!pinlen_min)
+ pinlen_min = 1;
+ if (!pinlen_max)
+ pinlen_max = 25;
+
+ /* Note that the 25 is the maximum value the SPR532 allows. */
+ if (pinlen_min < 1 || pinlen_min > 25
+ || pinlen_max < 1 || pinlen_max > 25
+ || pinlen_min > pinlen_max)
+ return CCID_DRIVER_ERR_INV_VALUE;
+
+ /* We have only tested this with an SCM reader so better don't risk
+ anything and do not allow the use with other readers. */
+ if (handle->id_vendor != VENDOR_SCM)
+ return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
+ if (testmode)
+ return 0; /* Success */
+
+ msg = send_buffer;
+ if (handle->id_vendor == VENDOR_SCM)
+ {
+ DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n");
+ rc = send_escape_cmd (handle, "\x80\x02\x00", 3);
+ if (rc)
+ return rc;
+ }
+
+ msg[0] = PC_to_RDR_Secure;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 4; /* bBWI */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ msg[10] = 0; /* Perform PIN verification. */
+ msg[11] = 0; /* Timeout in seconds. */
+ msg[12] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
+ if (handle->id_vendor == VENDOR_SCM)
+ {
+ /* For the SPR532 the next 2 bytes need to be zero. We do this
+ for all SCM product. Kudos to to Martin Paljak for this
+ hint. */
+ msg[13] = msg[14] = 0;
+ }
+ else
+ {
+ msg[13] = 0x00; /* bmPINBlockString:
+ 0 bits of pin length to insert.
+ 0 bytes of PIN block size. */
+ msg[14] = 0x00; /* bmPINLengthFormat:
+ Units are bytes, position is 0. */
+ }
+ msg[15] = pinlen_min; /* wPINMaxExtraDigit-Minimum. */
+ msg[16] = pinlen_max; /* wPINMaxExtraDigit-Maximum. */
+ msg[17] = 0x02; /* bEntryValidationCondition:
+ Validation key pressed */
+ if (pinlen_min && pinlen_max && pinlen_min == pinlen_max)
+ msg[17] |= 0x01; /* Max size reached. */
+ msg[18] = 0xff; /* bNumberMessage: Default. */
+ msg[19] = 0x04; /* wLangId-High. */
+ msg[20] = 0x09; /* wLangId-Low: English FIXME: use the first entry. */
+ msg[21] = 0; /* bMsgIndex. */
+ /* bTeoProlog follows: */
+ msg[22] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+ msg[23] = ((handle->t1_ns & 1) << 6); /* I-block */
+ msg[24] = 4; /* apdulen. */
+ /* APDU follows: */
+ msg[25] = apdu_buf[0]; /* CLA */
+ msg[26] = apdu_buf[1]; /* INS */
+ msg[27] = apdu_buf[2]; /* P1 */
+ msg[28] = apdu_buf[3]; /* P2 */
+ msglen = 29;
+ set_msg_len (msg, msglen - 10);
+
+ DEBUGOUT ("sending");
+ for (i=0; i < msglen; i++)
+ DEBUGOUT_CONT_1 (" %02X", msg[i]);
+ DEBUGOUT_LF ();
+
+ rc = bulk_out (handle, msg, msglen);
+ if (rc)
+ return rc;
+
+ msg = recv_buffer;
+ rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
+ RDR_to_PC_DataBlock, seqno);
+ if (rc)
+ return rc;
+
+ tpdu = msg + 10;
+ tpdulen = msglen - 10;
+
+ if (tpdulen < 4)
+ {
+ usb_clear_halt (handle->idev, 0x82);
+ return CCID_DRIVER_ERR_ABORTED;
+ }
+#ifdef DEBUG_T1
+ fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
+ ((msg[11] & 0xc0) == 0x80)? 'R' :
+ (msg[11] & 0x80)? 'S' : 'I',
+ ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
+ ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0
+ );
+#endif
+
+ if (!(tpdu[1] & 0x80))
+ { /* This is an I-block. */
+ /* Last block sent was successful. */
+ handle->t1_ns ^= 1;
+
+ if (!!(tpdu[1] & 0x40) != handle->t1_nr)
+ { /* Reponse does not match our sequence number. */
+ DEBUGOUT ("I-block with wrong seqno received\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+
+ handle->t1_nr ^= 1;
+
+ p = tpdu + 3; /* Skip the prologue field. */
+ n = tpdulen - 3 - 1; /* Strip the epilogue field. */
+ /* fixme: verify the checksum. */
+ if (resp)
+ {
+ if (n > maxresplen)
+ {
+ DEBUGOUT_2 ("provided buffer too short for received data "
+ "(%u/%u)\n",
+ (unsigned int)n, (unsigned int)maxresplen);
+ return CCID_DRIVER_ERR_INV_VALUE;
+ }
+
+ memcpy (resp, p, n);
+ resp += n;
+ *nresp += n;
+ maxresplen -= n;
+ }
+
+ if (!(tpdu[1] & 0x20))
+ return 0; /* No chaining requested - ready. */
+
+ DEBUGOUT ("chaining requested but not supported for Secure operation\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ else if ((tpdu[1] & 0xc0) == 0x80)
+ { /* This is a R-block. */
+ if ( (tpdu[1] & 0x0f))
+ { /* Error: repeat last block */
+ DEBUGOUT ("No retries supported for Secure operation\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ else if (!!(tpdu[1] & 0x40) == handle->t1_ns)
+ { /* Reponse does not match our sequence number. */
+ DEBUGOUT ("R-block with wrong seqno received on more bit\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ else
+ { /* Send next chunk. */
+ DEBUGOUT ("chaining not supported on Secure operation\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ }
+ else
+ { /* This is a S-block. */
+ DEBUGOUT_2 ("T1 S-block %s received cmd=%d for Secure operation\n",
+ (tpdu[1] & 0x20)? "response": "request",
+ (tpdu[1] & 0x1f));
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+
+ return 0;
+}
+
+
#ifdef TEST
+
static void
print_error (int err)
{
@@ -1682,6 +1970,9 @@ main (int argc, char **argv)
unsigned int slotstat;
unsigned char result[512];
size_t resultlen;
+ int no_pinpad = 0;
+ int verify_123456 = 0;
+ int did_verify = 0;
if (argc)
{
@@ -1706,6 +1997,16 @@ main (int argc, char **argv)
ccid_set_debug_level (1);
argc--; argv++;
}
+ else if ( !strcmp (*argv, "--no-pinpad"))
+ {
+ no_pinpad = 1;
+ argc--; argv++;
+ }
+ else if ( !strcmp (*argv, "--verify-123456"))
+ {
+ verify_123456 = 1;
+ argc--; argv++;
+ }
else
break;
}
@@ -1755,28 +2056,55 @@ main (int argc, char **argv)
print_result (rc, result, resultlen);
}
- ccid_poll (ccid);
+ if (!no_pinpad)
+ {
+ }
+
+ if (!no_pinpad)
+ {
+ static unsigned char apdu[] = { 0, 0x20, 0, 0x81 };
+
+
+ if (ccid_transceive_secure (ccid,
+ apdu, sizeof apdu,
+ 1, 0, 0, 0,
+ NULL, 0, NULL))
+ fputs ("can't verify using a PIN-Pad reader\n", stderr);
+ else
+ {
+ fputs ("verifying CHV1 using the PINPad ....\n", stderr);
+
+ rc = ccid_transceive_secure (ccid,
+ apdu, sizeof apdu,
+ 1, 0, 0, 0,
+ result, sizeof result, &resultlen);
+ print_result (rc, result, resultlen);
+ did_verify = 1;
+ }
+ }
+
+ if (verify_123456 && !did_verify)
+ {
+ fputs ("verifying that CHV1 is 123456....\n", stderr);
+ {
+ static unsigned char apdu[] = {0, 0x20, 0, 0x81,
+ 6, '1','2','3','4','5','6'};
+ rc = ccid_transceive (ccid, apdu, sizeof apdu,
+ result, sizeof result, &resultlen);
+ print_result (rc, result, resultlen);
+ }
+ }
-/* if (!ccid->has_pinpad) */
-/* { */
-/* fputs ("verifying that CHV1 is 123456....\n", stderr); */
-/* { */
-/* static unsigned char apdu[] = {0, 0x20, 0, 0x81, */
-/* 6, '1','2','3','4','5','6'}; */
-/* rc = ccid_transceive (ccid, apdu, sizeof apdu, */
-/* result, sizeof result, &resultlen); */
-/* print_result (rc, result, resultlen); */
-/* } */
-/* } */
-/* else */
-/* { */
-/* fputs ("verifying CHV1 using the PINPad ....\n", stderr); */
-/* { */
-/* rc = ccid_secure_transceive (ccid, */
-/* result, sizeof result, &resultlen); */
-/* print_result (rc, result, resultlen); */
-/* } */
-/* } */
+ if (!rc)
+ {
+ fputs ("getting OpenPGP DO 0x5E ....\n", stderr);
+ {
+ static unsigned char apdu[] = { 0, 0xCA, 0, 0x5E, 254 };
+ rc = ccid_transceive (ccid, apdu, sizeof apdu,
+ result, sizeof result, &resultlen);
+ print_result (rc, result, resultlen);
+ }
+ }
ccid_close_reader (ccid);
diff --git a/g10/ccid-driver.h b/g10/ccid-driver.h
index cbadb40c1..9cb23253b 100644
--- a/g10/ccid-driver.h
+++ b/g10/ccid-driver.h
@@ -86,6 +86,11 @@ int ccid_slot_status (ccid_driver_t handle, int *statusbits);
int ccid_transceive (ccid_driver_t handle,
const unsigned char *apdu, size_t apdulen,
unsigned char *resp, size_t maxresplen, size_t *nresp);
+int ccid_transceive_secure (ccid_driver_t handle,
+ const unsigned char *apdu, size_t apdulen,
+ int pin_mode,
+ int pinlen_min, int pinlen_max, int pin_padlen,
+ unsigned char *resp, size_t maxresplen, size_t *nresp);
diff --git a/g10/iso7816.h b/g10/iso7816.h
index 8f2b150e6..97de9abbd 100644
--- a/g10/iso7816.h
+++ b/g10/iso7816.h
@@ -25,6 +25,8 @@
#include "cardglue.h"
#endif
+gpg_error_t iso7816_map_sw (int sw);
+
gpg_error_t iso7816_select_application (int slot,
const char *aid, size_t aidlen);
gpg_error_t iso7816_select_file (int slot, int tag, int is_dir,
diff --git a/g10/keyserver.c b/g10/keyserver.c
index cfdfe561b..5e29efdf2 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -894,7 +894,7 @@ keyserver_spawn(int action,STRLIST list,KEYDB_SEARCH_DESC *desc,
log_info(_("requesting key %s from %s server %s\n"),
keystr_from_desc(&desc[i]),
- keyserver->scheme,keyserver->host);
+ keyserver->scheme,keyserver->host?keyserver->host:"");
}
fprintf(spawn->tochild,"\n");
@@ -1039,7 +1039,7 @@ keyserver_spawn(int action,STRLIST list,KEYDB_SEARCH_DESC *desc,
log_info(_("sending key %s to %s server %s\n"),
keystr(block->pkt->pkt.public_key->keyid),
- keyserver->scheme,keyserver->host);
+ keyserver->scheme,keyserver->host?keyserver->host:"");
release_kbnode(block);
}
@@ -1080,7 +1080,7 @@ keyserver_spawn(int action,STRLIST list,KEYDB_SEARCH_DESC *desc,
fprintf(spawn->tochild,"\n");
log_info(_("searching for \"%s\" from %s server %s\n"),
- searchstr,keyserver->scheme,keyserver->host);
+ searchstr,keyserver->scheme,keyserver->host?keyserver->host:"");
break;
}
diff --git a/keyserver/ChangeLog b/keyserver/ChangeLog
index 37dfa91cb..4b3855a62 100644
--- a/keyserver/ChangeLog
+++ b/keyserver/ChangeLog
@@ -1,3 +1,7 @@
+2004-10-11 Werner Koch <[email protected]>
+
+ * gpgkeys_finger.c: New.
+
2004-08-27 Stefan Bellon <[email protected]>
* gpgkeys_hkp.c (search_key): Fix the prior faulty fix by
diff --git a/keyserver/Makefile.am b/keyserver/Makefile.am
index ddf2a4c98..c9f58259d 100644
--- a/keyserver/Makefile.am
+++ b/keyserver/Makefile.am
@@ -19,17 +19,18 @@
## Process this file with automake to produce Makefile.in
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
-EXTRA_PROGRAMS = gpgkeys_ldap gpgkeys_hkp gpgkeys_http
+EXTRA_PROGRAMS = gpgkeys_ldap gpgkeys_hkp gpgkeys_http gpgkeys_finger
EXTRA_SCRIPTS = gpgkeys_mailto
libexecdir = @libexecdir@/@PACKAGE@
-libexec_PROGRAMS = @GPGKEYS_LDAP@ @GPGKEYS_HKP@ @GPGKEYS_HTTP@
+libexec_PROGRAMS = @GPGKEYS_LDAP@ @GPGKEYS_HKP@ @GPGKEYS_HTTP@ @GPGKEYS_FINGER@
libexec_SCRIPTS = @GPGKEYS_MAILTO@
noinst_SCRIPTS = gpgkeys_test
gpgkeys_ldap_LDADD = ../util/libutil.a @LDAPLIBS@ @NETLIBS@ @LIBINTL@ @CAPLIBS@ @GETOPT@ @W32LIBS@
gpgkeys_hkp_LDADD = ../util/libutil.a @NETLIBS@ @SRVLIBS@ @LIBINTL@ @CAPLIBS@ @GETOPT@ @W32LIBS@
gpgkeys_http_LDADD = ../util/libutil.a @NETLIBS@ @SRVLIBS@ @LIBINTL@ @CAPLIBS@ @GETOPT@ @W32LIBS@
+gpgkeys_finger_LDADD = ../util/libutil.a @NETLIBS@ @LIBINTL@ @CAPLIBS@ @GETOPT@ @W32LIBS@
install-exec-hook:
if GPGKEYS_LDAP
diff --git a/keyserver/gpgkeys_finger b/keyserver/gpgkeys_finger
new file mode 100755
index 000000000..2e46a1e10
--- /dev/null
+++ b/keyserver/gpgkeys_finger
Binary files differ