--- configure.ac.~1~	Thu Mar 20 20:15:18 2003
+++ configure.ac	Wed Apr 16 20:21:13 2003
@@ -776,6 +776,14 @@
 	AC_CHECK_LIB(crypt, crypt)
 fi
 
+GPG_MSG=no
+AC_ARG_WITH(gpg, [support gpg host keys], [
+  if [ x"$with_gpg" != xno ]; then
+    AC_DEFINE(WITH_GPG, 1, [Support gpg host keys.])
+    GPG_MSG=yes
+  fi
+], [GPG_MSG=yes; AC_DEFINE(WITH_GPG, 1, [Support gpg host keys.])])
+
 # Search for OpenSSL
 saved_CPPFLAGS="$CPPFLAGS"
 saved_LDFLAGS="$LDFLAGS"
@@ -2524,6 +2532,7 @@
 echo "                       PAM support: ${PAM_MSG}"
 echo "                KerberosIV support: $KRB4_MSG"
 echo "                 KerberosV support: $KRB5_MSG"
+echo "                       GPG support: $GPG_MSG"
 echo "                 Smartcard support: $SCARD_MSG"
 echo "                       AFS support: $AFS_MSG"
 echo "                     S/KEY support: $SKEY_MSG"
--- config.h.in.~1~	Wed Mar 26 00:12:36 2003
+++ config.h.in	Wed Apr 16 20:21:13 2003
@@ -921,6 +921,9 @@
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
+/* Support gpg host keys. */
+#undef WITH_GPG
+
 /* Define to 1 if your processor stores words with the most significant byte
    first (like Motorola and SPARC, unlike Intel and VAX). */
 #undef WORDS_BIGENDIAN
--- Makefile.in.~1~	Thu Mar 20 19:51:35 2003
+++ Makefile.in	Wed Apr 16 20:21:13 2003
@@ -67,7 +67,7 @@
 	key.o dispatch.o kex.o mac.o uuencode.o misc.o \
 	rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o kexgex.o \
 	kexdhc.o kexgexc.o scard.o msg.o progressmeter.o \
-	entropy.o
+	entropy.o ssh-gpg.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
 	sshconnect.o sshconnect1.o sshconnect2.o
--- sshd.c.~1~	Sun Mar  9 19:38:10 2003
+++ sshd.c	Wed Apr 16 20:21:13 2003
@@ -39,6 +39,31 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * GPG modifications:
+ *
+ * Copyright (c) 2002 Joel N. Weber II.
+ *
+ * Redistribution, copying, and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
  */
 
 #include "includes.h"
@@ -85,6 +110,10 @@
 #include "monitor_wrap.h"
 #include "monitor_fdpass.h"
 
+#ifdef WITH_GPG
+#include "ssh-gpg.h"
+#endif
+
 #ifdef LIBWRAP
 #include <tcpd.h>
 #include <syslog.h>
@@ -177,6 +206,10 @@
 	u_char	ssh1_cookie[SSH_SESSION_KEY_LENGTH];
 } sensitive_data;
 
+/* The value of options.num_host_key_files, plus the number of OpenPGP
+ * host keys. */
+static int num_host_keys;
+
 /*
  * Flag indicating whether the RSA server key needs to be regenerated.
  * Is set in the SIGALRM handler and cleared when the key is regenerated.
@@ -493,7 +526,7 @@
 		key_free(sensitive_data.server_key);
 		sensitive_data.server_key = NULL;
 	}
-	for (i = 0; i < options.num_host_key_files; i++) {
+	for (i = 0; i < num_host_keys; i++) {
 		if (sensitive_data.host_keys[i]) {
 			key_free(sensitive_data.host_keys[i]);
 			sensitive_data.host_keys[i] = NULL;
@@ -516,6 +549,8 @@
 		sensitive_data.server_key = tmp;
 	}
 
+	/* We use the number of host key files here, because OpenPGP keys
+	   don't need to be demoted, and they will appear at the end. */
 	for (i = 0; i < options.num_host_key_files; i++) {
 		if (sensitive_data.host_keys[i]) {
 			tmp = key_demote(sensitive_data.host_keys[i]);
@@ -688,13 +723,17 @@
 	int i;
 
 	buffer_init(&b);
-	for (i = 0; i < options.num_host_key_files; i++) {
+	for (i = 0; i < num_host_keys; i++) {
 		Key *key = sensitive_data.host_keys[i];
 		if (key == NULL)
 			continue;
 		switch (key->type) {
 		case KEY_RSA:
 		case KEY_DSA:
+#ifdef WITH_GPG
+		case KEY_PGP_RSA:
+		case KEY_PGP_DSA:
+#endif
 			if (buffer_len(&b) > 0)
 				buffer_append(&b, ",", 1);
 			p = key_ssh_name(key);
@@ -714,7 +753,7 @@
 {
 	int i;
 
-	for (i = 0; i < options.num_host_key_files; i++) {
+	for (i = 0; i < num_host_keys; i++) {
 		Key *key = sensitive_data.host_keys[i];
 		if (key != NULL && key->type == type)
 			return key;
@@ -725,7 +764,7 @@
 Key *
 get_hostkey_by_index(int ind)
 {
-	if (ind < 0 || ind >= options.num_host_key_files)
+	if (ind < 0 || ind >= num_host_keys)
 		return (NULL);
 	return (sensitive_data.host_keys[ind]);
 }
@@ -735,7 +774,7 @@
 {
 	int i;
 
-	for (i = 0; i < options.num_host_key_files; i++) {
+	for (i = 0; i < num_host_keys; i++) {
 		if (key == sensitive_data.host_keys[i])
 			return (i);
 	}
@@ -820,6 +859,9 @@
 	Authctxt *authctxt;
 	Key *key;
 	int ret, key_used = 0;
+#ifdef WITH_GPG
+	int status;
+#endif
 
 #ifdef HAVE_SECUREWARE
 	(void)set_auth_parameters(ac, av);
@@ -978,8 +1020,26 @@
 	debug("sshd version %.100s", SSH_VERSION);
 
 	/* load private host keys */
-	sensitive_data.host_keys = xmalloc(options.num_host_key_files *
-	    sizeof(Key *));
+	num_host_keys = options.num_host_key_files;
+#ifdef WITH_GPG
+	if (options.rsa_pgp_key_name) {
+		num_host_keys++;
+	}
+	if (options.dsa_pgp_key_name) {
+		num_host_keys++;
+	}
+	if (options.rsa_pgp_key_name || options.dsa_pgp_key_name) {
+		if (options.gpg_absolute_filename)
+			gpg_absolute_filename = options.gpg_absolute_filename;
+		else
+			fatal ("PGP host key specified, but GPGAbsoluteFilename not set.");
+		if (options.gpg_homedir)
+			gpg_homedir = options.gpg_homedir;
+		else
+			fatal ("PGP host key specified, but GPGHomedir not set.");
+	}
+#endif
+	sensitive_data.host_keys = xmalloc(num_host_keys*sizeof(Key*));
 	for (i = 0; i < options.num_host_key_files; i++)
 		sensitive_data.host_keys[i] = NULL;
 	sensitive_data.server_key = NULL;
@@ -1009,6 +1069,36 @@
 		debug("private host key: #%d type %d %s", i, key->type,
 		    key_type(key));
 	}
+#ifdef WITH_GPG
+	if (options.rsa_pgp_key_name) {
+		key = key_new(KEY_PGP_RSA);
+		key->pgp_key_name = xstrdup(options.rsa_pgp_key_name);
+		status = ssh_gpg_export (options.rsa_pgp_key_name,
+					 &(key->pgp_key_data),
+					 &(key->pgp_key_data_size));
+		if (status) {
+			fatal ("ssh_gpg_export failed on RSA key");
+		}
+		sensitive_data.host_keys[i] = key;
+		debug("private host key: #%d type %d %s", i, key->type,
+		    key_type(key));
+		i++;
+	}
+	if (options.dsa_pgp_key_name) {
+		key = key_new(KEY_PGP_DSA);
+		key->pgp_key_name = xstrdup(options.dsa_pgp_key_name);
+		status = ssh_gpg_export (options.dsa_pgp_key_name,
+					 &(key->pgp_key_data),
+					 &(key->pgp_key_data_size));
+		if (status) {
+			fatal ("ssh_gpg_export failed on DSA key");
+		}
+		sensitive_data.host_keys[i] = key;
+		debug("private host key: #%d type %d %s", i, key->type,
+		    key_type(key));
+		i++;
+	}
+#endif
 	if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) {
 		log("Disabling protocol version 1. Could not load host key");
 		options.protocol &= ~SSH_PROTO_1;
--- key.h.~1~	Sun Feb 23 20:01:41 2003
+++ key.h	Wed Apr 16 20:21:13 2003
@@ -34,6 +34,8 @@
 	KEY_RSA1,
 	KEY_RSA,
 	KEY_DSA,
+	KEY_PGP_RSA,
+	KEY_PGP_DSA,
 	KEY_UNSPEC
 };
 enum fp_type {
@@ -46,6 +48,7 @@
 };
 
 /* key is stored in external hardware */
+/* or otherwise not directly used by ssh (as in GPG) */
 #define KEY_FLAG_EXT		0x0001
 
 struct Key {
@@ -53,6 +56,15 @@
 	int	 flags;
 	RSA	*rsa;
 	DSA	*dsa;
+#ifdef WITH_GPG
+	char	*pgp_key_name;
+	u_char	*pgp_key_data;
+	size_t	pgp_key_data_size;
+	u_char	*pgp_key_fingerprint;
+	Key	*pgp_subkey;
+	int	pgp_key_type;
+	char	pgp_key_trust;
+#endif
 };
 
 Key	*key_new(int);
--- key.c.~1~	Sun Feb 23 20:01:41 2003
+++ key.c	Wed Apr 16 20:21:13 2003
@@ -30,6 +30,32 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * GPG modifications:
+ *
+ * Copyright (c) 2002, 2003 Joel N. Weber II.
+ *
+ * Redistribution, copying, and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
  */
 #include "includes.h"
 RCSID("$OpenBSD: key.c,v 1.51 2003/02/12 09:33:04 markus Exp $");
@@ -39,6 +65,9 @@
 #include "xmalloc.h"
 #include "key.h"
 #include "rsa.h"
+#ifdef WITH_GPG
+#include "ssh-gpg.h"
+#endif
 #include "uuencode.h"
 #include "buffer.h"
 #include "bufaux.h"
@@ -52,9 +81,22 @@
 	DSA *dsa;
 	k = xmalloc(sizeof(*k));
 	k->type = type;
-	k->flags = 0;
+	if ((type == KEY_PGP_RSA) || (type == KEY_PGP_DSA)) {
+		k->flags = KEY_FLAG_EXT;
+	} else {
+		k->flags = 0;
+	}
 	k->dsa = NULL;
 	k->rsa = NULL;
+#ifdef WITH_GPG
+	k->pgp_key_name = NULL;
+	k->pgp_key_data = NULL;
+	k->pgp_key_data_size = 0;
+	k->pgp_key_fingerprint = NULL;
+	k->pgp_subkey = NULL;
+	k->pgp_key_type = 0xdeadbeef;
+	k->pgp_key_trust = 0;
+#endif
 	switch (k->type) {
 	case KEY_RSA1:
 	case KEY_RSA:
@@ -79,6 +121,10 @@
 			fatal("key_new: BN_new failed");
 		k->dsa = dsa;
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+	case KEY_PGP_DSA:
+#endif
 	case KEY_UNSPEC:
 		break;
 	default:
@@ -112,6 +158,12 @@
 		if ((k->dsa->priv_key = BN_new()) == NULL)
 			fatal("key_new_private: BN_new failed");
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+	case KEY_PGP_DSA:
+		fatal("key_new_private: PGP not supported");
+		break;
+#endif
 	case KEY_UNSPEC:
 		break;
 	default:
@@ -123,6 +175,9 @@
 void
 key_free(Key *k)
 {
+#ifdef WITH_GPG
+	Key *sub, *sub2;
+#endif
 	switch (k->type) {
 	case KEY_RSA1:
 	case KEY_RSA:
@@ -135,6 +190,26 @@
 			DSA_free(k->dsa);
 		k->dsa = NULL;
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+	case KEY_PGP_DSA:
+		if (k->pgp_key_name != NULL)
+			xfree(k->pgp_key_name);
+		if (k->pgp_key_data != NULL)
+			xfree(k->pgp_key_data);
+		if (k->pgp_key_fingerprint != NULL)
+			xfree(k->pgp_key_fingerprint);
+		if (k->pgp_subkey != NULL) {
+			sub = k->pgp_subkey;
+			while (sub) {
+				sub2 = sub->pgp_subkey;
+				sub->pgp_subkey = 0;
+				key_free(sub);
+				sub = sub2;
+			}
+		}
+		break;
+#endif
 	case KEY_UNSPEC:
 		break;
 	default:
@@ -162,6 +237,24 @@
 		    BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
 		    BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+	case KEY_PGP_DSA:
+		if (a->pgp_key_name != NULL
+			&& b->pgp_key_name != NULL) {
+			return !strcmp (a->pgp_key_name, b->pgp_key_name);
+		} else if (a->pgp_key_data != NULL
+			&& b->pgp_key_data != NULL) {
+			return a->pgp_key_data_size == b->pgp_key_data_size
+				&& !memcmp (a->pgp_key_data, b->pgp_key_data,
+					a->pgp_key_data_size);
+		} else {
+			return a->pgp_key_fingerprint != NULL
+				&& b->pgp_key_fingerprint != NULL
+				&& !strcmp (a->pgp_key_fingerprint,
+					b->pgp_key_fingerprint);
+		}
+#endif
 	default:
 		fatal("key_equal: bad key type %d", a->type);
 		break;
@@ -296,6 +389,15 @@
 	u_char *dgst_raw;
 	u_int dgst_raw_len;
 
+#ifdef WITH_GPG
+	if ((k->type == KEY_PGP_RSA) || (k->type == KEY_PGP_DSA)) {
+		if (!k->pgp_key_fingerprint) {
+			debug("key_fingerprint: null k->pgp_key_fingerprint");
+			return xstrdup("NO FINGERPRINT");
+		}
+		return xstrdup (k->pgp_key_fingerprint);
+	}
+#endif
 	dgst_raw = key_fingerprint_raw(k, dgst_type, &dgst_raw_len);
 	if (!dgst_raw)
 		fatal("key_fingerprint: null from key_fingerprint_raw()");
@@ -406,6 +508,10 @@
 	case KEY_UNSPEC:
 	case KEY_RSA:
 	case KEY_DSA:
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+	case KEY_PGP_DSA:
+#endif
 		space = strchr(cp, ' ');
 		if (space == NULL) {
 			debug3("key_read: missing whitespace");
@@ -430,6 +536,25 @@
 			debug3("key_read: type mismatch");
 			return -1;
 		}
+#ifdef WITH_GPG
+		if ((ret->type == KEY_PGP_RSA) || (ret->type == KEY_PGP_DSA)) {
+			space = strchr (cp, ' ');
+			/* If there's no space found after the key, find
+			   the newline instead, so that a fingerprint without
+			   a comment will be accepted. */
+			if (space == NULL)
+				space = strchr (cp, '\n');
+			if (space != NULL) {
+				*space = 0;
+			}
+			ret->pgp_key_fingerprint = xstrdup (cp);
+			if (space != NULL) {
+				*space = ' ';
+			}
+			success = 1;
+			goto key_read_advance;
+		}
+#endif
 		len = 2*strlen(cp);
 		blob = xmalloc(len);
 		n = uudecode(cp, blob, len);
@@ -474,6 +599,9 @@
 		if (success != 1)
 			break;
 		/* advance cp: skip whitespace and data */
+#ifdef WITH_GPG
+key_read_advance:
+#endif
 		while (*cp == ' ' || *cp == '\t')
 			cp++;
 		while (*cp != '\0' && *cp != ' ' && *cp != '\t')
@@ -533,6 +661,14 @@
 	case KEY_DSA:
 		return "DSA";
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+		return "OpenPGP RSA";
+		break;
+	case KEY_PGP_DSA:
+		return "OpenPGP DSA";
+		break;
+#endif
 	}
 	return "unknown";
 }
@@ -547,6 +683,14 @@
 	case KEY_DSA:
 		return "ssh-dss";
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+		return "pgp-sign-rsa";
+		break;
+	case KEY_PGP_DSA:
+		return "pgp-sign-dss";
+		break;
+#endif
 	}
 	return "ssh-unknown";
 }
@@ -601,6 +745,8 @@
 	case KEY_RSA1:
 		k->rsa = rsa_generate_private_key(bits);
 		break;
+	/* I don't think we need key_generate to do anything useful for the pgp
+	   case, hence I'm allowing this to fall through to this error. */
 	default:
 		fatal("key_generate: unknown type %d", type);
 	}
@@ -626,6 +772,9 @@
 		BN_copy(n->rsa->n, k->rsa->n);
 		BN_copy(n->rsa->e, k->rsa->e);
 		break;
+	/* I don't think we need key_from_private to do anything useful for
+	   the pgp case, hence I'm allowing this to fall through to this
+	   error. */
 	default:
 		fatal("key_from_private: unknown type %d", k->type);
 		break;
@@ -646,6 +795,12 @@
 		return KEY_RSA;
 	} else if (strcmp(name, "ssh-dss") == 0) {
 		return KEY_DSA;
+#ifdef WITH_GPG
+	} else if (strcmp(name, "pgp-sign-rsa") == 0) {
+		return KEY_PGP_RSA;
+	} else if (strcmp(name, "pgp-sign-dss") == 0) {
+		return KEY_PGP_DSA;
+#endif
 	}
 	debug2("key_type_from_name: unknown key type '%s'", name);
 	return KEY_UNSPEC;
@@ -708,6 +863,14 @@
 		DSA_print_fp(stderr, key->dsa, 8);
 #endif
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+	case KEY_PGP_DSA:
+		key = key_new(type);
+		key->pgp_key_data = buffer_get_string (&b,
+			&key->pgp_key_data_size);
+		break;
+#endif
 	case KEY_UNSPEC:
 		key = key_new(type);
 		break;
@@ -747,6 +910,18 @@
 		buffer_put_bignum2(&b, key->rsa->e);
 		buffer_put_bignum2(&b, key->rsa->n);
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_DSA:
+	case KEY_PGP_RSA:
+		if (key->pgp_key_data) {
+			buffer_put_cstring(&b, key_ssh_name(key));
+			buffer_put_string(&b, key->pgp_key_data,
+				 key->pgp_key_data_size);
+		} else {
+			fatal ("key_to_blob: PGP key structure lacks exported data");
+		}
+		break;
+#endif
 	default:
 		error("key_to_blob: unsupported key type %d", key->type);
 		buffer_free(&b);
@@ -761,6 +936,7 @@
 	}
 	memset(buffer_ptr(&b), 0, len);
 	buffer_free(&b);
+ 	debug2("key_to_blob: returning %d bytes", len);
 	return len;
 }
 
@@ -777,6 +953,12 @@
 	case KEY_RSA:
 		return ssh_rsa_sign(key, sigp, lenp, data, datalen);
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+	case KEY_PGP_DSA:
+		return ssh_gpg_sign(key, sigp, lenp, data, datalen);
+		break;
+#endif
 	default:
 		error("key_sign: illegal key type %d", key->type);
 		return -1;
@@ -804,6 +986,12 @@
 	case KEY_RSA:
 		return ssh_rsa_verify(key, signature, signaturelen, data, datalen);
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+	case KEY_PGP_DSA:
+		return ssh_gpg_verify_sig(key, signature, signaturelen, data, datalen);
+		break;
+#endif
 	default:
 		error("key_verify: illegal key type %d", key->type);
 		return -1;
@@ -845,8 +1033,11 @@
 		if ((pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL)
 			fatal("key_demote: BN_dup failed");
 		break;
+	/* I don't think we need key_demote to do anything useful for
+	   the pgp case, hence I'm allowing this to fall through to this
+	   error. */
 	default:
-		fatal("key_free: bad key type %d", k->type);
+		fatal("key_demote: bad key type %d", k->type);
 		break;
 	}
 
--- ssh.c.~1~	Sun Feb 23 19:57:32 2003
+++ ssh.c	Wed Apr 16 20:21:13 2003
@@ -73,6 +73,10 @@
 #include "scard.h"
 #endif
 
+#ifdef WITH_GPG
+#include "ssh-gpg.h"
+#endif
+
 #ifdef HAVE___PROGNAME
 extern char *__progname;
 #else
@@ -684,6 +688,16 @@
 		if (mkdir(buf, 0700) < 0)
 			error("Could not create directory '%.200s'.", buf);
 
+#ifdef WITH_GPG
+	if (options.gpg_absolute_filename != NULL) {
+		gpg_absolute_filename = options.gpg_absolute_filename;
+		if (options.gpg_homedir == NULL)
+			gpg_homedir = getenv("HOME");
+		else
+			gpg_homedir = options.gpg_homedir;
+	}
+#endif
+
 	/* load options.identity_files */
 	load_public_identity_files();
 
@@ -1169,6 +1183,9 @@
 	char *filename;
 	int i = 0;
 	Key *public;
+#ifdef WITH_GPG
+	int status;
+#endif
 #ifdef SMARTCARD
 	Key **keys;
 
@@ -1202,4 +1219,34 @@
 		options.identity_files[i] = filename;
 		options.identity_keys[i] = public;
 	}
+#ifdef WITH_GPG
+	if (options.rsa_pgp_key_name) {
+		options.identity_keys[i] = key_new(KEY_PGP_RSA);
+		options.identity_keys[i]->pgp_key_name = xstrdup(options.rsa_pgp_key_name);
+		status = ssh_gpg_export (options.rsa_pgp_key_name,
+			&(options.identity_keys[i]->pgp_key_data),
+			&(options.identity_keys[i]->pgp_key_data_size));
+		if (status) {
+			fatal ("ssh_gpg_export failed on RSA key");
+		}
+		options.identity_files[i] = xstrdup("external gpg key");
+		i++;
+		options.num_identity_files++;
+		debug ("RSA GPG identity %s", options.rsa_pgp_key_name);
+	}
+	if (options.dsa_pgp_key_name) {
+		options.identity_keys[i] = key_new(KEY_PGP_DSA);
+		options.identity_keys[i]->pgp_key_name = xstrdup(options.dsa_pgp_key_name);
+		status = ssh_gpg_export (options.dsa_pgp_key_name,
+			&(options.identity_keys[i]->pgp_key_data),
+			&(options.identity_keys[i]->pgp_key_data_size));
+		if (status) {
+			fatal ("ssh_gpg_export failed on DSA key");
+		}
+		options.identity_files[i] = xstrdup("external gpg key");
+		i++;
+		options.num_identity_files++;
+		debug ("DSA GPG identity %s", options.dsa_pgp_key_name);
+	}
+#endif
 }
--- sshconnect.c.~1~	Sun Dec 22 21:06:20 2002
+++ sshconnect.c	Wed Apr 16 20:21:13 2003
@@ -10,6 +10,31 @@
  * software must be clearly marked as such, and if the derived work is
  * incompatible with the protocol description in the RFC file, it must be
  * called by a name other than "ssh" or "Secure Shell".
+ *
+ * GPG modifications:
+ *
+ * Copyright (c) 2002, 2003 Joel N. Weber II.
+ *
+ * Redistribution, copying, and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
  */
 
 #include "includes.h"
@@ -33,6 +58,10 @@
 #include "misc.h"
 #include "readpass.h"
 
+#ifdef WITH_GPG
+#include "ssh-gpg.h"
+#endif
+
 char *client_version_string = NULL;
 char *server_version_string = NULL;
 
@@ -800,6 +829,16 @@
 {
 	struct stat st;
 
+#ifdef WITH_GPG
+	char *email;
+
+	if ((host_key->type == KEY_PGP_RSA)
+	    || (host_key->type == KEY_PGP_DSA)) {
+	  email = malloc (strlen (host) + 5);
+	  sprintf (email, "ssh@%s", host);
+	  return ssh_gpg_get_key_info (host_key, email, 0);
+	}
+#endif
 	/* return ok if the key can be found in an old keyfile */
 	if (stat(options.system_hostfile2, &st) == 0 ||
 	    stat(options.user_hostfile2, &st) == 0) {
--- sshconnect2.c.~1~	Sun Mar  9 19:21:18 2003
+++ sshconnect2.c	Wed Apr 16 23:46:35 2003
@@ -20,6 +20,32 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * GPG modifications:
+ *
+ * Copyright (c) 2002, 2003 Joel N. Weber II.
+ *
+ * Redistribution, copying, and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
  */
 
 #include "includes.h"
@@ -48,6 +74,11 @@
 #include "msg.h"
 #include "pathnames.h"
 
+#ifdef WITH_GPG
+#include "ssh-gpg.h"
+#endif
+
+
 /* import */
 extern char *client_version_string;
 extern char *server_version_string;
@@ -77,6 +108,10 @@
 ssh_kex2(char *host, struct sockaddr *hostaddr)
 {
 	Kex *kex;
+#ifdef WITH_GPG
+        char *gpg_orig;
+        int gpg_len;
+#endif
 
 	xxx_host = host;
 	xxx_hostaddr = hostaddr;
@@ -107,6 +142,15 @@
 	if (options.hostkeyalgorithms != NULL)
 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
 		    options.hostkeyalgorithms;
+#ifdef WITH_GPG
+	/* If we have GPG, then add the algorithms that GPG supports. */
+	if (options.gpg_absolute_filename != NULL) {
+		gpg_orig=myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
+		gpg_len = strlen(gpg_orig)+sizeof("pgp-sign-rsa,pgp-sign-dss,");
+		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]=xmalloc(gpg_len);
+		snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],gpg_len,"pgp-sign-rsa,pgp-sign-dss,%s",gpg_orig);  
+	}
+#endif
 
 	/* start key exchange */
 	kex = kex_setup(myproposal);
--- auth2-pubkey.c.~1~	Thu Jun  6 16:27:56 2002
+++ auth2-pubkey.c	Wed Apr 16 20:21:13 2003
@@ -41,6 +41,10 @@
 #include "canohost.h"
 #include "monitor_wrap.h"
 
+#ifdef WITH_GPG
+#include "ssh-gpg.h"
+#endif
+
 /* import */
 extern ServerOptions options;
 extern u_char *session_id2;
@@ -180,6 +184,14 @@
 
 	/* Temporarily use the user's uid. */
 	temporarily_use_uid(pw);
+
+#ifdef WITH_GPG
+	if ((key->type == KEY_PGP_RSA) || (key->type == KEY_PGP_DSA)) {
+		gpg_homedir = pw->pw_dir;
+		if (!key->pgp_key_fingerprint)
+			ssh_gpg_get_key_info (key, 0, 1);
+	}
+#endif
 
 	debug("trying public key file %s", file);
 
--- monitor.c.~1~	Sun Mar 23 17:12:50 2003
+++ monitor.c	Wed Apr 16 20:21:13 2003
@@ -22,6 +22,32 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * GPG modifications:
+ *
+ * Copyright (c) 2002 Joel N. Weber II.
+ *
+ * Redistribution, copying, and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
  */
 
 #include "includes.h"
@@ -59,6 +85,11 @@
 #include "ssh2.h"
 #include "mpaux.h"
 
+#ifdef WITH_GPG
+#include "uidswap.h"
+#include "ssh-gpg.h"
+#endif
+
 /* Imports */
 extern ServerOptions options;
 extern u_int utmp_len;
@@ -987,7 +1018,24 @@
 	if (!valid_data)
 		fatal("%s: bad signature data blob", __func__);
 
+#ifdef WITH_GPG
+	if ((key->type == KEY_PGP_RSA) || (key->type == KEY_PGP_DSA)) {
+		temporarily_use_uid(authctxt->pw);
+		gpg_homedir = authctxt->pw->pw_dir;
+		/* FIXME: calling ssh_gpg_get_key_info here to get the
+		   fingerprint, and the key structure which may contain
+		   subkeys to get the key type information, adds extra
+		   overhead which is somewhat annoying.  It would be nice
+		   to cache the key structure. */
+		ssh_gpg_get_key_info (key, 0, 1);
+	}
+#endif
 	verified = key_verify(key, signature, signaturelen, data, datalen);
+#ifdef WITH_GPG
+	if ((key->type == KEY_PGP_RSA) || (key->type == KEY_PGP_DSA)) {
+		restore_uid();
+	}
+#endif
 	debug3("%s: key %p signature %s",
 	    __func__, key, verified ? "verified" : "unverified");
 
--- servconf.c.~1~	Sun Feb 23 20:04:34 2003
+++ servconf.c	Wed Apr 16 20:21:13 2003
@@ -7,6 +7,31 @@
  * software must be clearly marked as such, and if the derived work is
  * incompatible with the protocol description in the RFC file, it must be
  * called by a name other than "ssh" or "Secure Shell".
+ *
+ * GPG modifications:
+ *
+ * Copyright (c) 2002 Joel N. Weber II.
+ *
+ * Redistribution, copying, and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
  */
 
 #include "includes.h"
@@ -97,6 +122,10 @@
 #ifdef AFS
 	options->afs_token_passing = -1;
 #endif
+#ifdef WITH_GPG
+	options->rsa_pgp_key_name = NULL;
+	options->dsa_pgp_key_name = NULL;
+#endif
 	options->password_authentication = -1;
 	options->kbd_interactive_authentication = -1;
 	options->challenge_response_authentication = -1;
@@ -289,6 +318,12 @@
 #ifdef AFS
 	sAFSTokenPassing,
 #endif
+#ifdef WITH_GPG
+	sRSAPGPKeyName,
+	sDSAPGPKeyName,
+	sGPGAbsoluteFilename,
+	sGPGHomedir,
+#endif
 	sChallengeResponseAuthentication,
 	sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
@@ -341,6 +376,12 @@
 #ifdef AFS
 	{ "afstokenpassing", sAFSTokenPassing },
 #endif
+#ifdef WITH_GPG
+	{ "rsapgpkeyname", sRSAPGPKeyName },
+	{ "dsapgpkeyname", sDSAPGPKeyName },
+	{ "gpgabsolutefilename", sGPGAbsoluteFilename },
+	{ "gpghomedir", sGPGHomedir },
+#endif
 	{ "passwordauthentication", sPasswordAuthentication },
 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
 	{ "challengeresponseauthentication", sChallengeResponseAuthentication },
@@ -668,7 +709,48 @@
 		intptr = &options->afs_token_passing;
 		goto parse_flag;
 #endif
-
+#ifdef WITH_GPG
+	case sRSAPGPKeyName:
+		charptr = &options->rsa_pgp_key_name;
+		arg = strdelim(&cp);
+		if (!arg || *arg == '\0')
+			fatal("%s line %d: missing key name.",
+			    filename, linenum);
+		if (*charptr == NULL) {
+			*charptr = xstrdup(arg);
+		}
+		break;
+	case sDSAPGPKeyName:
+		charptr = &options->dsa_pgp_key_name;
+		arg = strdelim(&cp);
+		if (!arg || *arg == '\0')
+			fatal("%s line %d: missing key name.",
+			    filename, linenum);
+		if (*charptr == NULL) {
+			*charptr = xstrdup(arg);
+		}
+		break;
+	case sGPGAbsoluteFilename:
+		charptr = &options->gpg_absolute_filename;
+		arg = strdelim(&cp);
+		if (!arg || *arg == '\0')
+			fatal("%s line %d: missing file name.",
+			    filename, linenum);
+		if (*charptr == NULL) {
+			*charptr = xstrdup(arg);
+		}
+		break;
+	case sGPGHomedir:
+		charptr = &options->gpg_homedir;
+		arg = strdelim(&cp);
+		if (!arg || *arg == '\0')
+			fatal("%s line %d: missing file name.",
+			    filename, linenum);
+		if (*charptr == NULL) {
+			*charptr = xstrdup(arg);
+		}
+		break;
+#endif
 	case sPasswordAuthentication:
 		intptr = &options->password_authentication;
 		goto parse_flag;
--- servconf.h.~1~	Wed Jul 31 21:28:39 2002
+++ servconf.h	Wed Apr 16 20:21:13 2003
@@ -91,6 +91,12 @@
 #ifdef AFS
 	int     afs_token_passing;	/* If true, permit AFS token passing. */
 #endif
+#ifdef WITH_GPG
+	char   *rsa_pgp_key_name;	/* Name of RSA PGP key to use as host key. */
+	char   *dsa_pgp_key_name;	/* Name of DSA PGP key to use as host key. */
+	char   *gpg_absolute_filename;	/* Absolute filename of gpg binary. */
+	char   *gpg_homedir;		/* Value to pass as $HOME to gpg binary. */
+#endif
 	int     password_authentication;	/* If true, permit password
 						 * authentication. */
 	int     kbd_interactive_authentication;	/* If true, permit */
--- readconf.c.~1~	Sun Feb 23 19:56:27 2003
+++ readconf.c	Wed Apr 16 20:21:13 2003
@@ -9,6 +9,32 @@
  * software must be clearly marked as such, and if the derived work is
  * incompatible with the protocol description in the RFC file, it must be
  * called by a name other than "ssh" or "Secure Shell".
+ *
+ *
+ * GPG modifications:
+ *
+ * Copyright (c) 2002 Joel N. Weber II.
+ *
+ * Redistribution, copying, and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
  */
 
 #include "includes.h"
@@ -94,6 +120,12 @@
 	oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
 	oPasswordAuthentication, oRSAAuthentication,
 	oChallengeResponseAuthentication, oXAuthLocation,
+#ifdef WITH_GPG
+	oGPGAbsoluteFilename,
+	oGPGHomedir,
+	oRSAPGPKeyName,
+	oDSAPGPKeyName,
+#endif
 #if defined(KRB4) || defined(KRB5)
 	oKerberosAuthentication,
 #endif
@@ -141,6 +173,12 @@
 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
+#ifdef WITH_GPG
+	{ "gpgabsolutefilename", oGPGAbsoluteFilename },
+	{ "gpghomedir", oGPGHomedir },
+	{ "rsapgpkeyname", oRSAPGPKeyName },
+	{ "dsapgpkeyname", oDSAPGPKeyName },
+#endif
 #if defined(KRB4) || defined(KRB5)
 	{ "kerberosauthentication", oKerberosAuthentication },
 #endif
@@ -488,6 +526,21 @@
 		charptr = &options->smartcard_device;
 		goto parse_string;
 
+#ifdef WITH_GPG
+	case oGPGAbsoluteFilename:
+		charptr = &options->gpg_absolute_filename;
+		goto parse_string;
+	case oGPGHomedir:
+		charptr = &options->gpg_homedir;
+		goto parse_string;
+	case oRSAPGPKeyName:
+		charptr = &options->rsa_pgp_key_name;
+		goto parse_string;
+	case oDSAPGPKeyName:
+		charptr = &options->dsa_pgp_key_name;
+		goto parse_string;
+#endif
+
 	case oProxyCommand:
 		charptr = &options->proxy_command;
 		len = strspn(s, WHITESPACE "=");
@@ -756,6 +809,12 @@
 #endif
 #ifdef AFS
 	options->afs_token_passing = -1;
+#endif
+#ifdef WITH_GPG
+	options->gpg_absolute_filename = NULL;
+	options->gpg_homedir = NULL;
+	options->rsa_pgp_key_name = NULL;
+	options->dsa_pgp_key_name = NULL;
 #endif
 	options->password_authentication = -1;
 	options->kbd_interactive_authentication = -1;
--- readconf.h.~1~	Sat Nov  9 10:52:33 2002
+++ readconf.h	Wed Apr 16 20:21:13 2003
@@ -41,6 +41,12 @@
 	int     hostbased_authentication;	/* ssh2's rhosts_rsa */
 	int     challenge_response_authentication;
 					/* Try S/Key or TIS, authentication. */
+#ifdef WITH_GPG
+	char	*gpg_absolute_filename;
+	char	*gpg_homedir;
+	char	*rsa_pgp_key_name;
+	char	*dsa_pgp_key_name;
+#endif
 #if defined(KRB4) || defined(KRB5)
 	int     kerberos_authentication;	/* Try Kerberos authentication. */
 #endif
--- /dev/null	Thu Apr 17 13:37:10 2003
+++ ssh-gpg.c	Thu Apr 17 00:07:56 2003
@@ -0,0 +1,975 @@
+/*
+ * Copyright (c) 2002, 2003 Joel N. Weber II.
+ *
+ * Redistribution, copying, and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_GPG
+
+#include "xmalloc.h"
+#include "key.h"
+#include "ssh-gpg.h"
+#include "log.h"
+#include "misc.h"
+
+#define SSH_GPG_BUFSIZ 16384
+#define SHORT_LBSIZE 100
+#define LONG_LBSIZE 10000
+
+char *gpg_homedir, *gpg_absolute_filename;
+
+/* Split the line s on the character sep, changing the sep characters
+   in s to '\0' in the process.  malloc an array of char * to return
+   as a, which consists of one pointer to each string, followed by a
+   null pointer.  also return the number of fields extracted in
+   count. */
+static void
+split_separated_list (char *s, char ***a, int *count, char sep)
+{
+  char *x, *y;
+  char **b;
+
+  *count = 1;
+  x = s;
+  while (*x) {
+    if ((*x) == sep)
+      (*count)++;
+    x++;
+  }
+  *a = xmalloc (((*count) + 1) * sizeof (char *));
+  x = s;
+  b = *a;
+  while (1) {
+    y = x;
+    while ((*y) && ((*y) != sep))
+      y++;
+    if (*y) {
+      *y = 0;
+      *b = x;
+      b++;
+      x = y + 1;
+    } else {
+      *b = x;
+      b++;
+      *b = 0;
+      return;
+    }
+  }
+}
+
+/* Read a line from f, and pass that line to split_separated_list, and
+   pass the results from split_separated_list back to the caller. */
+static char **
+read_and_split_line (FILE *f, char ***a, int *count, char sep, char *dbg)
+{
+  char buf[LONG_LBSIZE];
+  int i;
+
+  if (fgets (buf, LONG_LBSIZE, f)) {
+    i = 0;
+    while (buf[i]) {
+      if (buf[i] == '\n')
+	buf[i] = 0;
+      else
+	i++;
+    }
+    if (dbg) {
+      debug2 (dbg, buf);
+    }
+    split_separated_list (buf, a, count, sep);
+  } else {
+    *a = 0;
+  }
+  return *a;
+}
+
+/* Call debug on each line in the file referenced by fd.  func is a string
+   containing the name of the calling function, and str is a string containing
+   a description of which pipe this is. */
+static void
+fd_to_debug (int fd, char *func, char *str)
+{
+  char buf[SHORT_LBSIZE];
+  int i;
+  FILE *f;
+
+  f = fdopen (fd, "r");
+  if (!f)
+    fatal ("%s: error fdopening %s", func, str);
+  while (fgets (buf, SHORT_LBSIZE, f)) {
+    i = 0;
+    while (buf[i]) {
+      if (buf[i] == '\n')
+	buf[i] = 0;
+      else
+	i++;
+    }
+    debug ("%s: %s: %s", func, str, buf);
+  }
+  if (ferror (f))
+    fatal ("%s: error reading %s", func, str);
+  if (fclose (f))
+    fatal ("%s: error closing %s: %s", func, str, strerror(errno));
+}
+
+
+/* Return 1 if email exactly matches the email section of uid,
+   else return 0.  Call fatal if there is a problem with the syntax
+   of either argument.  */
+static int
+ssh_gpg_email_value_matches (char *uid, char *email)
+{
+  char *startbracket, *endbracket;
+  char *extrastartbracket, *extraendbracket, *firstendbracket;
+  char *at, *dot;
+
+  /* Deliberately prevent people from using unqualified hostnames, as I
+     have some concern that namespace collision between different
+     hosts with the same name in different domains may be a security
+     risk.  It is not entirely clear that there is no solution to this
+     problem, but for now, this seems like a reasonable way to make sure
+     that this is not a risk.  */
+  at = strchr (email, '@');
+  if (!at)
+    fatal ("ssh_gpg_email_value_matches: no at character found");
+  dot = strchr (at, '.');
+  if (!dot)
+    fatal ("ssh_gpg_email_value_matches: host name is not fully qualified");
+
+  startbracket = strchr (uid, '<');
+  if (!startbracket)
+    fatal ("ssh_gpg_email_value_matches: No < character found in uid");
+
+  extrastartbracket = strchr (startbracket + 1, '<');
+  if (extrastartbracket)
+    fatal ("ssh_gpg_email_value_matches: More than one < character found in uid");
+
+  endbracket = strchr (startbracket, '>');
+  if (!endbracket)
+    fatal ("ssh_gpg_email_value_matches: No > character found in uid");
+
+  extraendbracket = strchr (endbracket + 1, '>');
+  if (extraendbracket)
+    fatal ("ssh_gpg_email_value_matches: More than one > character found in uid");
+
+  firstendbracket = strchr (uid, '>');
+  if (endbracket != firstendbracket)
+    fatal ("ssh_gpg_email_value_matches: More than one > character found in uid");
+
+  if (!strncasecmp (startbracket + 1, email,
+		    (endbracket - startbracket) - 1))
+    return 1;
+  return 0;
+}
+
+/* Return 1 if the key is adaquately trusted.  By ``adaquate'', we mean
+   we don't care whether the web of trust tells us we should trust the
+   key, but we do at least care that it's got proper self-signatures,
+   it's not expired or revoked, etc.  ssh_gpg_get_key_info does the web
+   of trust checks. */
+static int
+adaquate_trust (Key *key)
+{
+  switch (key->pgp_key_trust) {
+  case '-':
+  case 'q':
+  case 'n':
+  case 'm':
+  case 'f':
+  case 'u':
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+/* Return a string explaining why the key is not trusted. */
+static char *
+bad_trust_reason (Key *key)
+{
+  switch (key->pgp_key_trust) {
+  case 'e':
+    return "expired";
+  case 'r':
+    return "revoked";
+  case 'i':
+    return "invalid";
+  case 'd':
+    return "disabled";
+  default:
+    return "not adaquately trusted";
+  }
+}
+
+/* return 1 if key types match, else return 0. */
+int
+ssh_key_type_matches_pgp_key_type (Key *key, int pgp_keytype)
+{
+  switch (key->type) {
+  case KEY_PGP_RSA:
+    if (pgp_keytype == 1)
+      return 1;
+    break;
+  case KEY_PGP_DSA:
+    if (pgp_keytype == 17)
+      return 1;
+    break;
+  default:
+    fatal ("ssh_key_type_matches_pgp_key_type: impossible ssh key type value");
+  }
+  return 0;
+}
+
+int
+ssh_gpg_export(char *pgp_key_name, u_char **data, u_int *data_count)
+{
+  int chin[2], chout[2], cherr[2], status;
+  pid_t pid, pid2;
+  char *env[2];
+  mysig_t old_sigchld;
+  ssize_t count;
+  u_int data_size;
+
+  status = pipe (chin);
+  if (status)
+    fatal("ssh_gpg_export: pipe: %s", strerror(errno));
+
+  status = pipe (chout);
+  if (status)
+    fatal("ssh_gpg_export: pipe: %s", strerror(errno));
+
+  status = pipe (cherr);
+  if (status)
+    fatal("ssh_gpg_export: pipe: %s", strerror(errno));
+
+  old_sigchld = mysignal(SIGCHLD, SIG_DFL);
+  pid = fork ();
+  if (pid == 0) {
+    env[0] = malloc (strlen (gpg_homedir) + 6);
+    sprintf (env[0], "HOME=%s", gpg_homedir);
+    env[1] = 0;
+    close (chin[1]);
+    close (0);
+    dup (chin[0]);
+    close (chin[0]);
+    close (chout[0]);
+    close (1);
+    dup (chout[1]);
+    close (chout[1]);
+    close (cherr[0]);
+    close (2);
+    dup (cherr[1]);
+    close (cherr[1]);
+    execle (gpg_absolute_filename, "gpg", "--export", pgp_key_name, (char *) 0,
+	    env);
+    perror ("ssh_gpg_export: execle");
+    exit (-1);
+  }
+
+  if (pid < 0)
+    fatal("ssh_gpg_export: fork: %s", strerror(errno));
+
+  close (chin[0]);
+  close (chin[1]);
+  close (chout[1]);
+  close (cherr[1]);
+
+  pid2 = waitpid(pid, &status, 0);
+  mysignal(SIGCHLD, old_sigchld);
+
+  if (pid2 < 0)
+    fatal("ssh_gpg_export: waitpid: %s", strerror(errno));
+
+  /* In theory, this could lose if data is getting written both to
+     stdout and stderr, and a pipe isn't large enough to contain all of the
+     data written to one stream and they get out of sequence.  In pratice,
+     I'm not really convinced this is an issue. */
+
+  /* Collect data from stderr before checking the exit status, so that if
+     gpg printed an error, we pass it along appropriately. */
+
+  /* This will contain a spurious newline, for reasons I haven't bothered
+     to chase down. */
+  fd_to_debug (cherr[0], "ssh_gpg_export", "gpg stderr");
+
+  if (WIFSIGNALED(status))
+    fatal("ssh_gpg_export: child died by signal %d", WTERMSIG(status));
+
+  if (WEXITSTATUS(status))
+    fatal("ssh_gpg_export: child exited with return code %d", WEXITSTATUS(status));
+
+  data_size = SSH_GPG_BUFSIZ;
+  *data_count = 0;
+  *data = xmalloc ((data_size) + 1);
+
+  do {
+    count = read (chout[0], (*data) + (*data_count),
+		  (data_size) - (*data_count));
+    (*data_count) += count;
+    if ((*data_count) == data_size) {
+      data_size += SSH_GPG_BUFSIZ;
+      (*data) = xrealloc ((*data), data_size + 1);
+      if (!(*data))
+	fatal ("ssh_gpg_export: xrealloc");
+    }
+  } while (count > 0);
+
+  close (chout[0]);
+
+  if (!(*data_count)) {
+    fatal ("ssh_gpg_export: failed to read any data from gpg");
+  }
+
+  return 0;
+}
+
+int
+ssh_gpg_sign(Key *key, u_char **sigp, u_int *lenp,
+	     u_char *data, u_int datalen)
+{
+  int chin[2], chout[2], cherr[2], chstatus[2], status;
+  pid_t pid, pid2;
+  char *env[2];
+  mysig_t old_sigchld;
+  ssize_t count;
+  u_int sig_size;
+  FILE *statusf;
+  char status_fd_string[64];
+  int keytype = 0;
+  char **fields;
+  int fieldcount;
+
+  status = pipe (chin);
+  if (status)
+    fatal("ssh_gpg_sign: pipe: %s", strerror(errno));
+
+  status = pipe (chout);
+  if (status)
+    fatal("ssh_gpg_sign: pipe: %s", strerror(errno));
+
+  status = pipe (cherr);
+  if (status)
+    fatal("ssh_gpg_sign: pipe: %s", strerror(errno));
+
+  status = pipe (chstatus);
+  if (status)
+    fatal("ssh_gpg_sign: pipe: %s", strerror(errno));
+
+  old_sigchld = mysignal(SIGCHLD, SIG_DFL);
+  pid = fork ();
+  if (pid == 0) {
+    env[0] = malloc (strlen (gpg_homedir) + 6);
+    sprintf (env[0], "HOME=%s", gpg_homedir);
+    env[1] = 0;
+    close (chin[1]);
+    close (0);
+    dup (chin[0]);
+    close (chin[0]);
+    close (chout[0]);
+    close (1);
+    dup (chout[1]);
+    close (chout[1]);
+    close (cherr[0]);
+    close (2);
+    dup (cherr[1]);
+    close (cherr[1]);
+    close (chstatus[0]);
+    sprintf (status_fd_string, "%d", chstatus[1]);
+    execle (gpg_absolute_filename, "gpg", "--status-fd",
+	    status_fd_string, "-u", key->pgp_key_name,
+	    "--detach-sign", (char *) 0, env);
+    perror ("ssh_gpg_sign: execle");
+    exit (-1);
+  }
+
+  if (pid < 0)
+    fatal("ssh_gpg_sign: fork: %s", strerror(errno));
+
+  count = write (chin[1], data, datalen);
+  if (count < 0)
+    fatal ("ssh_gpg_sign: write failed writing to child's input: %s",
+	   strerror(errno));
+  if (count != datalen)
+    fatal ("ssh_gpg_sign: write failed writing to child's input");
+
+  close (chin[0]);
+  close (chin[1]);
+  close (chout[1]);
+  close (cherr[1]);
+  close (chstatus[1]);
+
+  pid2 = waitpid(pid, &status, 0);
+  mysignal(SIGCHLD, old_sigchld);
+
+  if (pid2 < 0)
+    fatal("ssh_gpg_sign: waitpid: %s", strerror(errno));
+
+  /* In theory, this could lose if data is getting written both to
+     stdout and stderr, and a pipe isn't large enough to contain all of the
+     data written to one stream and they get out of sequence.  In pratice,
+     I'm not really convinced this is an issue. */
+
+  /* Collect data from stderr before checking the exit status, so that if
+     gpg printed an error, we pass it along appropriately. */
+
+  fd_to_debug (cherr[0], "ssh_gpg_sign", "gpg stderr");
+
+  if (WIFSIGNALED(status))
+    fatal("ssh_gpg_sign: child died by signal %d", WTERMSIG(status));
+
+  if (WEXITSTATUS(status))
+    fatal("ssh_gpg_sign: child exited with return code %d", WEXITSTATUS(status));
+
+  sig_size = SSH_GPG_BUFSIZ;
+  *lenp = 0;
+  *sigp = xmalloc ((sig_size) + 1);
+
+  do {
+    count = read (chout[0], (*sigp) + (*lenp),
+		  (sig_size) - (*lenp));
+    (*lenp) += count;
+    if ((*lenp) == sig_size) {
+      sig_size += SSH_GPG_BUFSIZ;
+      (*sigp) = xrealloc ((*sigp), sig_size + 1);
+      if (!(*sigp))
+	fatal ("ssh_gpg_sign: xrealloc");
+    }
+  } while (count > 0);
+
+  close (chout[0]);
+
+  if (!(*lenp)) {
+    fatal ("ssh_gpg_sign: failed to read any signature from gpg");
+  }
+
+  statusf = fdopen (chstatus[0], "r");
+  while (read_and_split_line (statusf, &fields, &fieldcount, ' ',
+			      "ssh_gpg_sign: gpg statusfd: %s")) {
+    if (fieldcount < 2)
+      fatal ("ssh_gpg_sign: not enough fields in status line");
+    if ((!strcmp ("[GNUPG:]", fields[0]))
+	&& (!strcmp ("SIG_CREATED", fields[1]))) {
+      if (keytype)
+	fatal ("ssh_gpg_sign: more than one SIG_CREATED line found; can't happen");
+      if (fieldcount < 4)
+	fatal ("ssh_gpg_sign: not enough fields in SIG_CREATED line");
+      keytype = atoi (fields[3]);
+      if (!keytype)
+	fatal ("ssh_gpg_sign: failed to parse keytype from SIG_CREATED line; can't happen");
+      debug2 ("key is of OpenPGP type %d", keytype);
+    }
+    xfree (fields);
+  }
+  if (ferror (statusf))
+    fatal ("ssh_gpg_sign: error reading gpg statusfd");
+  fclose (statusf);
+
+  if (!keytype)
+    fatal ("ssh_gpg_sign: no SIG_CREATED line found.");
+
+  /* fascistly force people to configure their computers correctly. */
+  if (!ssh_key_type_matches_pgp_key_type (key, keytype))
+    fatal ("ssh expects %s key, but GPG key type is %d",
+	   key_ssh_name (key), keytype);
+
+  return 0;
+}
+
+static void
+ssh_gpg_import(Key *key, u_char *data, u_int data_count, int dry_run)
+{
+  int chin[2], chout[2], cherr[2], chstatus[2], status;
+  pid_t pid, pid2;
+  char *env[2];
+  mysig_t old_sigchld;
+  char status_fd_string[64];
+  int count;
+  FILE *statusf;
+  char **fields;
+  int fieldcount;
+
+  debug2 ("entering ssh_gpg_import");
+
+  if (!data_count)
+    fatal ("ssh_gpg_import: data_count is 0");
+
+  if (!data)
+    fatal ("ssh_gpg_import: data_count is NULL");
+
+  status = pipe (chin);
+  if (status)
+    fatal("ssh_gpg_import: pipe: %s", strerror(errno));
+
+  status = pipe (chout);
+  if (status)
+    fatal("ssh_gpg_import: pipe: %s", strerror(errno));
+
+  status = pipe (cherr);
+  if (status)
+    fatal("ssh_gpg_import: pipe: %s", strerror(errno));
+
+  status = pipe (chstatus);
+  if (status)
+    fatal("ssh_gpg_import: pipe: %s", strerror(errno));
+
+  old_sigchld = mysignal(SIGCHLD, SIG_DFL);
+  pid = fork ();
+  if (pid == 0) {
+    env[0] = malloc (strlen (gpg_homedir) + 6);
+    sprintf (env[0], "HOME=%s", gpg_homedir);
+    env[1] = 0;
+    close (chin[1]);
+    close (0);
+    dup (chin[0]);
+    close (chin[0]);
+    close (chout[0]);
+    close (1);
+    dup (chout[1]);
+    close (chout[1]);
+    close (cherr[0]);
+    close (2);
+    dup (cherr[1]);
+    close (cherr[1]);
+    close (chstatus[0]);
+    sprintf (status_fd_string, "%d", chstatus[1]);
+    if (dry_run)
+      execle (gpg_absolute_filename, "gpg", "--quiet", "--status-fd",
+	      status_fd_string, "--dry-run", "--import", (char *) 0, env);
+    else
+      execle (gpg_absolute_filename, "gpg", "--quiet", "--status-fd",
+	      status_fd_string, "--import", (char *) 0, env);
+    perror ("ssh_gpg_import: execle");
+    exit (-1);
+  }
+
+  if (pid < 0)
+    fatal("ssh_gpg_import: fork: %s", strerror(errno));
+
+  close (chin[0]);
+  /* We don't use stdout at all. */
+  close (chout[0]);
+  close (chout[1]);
+  close (cherr[1]);
+  close (chstatus[1]);
+
+  do {
+    count = write (chin[1], data, data_count);
+    if (count < 0)
+      fatal("ssh_gpg_import: writing data to gpg: %s", strerror(errno));
+    debug2 ("ssh_gpg_import: wrote %d bytes to gpg child", count);
+    data += count, data_count -= count;
+  } while (data_count);
+
+  close (chin[1]);
+
+  fd_to_debug (cherr[0], "ssh_gpg_import", "gpg stderr");
+
+  statusf = fdopen (chstatus[0], "r");
+  while (read_and_split_line (statusf, &fields, &fieldcount, ' ',
+			      "ssh_gpg_import: gpg statusfd: %s")) {
+    if ((!strcmp ("[GNUPG:]", fields[0]))
+	&& (!strcmp ("IMPORT_OK", fields[1]))) {
+      if (key->pgp_key_fingerprint)
+	fatal ("ssh_gpg_import: pgp_key_fingerprint is not NULL before adding fingerprint");
+      key->pgp_key_fingerprint = xstrdup (fields [3]);
+      debug2 ("ssh_gpg_import: key->pgp_key_fingerprint is '%s'", key->pgp_key_fingerprint);
+    }
+  }
+  if (ferror (statusf))
+    fatal ("ssh_gpg_import: error reading gpg statusfd");
+  fclose (statusf);
+
+  pid2 = waitpid(pid, &status, 0);
+  mysignal(SIGCHLD, old_sigchld);
+
+  if (pid2 < 0)
+    fatal("ssh_gpg_import: waitpid: %s", strerror(errno));
+
+  if (WIFSIGNALED(status))
+    fatal("ssh_gpg_import: child died by signal %d", WTERMSIG(status));
+
+  if (WEXITSTATUS(status))
+    fatal("ssh_gpg_import: child exited with return code %d", WEXITSTATUS(status));
+
+  debug2 ("about to exit ssh_gpg_import");
+}
+
+
+int
+ssh_gpg_verify_sig(Key *key,  u_char *signature, u_int signaturelen,
+	       u_char *data, u_int data_count)
+{
+  int chin[2], chout[2], cherr[2], chstatus[2], chsig[2], status;
+  pid_t pid, pid2;
+  char *env[2];
+  mysig_t old_sigchld;
+  char status_fd_string[64], sig_fd_string[64];
+  int count;
+  FILE *statusf;
+  int retval = 0;
+  Key *subkey;
+  char **fields;
+  int fieldcount;
+
+  debug2 ("entering ssh_gpg_verify_sig, signaturelen == %d, data_count == %d",
+	  signaturelen, data_count);
+
+  if (!key->pgp_key_fingerprint)
+    ssh_gpg_import (key, key->pgp_key_data, key->pgp_key_data_size, 1);
+
+  if (!adaquate_trust (key))
+    fatal ("ssh_gpg_verify_sig: primary public key is %s", bad_trust_reason (key));
+
+  status = pipe (chin);
+  if (status)
+    fatal("ssh_gpg_verify_sig: pipe: %s", strerror(errno));
+
+  status = pipe (chout);
+  if (status)
+    fatal("ssh_gpg_verify_sig: pipe: %s", strerror(errno));
+
+  status = pipe (cherr);
+  if (status)
+    fatal("ssh_gpg_verify_sig: pipe: %s", strerror(errno));
+
+  status = pipe (chstatus);
+  if (status)
+    fatal("ssh_gpg_verify_sig: pipe: %s", strerror(errno));
+
+  status = pipe (chsig);
+  if (status)
+    fatal("ssh_gpg_verify_sig: pipe: %s", strerror(errno));
+
+  old_sigchld = mysignal(SIGCHLD, SIG_DFL);
+  pid = fork ();
+  if (pid == 0) {
+    env[0] = malloc (strlen (gpg_homedir) + 6);
+    sprintf (env[0], "HOME=%s", gpg_homedir);
+    env[1] = 0;
+    close (chin[1]);
+    close (0);
+    dup (chin[0]);
+    close (chin[0]);
+    close (chout[0]);
+    close (1);
+    dup (chout[1]);
+    close (chout[1]);
+    close (cherr[0]);
+    close (2);
+    dup (cherr[1]);
+    close (cherr[1]);
+    close (chstatus[0]);
+    close (chsig[1]);
+    sprintf (status_fd_string, "%d", chstatus[1]);
+    sprintf (sig_fd_string, "-&%d", chsig[0]);
+    execle (gpg_absolute_filename, "gpg", "--quiet", "--status-fd",
+	    status_fd_string, "--enable-special-filenames", "--verify",
+	    "--", sig_fd_string, "-", (char *) 0, env);
+    perror ("ssh_gpg_verify_sig: execle");
+    exit (-1);
+  }
+
+  if (pid < 0)
+    fatal("ssh_gpg_verify_sig: fork: %s", strerror(errno));
+
+  close (chin[0]);
+  close (chout[1]);
+  close (cherr[1]);
+  close (chstatus[1]);
+  close (chsig[0]);
+
+  /* We ignore anything sent to stdout. */
+  close (chout[0]);
+
+  do {
+    count = write (chsig[1], signature, signaturelen);
+    if (count < 0)
+      fatal("ssh_gpg_verify_sig: writing signature data to gpg: %s",
+	    strerror(errno));
+    debug2 ("ssh_gpg_verify_sig: wrote %d bytes of signature to gpg child", count);
+    signature += count, signaturelen -= count;
+  } while (signaturelen);
+
+  close (chsig[1]);
+
+  do {
+    count = write (chin[1], data, data_count);
+    if (count < 0)
+      fatal("ssh_gpg_verify_sig: writing data to gpg: %s", strerror(errno));
+    debug2 ("ssh_gpg_verify_sig: wrote %d bytes to gpg child", count);
+    data += count, data_count -= count;
+  } while (data_count);
+
+  close (chin[1]);
+
+  /* This will normally print a message saying that verify succeeded.
+     It might be that we should use --logger-fd and redirect that to
+     debug, and then make stderr cause ``error'' to be called, but that
+     would be effort, and everyone knows to try again ssh -v when things
+     fail, anyway. */
+  fd_to_debug (cherr[0], "ssh_gpg_verify_sig", "gpg stderr");
+
+  statusf = fdopen (chstatus[0], "r");
+  while (read_and_split_line (statusf, &fields, &fieldcount, ' ',
+			      "ssh_gpg_verify_sig: gpg statusfd: %s")) {
+    if (fieldcount < 2)
+      fatal ("ssh_gpg_verify_sig: not enough fields in status line");
+    if ((!strcmp ("[GNUPG:]", fields[0]))
+	&& (!strcmp ("VALIDSIG", fields[1]))) {
+      subkey = key;
+      while (subkey && !retval) {
+	debug2 ("ssh_gpg_verify_sig: Comparing key used to make signature against %s",
+		subkey->pgp_key_fingerprint);
+	if (fieldcount < 3)
+	  fatal ("ssh_gpg_verify_sig: not enough fields in VALIDSIG line");
+	if (!strcmp(subkey->pgp_key_fingerprint, fields[2])) {
+	  debug2 ("ssh_gpg_verify_sig: Match found.");
+	  if (!adaquate_trust (subkey))
+	    fatal ("ssh_gpg_verify_sig: subkey is %s", bad_trust_reason (subkey));
+	  retval = 1;
+	  /* fascistly force people to configure their computers correctly.
+	     draft-ietf-secsh-transport-15.txt says that pgp-sign-rsa means
+	     that ``the key'' is in RSA format.  It's not clear what
+	     ``the key'' means when the primary public key is one type, and
+	     the subkey used for the sig another, and sending mail asking
+	     for claification didn't yield responses, so this code simply
+	     verifies that the key type used for the signature matches the
+	     key type that the ssh protocol said would be used. */
+	  if (!ssh_key_type_matches_pgp_key_type (subkey,
+						  subkey->pgp_key_type))
+	    fatal ("ssh expects %s key, but GPG key type is %d",
+		   key_ssh_name (subkey), subkey->pgp_key_type);
+	} else {
+	  subkey = subkey->pgp_subkey;
+	}
+      }
+      if (!retval)
+	fatal ("ssh_gpg_verify_sig: pgp_key_fingerprint doesn't match fingerprint of imported key");
+    }
+    xfree (fields);
+  }
+  if (ferror (statusf))
+    fatal ("ssh_gpg_verify_sig: error reading gpg statusfd");
+  fclose (statusf);
+
+  pid2 = waitpid(pid, &status, 0);
+  mysignal(SIGCHLD, old_sigchld);
+
+  if (pid2 < 0)
+    fatal("ssh_gpg_verify_sig: waitpid: %s", strerror(errno));
+
+  if (WIFSIGNALED(status))
+    fatal("ssh_gpg_verify_sig: child died by signal %d", WTERMSIG(status));
+
+  if (WEXITSTATUS(status))
+    fatal("ssh_gpg_verify_sig: child exited with return code %d", WEXITSTATUS(status));
+
+  debug2 ("about to exit ssh_gpg_verify_sig; retval == %d", retval);
+
+  return retval;
+}
+
+
+typedef enum {
+  KL_START,
+  KL_PUB,
+  KL_PUB_FPR,
+  KL_UID,
+  KL_SUB,
+  KL_SUB_FPR
+} keylist_state;
+
+/* Call gpg --list-keys with appropriate args, to fill in subkey info,
+   key type and trust info.
+
+   If email is non-null, return -1 if key doesn't have a trusted
+   uid that matches email.  Else, return 0.
+
+   Add key to keyring unless dry_run is non-null.
+
+   This tries to call fatal rather agressively if gpg's output doesn't
+   match what it expects, in order to try to make sure that if gpg
+   evolves or I misunderstood what its output should be, that is as
+   unlikely to cause security problems as possible. */
+int
+ssh_gpg_get_key_info(Key *key, char *email, int dry_run)
+{
+  int chin[2], chout[2], cherr[2], status;
+  pid_t pid, pid2;
+  char *env[2];
+  mysig_t old_sigchld;
+  FILE *outf;
+  int trusted_email_match = 0;
+  keylist_state kl_state = KL_START;
+  Key *subkey;
+  char **fields;
+  int fieldcount;
+
+  debug2 ("entering ssh_gpg_get_key_info, email == %s", email);
+
+  if (!key->pgp_key_fingerprint) {
+    if (!key->pgp_key_data)
+      fatal ("ssh_gpg_get_key_info: no key->pgp_key_fingerprint, and no key->pgp_key_data");
+    ssh_gpg_import (key, key->pgp_key_data, key->pgp_key_data_size, dry_run);
+    if (!key->pgp_key_fingerprint)
+      fatal ("ssh_gpg_get_key_info: key->pgp_key_fingerprint is NULL after ssh_gpg_import; perhaps your version of gnupg is too old?");
+  }
+
+  subkey = key;
+
+  status = pipe (chin);
+  if (status)
+    fatal("ssh_gpg_get_key_info: pipe: %s", strerror(errno));
+
+  status = pipe (chout);
+  if (status)
+    fatal("ssh_gpg_get_key_info: pipe: %s", strerror(errno));
+
+  status = pipe (cherr);
+  if (status)
+    fatal("ssh_gpg_get_key_info: pipe: %s", strerror(errno));
+
+  old_sigchld = mysignal(SIGCHLD, SIG_DFL);
+  pid = fork ();
+  if (pid == 0) {
+    env[0] = malloc (strlen (gpg_homedir) + 6);
+    sprintf (env[0], "HOME=%s", gpg_homedir);
+    env[1] = 0;
+    close (chin[1]);
+    close (0);
+    dup (chin[0]);
+    close (chin[0]);
+    close (chout[0]);
+    close (1);
+    dup (chout[1]);
+    close (chout[1]);
+    close (cherr[0]);
+    close (2);
+    dup (cherr[1]);
+    close (cherr[1]);
+    execle (gpg_absolute_filename, "gpg", "--fixed-list-mode",
+	    "--with-colons", "--fingerprint", "--fingerprint",
+	    key->pgp_key_fingerprint, (char *) 0, env);
+    perror ("ssh_gpg_get_key_info: execle");
+    exit (-1);
+  }
+
+  if (pid < 0)
+    fatal("ssh_gpg_get_key_info: fork: %s", strerror(errno));
+
+  close (chin[0]);
+  close (chout[1]);
+  close (cherr[1]);
+
+  /* Nothing to send to gpg. */
+  close (chin[1]);
+
+  fd_to_debug (cherr[0], "ssh_gpg_get_key_info", "gpg stderr");
+
+  outf = fdopen (chout[0], "r");
+  while (read_and_split_line (outf, &fields, &fieldcount, ':',
+			      "ssh_gpg_get_key_info: gpg stdout: %s")) {
+    if (!fields[0])
+	fatal ("ssh_gpg_get_key_info: empty first field of gpg output, can't happen.");
+    if (!strcmp ("pub", fields[0])) {
+      if (kl_state != KL_START)
+	fatal ("ssh_gpg_get_key_info: pub seen, not at begining of key info.");
+      kl_state = KL_PUB;
+      if (fieldcount < 4)
+	fatal ("ssh_gpg_get_key_info: not enough fields in pub line");
+      key->pgp_key_trust = fields[1][0];
+      key->pgp_key_type = atoi (fields[3]);
+      debug2 ("key->pgp_key_type is %d", key->pgp_key_type);
+    } else if (!strcmp ("uid", fields[0])) {
+      if ((kl_state != KL_PUB_FPR)
+	  && (kl_state != KL_UID)) {
+	fatal ("ssh_gpg_get_key_info: uid seen, in wrong place; can't happen.");
+      }
+      kl_state = KL_UID;
+      if (fieldcount < 10)
+	fatal ("ssh_gpg_get_key_info: not enough fields in uid line");
+      /* We skip over untrusted uids, because there might in theory be a good
+	 reason why some uids would get more sigs than others, or something. */
+      if ((fields[1][0] == 'f') || (fields[1][0] == 'u')) {
+	debug2 ("ssh_gpg_get_key_info: uid is fully trusted, checking identity value");
+	if (email) {
+	  if (ssh_gpg_email_value_matches (fields[9], email)) {
+	    debug2 ("ssh_gpg_get_key_info: key is trusted and has correct uid");
+	    trusted_email_match = 1;
+	  }
+	}
+      }
+    } else if (!strcmp ("fpr", fields[0])) {
+      if (kl_state == KL_PUB) {
+	kl_state = KL_PUB_FPR;
+	if (strcmp (key->pgp_key_fingerprint, fields[9]))
+	  fatal ("ssh_gpg_get_key_info: fingerprint doesn't match fingerprint we have");
+      } else if (kl_state == KL_SUB) {
+	kl_state = KL_SUB_FPR;
+	subkey->pgp_key_fingerprint = xmalloc (strlen (fields[9]) + 1);
+	strcpy (subkey->pgp_key_fingerprint, fields[9]);
+	debug2 ("ssh_gpg_get_key_info: subkey->pgp_key_fingerprint is %s", subkey->pgp_key_fingerprint);
+      } else {
+	fatal ("ssh_gpg_get_key_info: fpr found in unexpected state.");
+      }
+    } else if (!strcmp ("sub", fields[0])) {
+      if ((kl_state == KL_UID) || (kl_state == KL_SUB_FPR)) {
+	subkey->pgp_subkey = key_new (key->type);
+	subkey = subkey->pgp_subkey;
+	kl_state = KL_SUB;
+      } else {
+	fatal ("ssh_gpg_get_key_info: sub found in unexpected state.");
+      }
+      subkey->pgp_key_trust = fields[1][0];
+      subkey->pgp_key_type = atoi (fields[3]);
+      debug2 ("ssh_gpg_get_key_info: subkey type is %d", subkey->pgp_key_type);
+    } else {
+      fatal ("ssh_gpg_get_key_info: unrecognized line type seen.");
+    }
+    xfree (fields);
+  }
+  if (ferror (outf))
+    fatal ("ssh_gpg_get_key_info: error reading gpg outfd");
+  fclose (outf);
+
+  pid2 = waitpid(pid, &status, 0);
+  mysignal(SIGCHLD, old_sigchld);
+
+  if (pid2 < 0)
+    fatal("ssh_gpg_get_key_info: waitpid: %s", strerror(errno));
+
+  if (WIFSIGNALED(status))
+    fatal("ssh_gpg_get_key_info: child died by signal %d", WTERMSIG(status));
+
+  if (WEXITSTATUS(status))
+    fatal("ssh_gpg_get_key_info: child exited with return code %d", WEXITSTATUS(status));
+
+  if (email && !trusted_email_match) {
+    error ("ssh_gpg_get_key_info: no trusted match for email value of uid.");
+    return -1;
+  }
+
+  return 1;
+}
+
+#endif /* WITH_GPG */
--- /dev/null	Thu Apr 17 13:37:10 2003
+++ ssh-gpg.h	Wed Apr 16 20:21:13 2003
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2002 Joel N. Weber II.
+ *
+ * Redistribution, copying, and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+int
+ssh_gpg_export(char *pgp_key_name, u_char **data, u_int *data_count);
+
+int
+ssh_gpg_sign(Key *key, u_char **sigp, u_int *lenp,
+	     u_char *data, u_int datalen);
+
+int
+ssh_gpg_verify_sig(Key *key,  u_char *signature, u_int signaturelen,
+		   u_char *data, u_int data_count);
+
+int
+ssh_gpg_get_key_info(Key *key, char *hostname, int dry_run);
+
+
+extern char *gpg_homedir, *gpg_absolute_filename;
--- LICENCE.~1~	Thu Jun 20 21:19:12 2002
+++ LICENCE	Wed Apr 16 20:21:13 2003
@@ -180,6 +180,30 @@
      * SUCH DAMAGE.
 
 7)
+    The code to use gpg was contributed by Joel N. Weber II under
+    the following license:
+
+     * Redistribution, copying, and use in source and binary forms, with or without
+     * modification, are permitted provided that the following conditions
+     * are met:
+     * 1. Redistributions of source code must retain the above copyright
+     *    notice, this list of conditions and the following disclaimer.
+     * 2. Redistributions in binary form must reproduce the above copyright
+     *    notice, this list of conditions and the following disclaimer in the
+     *    documentation and/or other materials provided with the distribution.
+     *
+     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+     * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+     * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+     * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+     * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+8)
     Remaining components of the software are provided under a standard
     2-term BSD licence with the following names as copyright holders:
 

