2 * Copyright (c) 2000 Softweyr LLC, South Jordan, Utah, USA.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY Softweyr LLC ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL Softweyr LLC BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: src/usr.sbin/pkg_install/sign/x509.c,v 1.1.2.2 2002/08/20 06:35:08 obrien Exp $
27 * $DragonFly: src/usr.sbin/pkg_install/sign/Attic/x509.c,v 1.2 2003/06/17 04:29:59 dillon Exp $
30 #include <sys/types.h>
40 #include <openssl/rsa.h>
41 #include <openssl/evp.h>
42 #include <openssl/objects.h>
43 #include <openssl/x509.h>
44 #include <openssl/err.h>
45 #include <openssl/pem.h>
46 #include <openssl/ssl.h>
54 * Default names for the signing key and certificate(s) for verification.
56 #define CERTFILE "/etc/ssl/pkg.crt"
57 #define KEYFILE "/etc/ssl/pkg.key"
61 * Private context for X.509 signature checker
66 const char * filename;
68 struct signature * signature;
70 STACK_OF(X509) * certs;
71 EVP_MD_CTX rsa_ctx, dsa_ctx;
76 static void key_from_name(char *, const char *);
79 * Initialize an X.509 "checker" context.
82 new_x509_checker(h, sign, userid, envp, filename)
83 struct mygzip_header *h;
84 struct signature *sign;
87 /*@observer@*/const char *filename;
90 struct x509_checker * me;
91 char certfile[PATH_MAX + 1] = CERTFILE;
95 assert(sign->type == TAG_X509);
98 * Make sure data conforms to what we can handle. We do not write a
99 * trailing null onto the signature like some other types, because
100 * the X.509 signature is binary data.
102 if (sign->length > MAXID) {
103 warnx("Corrupted X.509 header in %s", filename);
107 me = malloc(sizeof *me);
109 warn("Cannot allocate x509_checker");
113 me->filename = filename;
114 me->signature = sign;
118 key_from_name(certfile, userkey);
121 * Load just the crypto library error strings.
123 ERR_load_crypto_strings();
126 * Load the stack of X.509 certs we will compare against.
128 * KLUDGE: this needs to be fleshed out a bit. We can do better
129 * than hard-coding the location of the cert key file.
131 me->certs = sk_X509_new_null();
133 fp = fopen(certfile, "r");
135 warnx("Cannot open public key %s", certfile);
140 printf("Loading certificates from %s:\n", certfile);
142 while (x509 = PEM_read_X509(fp, NULL, NULL, 0)) {
143 sk_X509_push(me->certs, x509);
145 switch (EVP_PKEY_type(X509_get_pubkey(x509)->type))
156 warnx("Uknown certificate type");
161 * By default, print the contents of the cert we matched so the
162 * user can decide if she is willing to accept a package from
163 * whoever signed this.
166 X509_print_fp(stdout, x509);
171 * Initialize the verification contexts for both RSA and DSA.
173 if (me->has_rsa) EVP_VerifyInit(&me->rsa_ctx, EVP_sha1());
174 if (me->has_dsa) EVP_VerifyInit(&me->dsa_ctx, EVP_dss1());
181 * "Add" another data block to an existing checker.
184 x509_add(arg, buffer, length)
189 struct x509_checker * me = arg;
191 if (me->has_rsa) EVP_VerifyUpdate(&me->rsa_ctx, buffer, length);
192 if (me->has_dsa) EVP_VerifyUpdate(&me->dsa_ctx, buffer, length);
197 * Finalize an existing checker and verify the signature matches one of the
198 * certs in our stack.
204 struct x509_checker * n = arg;
211 printf("\n\n-------\n\nChecking package signature:\n");
213 while ((x509 = sk_X509_pop(n->certs)) != NULL) {
215 * Get public key from cert.
217 pkey = X509_get_pubkey(x509);
219 warnx("Getting public key:");
220 ERR_print_errors_fp(stderr);
225 X509_print_fp(stdout, x509);
227 switch (EVP_PKEY_type(pkey->type))
230 md_ctx = &n->rsa_ctx;
234 md_ctx = &n->dsa_ctx;
240 status = EVP_VerifyFinal(md_ctx,
242 n->signature->length,
249 fprintf(stderr, "X.509 signature matched\n");
252 * KLUDGE: Does this free the rest of the certs, or just the
253 * stack itself? Enquiring minds want to know.
255 sk_X509_free(n->certs);
260 warnx("Verifying signature:");
261 ERR_print_errors_fp(stderr);
262 sk_X509_free(n->certs);
268 * Sign the specified filename into sign.
271 retrieve_x509_marker(filename, sign, userid)
272 const char * filename;
273 struct signature ** sign;
276 struct signature * n;
277 struct mygzip_header h;
283 unsigned char * sig_buf;
288 char keyfile[PATH_MAX + 1] = KEYFILE;
291 key_from_name(keyfile, userkey);
293 f = fopen(filename, "r");
298 if (gzip_read_header(f, &h, sign) == GZIP_NOT_GZIP) {
299 warnx("File %s is not a gzip file\n", filename);
306 * Sign the remaining data:
307 * Load just the crypto library error strings.
309 ERR_load_crypto_strings();
314 keyf = fopen(keyfile, "r");
317 warnx("Cannot open private key %s.", keyfile);
321 pkey = PEM_read_PrivateKey(keyf, NULL, NULL, 0);
326 warnx("Reading private key %s:", keyfile);
327 ERR_print_errors_fp(stderr);
332 * Do the signature. The remaining bytes of the GZIP file are the
333 * compressed tar image, which is what we are signing.
335 switch (EVP_PKEY_type(pkey->type))
338 md_type = EVP_sha1();
339 printf("*** It's an RSA key.\n");
343 md_type = EVP_dss1();
344 printf("@@@ It's a DSA key, yippee!\n");
348 warnx("Uknown key type");
352 EVP_SignInit(&md_ctx, md_type);
354 while ((length = fread(buffer, 1, sizeof buffer, f)) > 0)
355 EVP_SignUpdate(&md_ctx, buffer, length);
357 sig_buf = malloc(sig_len);
358 if (sig_buf == NULL) {
359 warnx("Cannot allocated %u bytes for signature buffer", sig_len);
363 err = EVP_SignFinal(&md_ctx, sig_buf, &sig_len, pkey);
367 warnx("Creating signature:");
368 ERR_print_errors_fp(stderr);
375 * Stuff the signature onto the head of the chain of signatures in
378 n = malloc(sizeof *n);
380 warnx("Cannot allocate %u bytes for new signature", sizeof *n);
386 memcpy(n->tag, x509tag, sizeof x509tag);
392 * Report our success.
399 key_from_name(char * filename, const char * ident)
404 * If an alternate keyfile was specified, treat it as the name of an
405 * alternate private key with which to sign or verify the package.
408 printf("Using alternate key/cert \"%s\".\n", ident);
409 if (strchr(ident, '/')) {
411 * The user specified a path, take it verbatim.
413 strncpy(filename, ident, PATH_MAX);
415 cp = dirname(filename);
417 warnx("Key directory not correctly specified.");
420 snprintf(filename, PATH_MAX, "%s/%s", cp, ident);
425 printf("Key is \"%s\".\n", filename);