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.
This commit is contained in:
wes 2001-02-06 06:46:42 +00:00
parent b056d4c773
commit 7f8fcc0b1f
17 changed files with 2514 additions and 0 deletions

View File

@ -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>

View File

@ -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$

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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));

View File

@ -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;
}
}

View File

@ -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];

View File

@ -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);
}

View File

@ -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[]));

View File

@ -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;
}

View File

@ -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]);
}
}
}

View File

@ -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>.

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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);
}