diff options
author | marius eriksen <marius@cvs.openbsd.org> | 2005-05-29 02:41:43 +0000 |
---|---|---|
committer | marius eriksen <marius@cvs.openbsd.org> | 2005-05-29 02:41:43 +0000 |
commit | 058ac3249a7c2b4d78bd54d65f4677cb22485125 (patch) | |
tree | 98d2cb309556f598181e5261538032547eeec6bb /usr.bin | |
parent | 6459f7741ea850327131e3bfa851528da8372f59 (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/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/gzsig/gzsig.1 | 6 | ||||
-rw-r--r-- | usr.bin/gzsig/key.c | 5 | ||||
-rw-r--r-- | usr.bin/gzsig/ssh.c | 343 | ||||
-rw-r--r-- | usr.bin/gzsig/ssh.h | 39 |
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 */ |