--- configure.ac.~2~	Tue Jul  2 16:37:57 2002
+++ configure.ac	Thu Sep 26 14:03:05 2002
@@ -725,6 +725,14 @@
 	)
 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.])])
+
 # Start of GSI/Globus 2.0 mods
 # Check whether the user wants GSI (Globus 2.0) support
 # if we are using GSI, we will also use the 
@@ -2471,6 +2479,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.~2~	Tue Jul  2 16:37:56 2002
+++ config.h.in	Thu Sep 26 13:38:31 2002
@@ -1,5 +1,5 @@
 /* config.h.in.  Generated from configure.ac by autoheader.  */
-/* $Id: config.h.in,v 1.4 2002/06/30 20:39:17 hartmans Exp $ */
+/* $Id: acconfig.h,v 1.6 2002/06/30 20:20:15 hartmans Exp $ */
 
 #ifndef _CONFIG_H
 #define _CONFIG_H
@@ -874,6 +874,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). */
--- Makefile.in.~2~	Tue Jul  2 16:37:56 2002
+++ Makefile.in	Thu Sep 26 14:04:19 2002
@@ -60,7 +60,7 @@
 
 TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} $(SFTP_PROGS)
 
-LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o msg.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o scard-opensc.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o monitor_wrap.o monitor_fdpass.o kexgss.o gss-genr.o
+LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o msg.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o scard-opensc.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o monitor_wrap.o monitor_fdpass.o kexgss.o gss-genr.o ssh-gpg.o
 
 SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o sshtty.o readconf.o clientloop.o
 
--- sshd.c.~2~	Tue Jul  2 16:37:58 2002
+++ sshd.c	Thu Sep 26 13:51:52 2002
@@ -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"
@@ -89,6 +114,10 @@
 #include "ssh-gss.h"
 #endif
 
+#ifdef WITH_GPG
+#include "ssh-gpg.h"
+#endif
+
 #ifdef LIBWRAP
 #include <tcpd.h>
 #include <syslog.h>
@@ -181,6 +210,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.
@@ -494,7 +527,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;
@@ -517,6 +550,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]);
@@ -681,13 +716,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);
@@ -707,7 +746,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;
@@ -718,7 +757,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]);
 }
@@ -728,7 +767,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);
 	}
@@ -814,6 +853,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);
@@ -965,7 +1007,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;
@@ -995,6 +1056,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.~2~	Tue Jul  2 16:37:57 2002
+++ key.h	Thu Sep 26 13:46:01 2002
@@ -35,6 +35,8 @@
 	KEY_RSA,
 	KEY_DSA,
 	KEY_NULL,
+	KEY_PGP_RSA,
+	KEY_PGP_DSA,
 	KEY_UNSPEC
 };
 enum fp_type {
@@ -54,6 +56,12 @@
 	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;
+#endif
 };
 
 Key	*key_new(int);
--- key.c.~2~	Tue Jul  2 16:37:57 2002
+++ key.c	Thu Sep 26 18:30:14 2002
@@ -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 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.45 2002/06/23 03:26:19 deraadt Exp $");
@@ -41,6 +67,9 @@
 #include "rsa.h"
 #include "ssh-dss.h"
 #include "ssh-rsa.h"
+#ifdef WITH_GPG
+#include "ssh-gpg.h"
+#endif
 #include "uuencode.h"
 #include "buffer.h"
 #include "bufaux.h"
@@ -57,6 +86,11 @@
 	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_fingerprint = NULL;
+#endif
 	switch (k->type) {
 	case KEY_RSA1:
 	case KEY_RSA:
@@ -81,6 +115,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:
@@ -114,6 +152,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:
@@ -137,6 +181,17 @@
 			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);
+		break;
+#endif
 	case KEY_UNSPEC:
 		break;
 	default:
@@ -164,6 +219,8 @@
 		    BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
 		    BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
 		break;
+	/* I don't think we need key_equal to do anything useful for the pgp
+	   case, hence I'm allowing this to fall through to this error. */
 	default:
 		fatal("key_equal: bad key type %d", a->type);
 		break;
@@ -210,6 +267,9 @@
 	case KEY_UNSPEC:
 		return retval;
 		break;
+	/* I don't think we need key_fingerprint_raw to do anything
+	   useful for the pgp case, hence I'm allowing this to fall
+	   through to this error. */
 	default:
 		fatal("key_fingerprint_raw: bad key type %d", k->type);
 		break;
@@ -482,6 +542,8 @@
 			cp++;
 		*cpp = cp;
 		break;
+	/* I don't think we need key_read to do anything useful for the pgp
+	   case, hence I'm allowing this to fall through to this error. */
 	default:
 		fatal("key_read: bad key type: %d", ret->type);
 		break;
@@ -534,6 +596,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";
 }
@@ -548,6 +618,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";
 }
@@ -602,6 +680,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);
 	}
@@ -627,6 +707,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;
@@ -647,6 +730,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
 	} else if (strcmp(name, "null") == 0){
 		return KEY_NULL;
 	}
@@ -683,6 +772,10 @@
 	char *ktype;
 	int rlen, type;
 	Key *key = NULL;
+#ifdef WITH_GPG
+	u_char *pgp_data;
+	u_int pgp_count;
+#endif
 
 #ifdef DEBUG_PK
 	dump_base64(stderr, blob, blen);
@@ -711,6 +804,15 @@
 		DSA_print_fp(stderr, key->dsa, 8);
 #endif
 		break;
+#ifdef WITH_GPG
+	case KEY_PGP_RSA:
+	case KEY_PGP_DSA:
+		key = key_new(type);
+		pgp_data = buffer_get_string(&b, &pgp_count);
+		ssh_gpg_import(key, pgp_data, pgp_count);
+		xfree(pgp_data);
+		break;
+#endif
 	case KEY_UNSPEC:
 		key = key_new(type);
 		break;
@@ -751,6 +853,13 @@
 		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:
+		buffer_put_cstring(&b, key_ssh_name(key));
+		buffer_put_string(&b, key->pgp_key_data, key->pgp_key_data_size);
+		break;
+#endif
 	default:
 		error("key_to_blob: unsupported key type %d", key->type);
 		buffer_free(&b);
@@ -765,6 +874,7 @@
 		*lenp = len;
 	if (blobp != NULL)
 		*blobp = buf;
+	debug2("key_to_blob: returning %d bytes", len);
 	return len;
 }
 
@@ -781,6 +891,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;
@@ -808,6 +924,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;
@@ -849,8 +971,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;
 	}
 
--- sshconnect.c.~2~	Tue Jul  2 16:37:58 2002
+++ sshconnect.c	Thu Sep 26 18:12:35 2002
@@ -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 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;
 
@@ -831,6 +860,12 @@
 {
 	struct stat st;
 
+#ifdef WITH_GPG
+	if ((host_key->type == KEY_PGP_RSA)
+	    || (host_key->type == KEY_PGP_DSA)) {
+	  return ssh_gpg_verify_key (host_key, host);
+	}
+#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.~2~	Tue Jul  2 16:37:58 2002
+++ sshconnect2.c	Thu Sep 26 15:08:49 2002
@@ -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 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,10 @@
 #include "msg.h"
 #include "pathnames.h"
 
+#ifdef WITH_GPG
+#include "ssh-gpg.h"
+#endif
+
 #ifdef GSSAPI
 #include "ssh-gss.h"
 #endif
@@ -127,7 +157,20 @@
 	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_absolute_filename = options.gpg_absolute_filename;
+		if (options.gpg_homedir == NULL)
+			gpg_homedir = getenv("HOME");
+		else
+			gpg_homedir = options.gpg_homedir;
+		orig=myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
+		len = strlen(orig)+sizeof("pgp-sign-rsa,pgp-sign-dss,");
+		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]=xmalloc(len);
+		snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],len,"pgp-sign-rsa,pgp-sign-dss,%s",orig);  
+	}
+#endif
 #ifdef GSSAPI
         /* If we've got GSSAPI algorithms, then we also support the
          * 'null' hostkey, as a last resort */
--- servconf.c.~2~	Tue Jul  2 16:37:58 2002
+++ servconf.c	Thu Sep 26 13:55:16 2002
@@ -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"
@@ -103,6 +128,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;
@@ -305,6 +334,12 @@
 #ifdef AFS
 	sAFSTokenPassing,
 #endif
+#ifdef WITH_GPG
+	sRSAPGPKeyName,
+	sDSAPGPKeyName,
+	sGPGAbsoluteFilename,
+	sGPGHomedir,
+#endif
 	sChallengeResponseAuthentication,
 	sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress,
 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
@@ -364,6 +399,12 @@
 #ifdef AFS
 	{ "afstokenpassing", sAFSTokenPassing },
 #endif
+#ifdef WITH_GPG
+	{ "rsapgpkeyname", sRSAPGPKeyName },
+	{ "dsapgpkeyname", sDSAPGPKeyName },
+	{ "gpgabsolutefilename", sGPGAbsoluteFilename },
+	{ "gpghomedir", sGPGHomedir },
+#endif
 	{ "passwordauthentication", sPasswordAuthentication },
 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
 	{ "challengeresponseauthentication", sChallengeResponseAuthentication },
@@ -704,7 +745,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.~2~	Tue Jul  2 16:37:58 2002
+++ servconf.h	Thu Sep 26 13:48:19 2002
@@ -98,6 +98,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.~2~	Tue Jul  2 16:37:57 2002
+++ readconf.c	Thu Sep 26 18:14:37 2002
@@ -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"
@@ -96,6 +122,10 @@
 	oForwardAgent, oForwardX11, oGatewayPorts, oRhostsAuthentication,
 	oPasswordAuthentication, oRSAAuthentication,
 	oChallengeResponseAuthentication, oXAuthLocation,
+#ifdef WITH_GPG
+	oGPGAbsoluteFilename,
+	oGPGHomedir,
+#endif
 #if defined(KRB4) || defined(KRB5)
 	oKerberosAuthentication,
 #endif
@@ -149,6 +179,10 @@
 	{ "challengeresponseauthentication", oChallengeResponseAuthentication },
 	{ "skeyauthentication", oChallengeResponseAuthentication }, /* alias */
 	{ "tisauthentication", oChallengeResponseAuthentication },  /* alias */
+#ifdef WITH_GPG
+	{ "gpgabsolutefilename", oGPGAbsoluteFilename },
+	{ "gpghomedir", oGPGHomedir },
+#endif
 #if defined(KRB4) || defined(KRB5)
 	{ "kerberosauthentication", oKerberosAuthentication },
 #endif
@@ -529,6 +563,15 @@
 		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;
+#endif
+
 	case oProxyCommand:
 		charptr = &options->proxy_command;
 		string = xstrdup("");
@@ -792,6 +835,10 @@
 	options->rsa_authentication = -1;
 	options->pubkey_authentication = -1;
 	options->challenge_response_authentication = -1;
+#ifdef WITH_GPG
+	options->gpg_absolute_filename = NULL;
+	options->gpg_homedir = NULL;
+#endif
 #ifdef GSSAPI
         options->gss_authentication = -1;
         options->gss_deleg_creds = -1;
--- readconf.h.~2~	Tue Jul  2 16:37:57 2002
+++ readconf.h	Thu Sep 26 14:14:49 2002
@@ -41,6 +41,10 @@
 	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;
+#endif
 #if defined(KRB4) || defined(KRB5)
 	int     kerberos_authentication;	/* Try Kerberos authentication. */
 #endif
--- /dev/null	Thu Sep 26 18:25:43 2002
+++ ssh-gpg.c	Thu Sep 26 18:30:52 2002
@@ -0,0 +1,878 @@
+/*
+ * 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"
+
+#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 LBSIZE 100
+
+char *gpg_homedir, *gpg_absolute_filename;
+
+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;
+  FILE *errf;
+  u_char buf[LBSIZE];
+  int i;
+
+  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. */
+
+  errf = fdopen (cherr[0], "r");
+  while (fgets (buf, LBSIZE, errf)) {
+    for (i = 0; i < (LBSIZE - 1); i++) {
+      if (!buf[i])
+	goto export_err_breakout;
+      if (buf[i] == '\n') {
+	buf[i] = 0;
+	goto export_err_breakout;
+      }
+    }
+  export_err_breakout:
+    error ("ssh_gpg_export: gpg stderr: %s", buf);
+  }
+  if (ferror (errf))
+    fatal ("ssh_gpg_export: error reading gpg stderr");
+  fclose (errf);
+
+  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;
+  FILE *errf;
+  u_char buf[LBSIZE];
+  char status_fd_string[64];
+  int keytype = 0;
+  int i;
+
+  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, "--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. */
+
+  errf = fdopen (cherr[0], "r");
+  while (fgets (buf, LBSIZE, errf)) {
+    for (i = 0; i < (LBSIZE - 1); i++) {
+      if (!buf[i])
+	goto sign_err_breakout;
+      if (buf[i] == '\n') {
+	buf[i] = 0;
+	goto sign_err_breakout;
+      }
+    }
+  sign_err_breakout:
+    error ("ssh_gpg_sign: gpg stderr: %s", buf);
+  }
+  if (ferror (errf))
+    fatal ("ssh_gpg_sign: error reading gpg stderr");
+  fclose (errf);
+
+  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 (fgets (buf, LBSIZE, statusf)) {
+    for (i = 0; i < (LBSIZE - 1); i++) {
+      if (!buf[i])
+	goto import_status_breakout;
+      if (buf[i] == '\n') {
+	buf[i] = 0;
+	goto import_status_breakout;
+      }
+    }
+  import_status_breakout:
+    debug2 ("ssh_gpg_sign: gpg statusfd: %s", buf);
+    if (!strncmp ("[GNUPG:] SIG_CREATED ", buf, 21)) {
+      if (keytype)
+	fatal ("ssh_gpg_sign: more than one SIG_CREATED line found; can't happen");
+      i = 21;
+      while ((buf[i] && isspace(buf[i])))
+	i++;
+      while ((buf[i] && isalnum(buf[i])))
+	i++;
+      while ((buf[i] && isspace(buf[i])))
+	i++;
+      while (isdigit (buf[i])) {
+	keytype *= 10;
+	keytype += buf[i] - '0';
+	i++;
+      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);
+    }
+  }
+  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. */
+  switch (key->type) {
+  case KEY_PGP_RSA:
+    if (keytype != 1)
+      fatal ("ssh expects RSA key, but GPG claims key is not RSA");
+    break;
+  case KEY_PGP_DSA:
+    if (keytype != 17)
+      fatal ("ssh expects DSA key, but GPG claims key is not DSA");
+    break;
+  }
+
+  return 0;
+}
+
+int
+ssh_gpg_import(Key *key, u_char *data, u_int data_count)
+{
+  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;
+  FILE *errf;
+  int i, j;
+  u_char buf[LBSIZE];
+
+  debug2 ("entering ssh_gpg_import");
+
+  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]);
+    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]);
+
+  errf = fdopen (cherr[0], "r");
+  while (fgets (buf, LBSIZE, errf)) {
+    for (i = 0; i < (LBSIZE - 1); i++) {
+      if (!buf[i])
+	goto import_err_breakout;
+      if (buf[i] == '\n') {
+	buf[i] = 0;
+	goto import_err_breakout;
+      }
+    }
+  import_err_breakout:
+    error ("ssh_gpg_import: gpg stderr: %s", buf);
+  }
+  if (ferror (errf))
+    fatal ("ssh_gpg_import: error reading gpg stderr");
+  fclose (errf);
+
+  statusf = fdopen (chstatus[0], "r");
+  while (fgets (buf, LBSIZE, statusf)) {
+    for (i = 0; i < (LBSIZE - 1); i++) {
+      if (!buf[i])
+	goto import_status_breakout;
+      if (buf[i] == '\n') {
+	buf[i] = 0;
+	goto import_status_breakout;
+      }
+    }
+  import_status_breakout:
+    debug2 ("ssh_gpg_import: gpg statusfd: %s", buf);
+    if (!strncmp ("[GNUPG:] IMPORT_OK", buf, 18)) {
+      i = 18;
+      while ((buf[i] && isspace(buf[i])))
+	i++;
+      while ((buf[i] && isdigit(buf[i])))
+	i++;
+      while ((buf[i] && isspace(buf[i])))
+	i++;
+      j = i;
+      while ((buf[i] && isalnum(buf[i])))
+	i++;
+      if (key->pgp_key_fingerprint)
+	fatal ("ssh_gpg_import: pgp_key_fingerprint is not NULL before adding fingerprint");
+      key->pgp_key_fingerprint = malloc (1 + i - j);
+      memcpy (key->pgp_key_fingerprint, buf + j, i - j);
+      key->pgp_key_fingerprint[i - j] = 0;
+      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");
+
+  return 0;
+}
+
+
+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;
+  FILE *errf;
+  int i, j;
+  u_char buf[LBSIZE];
+  int retval = 0;
+
+  debug2 ("entering ssh_gpg_verify_sig, signaturelen == %d, data_count == %d",
+	  signaturelen, data_count);
+
+  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]);
+
+  errf = fdopen (cherr[0], "r");
+  while (fgets (buf, LBSIZE, errf)) {
+    for (i = 0; i < (LBSIZE - 1); i++) {
+      if (!buf[i])
+	goto verify_err_breakout;
+      if (buf[i] == '\n') {
+	buf[i] = 0;
+	goto verify_err_breakout;
+      }
+    }
+  verify_err_breakout:
+    error ("ssh_gpg_verify_sig: gpg stderr: %s", buf);
+  }
+  if (ferror (errf))
+    fatal ("ssh_gpg_verify_sig: error reading gpg stderr");
+  fclose (errf);
+
+  statusf = fdopen (chstatus[0], "r");
+  while (fgets (buf, LBSIZE, statusf)) {
+    for (i = 0; i < (LBSIZE - 1); i++) {
+      if (!buf[i])
+	goto verify_status_breakout;
+      if (buf[i] == '\n') {
+	buf[i] = 0;
+	goto verify_status_breakout;
+      }
+    }
+  verify_status_breakout:
+    debug2 ("ssh_gpg_verify_sig: gpg statusfd: %s", buf);
+    if (!strncmp ("[GNUPG:] VALIDSIG", buf, 17)) {
+      i = 18;
+      while ((buf[i] && isspace(buf[i])))
+	i++;
+      j = i;
+      while ((buf[i] && isalnum(buf[i])))
+	i++;
+      if (strncmp(key->pgp_key_fingerprint, buf + j, strlen (key->pgp_key_fingerprint)))
+	fatal ("ssh_gpg_verify_sig: pgp_key_fingerprint doesn't match fingerprint of imported key");
+      retval = 1;
+      debug2 ("ssh_gpg_verify_sig: setting retval to 1");
+    }
+  }
+  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;
+}
+
+
+
+int
+ssh_gpg_verify_key(Key *key, char *hostname)
+{
+  int chin[2], chout[2], cherr[2], status;
+  pid_t pid, pid2;
+  char *env[2];
+  mysig_t old_sigchld;
+  FILE *outf;
+  FILE *errf;
+  int i;
+  u_char buf[LBSIZE];
+  int retval = 0, keytype = 0;
+
+  debug2 ("entering ssh_gpg_verify_key, hostname == %s", hostname);
+
+  status = pipe (chin);
+  if (status)
+    fatal("ssh_gpg_verify_key: pipe: %s", strerror(errno));
+
+  status = pipe (chout);
+  if (status)
+    fatal("ssh_gpg_verify_key: pipe: %s", strerror(errno));
+
+  status = pipe (cherr);
+  if (status)
+    fatal("ssh_gpg_verify_key: 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", "--list-keys", key->pgp_key_fingerprint,
+	    (char *) 0, env);
+    perror ("ssh_gpg_verify_key: execle");
+    exit (-1);
+  }
+
+  if (pid < 0)
+    fatal("ssh_gpg_verify_key: fork: %s", strerror(errno));
+
+  close (chin[0]);
+  close (chout[1]);
+  close (cherr[1]);
+
+  /* Nothing to send to gpg. */
+  close (chin[1]);
+
+  errf = fdopen (cherr[0], "r");
+  while (fgets (buf, LBSIZE, errf)) {
+    for (i = 0; i < (LBSIZE - 1); i++) {
+      if (!buf[i])
+	goto verify_key_err_breakout;
+      if (buf[i] == '\n') {
+	buf[i] = 0;
+	goto verify_key_err_breakout;
+      }
+    }
+  verify_key_err_breakout:
+    error ("ssh_gpg_verify_key: gpg stderr: %s", buf);
+  }
+  if (ferror (errf))
+    fatal ("ssh_gpg_verify_key: error reading gpg stderr");
+  fclose (errf);
+
+  outf = fdopen (chout[0], "r");
+  while (fgets (buf, LBSIZE, outf)) {
+    for (i = 0; i < (LBSIZE - 1); i++) {
+      if (!buf[i])
+	goto verify_key_status_breakout;
+      if (buf[i] == '\n') {
+	buf[i] = 0;
+	goto verify_key_status_breakout;
+      }
+    }
+  verify_key_status_breakout:
+    debug2 ("ssh_gpg_verify_key: gpg outfd: %s", buf);
+    if (!strncmp ("pub:", buf, 4)) {
+      /* If keytype already has a value, then we've seen more than one
+	 public key line, which Shouldn't Happen. */
+      if (keytype)
+	fatal ("ssh_gpg_verify_key: more than one pub line seen; can't happen.");
+      i = 4;
+      /* FIXME: the following while loop just skips over the trust value for
+	 the public key.  Is that what we really want? */
+      while ((buf[i] && (buf[i] != ':')))
+	i++;
+      if (buf[i])
+	i++;
+      /* Skip over the key size, because we don't really care about that. */
+      while ((buf[i] && (buf[i] != ':')))
+	i++;
+      if (buf[i])
+	i++;
+      if (!buf[i])
+	fatal ("ssh_gpg_verify_key: pub line too short; can't happen.");
+      while (isdigit (buf[i])) {
+	keytype *= 10;
+	keytype += buf[i] - '0';
+	i++;
+      }
+      debug2 ("key is of OpenPGP type %d", keytype);
+      if (buf[i] != ':')
+	fatal ("ssh_gpg_verify_key: pub line too short; can't happen.");
+      /* We don't care about the rest of the fields on the line. */
+    } else if (!strncmp ("uid:", buf, 4)) {
+      if ((buf[4] == 'f') || (buf[4] == 'u')) {
+	debug2 ("ssh_gpg_verify_key: key is fully trusted, checking identity value");
+	i = 5;
+	while (buf[i] && (buf[i] != ':'))
+	  i++;
+	if (buf[i])
+	  i++;
+	while (buf[i] && (buf[i] != ':'))
+	  i++;
+	if (buf[i])
+	  i++;
+	while (buf[i] && (buf[i] != ':'))
+	  i++;
+	if (buf[i])
+	  i++;
+	while (buf[i] && (buf[i] != ':'))
+	  i++;
+	if (buf[i])
+	  i++;
+	while (buf[i] && (buf[i] != ':'))
+	  i++;
+	if (buf[i])
+	  i++;
+	while (buf[i] && (buf[i] != ':'))
+	  i++;
+	if (buf[i])
+	  i++;
+	while (buf[i] && (buf[i] != ':'))
+	  i++;
+	if (buf[i])
+	  i++;
+	while (buf[i] && (buf[i] != ':'))
+	  i++;
+	if (buf[i])
+	  i++;
+	while (buf[i] && (buf[i] != '<'))
+	  i++;
+	if (buf[i])
+	  i++;
+	if (strncmp (buf + i, "sshd@", 5) ){
+	  debug2 ("ssh_gpg_verify_key: UID doesn't match sshd@");
+	} else {
+	  i += 5;
+	  if (strncmp (buf + i, hostname, strlen (hostname))) {
+	    debug2 ("ssh_gpg_verify_key: hostname doesn't match");
+	  } else {
+	    if (buf[i + strlen (hostname)] != '>') {
+	      debug2 ("ssh_gpg_verify_key: garbage at end of hostname in uid");
+	    } else {
+	      debug2 ("ssh_gpg_verify_key: key is trusted and has correct uid");
+	      retval = 1;
+	    }
+	  }
+	}
+      }
+    }
+  }
+  if (ferror (outf))
+    fatal ("ssh_gpg_verify_key: error reading gpg outfd");
+  fclose (outf);
+
+  pid2 = waitpid(pid, &status, 0);
+  mysignal(SIGCHLD, old_sigchld);
+
+  if (pid2 < 0)
+    fatal("ssh_gpg_verify_key: waitpid: %s", strerror(errno));
+
+  if (WIFSIGNALED(status))
+    fatal("ssh_gpg_verify_key: child died by signal %d", WTERMSIG(status));
+
+  if (WEXITSTATUS(status))
+    fatal("ssh_gpg_verify_key: child exited with return code %d", WEXITSTATUS(status));
+
+  /* fascistly force people to configure their computers correctly. */
+  switch (key->type) {
+  case KEY_PGP_RSA:
+    if (keytype != 1)
+      fatal ("ssh expects RSA key, but GPG claims key is not RSA");
+    break;
+  case KEY_PGP_DSA:
+    if (keytype != 17)
+      fatal ("ssh expects DSA key, but GPG claims key is not DSA");
+    break;
+  }
+
+  /* FIXME: it looks to me like the callers aren't actually paying attention
+     to the return value, so until I bother to chase that down, we'll just
+     call fatal here if need be. */
+  if (retval != 1)
+    fatal ("ssh_gpg_verify_key: verification failed.");
+
+  debug2 ("about to exit ssh_gpg_verify_key; retval == %d", retval);
+
+  return retval;
+}
+
+#endif /* WITH_GPG */
--- /dev/null	Thu Sep 26 18:25:43 2002
+++ ssh-gpg.h	Thu Sep 26 16:08:50 2002
@@ -0,0 +1,43 @@
+/*
+ * 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_import(Key *k, u_char *data, u_int data_count);
+
+int
+ssh_gpg_verify_sig(Key *key,  u_char *signature, u_int signaturelen,
+		   u_char *data, u_int data_count);
+
+int
+ssh_gpg_verify_key(Key *key, char *hostname);
+
+
+extern char *gpg_homedir, *gpg_absolute_filename;
--- LICENCE.~1~	Thu Jun 20 21:19:12 2002
+++ LICENCE	Sun Sep  1 16:16:56 2002
@@ -180,6 +180,30 @@
      * SUCH DAMAGE.
 
 7)
+    The code to use libgpgme 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:
 

