diff options
author | marius eriksen <marius@cvs.openbsd.org> | 2005-05-28 01:57:31 +0000 |
---|---|---|
committer | marius eriksen <marius@cvs.openbsd.org> | 2005-05-28 01:57:31 +0000 |
commit | 010931b7acab26046e0adaef4808f43f0a87050f (patch) | |
tree | 73441fc9a82db0aca0b0acfbf728d3aff9cc136b /usr.bin | |
parent | 25f01a945904da779dc25261b49b8e79b32b6fb9 (diff) |
import gzsig by Dug Song.
a bunch of lumberjack work, zapped support for keynote
and SSH1 and added support for SSH2 keys.
ok millert@ deraadt@
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/gzsig/Makefile | 10 | ||||
-rw-r--r-- | usr.bin/gzsig/extern.h | 45 | ||||
-rw-r--r-- | usr.bin/gzsig/gzip.h | 107 | ||||
-rw-r--r-- | usr.bin/gzsig/gzsig.1 | 113 | ||||
-rw-r--r-- | usr.bin/gzsig/gzsig.c | 64 | ||||
-rw-r--r-- | usr.bin/gzsig/key.c | 216 | ||||
-rw-r--r-- | usr.bin/gzsig/key.h | 57 | ||||
-rw-r--r-- | usr.bin/gzsig/sign.c | 306 | ||||
-rw-r--r-- | usr.bin/gzsig/ssh2.c | 221 | ||||
-rw-r--r-- | usr.bin/gzsig/ssh2.h | 29 | ||||
-rw-r--r-- | usr.bin/gzsig/util.c | 77 | ||||
-rw-r--r-- | usr.bin/gzsig/util.h | 39 | ||||
-rw-r--r-- | usr.bin/gzsig/verify.c | 212 | ||||
-rw-r--r-- | usr.bin/gzsig/x509.c | 137 | ||||
-rw-r--r-- | usr.bin/gzsig/x509.h | 40 |
15 files changed, 1673 insertions, 0 deletions
diff --git a/usr.bin/gzsig/Makefile b/usr.bin/gzsig/Makefile new file mode 100644 index 00000000000..8b6f0cb7db1 --- /dev/null +++ b/usr.bin/gzsig/Makefile @@ -0,0 +1,10 @@ +# $OpenBSD: Makefile,v 1.1 2005/05/28 01:57:30 marius Exp $ + +PROG = gzsig +SRCS = gzsig.c key.c sign.c ssh2.c util.c verify.c x509.c + +LDADD = -lcrypto -lm + +CLEANFILES += TAGS *~ + +.include <bsd.prog.mk> diff --git a/usr.bin/gzsig/extern.h b/usr.bin/gzsig/extern.h new file mode 100644 index 00000000000..eb43b1e1c3e --- /dev/null +++ b/usr.bin/gzsig/extern.h @@ -0,0 +1,45 @@ +/* + * extern.h + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: extern.h,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#ifndef EXTERN_H +#define EXTERN_H + +void sign(int argc, char *argv[]); +void verify(int argc, char *argv[]); + +int sign_passwd_cb(char *buf, int size, int rwflag, void *u); + +void sign_usage(void); +void verify_usage(void); + +#endif /* EXTERN_H */ diff --git a/usr.bin/gzsig/gzip.h b/usr.bin/gzsig/gzip.h new file mode 100644 index 00000000000..11f0b2c65bb --- /dev/null +++ b/usr.bin/gzsig/gzip.h @@ -0,0 +1,107 @@ +/* + * gzip.h + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: gzip.h,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#ifndef GZIP_H +#define GZIP_H + +/* RFC 1952 is b0rked! This is from gzip-1.2.4's algorithm.doc... */ + +/* Magic header */ +#define GZIP_MAGIC "\037\213" + +/* Compression methods */ +#define GZIP_MSTORED 0 +#define GZIP_MCOMPRESS 1 +#define GZIP_MPACKED 2 +#define GZIP_MLZHED 3 +#define GZIP_MDEFLATE 8 + +/* Flags */ +#define GZIP_FTEXT 0x01 +#define GZIP_FCONT 0x02 /* never set by gzip-1.2.4 */ +#define GZIP_FEXTRA 0x04 +#define GZIP_FNAME 0x08 +#define GZIP_FCOMMENT 0x10 +#define GZIP_FENCRYPT 0x20 +#define GZIP_FRESERVED 0xC0 + +#define GZIP_FENCRYPT_LEN 12 + +#define GZSIG_ID "GS" +#define GZSIG_VERSION 1 + +struct gzsig_data { + u_char version; +#ifdef COMMENT_ONLY + u_char signature[]; +#endif +}; + +/* + * Note: all number fields below are in little-endian byte order. + */ + +struct gzip_xfield { + u_short len; + struct gzip_subfield { + u_char id[2]; + u_short len; +#ifdef COMMENT_ONLY + u_char data[]; +#endif + } subfield; +}; + +struct gzip_header { + u_char magic[2]; + u_char method; + u_char flags; + u_char mtime[4]; + u_char xflags; + u_char os; +#if COMMENT_ONLY + /* Optional fields */ + u_char part[2]; /* flags & GZIP_FCONT */ + struct gzip_xfield xfield; /* flags & GZIP_FEXTRA */ + char filename[]; /* flags & GZIP_FNAME */ + char comment[]; /* flags & GZIP_FCOMMENT */ + u_char encrypt_hdr[12]; /* flags & GZIP_FENCRYPT */ +#endif +}; + +struct gzip_trailer { + u_int32_t crc32[4]; + u_int32_t size[4]; +}; + +#endif /* GZIP_H */ diff --git a/usr.bin/gzsig/gzsig.1 b/usr.bin/gzsig/gzsig.1 new file mode 100644 index 00000000000..56a29f76d2d --- /dev/null +++ b/usr.bin/gzsig/gzsig.1 @@ -0,0 +1,113 @@ +.\" $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 $ +.\" +.\" Copyright (c) 2001 Dug Song <dugsong@arbor.net> +.\" Copyright (c) 2001 Arbor Networks, Inc. +.\" +.\" 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. +.\" +.Dd July 6, 2001 +.Dt GZSIG 1 +.Sh NAME +.Nm gzsig +.Nd gzip signing utility +.Sh SYNOPSIS +.Nm gzsig sign +.Op Fl v +.Ar privkey +.Op Ar +.Pp +.Nm gzsig verify +.Op Fl v +.Ar pubkey +.Op Ar +.Sh DESCRIPTION +.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. +.Pp +The +.Ar file +operands are processed in command-line order. If +.Ar file +is a single dash +.Pq Sq \&- +or absent, +.Nm +reads from the standard input. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Nm sign +Sign the input using the private key in +.Ar privkey . +.It Nm verify +Verify the signature using the public key in +.Ar pubkey . +.It Fl v +Enable verbose mode. +.It Fl p +Supply a passphrase for decrypting private keys when signing. +.El +.Pp +The +.Nm +utility exits 0 on success or >0 if an error occured. +.Sh EXAMPLES +.Cm gzsign sign ~/.ssh/id_rsa file1 file2 +.Pp +Sign +.Ar file1 +and +.Ar file2 +with the SSH2 identity key in +.Ar ~/.ssh/id_rsa . +.Pp +.Cm gzsign sign ~/.ssh/id_rsa < file1 > file2 +.Pp +Sign +.Ar file1 +with the SSH2 identity key, saving the signed file in +.Ar file2 . +.Pp +.Cm gzsign verify /etc/ssl/server.crt < file1 +.Pp +Verify the signature on +.Ar file1 +using the SSL certificate in +.Ar /etc/ssl/server.crt . +.Pp +.Sh SEE ALSO +.Xr gzip 1 , +.Xr ssh-keygen 1 , +.Xr ssl 8 +.Sh AUTHORS +Dug Song +.Aq dugsong@arbor.net +.Pp +SSH2 support by +Marius Eriksen +.Aq marius@openbsd.org diff --git a/usr.bin/gzsig/gzsig.c b/usr.bin/gzsig/gzsig.c new file mode 100644 index 00000000000..0ebf4c34584 --- /dev/null +++ b/usr.bin/gzsig/gzsig.c @@ -0,0 +1,64 @@ +/* $OpenBSD: gzsig.c,v 1.1 2005/05/28 01:57:30 marius Exp $ */ + +/* + * gzsig.c + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: gzsig.c,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#include <stdio.h> +#include <string.h> + +#include "extern.h" + +static void +usage(void) +{ + sign_usage(); + verify_usage(); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + if (argc < 2) + usage(); + + if (strcmp(argv[1], "sign") == 0) { + sign(argc - 1, argv + 1); + } else if (strcmp(argv[1], "verify") == 0) { + verify(argc - 1, argv + 1); + } else { + usage(); + } + + exit(0); +} diff --git a/usr.bin/gzsig/key.c b/usr.bin/gzsig/key.c new file mode 100644 index 00000000000..b7909384e88 --- /dev/null +++ b/usr.bin/gzsig/key.c @@ -0,0 +1,216 @@ +/* $OpenBSD: key.c,v 1.1 2005/05/28 01:57:30 marius Exp $ */ + +/* + * key.c + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: key.c,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/uio.h> + +#include <openssl/ssl.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "key.h" +#include "ssh2.h" +#include "util.h" +#include "x509.h" + +typedef int (*key_loader)(struct key *, struct iovec *); + +static key_loader pubkey_loaders[] = { + ssh2_load_public, + x509_load_public, + NULL +}; + +static key_loader privkey_loaders[] = { + x509_load_private, + NULL +}; + +static int +load_file(struct iovec *iov, char *filename) +{ + struct stat st; + int fd; + + if ((fd = open(filename, O_RDONLY)) < 0) + return (-1); + + if (fstat(fd, &st) < 0) + return (-1); + + if (st.st_size == 0) { + errno = EINVAL; + return (-1); + } + if ((iov->iov_base = malloc(st.st_size + 1)) == NULL) + return (-1); + + iov->iov_len = st.st_size; + ((u_char *)iov->iov_base)[iov->iov_len] = '\0'; + + if (read(fd, iov->iov_base, iov->iov_len) != iov->iov_len) { + free(iov->iov_base); + return (-1); + } + close(fd); + + return (0); +} + +struct key * +key_new(void) +{ + struct key *k; + + if ((k = calloc(sizeof(*k), 1)) == NULL) + return (NULL); + + return (k); +} + +int +key_load_private(struct key *k, char *filename) +{ + struct iovec iov; + int i; + + if (load_file(&iov, filename) < 0) + return (-1); + + for (i = 0; privkey_loaders[i] != NULL; i++) { + if (privkey_loaders[i](k, &iov) == 0) + return (0); + } + return (-1); +} + +int +key_load_public(struct key *k, char *filename) +{ + struct iovec iov; + int i; + + if (load_file(&iov, filename) < 0) + return (-1); + + for (i = 0; pubkey_loaders[i] != NULL; i++) { + if (pubkey_loaders[i](k, &iov) == 0) + return (0); + } + return (-1); +} + +int +key_sign(struct key *k, u_char *msg, int mlen, u_char *sig, int slen) +{ + switch (k->type) { + case KEY_RSA: + if (RSA_size((RSA *)k->data) > slen) { + fprintf(stderr, "RSA modulus too large: %d bits\n", + RSA_size((RSA *)k->data)); + return (-1); + } + if (RSA_sign(NID_sha1, msg, mlen, sig, &slen, + (RSA *)k->data) <= 0) { + fprintf(stderr, "RSA signing failed\n"); + return (-1); + } + break; + + case KEY_DSA: + if (DSA_size((DSA *)k->data) > slen) { + fprintf(stderr, "DSA signature size too large: " + "%d bits\n", DSA_size((DSA *)k->data)); + return (-1); + } + if (DSA_sign(NID_sha1, msg, mlen, sig, &slen, + (DSA *)k->data) <= 0) { + fprintf(stderr, "DSA signing failed\n"); + return (-1); + } + break; + + default: + fprintf(stderr, "Unknown key type: %d\n", k->type); + return (-1); + } + return (slen); +} + +int +key_verify(struct key *k, u_char *msg, int mlen, u_char *sig, int slen) +{ + switch (k->type) { + + case KEY_RSA: + if (RSA_verify(NID_sha1, msg, mlen, + sig, slen, (RSA *)k->data) <= 0) { + fprintf(stderr, "RSA verification failed\n"); + return (-1); + } + break; + + case KEY_DSA: + if (DSA_verify(NID_sha1, msg, mlen, + sig, slen, (DSA *)k->data) <= 0) { + fprintf(stderr, "DSA verification failed\n"); + return (-1); + } + break; + + default: + fprintf(stderr, "Unknown key type: %d\n", k->type); + return (-1); + } + return (slen); +} + +void +key_free(struct key *k) +{ + if (k->type == KEY_RSA) + RSA_free((RSA *)k->data); + else if (k->type == KEY_DSA) + DSA_free((DSA *)k->data); + else if (k->data != NULL) + free(k->data); + + free(k); +} diff --git a/usr.bin/gzsig/key.h b/usr.bin/gzsig/key.h new file mode 100644 index 00000000000..7aac3ad8bb8 --- /dev/null +++ b/usr.bin/gzsig/key.h @@ -0,0 +1,57 @@ +/* + * key.h + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: key.h,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#ifndef KEY_H +#define KEY_H + +enum key_type { + KEY_UNSPEC, + KEY_RSA, + KEY_DSA +}; + +struct key { + int type; + void *data; +}; + +struct key *key_new(void); +int key_load_public(struct key *k, char *filename); +int key_load_private(struct key *k, char *filename); +int key_sign(struct key *k, u_char *msg, int mlen, + u_char *sig, int slen); +int key_verify(struct key *k, u_char *msg, int mlen, + u_char *sig, int slen); +void key_free(struct key *k); + +#endif /* KEY_H */ diff --git a/usr.bin/gzsig/sign.c b/usr.bin/gzsig/sign.c new file mode 100644 index 00000000000..a10e5c28d98 --- /dev/null +++ b/usr.bin/gzsig/sign.c @@ -0,0 +1,306 @@ +/* $OpenBSD: sign.c,v 1.1 2005/05/28 01:57:30 marius Exp $ */ + +/* + * sign.c + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: sign.c,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <openssl/ssl.h> +#include <openssl/evp.h> +#include <openssl/sha.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "extern.h" +#include "gzip.h" +#include "key.h" +#include "util.h" + +static char *passphrase = NULL; + +static int +embed_signature(struct key *key, FILE *fin, FILE *fout) +{ + struct gzip_header gh; + struct gzip_xfield *gx; + struct gzsig_data *gd; + u_char *sig, digest[20], buf[8192]; + SHA_CTX ctx; + int i, siglen; + long offset; + + /* Read gzip header. */ + if (fread((u_char *)&gh, 1, sizeof(gh), fin) != sizeof(gh)) { + fprintf(stderr, "Error reading gzip header: %s\n", + strerror(errno)); + return (-1); + } + /* Verify gzip header. */ + if (memcmp(gh.magic, GZIP_MAGIC, sizeof(gh.magic)) != 0) { + fprintf(stderr, "Invalid gzip file\n"); + return (-1); + } + if (gh.flags & GZIP_FCONT) { + fprintf(stderr, "Multi-part gzip files not supported\n"); + return (-1); + } + /* Skip over any existing signature. */ + if (gh.flags & GZIP_FEXTRA) { + gx = (struct gzip_xfield *)buf; + gd = (struct gzsig_data *)(gx + 1); + + if (fread((u_char *)gx, 1, sizeof(*gx), fin) != sizeof(*gx)) { + fprintf(stderr, "Error reading extra field: %s\n", + strerror(errno)); + return (-1); + } + if (memcmp(gx->subfield.id, GZSIG_ID, 2) != 0) { + fprintf(stderr, "Unknown extra field\n"); + return (-1); + } + gx->subfield.len = letoh16(gx->subfield.len); + + if (gx->subfield.len < sizeof(*gd) || + gx->subfield.len > sizeof(buf) - sizeof(*gx)) { + fprintf(stderr, "Invalid signature length\n"); + return (-1); + } + if (fread((u_char *)gd, 1, gx->subfield.len, fin) != + gx->subfield.len) { + fprintf(stderr, "Error reading signature: %s\n", + strerror(errno)); + return (-1); + } + fprintf(stderr, "Overwriting existing signature\n"); + } + /* Skip over any options. */ + offset = ftell(fin); + + if (gh.flags & GZIP_FNAME) { + while (getc(fin) != '\0') + ; + } + if (gh.flags & GZIP_FCOMMENT) { + while (getc(fin) != '\0') + ; + } + if (gh.flags & GZIP_FENCRYPT) { + if (fread(buf, 1, GZIP_FENCRYPT_LEN, fin) != GZIP_FENCRYPT_LEN) + return (-1); + } + /* Compute checksum over compressed data and trailer. */ + SHA1_Init(&ctx); + + while ((i = fread(buf, 1, sizeof(buf), fin)) > 0) { + SHA1_Update(&ctx, buf, i); + } + SHA1_Final(digest, &ctx); + + /* Generate signature. */ + gx = (struct gzip_xfield *)buf; + gd = (struct gzsig_data *)(gx + 1); + sig = (u_char *)(gd + 1); + + siglen = key_sign(key, digest, sizeof(digest), sig, + sizeof(buf) - (sig - buf)); + + if (siglen < 0) { + fprintf(stderr, "Error signing checksum\n"); + return (-1); + } + i = sizeof(*gd) + siglen; + gx->subfield.len = htole16(i); + gx->len = htole16(sizeof(gx->subfield) + i); + memcpy(gx->subfield.id, GZSIG_ID, sizeof(gx->subfield.id)); + gd->version = GZSIG_VERSION; + + /* Write out gzip header. */ + gh.flags |= GZIP_FEXTRA; + + if (fwrite((u_char *)&gh, 1, sizeof(gh), fout) != sizeof(gh)) { + fprintf(stderr, "Error writing output: %s\n", strerror(errno)); + return (-1); + } + /* Write out signature. */ + if (fwrite(buf, 1, sizeof(*gx) + i, fout) != sizeof(*gx) + i) { + fprintf(stderr, "Error writing output: %s\n", strerror(errno)); + return (-1); + } + /* Write out options, compressed data, and trailer. */ + if (fseek(fin, offset, SEEK_SET) < 0) { + fprintf(stderr, "Error writing output: %s\n", strerror(errno)); + return (-1); + } + while ((i = fread(buf, 1, sizeof(buf), fin)) > 0) { + if (fwrite(buf, 1, i, fout) != i) { + fprintf(stderr, "Error writing output: %s\n", + strerror(errno)); + return (-1); + } + } + if (ferror(fin)) { + fprintf(stderr, "Error reading input: %s\n", strerror(errno)); + return (-1); + } + return (0); +} + +void +sign_usage(void) +{ + fprintf(stderr, "Usage: gzsig sign [-v] privkey [file ...]\n"); +} + +int +sign_passwd_cb(char *buf, int size, int rwflag, void *u) +{ + char *p; + + if (passphrase != NULL) { + if (strlcpy(buf, passphrase, size) >= size) + errx(1, "Passphrase too long"); + } else { + p = getpass("Enter passphrase: "); + if (strlcpy(buf, p, size) >= size) + errx(1, "Passphrase too long"); + memset(p, 0, strlen(p)); + } + + return (strlen(buf)); +} + +void +sign(int argc, char *argv[]) +{ + struct key *key; + char *gzipfile, tmpfile[MAXPATHLEN]; + FILE *fin, *fout; + int i, fd, error, vflag; + + vflag = 0; + + while ((i = getopt(argc, argv, "vh?p:")) != -1) { + switch (i) { + case 'v': + vflag = 1; + break; + case 'p': + passphrase = optarg; + break; + default: + sign_usage(); + exit(1); + } + } + argc -= optind; + argv += optind; + + if (argc < 1) { + sign_usage(); + exit(1); + } + OpenSSL_add_all_algorithms(); + + if ((key = key_new()) == NULL) + fatal(1, "Couldn't initialize private key"); + + if (key_load_private(key, argv[0]) < 0) + fatal(1, "Couldn't load private key"); + + if (argc == 1 || *argv[1] == '-') { + argc = 0; + + if (embed_signature(key, stdin, stdout) == 0) { + if (vflag) + fprintf(stderr, "Signed input\n"); + } else + fatal(1, "Couldn't sign input"); + } + for (i = 1; i < argc; i++) { + gzipfile = argv[i]; + + if ((fin = fopen(gzipfile, "r+")) == NULL) { + fprintf(stderr, "Error opening %s: %s\n", + gzipfile, strerror(errno)); + continue; + } + snprintf(tmpfile, sizeof(tmpfile), "%s.XXXXXX", gzipfile); + + if ((fd = mkstemp(tmpfile)) < 0) { + fprintf(stderr, "Error creating %s: %s\n", + tmpfile, strerror(errno)); + fclose(fin); + continue; + } + if ((fout = fdopen(fd, "w")) == NULL) { + fprintf(stderr, "Error opening %s: %s\n", + tmpfile, strerror(errno)); + fclose(fin); + close(fd); + continue; + } + if (copy_permissions(gzipfile, tmpfile) < 0) { + fprintf(stderr, "Error initializing %s: %s\n", + tmpfile, strerror(errno)); + fclose(fin); + fclose(fout); + continue; + } + error = embed_signature(key, fin, fout); + + fclose(fin); + fclose(fout); + + if (!error) { + if (rename(tmpfile, gzipfile) < 0) { + unlink(tmpfile); + fatal(1, "Couldn't sign %s", gzipfile); + } + if (vflag) + fprintf(stderr, "Signed %s\n", gzipfile); + } else { + unlink(tmpfile); + fatal(1, "Couldn't sign %s", gzipfile); + } + } + key_free(key); + + if (passphrase != NULL) + memset(passphrase, 0, strlen(passphrase)); +} diff --git a/usr.bin/gzsig/ssh2.c b/usr.bin/gzsig/ssh2.c new file mode 100644 index 00000000000..f508058ca00 --- /dev/null +++ b/usr.bin/gzsig/ssh2.c @@ -0,0 +1,221 @@ +/* $OpenBSD: ssh2.c,v 1.1 2005/05/28 01:57:30 marius Exp $ */ +/* + * ssh2.c + * + * Copyright (c) 2005 Marius Eriksen <marius@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#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 <err.h> + +#include "key.h" +#include "ssh2.h" + +#define GET_32BIT(cp) (((u_long)(u_char)(cp)[0] << 24) | \ + ((u_long)(u_char)(cp)[1] << 16) | \ + ((u_long)(u_char)(cp)[2] << 8) | \ + ((u_long)(u_char)(cp)[3])) + +/* From OpenSSH */ +static int +_uudecode(const char *src, u_char *target, size_t targsize) +{ + int len; + char *encoded, *p; + + /* copy the 'readonly' source */ + if ((encoded = strdup(src)) == NULL) + err(1, ""); + /* skip whitespace and data */ + for (p = encoded; *p == ' ' || *p == '\t'; p++) + ; + for (; *p != '\0' && *p != ' ' && *p != '\t'; p++) + ; + /* and remove trailing whitespace because __b64_pton needs this */ + *p = '\0'; + len = __b64_pton(encoded, target, targsize); + + free(encoded); + + return len; +} + +/* + * Small compatibility layer for the OpenSSH buffers. Only what we + * need here. + */ + +static int +_keyfromstr(char *str, int len) +{ + if (strncmp(str, "rsa", len) == 0 || + strncmp(str, "ssh-rsa", len) == 0) + return KEY_RSA; + else if (strncmp(str, "dsa", len) == 0 || + strncmp(str, "ssh-dss", len) == 0) + return KEY_DSA; + + return (-1); +} + +static int +_read_int(struct iovec *iov, int *ival) +{ + iov->iov_len -= 4; + if (iov->iov_len < 0) + return (-1); + *ival = GET_32BIT((u_char *)iov->iov_base); + (u_char*)iov->iov_base += 4; + + return (0); +} + +static int +_read_opaque(struct iovec *iov, u_char **buf, int *len) +{ + if (_read_int(iov, len) < 0 || *len < 0) + return (-1); + + iov->iov_len -= *len; + if (iov->iov_len < 0) + return (-1); + + *buf = iov->iov_base; + (u_char*)iov->iov_base += *len; + + return (0); +} + +static int +_read_bignum(struct iovec *iov, BIGNUM *bn) +{ + u_char *bp; + int blen; + + if (_read_opaque(iov, &bp, &blen) < 0) + return (-1); + + if ((blen > 0 && bp[0] & 0x80) || /* No negative values */ + (blen > 8*1024)) /* Too large */ + return (-1); + + BN_bin2bn(bp, blen, bn); + + return (0); +} + +int +ssh2_load_public(struct key *k, struct iovec *iovp) +{ + int len, keytype, error = 0, blen; + u_char *bp; + struct iovec iov; + /* iov->iov_base is NULL terminated */ + char *cp0, *savep = NULL, *cp = iovp->iov_base; + + if ((cp0 = strchr(cp, ' ')) == NULL) + return (-1); + + len = cp0 - cp; + + if ((keytype = _keyfromstr(cp, len)) < 0) + return (-1); + + /* cp0 is a space (' '), so we have at least one more */ + cp = cp0 + 1; + + len = 2*strlen(cp); + if ((savep = iov.iov_base = malloc(len)) == NULL) + err(1, ""); + iov.iov_len = _uudecode(cp, iov.iov_base, len); + + if (_read_opaque(&iov, &bp, &len) < 0 || + keytype != _keyfromstr(bp, len)) { + error = -1; + goto out; + } + + k->type = keytype; + switch (keytype) { + case KEY_RSA: { + RSA *rsa; + + if ((rsa = RSA_new()) == NULL || + (rsa->e = BN_new()) == NULL || + (rsa->n = BN_new()) == NULL) + errx(1, ""); + + if (_read_bignum(&iov, rsa->e) < 0 || + _read_bignum(&iov, rsa->n) < 0) { + error = -1; + RSA_free(rsa); + goto out; + } + + k->data = (void *)rsa; + + break; + } + case KEY_DSA: { + DSA *dsa; + + if ((dsa = DSA_new()) == NULL || + (dsa->p = BN_new()) == NULL || + (dsa->q = BN_new()) == NULL || + (dsa->g = BN_new()) == NULL || + (dsa->pub_key = BN_new()) == NULL) + errx(1, ""); + + if (_read_bignum(&iov, dsa->p) < 0 || + _read_bignum(&iov, dsa->q) < 0 || + _read_bignum(&iov, dsa->g) < 0 || + _read_bignum(&iov, dsa->pub_key) < 0) { + error = -1; + DSA_free(dsa); + goto out; + } + + k->data = (void *)dsa; + + break; + } + default: + error = -1; + } + +#if 0 + if (iov->iov_len != 0) + /* Sanity check. */ + return (-1); +#endif + + +out: + if (savep != NULL) + free(savep); + return (error); +} diff --git a/usr.bin/gzsig/ssh2.h b/usr.bin/gzsig/ssh2.h new file mode 100644 index 00000000000..d70382284ad --- /dev/null +++ b/usr.bin/gzsig/ssh2.h @@ -0,0 +1,29 @@ +/* $OpenBSD: ssh2.h,v 1.1.1.1 2005/05/28 01:57:30 marius Exp $ */ +/* + * ssh2.h + * + * Copyright (c) 2005 Marius Eriksen <marius@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef SSH2_H +#define SSH2_H + +int ssh2_load_public(struct key *k, struct iovec *iovp); + +#endif /* SSH2_H */ + + + + diff --git a/usr.bin/gzsig/util.c b/usr.bin/gzsig/util.c new file mode 100644 index 00000000000..84270a1fe87 --- /dev/null +++ b/usr.bin/gzsig/util.c @@ -0,0 +1,77 @@ +/* $OpenBSD: util.c,v 1.1 2005/05/28 01:57:30 marius Exp $ */ + +/* + * util.c + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: util.c,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> + +#include "util.h" + +int +copy_permissions(char *srcfile, char *dstfile) +{ + struct stat st; + + if (stat(srcfile, &st) < 0) + return (-1); + + if (chmod(dstfile, st.st_mode) < 0) + return (-1); + + if (chown(dstfile, st.st_uid, st.st_gid) < 0) + return (-1); + + return (0); +} + +void +fatal(int status, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, "\n"); + + exit(status); +} diff --git a/usr.bin/gzsig/util.h b/usr.bin/gzsig/util.h new file mode 100644 index 00000000000..c98c2264b08 --- /dev/null +++ b/usr.bin/gzsig/util.h @@ -0,0 +1,39 @@ +/* + * util.h + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: util.h,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#ifndef UTIL_H + +int copy_permissions(char *srcfile, char *dstfile); +void fatal(int status, const char *fmt, ...); + +#endif /* UTIL_H */ diff --git a/usr.bin/gzsig/verify.c b/usr.bin/gzsig/verify.c new file mode 100644 index 00000000000..bdef51f460c --- /dev/null +++ b/usr.bin/gzsig/verify.c @@ -0,0 +1,212 @@ +/* $OpenBSD: verify.c,v 1.1 2005/05/28 01:57:30 marius Exp $ */ + +/* + * verify.c + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: verify.c,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#include <sys/types.h> + +#include <openssl/ssl.h> +#include <openssl/evp.h> +#include <openssl/sha.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "extern.h" +#include "gzip.h" +#include "key.h" +#include "util.h" + +static int +verify_signature(struct key *key, FILE *fin) +{ + struct gzip_header gh; + struct gzip_xfield *gx; + struct gzsig_data *gd; + u_char *sig, digest[20], buf[8192], sbuf[4096]; + SHA_CTX ctx; + int i, siglen; + + /* Read gzip header. */ + if ((i = fread((u_char *)&gh, 1, sizeof(gh), fin)) != sizeof(gh)) { + fprintf(stderr, "Error reading gzip header: %s\n", + strerror(errno)); + return (-1); + } + /* Verify gzip header. */ + if (memcmp(gh.magic, GZIP_MAGIC, sizeof(gh.magic)) != 0) { + fprintf(stderr, "Invalid gzip file\n"); + return (-1); + } else if (gh.flags & GZIP_FCONT){ + fprintf(stderr, "Multi-part gzip files not supported\n"); + return (-1); + } else if ((gh.flags & GZIP_FEXTRA) == 0) { + fprintf(stderr, "No gzip signature found\n"); + return (-1); + } + /* Read signature. */ + gx = (struct gzip_xfield *)buf; + + if ((i = fread((u_char *)gx, 1, sizeof(*gx), fin)) != sizeof(*gx)) { + fprintf(stderr, "Error reading extra field: %s\n", + strerror(errno)); + return (-1); + } + if (memcmp(gx->subfield.id, GZSIG_ID, sizeof(gx->subfield.id)) != 0) { + fprintf(stderr, "Unknown extra field\n"); + return (-1); + } + gx->subfield.len = letoh16(gx->subfield.len); + + if (gx->subfield.len <= 0 || gx->subfield.len > sizeof(sbuf)) { + fprintf(stderr, "Invalid signature length\n"); + return (-1); + } + gd = (struct gzsig_data *)sbuf; + + if ((i = fread((u_char *)gd, 1, gx->subfield.len, fin)) != + gx->subfield.len) { + fprintf(stderr, "Error reading signature: %s\n", + strerror(errno)); + return (-1); + } + /* Skip over any options. */ + if (gh.flags & GZIP_FNAME) { + while (getc(fin) != '\0') + ; + } + if (gh.flags & GZIP_FCOMMENT) { + while (getc(fin) != '\0') + ; + } + if (gh.flags & GZIP_FENCRYPT && + fread(buf, 1, GZIP_FENCRYPT_LEN, fin) != GZIP_FENCRYPT_LEN) + return (-1); + + /* Check signature version. */ + if (gd->version != GZSIG_VERSION) { + fprintf(stderr, "Unknown signature version: %d\n", + gd->version); + return (-1); + } + /* Compute SHA1 checksum over compressed data and trailer. */ + sig = (u_char *)(gd + 1); + siglen = gx->subfield.len - sizeof(*gd); + + SHA1_Init(&ctx); + + while ((i = fread(buf, 1, sizeof(buf), fin)) > 0) { + SHA1_Update(&ctx, buf, i); + } + SHA1_Final(digest, &ctx); + + /* Verify signature. */ + if (key_verify(key, digest, sizeof(digest), sig, siglen) < 0) { + fprintf(stderr, "Error verifying signature\n"); + return (-1); + } + return (0); +} + +void +verify_usage(void) +{ + fprintf(stderr, "Usage: gzsig verify [-v] pubkey [file ...]\n"); +} + +void +verify(int argc, char *argv[]) +{ + struct key *key; + char *gzipfile; + FILE *fin; + int i, error, vflag; + + vflag = 0; + + while ((i = getopt(argc, argv, "vh?")) != -1) { + switch (i) { + case 'v': + vflag = 1; + break; + default: + verify_usage(); + exit(1); + } + } + argc -= optind; + argv += optind; + + if (argc < 1) { + verify_usage(); + exit(1); + } + OpenSSL_add_all_algorithms(); + + if ((key = key_new()) == NULL) + fatal(1, "Can't initialize public key"); + + if (key_load_public(key, argv[0]) < 0) + fatal(1, "Can't load public key"); + + if (argc == 1 || *argv[1] == '-') { + argc = 0; + + if (verify_signature(key, stdin) == 0) { + if (vflag) + fprintf(stderr, "Verified input\n"); + } else + fatal(1, "Couldn't verify input"); + } + for (i = 1; i < argc; i++) { + gzipfile = argv[i]; + + if ((fin = fopen(gzipfile, "r")) < 0) { + fprintf(stderr, "Couldn't open %s: %s\n", + gzipfile, strerror(errno)); + continue; + } + error = verify_signature(key, fin); + fclose(fin); + + if (!error) { + if (vflag) + fprintf(stderr, "Verified %s\n", gzipfile); + } else + fatal(1, "Couldn't verify %s", gzipfile); + } + key_free(key); +} diff --git a/usr.bin/gzsig/x509.c b/usr.bin/gzsig/x509.c new file mode 100644 index 00000000000..acb80f2f8b8 --- /dev/null +++ b/usr.bin/gzsig/x509.c @@ -0,0 +1,137 @@ +/* $OpenBSD: x509.c,v 1.1 2005/05/28 01:57:30 marius Exp $ */ + +/* + * x509.c + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: x509.c,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#include <sys/types.h> +#include <sys/uio.h> + +#include <openssl/ssl.h> + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "key.h" +#include "extern.h" +#include "x509.h" + +#define X509_CERT_MAGIC "-----BEGIN CERTIFICATE-----" +#define X509_RSA_MAGIC "-----BEGIN RSA PRIVATE KEY-----" +#define X509_DSA_MAGIC "-----BEGIN DSA PRIVATE KEY-----" + +int +x509_load_public(struct key *k, struct iovec *iov) +{ + BIO *bio; + X509 *cert; + EVP_PKEY *evp; + + if (strncmp((char *)iov->iov_base, X509_CERT_MAGIC, + strlen(X509_CERT_MAGIC)) != 0) + return (-1); + + if ((bio = BIO_new(BIO_s_mem())) == NULL) + return (-1); + + if (BIO_write(bio, iov->iov_base, iov->iov_len + 1) <= 0) { + BIO_free(bio); + return (-1); + } + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + + if (cert == NULL) + return (-1); + + evp = X509_get_pubkey(cert); + + if (evp->type == EVP_PKEY_RSA) { + k->type = KEY_RSA; + k->data = (void *)RSAPublicKey_dup(evp->pkey.rsa); + } else if (evp->type == EVP_PKEY_DSA) { + k->type = KEY_DSA; + k->data = (void *)evp->pkey.dsa; + evp->pkey.dsa = NULL; /* XXX */ + } else { + X509_free(cert); + return (-1); + } + X509_free(cert); + + return (0); +} + +int +x509_load_private(struct key *k, struct iovec *iov) +{ + BIO *bio; + EVP_PKEY *evp; + + if (strncmp((char *)iov->iov_base, X509_RSA_MAGIC, + strlen(X509_RSA_MAGIC)) != 0 && + strncmp((char *)iov->iov_base, X509_DSA_MAGIC, + strlen(X509_DSA_MAGIC)) != 0) { + return (-1); + } + if ((bio = BIO_new(BIO_s_mem())) == NULL) + return (-1); + + if (BIO_write(bio, iov->iov_base, iov->iov_len + 1) <= 0) { + BIO_free(bio); + return (-1); + } + + evp = PEM_read_bio_PrivateKey(bio, NULL, sign_passwd_cb, NULL); + + BIO_free(bio); + + if (evp == NULL) + return (-1); + + if (evp->type == EVP_PKEY_RSA) { + k->type = KEY_RSA; + k->data = (void *)evp->pkey.rsa; + evp->pkey.rsa = NULL; /* XXX */ + } else if (evp->type == EVP_PKEY_DSA) { + k->type = KEY_DSA; + k->data = (void *)evp->pkey.dsa; + evp->pkey.dsa = NULL; /* XXX */ + } else { + EVP_PKEY_free(evp); + return (-1); + } + EVP_PKEY_free(evp); + + return (0); +} diff --git a/usr.bin/gzsig/x509.h b/usr.bin/gzsig/x509.h new file mode 100644 index 00000000000..7a12da9b56c --- /dev/null +++ b/usr.bin/gzsig/x509.h @@ -0,0 +1,40 @@ +/* + * x509.h + * + * Copyright (c) 2001 Dug Song <dugsong@arbor.net> + * Copyright (c) 2001 Arbor Networks, Inc. + * + * 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. + * + * $Id: x509.h,v 1.1 2005/05/28 01:57:30 marius Exp $ + */ + +#ifndef X509_H +#define X509_H + +int x509_load_public(struct key *k, struct iovec *iov); +int x509_load_private(struct key *k, struct iovec *iov); + +#endif /* X509_H */ |