summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authormarius eriksen <marius@cvs.openbsd.org>2005-05-29 02:41:43 +0000
committermarius eriksen <marius@cvs.openbsd.org>2005-05-29 02:41:43 +0000
commit058ac3249a7c2b4d78bd54d65f4677cb22485125 (patch)
tree98d2cb309556f598181e5261538032547eeec6bb /usr.bin
parent6459f7741ea850327131e3bfa851528da8372f59 (diff)
add back support for SSH1 keys. it is being used in practice.
ok markus@
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/gzsig/Makefile4
-rw-r--r--usr.bin/gzsig/gzsig.16
-rw-r--r--usr.bin/gzsig/key.c5
-rw-r--r--usr.bin/gzsig/ssh.c343
-rw-r--r--usr.bin/gzsig/ssh.h39
5 files changed, 391 insertions, 6 deletions
diff --git a/usr.bin/gzsig/Makefile b/usr.bin/gzsig/Makefile
index 8b6f0cb7db1..1dd980d7b5b 100644
--- a/usr.bin/gzsig/Makefile
+++ b/usr.bin/gzsig/Makefile
@@ -1,7 +1,7 @@
-# $OpenBSD: Makefile,v 1.1 2005/05/28 01:57:30 marius Exp $
+# $OpenBSD: Makefile,v 1.2 2005/05/29 02:41:42 marius Exp $
PROG = gzsig
-SRCS = gzsig.c key.c sign.c ssh2.c util.c verify.c x509.c
+SRCS = gzsig.c key.c sign.c ssh.c ssh2.c util.c verify.c x509.c
LDADD = -lcrypto -lm
diff --git a/usr.bin/gzsig/gzsig.1 b/usr.bin/gzsig/gzsig.1
index 56a29f76d2d..ec1b8bc35c1 100644
--- a/usr.bin/gzsig/gzsig.1
+++ b/usr.bin/gzsig/gzsig.1
@@ -1,5 +1,5 @@
-.\" $OpenBSD: gzsig.1,v 1.1 2005/05/28 01:57:30 marius Exp $
-.\" $Id: gzsig.1,v 1.1 2005/05/28 01:57:30 marius Exp $
+.\" $OpenBSD: gzsig.1,v 1.2 2005/05/29 02:41:42 marius Exp $
+.\" $Id: gzsig.1,v 1.2 2005/05/29 02:41:42 marius Exp $
.\"
.\" Copyright (c) 2001 Dug Song <dugsong@arbor.net>
.\" Copyright (c) 2001 Arbor Networks, Inc.
@@ -47,7 +47,7 @@
.Nm
embeds or verifies RSA PKCS #1 v2.0 or DSA SHA1 signatures in
.Xr gzip 1
-compressed files using SSH2 identity keys or X509 certificates.
+compressed files using SSH identity keys or X509 certificates.
.Pp
The
.Ar file
diff --git a/usr.bin/gzsig/key.c b/usr.bin/gzsig/key.c
index c0605e3a7aa..0810131d809 100644
--- a/usr.bin/gzsig/key.c
+++ b/usr.bin/gzsig/key.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.c,v 1.2 2005/05/28 08:07:45 marius Exp $ */
+/* $OpenBSD: key.c,v 1.3 2005/05/29 02:41:42 marius Exp $ */
/*
* key.c
@@ -46,6 +46,7 @@
#include <unistd.h>
#include "key.h"
+#include "ssh.h"
#include "ssh2.h"
#include "util.h"
#include "x509.h"
@@ -53,12 +54,14 @@
typedef int (*key_loader)(struct key *, struct iovec *);
static key_loader pubkey_loaders[] = {
+ ssh_load_public,
ssh2_load_public,
x509_load_public,
NULL
};
static key_loader privkey_loaders[] = {
+ ssh_load_private,
x509_load_private,
NULL
};
diff --git a/usr.bin/gzsig/ssh.c b/usr.bin/gzsig/ssh.c
new file mode 100644
index 00000000000..78f3c103a34
--- /dev/null
+++ b/usr.bin/gzsig/ssh.c
@@ -0,0 +1,343 @@
+/* $OpenBSD: ssh.c,v 1.1 2005/05/29 02:41:42 marius Exp $ */
+
+/*
+ * ssh.c
+ *
+ * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
+ * Copyright (c) 2000 Niels Provos <provos@monkey.org>
+ * Copyright (c) 2000 Markus Friedl <markus@monkey.org>
+ *
+ * Redistribution 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.
+ * 3. The names of the copyright holders may not be used to endorse or
+ * promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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.
+ *
+ * $Vendor: ssh.c,v 1.2 2005/04/01 16:47:31 dugsong Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <arpa/nameser.h>
+#include <openssl/ssl.h>
+#include <openssl/des.h>
+#include <openssl/md5.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "key.h"
+#include "ssh.h"
+
+#define SSH1_MAGIC "SSH PRIVATE KEY FILE FORMAT 1.1\n"
+
+struct des3_state {
+ des_key_schedule k1, k2, k3;
+ des_cblock iv1, iv2, iv3;
+};
+
+static int
+get_bn(BIGNUM *bn, u_char **pp, int *lenp)
+{
+ short i;
+
+ if (*lenp < 2) {
+ errno = EINVAL;
+ return (-1);
+ }
+ GETSHORT(i, *pp); *lenp -= 2;
+
+ i = ((i + 7) / 8);
+
+ if (*lenp < i) {
+ errno = EINVAL;
+ return (-1);
+ }
+ BN_bin2bn(*pp, i, bn);
+
+ *pp += i; *lenp -= i;
+
+ return (0);
+}
+
+static int
+get_string(char *dst, int len, u_char **pp, int *lenp)
+{
+ long i;
+
+ if (*lenp < 4) {
+ errno = EINVAL;
+ return (-1);
+ }
+ GETLONG(i, *pp); *lenp -= 4;
+
+ if (*lenp < i || len < i) {
+ errno = EINVAL;
+ return (-1);
+ }
+ memcpy(dst, *pp, i);
+
+ *pp += i; *lenp -= i;
+
+ return (0);
+}
+
+static int
+read_ssh1_bn(BIGNUM *value, char **cpp)
+{
+ char *cp = *cpp;
+ int old;
+
+ /* Skip any leading whitespace. */
+ for (; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+
+ /* Check that it begins with a decimal digit. */
+ if (*cp < '0' || *cp > '9') {
+ errno = EINVAL;
+ return (-1);
+ }
+ /* Save starting position. */
+ *cpp = cp;
+
+ /* Move forward until all decimal digits skipped. */
+ for (; *cp >= '0' && *cp <= '9'; cp++)
+ ;
+
+ /* Save the old terminating character, and replace it by \0. */
+ old = *cp;
+ *cp = 0;
+
+ /* Parse the number. */
+ if (BN_dec2bn(&value, *cpp) == 0)
+ return (-1);
+
+ /* Restore old terminating character. */
+ *cp = old;
+
+ /* Move beyond the number and return success. */
+ *cpp = cp;
+ return (0);
+}
+
+/* XXX - SSH1's weirdo 3DES... */
+static void *
+des3_init(u_char *sesskey, int len)
+{
+ struct des3_state *state;
+
+ if ((state = malloc(sizeof(*state))) == NULL)
+ return (NULL);
+
+ des_set_key((void *)sesskey, state->k1);
+ des_set_key((void *)(sesskey + 8), state->k2);
+
+ if (len <= 16)
+ des_set_key((void *)sesskey, state->k3);
+ else
+ des_set_key((void *)(sesskey + 16), state->k3);
+
+ memset(state->iv1, 0, 8);
+ memset(state->iv2, 0, 8);
+ memset(state->iv3, 0, 8);
+
+ return (state);
+}
+
+static void
+des3_decrypt(u_char *src, u_char *dst, int len, void *state)
+{
+ struct des3_state *dstate;
+
+ dstate = (struct des3_state *)state;
+ memcpy(dstate->iv1, dstate->iv2, 8);
+
+ des_ncbc_encrypt(src, dst, len, dstate->k3, &dstate->iv3, DES_DECRYPT);
+ des_ncbc_encrypt(dst, dst, len, dstate->k2, &dstate->iv2, DES_ENCRYPT);
+ des_ncbc_encrypt(dst, dst, len, dstate->k1, &dstate->iv1, DES_DECRYPT);
+}
+
+static int
+load_ssh1_public(RSA *rsa, struct iovec *iov)
+{
+ char *p;
+ u_int bits;
+
+ /* Skip leading whitespace. */
+ for (p = iov->iov_base; *p == ' ' || *p == '\t'; p++)
+ ;
+
+ /* Get number of bits. */
+ if (*p < '0' || *p > '9')
+ return (-1);
+
+ for (bits = 0; *p >= '0' && *p <= '9'; p++)
+ bits = 10 * bits + *p - '0';
+
+ if (bits == 0)
+ return (-1);
+
+ /* Get public exponent, public modulus. */
+ if (read_ssh1_bn(rsa->e, &p) < 0)
+ return (-1);
+
+ if (read_ssh1_bn(rsa->n, &p) < 0)
+ return (-1);
+
+ return (0);
+}
+
+static int
+load_ssh1_private(RSA *rsa, struct iovec *iov)
+{
+ BN_CTX *ctx;
+ BIGNUM *aux;
+ MD5_CTX md;
+ char pass[128], prompt[128], comment[BUFSIZ];
+ u_char *p, cipher_type, digest[16];
+ void *dstate;
+ int i;
+
+ i = strlen(SSH1_MAGIC) + 1;
+
+ /* Make sure it begins with the id string. */
+ if (iov->iov_len < i || memcmp(iov->iov_base, SSH1_MAGIC, i) != 0)
+ return (-1);
+
+ p = (u_char *)iov->iov_base + i;
+ i = iov->iov_len - i;
+
+ /* Skip cipher_type, reserved data, bits. */
+ cipher_type = *p;
+ p += 1 + 4 + 4;
+ i -= 1 + 4 + 4;
+
+ /* Read public key. */
+ if (get_bn(rsa->n, &p, &i) < 0 || get_bn(rsa->e, &p, &i) < 0)
+ return (-1);
+
+ /* Read comment. */
+ if (get_string(comment, sizeof(comment), &p, &i) < 0)
+ return (-1);
+
+ /* Decrypt private key. */
+ if (cipher_type != 0) {
+ sign_passwd_cb(pass, sizeof(pass), 0, NULL);
+
+ MD5_Init(&md);
+ MD5_Update(&md, (const u_char *)pass, strlen(pass));
+ MD5_Final(digest, &md);
+
+ memset(pass, 0, strlen(pass));
+
+ if ((dstate = des3_init(digest, sizeof(digest))) == NULL)
+ return (-1);
+
+ des3_decrypt(p, p, i, dstate);
+
+ if (p[0] != p[2] || p[1] != p[3]) {
+ fprintf(stderr, "Bad passphrase for %s\n", comment);
+ return (-1);
+ }
+ }
+ else if (p[0] != p[2] || p[1] != p[3])
+ return (-1);
+
+ p += 4;
+ i -= 4;
+
+ /* Read the private key. */
+ if (get_bn(rsa->d, &p, &i) < 0 ||
+ get_bn(rsa->iqmp, &p, &i) < 0)
+ return (-1);
+
+ /* In SSL and SSH v1 p and q are exchanged. */
+ if (get_bn(rsa->q, &p, &i) < 0 ||
+ get_bn(rsa->p, &p, &i) < 0)
+ return (-1);
+
+ /* Calculate p-1 and q-1. */
+ ctx = BN_CTX_new();
+ aux = BN_new();
+
+ BN_sub(aux, rsa->q, BN_value_one());
+ BN_mod(rsa->dmq1, rsa->d, aux, ctx);
+
+ BN_sub(aux, rsa->p, BN_value_one());
+ BN_mod(rsa->dmp1, rsa->d, aux, ctx);
+
+ BN_clear_free(aux);
+ BN_CTX_free(ctx);
+
+ return (0);
+}
+
+int
+ssh_load_public(struct key *k, struct iovec *iov)
+{
+ RSA *rsa;
+
+ rsa = RSA_new();
+
+ rsa->n = BN_new();
+ rsa->e = BN_new();
+
+ if (load_ssh1_public(rsa, iov) < 0) {
+ RSA_free(rsa);
+ return (-1);
+ }
+ k->type = KEY_RSA;
+ k->data = (void *)rsa;
+
+ return (0);
+}
+
+int
+ssh_load_private(struct key *k, struct iovec *iov)
+{
+ RSA *rsa;
+
+ rsa = RSA_new();
+
+ rsa->n = BN_new();
+ rsa->e = BN_new();
+
+ rsa->d = BN_new();
+ rsa->iqmp = BN_new();
+ rsa->q = BN_new();
+ rsa->p = BN_new();
+ rsa->dmq1 = BN_new();
+ rsa->dmp1 = BN_new();
+
+ if (load_ssh1_private(rsa, iov) < 0) {
+ RSA_free(rsa);
+ return (-1);
+
+ }
+ k->type = KEY_RSA;
+ k->data = (void *)rsa;
+
+ return (0);
+}
diff --git a/usr.bin/gzsig/ssh.h b/usr.bin/gzsig/ssh.h
new file mode 100644
index 00000000000..19c1d8ae876
--- /dev/null
+++ b/usr.bin/gzsig/ssh.h
@@ -0,0 +1,39 @@
+/*
+ * ssh.h
+ *
+ * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
+ *
+ * Redistribution 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.
+ * 3. The names of the copyright holders may not be used to endorse or
+ * promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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.
+ *
+ * $Vendor: ssh.h,v 1.2 2005/04/01 16:47:31 dugsong Exp $
+ */
+
+#ifndef SSH_H
+#define SSH_H
+
+int ssh_load_public(struct key *k, struct iovec *iov);
+int ssh_load_private(struct key *k, struct iovec *iov);
+
+#endif /* SSH_H */