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:
parent
b056d4c773
commit
7f8fcc0b1f
14
usr.sbin/pkg_install/sign/Makefile
Normal file
14
usr.sbin/pkg_install/sign/Makefile
Normal 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>
|
||||
|
55
usr.sbin/pkg_install/sign/README
Normal file
55
usr.sbin/pkg_install/sign/README
Normal 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$
|
117
usr.sbin/pkg_install/sign/check.c
Normal file
117
usr.sbin/pkg_install/sign/check.c
Normal 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;
|
||||
}
|
||||
|
88
usr.sbin/pkg_install/sign/common.c
Normal file
88
usr.sbin/pkg_install/sign/common.c
Normal 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;
|
||||
}
|
||||
|
99
usr.sbin/pkg_install/sign/extern.h
Normal file
99
usr.sbin/pkg_install/sign/extern.h
Normal 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));
|
315
usr.sbin/pkg_install/sign/gzip.c
Normal file
315
usr.sbin/pkg_install/sign/gzip.c
Normal 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;
|
||||
}
|
||||
}
|
92
usr.sbin/pkg_install/sign/gzip.h
Normal file
92
usr.sbin/pkg_install/sign/gzip.h
Normal 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];
|
183
usr.sbin/pkg_install/sign/main.c
Normal file
183
usr.sbin/pkg_install/sign/main.c
Normal 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);
|
||||
}
|
25
usr.sbin/pkg_install/sign/pgp.h
Normal file
25
usr.sbin/pkg_install/sign/pgp.h
Normal 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[]));
|
194
usr.sbin/pkg_install/sign/pgp_check.c
Normal file
194
usr.sbin/pkg_install/sign/pgp_check.c
Normal 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;
|
||||
}
|
275
usr.sbin/pkg_install/sign/pgp_sign.c
Normal file
275
usr.sbin/pkg_install/sign/pgp_sign.c
Normal 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
186
usr.sbin/pkg_install/sign/pkg_sign.1
Normal file
186
usr.sbin/pkg_install/sign/pkg_sign.1
Normal 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>.
|
221
usr.sbin/pkg_install/sign/sha1.c
Normal file
221
usr.sbin/pkg_install/sign/sha1.c
Normal 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;
|
||||
}
|
||||
|
142
usr.sbin/pkg_install/sign/sign.c
Normal file
142
usr.sbin/pkg_install/sign/sign.c
Normal 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;
|
||||
}
|
||||
|
56
usr.sbin/pkg_install/sign/stand.c
Normal file
56
usr.sbin/pkg_install/sign/stand.c
Normal 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
|
28
usr.sbin/pkg_install/sign/stand.h
Normal file
28
usr.sbin/pkg_install/sign/stand.h
Normal 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
|
424
usr.sbin/pkg_install/sign/x509.c
Normal file
424
usr.sbin/pkg_install/sign/x509.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user