summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pkg_install/sign
diff options
context:
space:
mode:
authorwes <wes@FreeBSD.org>2001-02-06 06:46:42 +0000
committerwes <wes@FreeBSD.org>2001-02-06 06:46:42 +0000
commit7f8fcc0b1fb980da09441142e1bd3634a4aa8dac (patch)
treeecd4d4a16dcbc5f078cdcc29693b19298050f8b9 /usr.sbin/pkg_install/sign
parentb056d4c773f52d7e095a7711daf1726d9c5edae1 (diff)
downloadFreeBSD-src-7f8fcc0b1fb980da09441142e1bd3634a4aa8dac.zip
FreeBSD-src-7f8fcc0b1fb980da09441142e1bd3634a4aa8dac.tar.gz
Add package signing utilities; somebody might actually want them.
These are not enabled in the pkg_install Makefile as of yet; adding the "sign" directory to the SUBDIR list will enable building of sign. Submitted by: Wes Peters Obtained from: Original framework from OpenBSD 2.7, X.509 bits from DoBox.
Diffstat (limited to 'usr.sbin/pkg_install/sign')
-rw-r--r--usr.sbin/pkg_install/sign/Makefile14
-rw-r--r--usr.sbin/pkg_install/sign/README55
-rw-r--r--usr.sbin/pkg_install/sign/check.c117
-rw-r--r--usr.sbin/pkg_install/sign/common.c88
-rw-r--r--usr.sbin/pkg_install/sign/extern.h99
-rw-r--r--usr.sbin/pkg_install/sign/gzip.c315
-rw-r--r--usr.sbin/pkg_install/sign/gzip.h92
-rw-r--r--usr.sbin/pkg_install/sign/main.c183
-rw-r--r--usr.sbin/pkg_install/sign/pgp.h25
-rw-r--r--usr.sbin/pkg_install/sign/pgp_check.c194
-rw-r--r--usr.sbin/pkg_install/sign/pgp_sign.c275
-rw-r--r--usr.sbin/pkg_install/sign/pkg_sign.1186
-rw-r--r--usr.sbin/pkg_install/sign/sha1.c221
-rw-r--r--usr.sbin/pkg_install/sign/sign.c142
-rw-r--r--usr.sbin/pkg_install/sign/stand.c56
-rw-r--r--usr.sbin/pkg_install/sign/stand.h28
-rw-r--r--usr.sbin/pkg_install/sign/x509.c424
17 files changed, 2514 insertions, 0 deletions
diff --git a/usr.sbin/pkg_install/sign/Makefile b/usr.sbin/pkg_install/sign/Makefile
new file mode 100644
index 0000000..ffb1b24
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD$
+# $OpenBSD: Makefile.bsd-wrapper,v 1.2 1999/10/07 16:30:32 espie Exp $
+
+PROG= pkg_sign
+SRCS= main.c check.c common.c gzip.c pgp_check.c pgp_sign.c sha1.c sign.c stand.c x509.c
+
+DPADD= ${LIBINSTALL}
+LDADD= ${LIBINSTALL} -lcrypto
+
+LINKS= ${BINDIR}/pkg_sign ${BINDIR}/pkg_check
+MLINKS= pkg_sign.1 pkg_check.1
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/pkg_install/sign/README b/usr.sbin/pkg_install/sign/README
new file mode 100644
index 0000000..8e81fcd
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/README
@@ -0,0 +1,55 @@
+To sign packages in a transparent way:
+gzip files can handle an extra field at the beginning that
+stores anything we wish.
+
+So it's just a question to choose a format for the signature, and to
+embed it there.
+
+We use the extra field to store signatures. Each signature consists
+of a 6 bytes type marker, a 2 bytes length, followed by the signature
+itself. We can potentially stack signatures: resign a signed archive
+by just prepending the new signature to the extra field.
+
+To check the first signature, the checker just needs to extract it, pass it
+off to the checking protocol (e.g. PGP), followed by the unsigned archive
+(e.g., regenerate the gzip header without the first signature, then put
+the gzip data).
+
+* Signed archives just look like normal .tar.gz files, except for programs
+that use the extra field for their own purpose,
+* Possibility to grab the files off the net and extract stuff/verify
+signatures on the fly (just need to wedge the checker as an intermediate
+pipe)
+* Pretty simple, small portable code to be able to check signatures
+everywhere (the signer itself needs getpass and corresponding functionality)
+
+The scheme should be extensible to any compressed format which allows for
+extended headers.
+
+
+Thanks to Angelos D. Keromytis for pointing out I did not need to
+uncompress the archive to sign it, and to other members of the OpenBSD
+project for various reasons.
+
+--
+ Marc Espie, 1999
+ $OpenBSD: README,v 1.2 1999/10/04 21:46:27 espie Exp $
+
+--
+
+X.509 notes:
+
+I added the ability to sign a package with an X.509 key, and to check
+against a stack of X.509 certificates. This allows a "vendor" to
+distribute a system with one or more certificates pre-installed, and
+to add certificates in a signed package by appending them to the
+default certficiate stack.
+
+The X.509 signatures are stored in the gzip header in the same manner
+as other signatures. This is known to compile against OpenSSL
+libraries on OpenBSD 2.7 and FreeBSD 5.0, your mileage may vary.
+
+--
+
+ Wes Peters, Dec 2000
+ $FreeBSD$
diff --git a/usr.sbin/pkg_install/sign/check.c b/usr.sbin/pkg_install/sign/check.c
new file mode 100644
index 0000000..d923538
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/check.c
@@ -0,0 +1,117 @@
+/* $FreeBSD$ */
+/* $OpenBSD: check.c,v 1.2 1999/10/04 21:46:27 espie Exp $ */
+/*-
+ * Copyright (c) 1999 Marc Espie.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Marc Espie for the OpenBSD
+ * Project.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+ * ``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 OPENBSD
+ * PROJECT OR CONTRIBUTORS 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.
+ */
+
+/* Simple code for a stand-alone package checker */
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "stand.h"
+#include "pgp.h"
+#include "gzip.h"
+#include "extern.h"
+
+struct checker {
+ void *context;
+ void (*add)(void *, const char *, size_t);
+ int (*get)(void *);
+ int status;
+};
+
+#define MAX_CHECKERS 20
+
+int
+check_signature(file, userid, envp, filename)
+ /*@dependent@*/FILE *file;
+ const char *userid;
+ char *envp[];
+ /*@observer@*/const char *filename;
+{
+ struct signature *sign;
+ struct mygzip_header h;
+ int status;
+ char buffer[1024];
+ size_t length;
+ struct checker checker[MAX_CHECKERS];
+ struct signature *sweep;
+ int i, j;
+
+ status = read_header_and_diagnose(file, &h, &sign, filename);
+ if (status != 1)
+ return PKG_UNSIGNED;
+
+ for (sweep = sign, i = 0;
+ sweep != NULL && i < MAX_CHECKERS;
+ sweep=sweep->next, i++) {
+ switch(sweep->type) {
+ case TAG_OLD:
+ fprintf(stderr, "File %s uses old signatures, no longer supported\n",
+ filename);
+ checker[i].context = NULL;
+ break;
+ case TAG_X509:
+ checker[i].context = new_x509_checker(&h, sweep, userid, envp, filename);
+ checker[i].add = x509_add;
+ checker[i].get = x509_sign_ok;
+ break;
+ case TAG_SHA1:
+ checker[i].context = new_sha1_checker(&h, sweep, userid, envp, filename);
+ checker[i].add = sha1_add;
+ checker[i].get = sha1_sign_ok;
+ break;
+ case TAG_PGP:
+ checker[i].context = new_pgp_checker(&h, sweep, userid, envp, filename);
+ checker[i].add = pgp_add;
+ checker[i].get = pgp_sign_ok;
+ break;
+ default:
+ abort();
+ }
+ }
+ while ((length = fread(buffer, 1, sizeof buffer, file)) > 0) {
+ for (j = 0; j < i; j++) {
+ if (checker[j].context) {
+ (*checker[j].add)(checker[j].context, buffer, length);
+ }
+ }
+ }
+// for (j = i-1; j >= 0; j--)
+ for (j = 0; j < i; j++) {
+ if (checker[j].context) {
+ checker[j].status = (*checker[j].get)(checker[j].context);
+ } else {
+ checker[j].status = PKG_SIGERROR;
+ }
+ }
+ free_signature(sign);
+ return checker[0].status;
+}
+
diff --git a/usr.sbin/pkg_install/sign/common.c b/usr.sbin/pkg_install/sign/common.c
new file mode 100644
index 0000000..8b41bcd
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/common.c
@@ -0,0 +1,88 @@
+/* $FreeBSD$ */
+/* $OpenBSD: common.c,v 1.3 1999/10/07 16:30:32 espie Exp $ */
+/*-
+ * Copyright (c) 1999 Marc Espie.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Marc Espie for the OpenBSD
+ * Project.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+ * ``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 OPENBSD
+ * PROJECT OR CONTRIBUTORS 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 <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "stand.h"
+#include "gzip.h"
+#include "pgp.h"
+#include "extern.h"
+
+/* Ensure consistent diagnostics */
+int
+read_header_and_diagnose(file, h, sign, filename)
+ FILE *file;
+ struct mygzip_header *h;
+ struct signature **sign;
+ const char *filename;
+{
+ switch(gzip_read_header(file, h, sign)) {
+ case GZIP_SIGNED:
+ if (sign == NULL) {
+ fprintf(stderr, "File %s is already signed\n", filename);
+ return 0;
+ } else
+ return 1;
+ case GZIP_UNSIGNED:
+ if (sign != NULL) {
+ fprintf(stderr, "File %s is not a signed gzip file\n", filename);
+ return 0;
+ } else
+ return 1;
+ case GZIP_NOT_GZIP:
+ fprintf(stderr, "File %s is not a gzip file\n", filename);
+ return 0;
+ case GZIP_NOT_PGPSIGNED:
+ fprintf(stderr, "File %s contains an unknown extension\n", filename);
+ return 0;
+ default:
+ /* this should not happen */
+ abort();
+ }
+}
+
+int
+reap(pid)
+ pid_t pid;
+{
+ int pstat;
+ pid_t result;
+
+ do {
+ result = waitpid(pid, &pstat, 0);
+ } while (result == -1 && errno == EINTR);
+ return result == -1 ? -1 : pstat;
+}
+
diff --git a/usr.sbin/pkg_install/sign/extern.h b/usr.sbin/pkg_install/sign/extern.h
new file mode 100644
index 0000000..760d39c
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/extern.h
@@ -0,0 +1,99 @@
+/* $FreeBSD$ */
+/* $OpenBSD: extern.h,v 1.3 1999/10/07 16:30:32 espie Exp $ */
+/*-
+ * Copyright (c) 1999 Marc Espie.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Marc Espie for the OpenBSD
+ * Project.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+ * ``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 OPENBSD
+ * PROJECT OR CONTRIBUTORS 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.
+ */
+
+/* Convention: all functions that operate on a FILE * also take a filename
+ for diagnostic purposes. The file can be connected to a pipe, so
+ - don't rewind
+ - don't reopen from filename.
+ */
+
+struct mygzip_header;
+struct signature;
+
+/* main.c */
+extern int verbose;
+extern int quiet;
+extern char *userkey;
+
+/* common.c */
+extern int read_header_and_diagnose __P((FILE *file, \
+ /*@out@*/struct mygzip_header *h, /*@null@*/struct signature **sign, \
+ const char *filename));
+extern int reap __P((pid_t pid));
+
+/* sign.c */
+extern int sign __P((/*@observer@*/const char *filename, int type, \
+ /*@null@*/const char *userid, char *envp[]));
+
+/* check.c */
+extern int check_signature __P((/*@dependent@*/FILE *file, \
+ /*@null@*/const char *userid, char *envp[], \
+ /*@observer@*/const char *filename));
+
+#define PKG_BADSIG 0
+#define PKG_GOODSIG 1
+#define PKG_UNSIGNED 2
+#define PKG_SIGNED 4
+#define PKG_SIGERROR 8
+#define PKG_SIGUNKNOWN 16
+
+typedef /*@observer@*/char *pchar;
+
+#define MAXID 512
+/* sha1.c */
+#define SHA1_DB_NAME "/var/db/pkg/SHA1"
+
+extern void *new_sha1_checker __P((struct mygzip_header *h, \
+ struct signature *sign, const char *userid, char *envp[], \
+ const char *filename));
+
+extern void sha1_add __P((void *arg, const char *buffer, \
+ size_t length));
+
+extern int sha1_sign_ok __P((void *arg));
+
+extern int retrieve_sha1_marker __P((const char *filename, \
+ struct signature **sign, const char *userid));
+
+/* x509.c */
+#define X509_DB_NAME "/var/db/pkg/X509"
+
+extern void *new_x509_checker __P((struct mygzip_header *h, \
+ struct signature *sign, const char *userid, char *envp[], \
+ const char *filename));
+
+extern void x509_add __P((void *arg, const char *buffer, \
+ size_t length));
+
+extern int x509_sign_ok __P((void *arg));
+
+extern int retrieve_x509_marker __P((const char *filename, \
+ struct signature **sign, const char *userid));
diff --git a/usr.sbin/pkg_install/sign/gzip.c b/usr.sbin/pkg_install/sign/gzip.c
new file mode 100644
index 0000000..4150bcc
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/gzip.c
@@ -0,0 +1,315 @@
+/* $FreeBSD$ */
+/* $OpenBSD: gzip.c,v 1.3 1999/10/04 21:46:28 espie Exp $ */
+/*-
+ * Copyright (c) 1999 Marc Espie.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Marc Espie for the OpenBSD
+ * Project.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+ * ``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 OPENBSD
+ * PROJECT OR CONTRIBUTORS 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 <sys/types.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include "stand.h"
+#include "gzip.h"
+#include "pgp.h"
+
+/* Signatures follow a simple format
+ (endianess was chosen to conform to gzip header format)
+ */
+
+SIGNTAG known_tags[KNOWN_TAGS] = {
+ {'S', 'I', 'G', 'P', 'G', 'P', 0, 0 },
+ {'C', 'K', 'S', 'H', 'A', '1', 0, 0 },
+ {'C', 'R', 'X', '5', '0', '9', 0, 0 },
+ {'S', 'i', 'g', 'P', 'G', 'P', 0, 0 } /* old format */
+};
+
+void
+sign_fill_tag(sign)
+ struct signature *sign;
+{
+ sign->tag[6] = sign->length % 256;
+ sign->tag[7] = sign->length / 256;
+}
+
+void
+sign_fill_length(sign)
+ struct signature *sign;
+{
+ sign->length = sign->tag[6] + 256 * sign->tag[7];
+}
+
+static size_t
+stack_sign(match, t, f, sign)
+ SIGNTAG match;
+ int t;
+ FILE *f;
+ struct signature **sign;
+{
+ struct signature *new_sign;
+ size_t length;
+
+ new_sign = malloc(sizeof *new_sign);
+ if (new_sign == NULL)
+ return 0;
+ new_sign->type = t;
+ new_sign->next = NULL;
+ memcpy(new_sign->tag, match, sizeof(SIGNTAG));
+ sign_fill_length(new_sign);
+ new_sign->data = malloc(new_sign->length);
+ if (new_sign->data == NULL ||
+ fread(new_sign->data, 1, new_sign->length, f) != new_sign->length) {
+ free_signature(new_sign);
+ return 0;
+ }
+ length = new_sign->length;
+ if (sign != NULL) {
+ if (!*sign)
+ *sign = new_sign;
+ else {
+ while ((*sign)->next != NULL)
+ sign = &((*sign)->next);
+ (*sign)->next = new_sign;
+ }
+ } else
+ free_signature(new_sign);
+ return length;
+}
+
+
+static int
+add_sign(f, sign)
+ FILE *f;
+ struct signature **sign;
+{
+ SIGNTAG match;
+ int i;
+
+ if (fread(match, 1, sizeof(SIGNTAG), f) != sizeof(SIGNTAG))
+ return -1;
+ for (i = 0; i < KNOWN_TAGS; i++) {
+ if (memcmp(match, known_tags[i], TAGCHECK) == 0) {
+ unsigned int sign_length = stack_sign(match, i, f, sign);
+ if (sign_length > 0)
+ return sign_length + sizeof(SIGNTAG);
+ else
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+gzip_magic(f)
+ FILE *f;
+{
+ int c, d;
+
+ c = fgetc(f);
+ d = fgetc(f);
+ if ((unsigned char)c != (unsigned char)GZIP_MAGIC0
+ || (unsigned char)d != (unsigned char)GZIP_MAGIC1)
+ return 0;
+ else
+ return 1;
+}
+
+static int
+fill_gzip_fields(f, h)
+ FILE *f;
+ struct mygzip_header *h;
+{
+ int method, flags;
+
+ method = fgetc(f);
+ flags = fgetc(f);
+
+ if (method == EOF || flags == EOF || fread(h->stamp, 1, 6, f) != 6)
+ return 0;
+ h->method = (char)method;
+ h->flags = (char)flags;
+ if ((h->flags & CONTINUATION) != 0)
+ if (fread(h->part, 1, 2, f) != 2)
+ return 0;
+ return 1;
+}
+
+/* retrieve a gzip header, including signatures */
+int
+gzip_read_header(f, h, sign)
+ FILE *f;
+ struct mygzip_header *h;
+ struct signature **sign;
+{
+ if (sign != NULL)
+ *sign = NULL;
+ if (!gzip_magic(f) || !fill_gzip_fields(f, h))
+ return GZIP_NOT_GZIP;
+
+ if ((h->flags & EXTRA_FIELD) == 0) {
+ h->remaining = 0;
+ return GZIP_UNSIGNED;
+ }
+ else {
+ int c;
+
+ c = fgetc(f);
+ if (c == EOF)
+ return GZIP_NOT_GZIP;
+ h->remaining = (unsigned)c;
+ c = fgetc(f);
+ if (c == EOF)
+ return GZIP_NOT_PGPSIGNED;
+ h->remaining += ((unsigned) c) << 8;
+ while (h->remaining >= sizeof(SIGNTAG)) {
+ int sign_length = add_sign(f, sign);
+ if (sign_length > 0)
+ h->remaining -= sign_length;
+ if (sign_length < 0)
+ return GZIP_NOT_GZIP;
+ if (sign_length == 0)
+ return GZIP_SIGNED;
+ }
+ return GZIP_SIGNED;
+ }
+}
+
+static unsigned
+sign_length(sign)
+ struct signature *sign;
+{
+ unsigned total = 0;
+
+ while (sign != NULL) {
+ total += sizeof(SIGNTAG) + sign->length;
+ sign = sign->next;
+ }
+ return total;
+}
+
+struct mydata {
+ FILE *file;
+ int ok;
+};
+
+static void myadd(arg, buffer, size)
+ void *arg;
+ const char *buffer;
+ size_t size;
+{
+ struct mydata *d = arg;
+
+ if (fwrite(buffer, 1, size, d->file) == size)
+ d->ok = 1;
+ else
+ d->ok = 0;
+}
+
+/* write a gzip header, including signatures */
+int
+gzip_write_header(f, h, sign)
+ FILE *f;
+ const struct mygzip_header *h;
+ struct signature *sign;
+{
+ struct mydata d;
+ d.file = f;
+ if (gzip_copy_header(h, sign, myadd, &d) == 0)
+ return 0;
+ return d.ok;
+}
+
+int
+gzip_copy_header(h, sign, add, data)
+ const struct mygzip_header *h;
+ struct signature *sign;
+ void (*add)(void *, const char *, size_t);
+ void *data;
+{
+ char flags;
+ size_t length;
+ size_t buflength;
+ size_t i;
+ char *buffer;
+
+ length = h->remaining + sign_length(sign);
+ if (length) {
+ buflength = length + 2;
+ flags = h->flags | EXTRA_FIELD;
+ } else {
+ flags = h->flags & ~EXTRA_FIELD;
+ buflength = 0;
+ }
+ buflength += 10;
+ if ((h->flags & CONTINUATION) != 0)
+ buflength += 2;
+
+ buffer = malloc(buflength);
+ if (buffer == NULL)
+ return 0;
+
+ i = 0;
+ buffer[i++] = GZIP_MAGIC0;
+ buffer[i++] = GZIP_MAGIC1;
+ buffer[i++] = h->method;
+ buffer[i++] = flags;
+ memcpy(buffer+i, h->stamp, 6);
+ i += 6;
+ if ((flags & CONTINUATION) != 0) {
+ memcpy(buffer+i, h->part, 2);
+ i += 2;
+ }
+ if (length) {
+ buffer[i++] = (char)(length % 256);
+ buffer[i++] = (char)(length / 256);
+ while (sign != NULL) {
+ memcpy(buffer+i, sign->tag, sizeof(SIGNTAG));
+ i += sizeof(SIGNTAG);
+ memcpy(buffer+i, sign->data, sign->length);
+ i += sign->length;
+ sign = sign->next;
+ }
+ }
+ (*add)(data, buffer, buflength);
+ free(buffer);
+ return 1;
+}
+
+void
+free_signature(sign)
+ struct signature *sign;
+{
+ struct signature *next;
+
+ while (sign != NULL) {
+ next = sign->next;
+ free(sign->data);
+ free(sign);
+ sign = next;
+ }
+}
diff --git a/usr.sbin/pkg_install/sign/gzip.h b/usr.sbin/pkg_install/sign/gzip.h
new file mode 100644
index 0000000..bc64aab
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/gzip.h
@@ -0,0 +1,92 @@
+/* $FreeBSD$ */
+/* $OpenBSD: gzip.h,v 1.2 1999/10/04 21:46:28 espie Exp $ */
+/*-
+ * Copyright (c) 1999 Marc Espie.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Marc Espie for the OpenBSD
+ * Project.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+ * ``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 OPENBSD
+ * PROJECT OR CONTRIBUTORS 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.
+ */
+
+#define GZIP_MAGIC0 '\037'
+#define GZIP_MAGIC1 '\213'
+/* flags values */
+#define CONTINUATION 0x02
+#define EXTRA_FIELD 0x04
+
+/* meaningful fields in a gzip header, see gzip proper for details.
+ This structure should not be fiddled with outside of gzip_read_header
+ and gzip_write_header
+ */
+struct mygzip_header {
+ char method;
+ char flags;
+ char stamp[6];
+ char part[2];
+ /* remaining extra, after know signs have been read */
+ unsigned int remaining;
+};
+
+#define TAGSIZE 8
+#define TAGCHECK 6
+
+typedef unsigned char SIGNTAG[8];
+
+/* stack of signatures */
+struct signature {
+ SIGNTAG tag;
+ int type;
+ int length;
+ char *data;
+ struct signature *next;
+};
+
+/* returns from gzip_read_header */
+#define GZIP_UNSIGNED 0 /* gzip file, no signature */
+#define GZIP_SIGNED 1 /* gzip file, signature parsed ok */
+#define GZIP_NOT_GZIP 2 /* not a proper gzip file */
+#define GZIP_NOT_PGPSIGNED 3 /* gzip file, unknown extension */
+extern int gzip_read_header __P((FILE *f, /*@out@*/struct mygzip_header *h, \
+ /*@null@*/struct signature **sign));
+/* gzip_write_header returns 1 for success */
+extern int gzip_write_header __P((FILE *f, const struct mygzip_header *h, \
+ /*@null@*/struct signature *sign));
+/* writing header to memory. Returns size needed, or 0 if buffer too small
+ buffer must be at least 14 characters */
+extern int gzip_copy_header __P((const struct mygzip_header *h, \
+ /*@null@*/struct signature *sign, \
+ void (*add)(void *, const char *, size_t), void *data));
+
+extern void free_signature __P((/*@null@*/struct signature *sign));
+extern void sign_fill_tag __P((struct signature *sign));
+#define KNOWN_TAGS 4
+#define TAG_PGP 0
+#define TAG_SHA1 1
+#define TAG_X509 2
+#define TAG_OLD 3
+#define TAG_ANY -1
+#define pgptag (known_tags[TAG_PGP])
+#define sha1tag (known_tags[TAG_SHA1])
+#define x509tag (known_tags[TAG_X509])
+extern SIGNTAG known_tags[KNOWN_TAGS];
diff --git a/usr.sbin/pkg_install/sign/main.c b/usr.sbin/pkg_install/sign/main.c
new file mode 100644
index 0000000..09df2d1
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/main.c
@@ -0,0 +1,183 @@
+/* $FreeBSD$ */
+/* $OpenBSD: main.c,v 1.2 1999/10/04 21:46:28 espie Exp $ */
+/*-
+ * Copyright (c) 1999 Marc Espie.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Marc Espie for the OpenBSD
+ * Project.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+ * ``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 OPENBSD
+ * PROJECT OR CONTRIBUTORS 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 <sys/types.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "stand.h"
+#include "gzip.h"
+#include "pgp.h"
+#include "extern.h"
+
+#ifdef __OpenBSD__
+extern char *__progname;
+#define argv0 __progname
+#else
+static char *argv0;
+#endif
+
+#define NM_SIGN "pkg_sign"
+
+int verbose = 0;
+int quiet = 0;
+char *userkey = NULL;
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: %s [-sc] [-t type] [-u userid] [-k keyfile] pkg1 ...\n", argv0);
+ exit(EXIT_FAILURE);
+}
+
+#define SIGN 0
+#define CHECK 1
+
+/* wrapper for the check_signature function (open file if needed) */
+static int
+check(filename, type, userid, envp)
+ /*@observer@*/const char *filename;
+ int type;
+ /*@null@*/const char *userid;
+ char *envp[];
+{
+ int result;
+ FILE *file;
+
+ if (strcmp(filename, "-") == 0)
+ return check_signature(stdin, userid, envp, "stdin");
+ file = fopen(filename, "r");
+ if (file == NULL) {
+ fprintf(stderr, "Can't open %s\n", filename);
+ return 0;
+ }
+ result = check_signature(file, userid, envp, filename);
+ if (fclose(file) == 0) {
+ if (result == PKG_BADSIG || result == PKG_SIGERROR)
+ return 0;
+ else
+ return 1;
+ } else
+ return 0;
+}
+
+int
+main(argc, argv, envp)
+ int argc;
+ char *argv[];
+ char *envp[];
+{
+ int success = 1;
+ int ch;
+ char *userid = NULL;
+ int mode;
+ int i;
+ int type = TAG_ANY;
+
+/* #ifndef BSD4_4 */
+ set_program_name(argv[0]);
+/* #endif */
+#ifdef CHECKER_ONLY
+ mode = CHECK;
+#else
+#ifndef __OpenBSD__
+ if ((argv0 = strrchr(argv[0], '/')) != NULL)
+ argv0++;
+ else
+ argv0 = argv[0];
+#endif
+ if (strcmp(argv0, NM_SIGN) == 0)
+ mode = SIGN;
+ else
+ mode = CHECK;
+#endif
+
+ while ((ch = getopt(argc, argv, "t:u:k:qscv")) != -1) {
+ switch(ch) {
+ case 't':
+ if (strcmp(optarg, "pgp") == 0)
+ type = TAG_PGP;
+ else if (strcmp(optarg, "sha1") == 0)
+ type = TAG_SHA1;
+ else if (strcmp(optarg, "x509") == 0)
+ type = TAG_X509;
+ else
+ usage();
+ break;
+ case 'u':
+ userid = strdup(optarg);
+ break;
+
+ case 'k':
+ userkey = optarg;
+ break;
+
+ case 'q':
+ quiet = 1;
+ break;
+
+#ifndef CHECKER_ONLY
+ case 's':
+ mode = SIGN;
+ break;
+#endif
+ case 'c':
+ mode = CHECK;
+ break;
+
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc == 0) {
+ if (mode == CHECK)
+ success &= check("-", 0, userid, envp);
+ else
+ usage();
+ }
+
+#ifndef CHECKER_ONLY
+ if (mode == SIGN && type == TAG_ANY)
+ type = TAG_PGP;
+ if (mode == SIGN && type == TAG_PGP)
+ handle_pgp_passphrase();
+#endif
+ for (i = 0; i < argc; i++)
+ success &= (mode == SIGN ? sign : check)(argv[i], type, userid, envp);
+ exit(success == 1 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
diff --git a/usr.sbin/pkg_install/sign/pgp.h b/usr.sbin/pkg_install/sign/pgp.h
new file mode 100644
index 0000000..99476f2
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/pgp.h
@@ -0,0 +1,25 @@
+/* $FreeBSD$ */
+/* $OpenBSD: pgp.h,v 1.2 1999/10/04 21:46:28 espie Exp $ */
+/* Estimate size of pgp signature */
+#define MAXPGPSIGNSIZE 1024
+
+#ifndef PGP
+#define PGP "/usr/local/bin/pgp"
+#endif
+
+struct mygzip_header;
+struct signature;
+
+extern void *new_pgp_checker __P((struct mygzip_header *h, \
+ struct signature *sign, const char *userid, char *envp[], \
+ const char *filename));
+
+extern void pgp_add __P((void *arg, const char *buffer, \
+ size_t length));
+
+extern int pgp_sign_ok __P((void *arg));
+
+extern void handle_pgp_passphrase __P((void));
+
+extern int retrieve_pgp_signature __P((const char *filename, \
+struct signature **sign, const char *userid, char *envp[]));
diff --git a/usr.sbin/pkg_install/sign/pgp_check.c b/usr.sbin/pkg_install/sign/pgp_check.c
new file mode 100644
index 0000000..d1fef13
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/pgp_check.c
@@ -0,0 +1,194 @@
+/* $FreeBSD$ */
+/* $OpenBSD: pgp_check.c,v 1.2 1999/10/07 16:30:32 espie Exp $ */
+/*-
+ * Copyright (c) 1999 Marc Espie.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Marc Espie for the OpenBSD
+ * Project.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+ * ``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 OPENBSD
+ * PROJECT OR CONTRIBUTORS 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 <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include "stand.h"
+#include "pgp.h"
+#include "gzip.h"
+#include "extern.h"
+
+#ifndef _PATH_DEVNULL
+#define _PATH_DEVNULL "/dev/null"
+#endif
+
+/* transform current process into pgp signature checker -u userid <fd */
+static void
+pgpcheck(fd, userid, envp)
+ int fd;
+ const char *userid;
+ char *envp[];
+{
+ int fdnull;
+ pchar argv[6];
+ int argc = 0;
+
+ argv[argc++] = PGP;
+ argv[argc++] = "+batchmode";
+ argv[argc++] = "-f";
+
+ if (userid) {
+ argv[argc++] = "-u";
+ argv[argc++] = (char *)userid;
+ }
+ argv[argc++] = NULL;
+
+ assert(argc <= sizeof argv / sizeof(pchar));
+
+ fdnull = open(_PATH_DEVNULL, O_RDWR);
+ if (fdnull == -1 ||
+ dup2(fd, fileno(stdin)) == -1 ||
+ dup2(fdnull, fileno(stdout)) == -1 ||
+ close(fdnull) == -1 || close(fd) == -1 ||
+ execve(PGP, argv, envp) == -1)
+ perror("launching pgp");
+ exit(errno);
+}
+
+struct pgp_checker {
+ pid_t id;
+ int fdout;
+ int status;
+#ifdef DEBUG_DUMP
+ FILE *out;
+#endif
+};
+
+void *
+new_pgp_checker(h, sign, userid, envp, filename)
+ struct mygzip_header *h;
+ struct signature *sign;
+ const char *userid;
+ char *envp[];
+ /*@observer@*/const char *filename;
+{
+ struct pgp_checker *n;
+ int topgpcheck[2];
+
+ assert(sign->type == TAG_PGP);
+ n = malloc(sizeof *n);
+
+ {
+ struct stat sbuf;
+
+ if (stat(PGP, &sbuf) == -1) {
+ warnx("%s does not exist", PGP);
+ return NULL;
+ }
+ }
+ if (n == NULL) {
+ warnx("Can't allocate pgp_checker");
+ return NULL;
+ }
+
+ if (pipe(topgpcheck) == -1) {
+ warn("Pgp checker pipe");
+ free(n);
+ return NULL;
+ }
+ switch(n->id = fork()) {
+ case -1:
+ warn("Pgp checker process");
+ free(n);
+ return NULL;
+ case 0:
+ if (close(topgpcheck[1]) == -1)
+ exit(errno);
+ pgpcheck(topgpcheck[0], userid, envp);
+ /*@notreached@*/
+ break;
+ default:
+ (void)close(topgpcheck[0]);
+ break;
+ }
+ n->fdout = topgpcheck[1];
+ /* so that subsequent fork() won't duplicate it inadvertently */
+ (void)fcntl(n->fdout, F_SETFD, FD_CLOEXEC);
+#ifdef DEBUG_DUMP
+ n->out = fopen("compare", "w");
+#endif
+ n->status = PKG_GOODSIG;
+
+ pgp_add(n, sign->data, sign->length);
+ if (gzip_copy_header(h, sign->next, pgp_add, n) == 0) {
+ warnx("Unexpected header in %s", filename);
+ n->status = PKG_SIGERROR;
+ }
+ return n;
+}
+
+void
+pgp_add(arg, buffer, length)
+ void *arg;
+ const char *buffer;
+ size_t length;
+{
+ struct pgp_checker *n = arg;
+
+ if (n->status == PKG_GOODSIG) {
+#ifdef DEBUG_DUMP
+ fwrite(buffer, 1, length, n->out);
+#endif
+ while (length > 0) {
+ ssize_t l = write(n->fdout, buffer, length);
+ if (l == -1) {
+ n->status = PKG_SIGERROR;
+ break;
+ }
+ length -= l;
+ buffer += l;
+ }
+ }
+}
+
+int
+pgp_sign_ok(arg)
+ void *arg;
+{
+ struct pgp_checker *n = arg;
+ int status = n->status;
+
+#ifdef DEBUG_DUMP
+ fclose(n->out);
+#endif
+ if (close(n->fdout) != 0)
+ status = PKG_SIGERROR;
+ if (reap(n->id) != 0)
+ status = PKG_BADSIG;
+ free(n);
+ return status;
+}
diff --git a/usr.sbin/pkg_install/sign/pgp_sign.c b/usr.sbin/pkg_install/sign/pgp_sign.c
new file mode 100644
index 0000000..1fada95
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/pgp_sign.c
@@ -0,0 +1,275 @@
+/* $FreeBSD$ */
+/* $OpenBSD: pgp_sign.c,v 1.1 1999/10/04 21:46:29 espie Exp $ */
+/*-
+ * Copyright (c) 1999 Marc Espie.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Marc Espie for the OpenBSD
+ * Project.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+ * ``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 OPENBSD
+ * PROJECT OR CONTRIBUTORS 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 <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <pwd.h>
+#include <assert.h>
+#include "stand.h"
+#include "pgp.h"
+#include "gzip.h"
+#include "extern.h"
+
+static void
+pgpsign(fdin, fdout, userid, envp)
+ int fdin, fdout;
+ const char *userid;
+ char *envp[];
+{
+ pchar argv[10];
+ int argc = 0;
+
+ argv[argc++] = PGP;
+ argv[argc++] = "+batchmode";
+ argv[argc++] = "+compress=off";
+ argv[argc++] = "-f";
+ argv[argc++] = "-s";
+ argv[argc++] = "-zAthlon";
+
+ if (userid) {
+ argv[argc++] = "-u";
+ argv[argc++] = (char *)userid;
+ }
+ argv[argc++] = NULL;
+ assert(argc <= sizeof argv / sizeof(pchar));
+
+ if (dup2(fdin, fileno(stdin)) == -1 ||
+ dup2(fdout, fileno(stdout)) == -1 ||
+ execve(PGP, argv, envp) == -1)
+ exit(errno);
+}
+
+static struct signature *
+new_pgpsignature(old)
+ struct signature *old;
+{
+ struct signature *n;
+
+ n = malloc(sizeof(*n));
+ if (n != NULL) {
+ n->data = malloc(MAXPGPSIGNSIZE);
+ if (n->data == NULL) {
+ free(n);
+ return NULL;
+ }
+ n->length = 0;
+ n->next = old;
+ n->type = TAG_PGP;
+ memcpy(n->tag, pgptag, sizeof pgptag);
+ }
+ return n;
+}
+
+int
+retrieve_pgp_signature(filename, sign, userid, envp)
+ const char *filename;
+ struct signature **sign;
+ const char *userid;
+ char *envp[];
+{
+ int topgp[2], frompgp[2];
+ pid_t pgpid;
+ struct mygzip_header h;
+ int success;
+
+ FILE *orig, *dest, *signin;
+ struct signature *old;
+
+ orig = fopen(filename, "r");
+ if (orig == NULL)
+ return 0;
+ if (gzip_read_header(orig, &h, &old) == GZIP_NOT_GZIP) {
+ warnx("File %s is not a gzip file\n", filename);
+ fclose(orig);
+ return 0;
+ }
+
+ if (pipe(topgp) == -1) {
+ fclose(orig);
+ return 0;
+ }
+ if (pipe(frompgp) == -1) {
+ fclose(orig);
+ (void)close(topgp[0]);
+ (void)close(topgp[1]);
+ return 0;
+ }
+ switch(pgpid = fork()) {
+ case 0:
+ (void)close(topgp[1]);
+ (void)close(frompgp[0]);
+ pgpsign(topgp[0], frompgp[1], userid, envp);
+ /*NOT REACHED */
+ case -1:
+ (void)close(topgp[0]);
+ (void)close(topgp[1]);
+ (void)close(frompgp[0]);
+ (void)close(frompgp[1]);
+ fclose(orig);
+ return 0;
+ default:
+ (void)close(topgp[0]);
+ (void)close(frompgp[1]);
+ }
+
+ dest = fdopen(topgp[1], "w");
+ if (dest == NULL) {
+ (void)close(topgp[1]);
+ (void)close(frompgp[0]);
+ (void)reap(pgpid);
+ return 0;
+ }
+
+ success = 1;
+ if (gzip_write_header(dest, &h, old) == 0)
+ success = 0;
+ else {
+ int c;
+
+ while ((c = fgetc(orig)) != EOF && fputc(c, dest) != EOF)
+ ;
+ if (ferror(dest))
+ success = 0;
+ }
+ if (fclose(dest) != 0)
+ success = 0;
+
+ if (fclose(orig) != 0)
+ success = 0;
+
+ signin = fdopen(frompgp[0], "r");
+ if (signin == NULL) {
+ (void)close(frompgp[0]);
+ } else {
+ enum { NONE, FIRST, DONE, COPY} magic = NONE;
+ int c;
+#ifdef DEBUG_DUMP
+ FILE *out = fopen("dump", "w");
+#endif
+
+ if ((*sign = new_pgpsignature(old)) == NULL)
+ success = 0;
+ else {
+ while ((c = fgetc(signin)) != EOF && magic != DONE &&
+ (*sign)->length < MAXPGPSIGNSIZE) {
+ switch(magic) {
+ case NONE:
+ (*sign)->data[(*sign)->length++] = c;
+ if ((unsigned char)c == (unsigned char)GZIP_MAGIC0)
+ magic = FIRST;
+ break;
+ case FIRST:
+ (*sign)->data[(*sign)->length++] = c;
+ if ((unsigned char)c == (unsigned char)GZIP_MAGIC1)
+#ifdef DEBUG_DUMP
+ magic = COPY;
+#else
+ magic = DONE;
+#endif
+ else if ((unsigned char)c != (unsigned char)GZIP_MAGIC0)
+ magic = NONE;
+ break;
+ case DONE:
+ case COPY:
+ break;
+ }
+#ifdef DEBUG_DUMP
+ fputc(c, out);
+#endif
+ }
+ if ((*sign)->length == MAXPGPSIGNSIZE)
+ success = 0;
+ (*sign)->length -= 2;
+ sign_fill_tag(*sign);
+ }
+ fclose(signin);
+#ifdef DEBUG_DUMP
+ fclose(out);
+#endif
+ reap(pgpid);
+ }
+ return success;
+}
+
+void
+handle_pgp_passphrase()
+{
+ pid_t pid;
+ int fd[2];
+ char *p;
+
+printf("Short-circuiting %s\n", __FUNCTION__);
+return;
+
+ /* Retrieve the pgp passphrase */
+ p = getpass("Enter passphrase:");
+
+ /* somewhat kludgy code to get the passphrase to pgp, see
+ pgp documentation for the gore
+ */
+ if (pipe(fd) != 0) {
+ perror("pkg_sign");
+ exit(EXIT_FAILURE);
+ }
+ switch(pid = fork()) {
+ case -1:
+ perror("pkg_sign");
+ exit(EXIT_FAILURE);
+ case 0:
+ {
+ (void)close(fd[0]);
+ /* the child fills the pipe with copies of the passphrase.
+ Expect violent death when father exits.
+ */
+ printf("Child process %d stuffing passphrase in pipe:\n", getpid());
+ for(;;) {
+ char c = '\n';
+ (void)write(fd[1], p, strlen(p));
+ (void)write(fd[1], &c, 1);
+ putchar('.'); fflush(stdout);
+ }
+ }
+ default:
+ {
+ char buf[10];
+
+ sleep(1);
+ (void)close(fd[1]);
+ (void)sprintf(buf, "%d", fd[0]);
+ (void)setenv("PGPPASSFD", buf, 1);
+ printf("Parent process PGPPASSFD=%d.\n", fd[0]);
+ }
+ }
+}
+
diff --git a/usr.sbin/pkg_install/sign/pkg_sign.1 b/usr.sbin/pkg_install/sign/pkg_sign.1
new file mode 100644
index 0000000..b6d4c3e
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/pkg_sign.1
@@ -0,0 +1,186 @@
+.\" $FreeBSD$
+.\" $OpenBSD: pkg_sign.1,v 1.6 2000/04/15 02:15:20 aaron Exp $
+.\"
+.\" Copyright (c) 1999 Marc Espie.
+.\"
+.\" 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. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Marc Espie for the OpenBSD
+.\" Project.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+.\" ``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 OPENBSD
+.\" PROJECT OR CONTRIBUTORS 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 September 24, 1999
+.Dt PKG_SIGN 1
+.Os
+.Sh NAME
+.Nm pkg_sign ,
+.Nm check_sign
+.Nd handle package signatures
+.Sh SYNOPSIS
+.Nm pkg_sign
+.Op Fl sc
+.Op Fl t Ar type
+.Op Fl u Ar id
+.Op Fl k Ar key
+.Op Ar
+.Nm pkg_check
+.Op Fl sc
+.Op Fl u Ar id
+.Op Fl k Ar cert
+.Op Ar
+.Sh DESCRIPTION
+.Nm pkg_sign
+embeds a cryptographic signature within a gzip file
+.Ar file .
+.Ar type
+can be
+.Li pgp
+(default),
+.Li sha1 ,
+or
+.Li x509 .
+If
+.Ar type
+is
+.Li pgp ,
+it will always prompt you for a passphrase to unlock your private
+pgp key, even if you don't use a passphrase (which is a bad idea, anyway).
+If
+.Ar type
+is
+.Li sha1 ,
+you must supply an
+.Ar id ,
+which will be recorded as the name of the package, and printed as the
+SHA1 checksum.
+.Pp
+.Nm pkg_check
+checks that cryptographic signature.
+It currently disregards
+.Ar type
+and checks only the topmost signature.
+For sha1, it checksums the file
+and verifies that the result matches the list of checksums recorded in
+.Pa /var/db/pkg/SHA1 .
+.Pp
+Options
+.Fl s
+and
+.Fl c
+can be used to force package signing or signature checking mode.
+.Pp
+For pgp, the
+.Ar id
+to use to sign the package or verify the signature can be forced with
+.Fl u .
+.Pp
+For X.509, the signing key or verification certificate may be
+specified with the
+.Fl k
+option. If not specified, packages are signed or verified with the
+default keys and certificates documented below.
+.Pp
+If
+.Ar file
+is a single dash
+.Pq Sq \&-
+or absent,
+.Nm check_sign
+reads from the standard input.
+.Pp
+Package signing uses a feature of the gzip format, namely that one can
+set a flag
+.Dv EXTRA_FIELD
+in the gzip header and store extra data between the gzip header and the
+compressed file proper.
+The OpenBSD signing scheme uses eight bytes markers such `SIGPGP' \+ length
+or `CKSHA1' \+ length for its signatures (those markers are conveniently
+eight bytes long).
+.Sh RESULTS
+.Nm pkg_sign
+and
+.Nm pkg_check
+return with an exit code > 0 if anything went wrong for any
+.Ar file .
+For
+.Nm pkg_check ,
+this usually indicates that the package is not signed, or that the
+signature is forged.
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "File %s is already signed"
+There is a signature embedded within the gzip file already.
+.Nm pkg_sign
+currently does not handle multiple signatures.
+.It "File %s is not a signed gzip file"
+This is an unsigned package.
+.It "File %s is not a gzip file"
+The program couldn't find a proper gzip header.
+.It "File %s contains an unknown extension"
+The extended area of the gzip file has been used for an unknown purpose.
+.It "File %s uses old signatures, no longer supported"
+The gzip file uses a very early version of package signing that was
+substantially slower.
+.El
+.Sh BUGS
+.Xr pgp 1
+is an ill-designed program, which is hard to interface with.
+For instance, the `separate signing scheme' it pretends to offer is
+useless, as it can't be used with pipes, so that
+.Nm pgp_sign
+needs to kludge it by knowing the length of a pgp signature, and invoking
+pgp in `seamless' signature mode, without compression of the main file,
+and just retrieving the signature.
+.Pp
+The checking scheme is little less convoluted, namely we rebuild the file
+that pgp expects on the fly.
+.Pp
+Paths to
+.Nm pgp
+and
+the checksum file are hard-coded to avoid tampering and hinder flexibility.
+.Sh FILES
+.Bl -tag -width "/usr/local/bin/pgp" -compact
+.It Pa file.sign
+Temporary file built by
+.Nm pkg_sign
+from
+.Ar file .
+.It Pa /usr/local/bin/pgp
+Default path to
+.Xr pgp 1 .
+.It Pa /var/db/pkgs/SHA1
+Recorded checksums.
+.It Pa /etc/ssl/pkg.key
+Default package signing key.
+.It Pa /etc/ssl/pkg.crt
+Default package verification certificate(s).
+.El
+.Sh SEE ALSO
+.Xr gzip 1 ,
+.Xr pgp 1 ,
+.Xr pkg_add 1 ,
+.Xr sha1 1
+.Sh AUTHORS
+.Nm pkg_sign
+was created by Marc Espie for the OpenBSD Project. X.509 signatures
+and FreeBSD support added by Wes Peters <wes@softweyr.com>.
diff --git a/usr.sbin/pkg_install/sign/sha1.c b/usr.sbin/pkg_install/sign/sha1.c
new file mode 100644
index 0000000..c16eb02
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/sha1.c
@@ -0,0 +1,221 @@
+/* $FreeBSD$ */
+/* $OpenBSD: sha1.c,v 1.1 1999/10/04 21:46:29 espie Exp $ */
+/*-
+ * Copyright (c) 1999 Marc Espie.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Marc Espie for the OpenBSD
+ * Project.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+ * ``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 OPENBSD
+ * PROJECT OR CONTRIBUTORS 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 <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <openssl/sha.h>
+#include "stand.h"
+#include "gzip.h"
+#include "extern.h"
+
+/* private context for sha1 signature checker */
+struct sha1_checker {
+ SHA_CTX context;
+ const char *id;
+ const char *filename;
+};
+
+
+#define SHA1_TEMPLATE "SHA1 (%s) = "
+#define BUFSIZE (MAXID+sizeof(SHA1_TEMPLATE)+2*SHA_DIGEST_LENGTH+1)
+
+/* Finalize SHA1 checksum for our sha1_context into result
+ (size at least BUFSIZE). Returns the length of the checksum
+ marker, e.g., SHA1 (id) = xxxxxxxxx
+ ^here
+ Return 0 for errors.
+ */
+size_t
+sha1_build_checksum(result, n)
+ char *result;
+ struct sha1_checker *n;
+{
+ size_t length;
+
+ sprintf(result, "SHA1 (%s) = ", n->id);
+ length = strlen(result);
+ SHA1_Final(result + length, &n->context);
+ strcat(result, "\n");
+ free(n);
+ return length;
+}
+
+void *
+new_sha1_checker(h, sign, userid, envp, filename)
+ struct mygzip_header *h;
+ struct signature *sign;
+ const char *userid;
+ char *envp[];
+ /*@observer@*/const char *filename;
+{
+ struct sha1_checker *n;
+
+ assert(sign->type == TAG_SHA1);
+ /* make sure data conforms to what we can handle */
+ if (sign->length > MAXID || sign->data[sign->length-1] != '\0') {
+ warnx("Corrupted SHA1 header in %s", filename);
+ return 0;
+ }
+
+ n = malloc(sizeof *n);
+ if (n == NULL) {
+ warnx("Can't allocate sha1_checker");
+ return NULL;
+ }
+ SHA1_Init(&n->context);
+ n->id = sign->data;
+ n->filename = filename;
+
+ /* copy header, as this is a checksum, we don't strip our own marker */
+ if (gzip_copy_header(h, sign, sha1_add, n) == 0) {
+ warnx("Unexpected header in %s", filename);
+ free(n);
+ return 0;
+ }
+ return n;
+}
+
+void
+sha1_add(arg, buffer, length)
+ void *arg;
+ const char *buffer;
+ size_t length;
+{
+ struct sha1_checker *n = arg;
+ SHA1_Update(&n->context, buffer, length);
+}
+
+int
+sha1_sign_ok(arg)
+ void *arg;
+{
+ struct sha1_checker *n = arg;
+ char buffer[BUFSIZE];
+ char scan[BUFSIZE];
+ size_t length;
+ FILE *f;
+ int tag_found;
+
+ length = sha1_build_checksum(buffer, n);
+ f= fopen(SHA1_DB_NAME, "r");
+ tag_found = 0;
+
+ if (f == NULL) {
+ warn("Can't access checksum file %s", SHA1_DB_NAME);
+ return PKG_BADSIG;
+ }
+ while (fgets(scan, sizeof(scan), f) != NULL) {
+ if (strcmp(scan, buffer) == 0) {
+ fprintf(stderr, "Checksum ok\n");
+ return PKG_GOODSIG;
+ }
+ if (strncmp(scan, buffer, length) == 0)
+ tag_found = 1;
+ }
+
+ if (tag_found) {
+ warnx("Checksum incorrect for %s (%s)", n->filename, n->id);
+ return PKG_BADSIG;
+ } else {
+ warnx("No checksum found for %s (%s)", n->filename, n->id);
+ return PKG_SIGUNKNOWN;
+ }
+}
+
+int
+retrieve_sha1_marker(filename, sign, userid)
+ const char *filename;
+ struct signature **sign;
+ const char *userid;
+{
+ struct signature *n;
+ struct mygzip_header h;
+ FILE *f;
+ char buffer[1024];
+ char result[BUFSIZE];
+ ssize_t length;
+ struct sha1_checker *checker;
+ struct signature *old;
+
+ *sign = NULL;
+ if (userid == NULL)
+ return 0;
+
+ /*
+ * Create a blank signature and fill it with the userid.
+ */
+ n = malloc(sizeof *n);
+ if (n == NULL)
+ return 0;
+ n->data = (char *)userid;
+ n->length = strlen(n->data)+1;
+ n->type = TAG_SHA1;
+ memcpy(n->tag, sha1tag, sizeof sha1tag);
+ sign_fill_tag(n);
+
+ /*
+ * Read the gzip header and add our "userid" signature to it.
+ */
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ free(n);
+ return 0;
+ }
+ if (gzip_read_header(f, &h, sign) == GZIP_NOT_GZIP) {
+ warnx("File %s is not a gzip file\n", filename);
+ fclose(f);
+ free(n);
+ return 0;
+ }
+ n->next = *sign;
+ *sign = n;
+
+ /*
+ * Calculate the SHA1 of the remaining data and write it to stderr.
+ */
+ checker = new_sha1_checker(&h, *sign, NULL, NULL, filename);
+ while ((length = fread(buffer, 1, sizeof buffer, f)) > 0)
+ sha1_add(checker, buffer, length);
+ if (fclose(f) != 0 || length == -1) {
+ warn("Problem checksumming %s", filename);
+ *sign = n->next;
+ free(n);
+ return 0;
+ }
+
+ (void)sha1_build_checksum(result, checker);
+ fputs(result, stderr);
+ return 1;
+}
+
diff --git a/usr.sbin/pkg_install/sign/sign.c b/usr.sbin/pkg_install/sign/sign.c
new file mode 100644
index 0000000..1bcbcf5
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/sign.c
@@ -0,0 +1,142 @@
+/* $FreeBSD$ */
+/* $OpenBSD: sign.c,v 1.3 1999/10/04 21:46:29 espie Exp $ */
+/*-
+ * Copyright (c) 1999 Marc Espie.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Marc Espie for the OpenBSD
+ * Project.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
+ * ``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 OPENBSD
+ * PROJECT OR CONTRIBUTORS 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 <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <pwd.h>
+#include <assert.h>
+#include "stand.h"
+#include "pgp.h"
+#include "gzip.h"
+#include "extern.h"
+
+#define COPY_TEMPLATE "%s.sign"
+
+static int
+embed_signature_FILE(orig, dest, sign, filename)
+ /*@temp@*/FILE *orig;
+ /*@temp@*/FILE *dest;
+ struct signature *sign;
+ const char *filename;
+{
+ struct mygzip_header h;
+ int c;
+
+ if (gzip_read_header(orig, &h, NULL) == GZIP_NOT_GZIP)
+ return 0;
+
+ if (gzip_write_header(dest, &h, sign) == 0)
+ return 0;
+ while ((c = fgetc(orig)) != EOF && fputc(c, dest) != EOF)
+ ;
+ if (ferror(dest) != 0)
+ return 0;
+ return 1;
+}
+
+static int
+embed_signature(filename, copy, sign)
+ const char *filename;
+ const char *copy;
+ struct signature *sign;
+{
+ FILE *orig, *dest;
+ int success;
+
+ success = 0;
+ orig= fopen(filename, "r");
+ if (orig) {
+ dest = fopen(copy, "w");
+ if (dest) {
+ success = embed_signature_FILE(orig, dest, sign, filename);
+ if (fclose(dest) != 0)
+ success = 0;
+ }
+ if (fclose(orig) != 0)
+ success = 0;
+ }
+ return success;
+}
+
+int
+sign(filename, type, userid, envp)
+ const char *filename;
+ const char *userid;
+ int type;
+ char *envp[];
+{
+ char *copy;
+ int result;
+ struct signature *sign;
+ int success;
+
+ switch(type) {
+ case TAG_PGP:
+ success = retrieve_pgp_signature(filename, &sign, userid, envp);
+ break;
+ case TAG_SHA1:
+ success = retrieve_sha1_marker(filename, &sign, userid);
+ break;
+ case TAG_X509:
+ success = retrieve_x509_marker(filename, &sign, userid);
+ break;
+ }
+
+ if (!success) {
+ fprintf(stderr, "Problem signing %s\n", filename);
+ free_signature(sign);
+ return 0;
+ }
+ copy = malloc(strlen(filename)+sizeof(COPY_TEMPLATE));
+ if (copy == NULL) {
+ fprintf(stderr, "Can't allocate memory\n");
+ free_signature(sign);
+ return 0;
+ }
+ sprintf(copy, COPY_TEMPLATE, filename);
+ result = embed_signature(filename, copy, sign);
+ if (result == 0) {
+ fprintf(stderr, "Can't embed signature in %s\n", filename);
+ } else if (unlink(filename) != 0) {
+ fprintf(stderr, "Can't unlink original %s\n", filename);
+ result = 0;
+ } else if (rename(copy, filename) != 0) {
+ fprintf(stderr, "Can't rename new file %s\n", copy);
+ result = 0;
+ }
+ free(copy);
+ free_signature(sign);
+ return result;
+}
+
diff --git a/usr.sbin/pkg_install/sign/stand.c b/usr.sbin/pkg_install/sign/stand.c
new file mode 100644
index 0000000..7fa84d2
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/stand.c
@@ -0,0 +1,56 @@
+/* $FreeBSD$ */
+
+#include "stand.h"
+
+#ifdef BSD4_4
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+
+/* shortened version of warn */
+static const char *program_name;
+
+void
+set_program_name(n)
+ const char *n;
+{
+ if ((program_name = strrchr(n, '/')) != NULL)
+ program_name++;
+ else
+ program_name = n;
+}
+
+void
+warn(const char *fmt, ...)
+{
+ va_list ap;
+ int interrno;
+
+ va_start(ap, fmt);
+
+ interrno = errno;
+ (void)fprintf(stderr, "%s: ", program_name);
+ if (fmt != NULL) {
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fprintf(stderr, ": ");
+ }
+ (void)fprintf(stderr, "%s\n", strerror(interrno));
+
+ va_end(ap);
+}
+
+void
+warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void)fprintf(stderr, "%s: ", program_name);
+ if (fmt != NULL)
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fprintf(stderr, "\n");
+ va_end(ap);
+}
+
+#endif
diff --git a/usr.sbin/pkg_install/sign/stand.h b/usr.sbin/pkg_install/sign/stand.h
new file mode 100644
index 0000000..bc8de2f
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/stand.h
@@ -0,0 +1,28 @@
+/* $FreeBSD$ */
+/* $OpenBSD: stand.h,v 1.2 1999/10/04 21:46:30 espie Exp $ */
+
+/* provided to cater for BSD idiosyncrasies */
+
+#if (defined(__unix__) || defined(unix)) && !defined(USG)
+#include <sys/param.h>
+#endif
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+#endif
+
+#if defined(BSD4_4)
+#include <err.h>
+#else
+extern void set_program_name __P((const char * name));
+extern void warn __P((const char *fmt, ...));
+extern void warnx __P((const char *fmt, ...));
+#endif
+
+#ifndef __GNUC__
+#define __attribute__(x)
+#endif
diff --git a/usr.sbin/pkg_install/sign/x509.c b/usr.sbin/pkg_install/sign/x509.c
new file mode 100644
index 0000000..27ab10a
--- /dev/null
+++ b/usr.sbin/pkg_install/sign/x509.c
@@ -0,0 +1,424 @@
+/* $FreeBSD$ */
+/*-
+ * Copyright (c) 2000 Softweyr LLC, South Jordan, Utah, USA.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Softweyr LLC ``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 Softweyr LLC 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 <sys/types.h>
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+
+#include "stand.h"
+#include "gzip.h"
+#include "extern.h"
+
+
+/*
+ * Default names for the signing key and certificate(s) for verification.
+ */
+#define CERTFILE "/etc/ssl/pkg.crt"
+#define KEYFILE "/etc/ssl/pkg.key"
+
+
+/*
+ * Private context for X.509 signature checker
+ */
+struct x509_checker
+{
+ const char * id;
+ const char * filename;
+
+ struct signature * signature;
+
+ STACK_OF(X509) * certs;
+ EVP_MD_CTX rsa_ctx, dsa_ctx;
+ int has_rsa, has_dsa;
+};
+
+
+static void key_from_name(char *, const char *);
+
+/*
+ * Initialize an X.509 "checker" context.
+ */
+void *
+new_x509_checker(h, sign, userid, envp, filename)
+ struct mygzip_header *h;
+ struct signature *sign;
+ const char *userid;
+ char *envp[];
+ /*@observer@*/const char *filename;
+{
+ FILE * fp;
+ struct x509_checker * me;
+ char certfile[PATH_MAX + 1] = CERTFILE;
+ char * cp;
+ X509 * x509;
+
+ assert(sign->type == TAG_X509);
+
+ /*
+ * Make sure data conforms to what we can handle. We do not write a
+ * trailing null onto the signature like some other types, because
+ * the X.509 signature is binary data.
+ */
+ if (sign->length > MAXID) {
+ warnx("Corrupted X.509 header in %s", filename);
+ return 0;
+ }
+
+ me = malloc(sizeof *me);
+ if (me == NULL) {
+ warn("Cannot allocate x509_checker");
+ return 0;
+ }
+ me->id = sign->data;
+ me->filename = filename;
+ me->signature = sign;
+ me->has_rsa = 0;
+ me->has_dsa = 0;
+
+ key_from_name(certfile, userkey);
+
+ /*
+ * Load just the crypto library error strings.
+ */
+ ERR_load_crypto_strings();
+
+ /*
+ * Load the stack of X.509 certs we will compare against.
+ *
+ * KLUDGE: this needs to be fleshed out a bit. We can do better
+ * than hard-coding the location of the cert key file.
+ */
+ me->certs = sk_X509_new_null();
+
+ fp = fopen(certfile, "r");
+ if (fp == NULL) {
+ warnx("Cannot open public key %s", certfile);
+ return 0;
+ }
+
+ if (verbose)
+ printf("Loading certificates from %s:\n", certfile);
+
+ while (x509 = PEM_read_X509(fp, NULL, NULL, 0)) {
+ sk_X509_push(me->certs, x509);
+
+ switch (EVP_PKEY_type(X509_get_pubkey(x509)->type))
+ {
+ case EVP_PKEY_RSA:
+ me->has_rsa = 1;
+ break;
+
+ case EVP_PKEY_DSA:
+ me->has_dsa = 1;
+ break;
+
+ default:
+ warnx("Uknown certificate type");
+ return 0;
+ }
+
+ /*
+ * By default, print the contents of the cert we matched so the
+ * user can decide if she is willing to accept a package from
+ * whoever signed this.
+ */
+ if (!quiet)
+ X509_print_fp(stdout, x509);
+ }
+ fclose(fp);
+
+ /*
+ * Initialize the verification contexts for both RSA and DSA.
+ */
+ if (me->has_rsa) EVP_VerifyInit(&me->rsa_ctx, EVP_sha1());
+ if (me->has_dsa) EVP_VerifyInit(&me->dsa_ctx, EVP_dss1());
+
+ return me;
+}
+
+
+/*
+ * "Add" another data block to an existing checker.
+ */
+void
+x509_add(arg, buffer, length)
+ void *arg;
+ const char *buffer;
+ size_t length;
+{
+ struct x509_checker * me = arg;
+
+ if (me->has_rsa) EVP_VerifyUpdate(&me->rsa_ctx, buffer, length);
+ if (me->has_dsa) EVP_VerifyUpdate(&me->dsa_ctx, buffer, length);
+}
+
+
+/*
+ * Finalize an existing checker and verify the signature matches one of the
+ * certs in our stack.
+ */
+int
+x509_sign_ok(arg)
+ void *arg;
+{
+ struct x509_checker * n = arg;
+ X509 * x509;
+ EVP_PKEY * pkey;
+ EVP_MD_CTX * md_ctx;
+ int status;
+
+ if (verbose)
+ printf("\n\n-------\n\nChecking package signature:\n");
+
+ while ((x509 = sk_X509_pop(n->certs)) != NULL) {
+ /*
+ * Get public key from cert.
+ */
+ pkey = X509_get_pubkey(x509);
+ if (pkey == NULL) {
+ warnx("Getting public key:");
+ ERR_print_errors_fp(stderr);
+ continue;
+ }
+
+ if (verbose)
+ X509_print_fp(stdout, x509);
+
+ switch (EVP_PKEY_type(pkey->type))
+ {
+ case EVP_PKEY_RSA:
+ md_ctx = &n->rsa_ctx;
+ break;
+
+ case EVP_PKEY_DSA:
+ md_ctx = &n->dsa_ctx;
+ break;
+
+ default:
+ }
+
+ status = EVP_VerifyFinal(md_ctx,
+ n->signature->data,
+ n->signature->length,
+ pkey);
+
+ EVP_PKEY_free(pkey);
+ X509_free(x509);
+
+ if (status == 1) {
+ fprintf(stderr, "X.509 signature matched\n");
+
+ /*
+ * KLUDGE: Does this free the rest of the certs, or just the
+ * stack itself? Enquiring minds want to know.
+ */
+ sk_X509_free(n->certs);
+ return PKG_GOODSIG;
+ }
+ }
+
+ warnx("Verifying signature:");
+ ERR_print_errors_fp(stderr);
+ sk_X509_free(n->certs);
+ return PKG_BADSIG;
+}
+
+
+/*
+ * Sign the specified filename into sign.
+ */
+int
+retrieve_x509_marker(filename, sign, userid)
+ const char * filename;
+ struct signature ** sign;
+ const char * userid;
+{
+ struct signature * n;
+ struct mygzip_header h;
+ FILE * f, * keyf;
+ char buffer[1024];
+ ssize_t length;
+ int err;
+ int sig_len = 4096;
+ unsigned char * sig_buf;
+ EVP_MD_CTX md_ctx;
+ EVP_MD * md_type;
+ EVP_PKEY * pkey;
+
+ char keyfile[PATH_MAX + 1] = KEYFILE;
+ char * kp;
+
+ key_from_name(keyfile, userkey);
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ free(n);
+ return 0;
+ }
+ if (gzip_read_header(f, &h, sign) == GZIP_NOT_GZIP) {
+ warnx("File %s is not a gzip file\n", filename);
+ fclose(f);
+ free(n);
+ return 0;
+ }
+
+ /*
+ * Sign the remaining data:
+ * Load just the crypto library error strings.
+ */
+ ERR_load_crypto_strings();
+
+ /*
+ * Read private key.
+ */
+ keyf = fopen(keyfile, "r");
+ if (keyf == NULL)
+ {
+ warnx("Cannot open private key %s.", keyfile);
+ return 0;
+ }
+
+ pkey = PEM_read_PrivateKey(keyf, NULL, NULL, 0);
+ fclose(keyf);
+
+ if (pkey == NULL)
+ {
+ warnx("Reading private key %s:", keyfile);
+ ERR_print_errors_fp(stderr);
+ return 0;
+ }
+
+ /*
+ * Do the signature. The remaining bytes of the GZIP file are the
+ * compressed tar image, which is what we are signing.
+ */
+ switch (EVP_PKEY_type(pkey->type))
+ {
+ case EVP_PKEY_RSA:
+ md_type = EVP_sha1();
+printf("*** It's an RSA key.\n");
+ break;
+
+ case EVP_PKEY_DSA:
+ md_type = EVP_dss1();
+printf("@@@ It's a DSA key, yippee!\n");
+ break;
+
+ default:
+ warnx("Uknown key type");
+ return 0;
+ }
+
+ EVP_SignInit(&md_ctx, md_type);
+
+ while ((length = fread(buffer, 1, sizeof buffer, f)) > 0)
+ EVP_SignUpdate(&md_ctx, buffer, length);
+
+ sig_buf = malloc(sig_len);
+ if (sig_buf == NULL) {
+ warnx("Cannot allocated %u bytes for signature buffer", sig_len);
+ return 0;
+ }
+
+ err = EVP_SignFinal(&md_ctx, sig_buf, &sig_len, pkey);
+
+ if (err != 1)
+ {
+ warnx("Creating signature:");
+ ERR_print_errors_fp(stderr);
+ return 0;
+ }
+
+ EVP_PKEY_free(pkey);
+
+ /*
+ * Stuff the signature onto the head of the chain of signatures in
+ * the package.
+ */
+ n = malloc(sizeof *n);
+ if (n == NULL) {
+ warnx("Cannot allocate %u bytes for new signature", sizeof *n);
+ return 0;
+ }
+ n->data = sig_buf;
+ n->length = sig_len;
+ n->type = TAG_X509;
+ memcpy(n->tag, x509tag, sizeof x509tag);
+ sign_fill_tag(n);
+ n->next = *sign;
+ *sign = n;
+
+ /*
+ * Report our success.
+ */
+ return 1;
+}
+
+
+static void
+key_from_name(char * filename, const char * ident)
+{
+ char * cp;
+
+ /*
+ * If an alternate keyfile was specified, treat it as the name of an
+ * alternate private key with which to sign or verify the package.
+ */
+ if (ident) {
+ printf("Using alternate key/cert \"%s\".\n", ident);
+ if (strchr(ident, '/')) {
+ /*
+ * The user specified a path, take it verbatim.
+ */
+ strncpy(filename, ident, PATH_MAX);
+ } else {
+ cp = dirname(filename);
+ if (cp == NULL) {
+ warnx("Key directory not correctly specified.");
+ return;
+ }
+ snprintf(filename, PATH_MAX, "%s/%s", cp, ident);
+ }
+ }
+
+ if (verbose)
+ printf("Key is \"%s\".\n", filename);
+}
OpenPOWER on IntegriCloud