Create defaults/uuids and adjust the build to copy the file to /etc/defaults
[dragonfly/vkernel-mp.git] / usr.sbin / pkg_install / sign / x509.c
blob588a520a734ad8a5e0577cea03dd886a44b1755d
1 /*-
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
6 * are met:
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.4 2004/06/29 19:06:42 eik Exp $
27 * $DragonFly: src/usr.sbin/pkg_install/sign/x509.c,v 1.4 2004/07/30 06:46:14 dillon Exp $
30 #include <sys/types.h>
31 #include <sys/wait.h>
33 #include <assert.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <libgen.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>
48 #include "stand.h"
49 #include "gzip.h"
50 #include "extern.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
63 struct x509_checker
65 const char * id;
66 const char * filename;
68 struct signature * signature;
70 STACK_OF(X509) * certs;
71 EVP_MD_CTX rsa_ctx, dsa_ctx;
72 int has_rsa, has_dsa;
76 static void key_from_name(char *, const char *);
79 * Initialize an X.509 "checker" context.
81 void *
82 new_x509_checker(h, sign, userid, envp, filename)
83 struct mygzip_header *h;
84 struct signature *sign;
85 const char *userid;
86 char *envp[];
87 /*@observer@*/const char *filename;
89 FILE * fp;
90 struct x509_checker * me;
91 char certfile[PATH_MAX + 1] = CERTFILE;
92 X509 * x509;
94 assert(sign->type == TAG_X509);
97 * Make sure data conforms to what we can handle. We do not write a
98 * trailing null onto the signature like some other types, because
99 * the X.509 signature is binary data.
101 if (sign->length > MAXID) {
102 warnx("Corrupted X.509 header in %s", filename);
103 return 0;
106 me = malloc(sizeof *me);
107 if (me == NULL) {
108 warn("Cannot allocate x509_checker");
109 return 0;
111 me->id = sign->data;
112 me->filename = filename;
113 me->signature = sign;
114 me->has_rsa = 0;
115 me->has_dsa = 0;
117 key_from_name(certfile, userkey);
120 * Load just the crypto library error strings.
122 ERR_load_crypto_strings();
125 * Load the stack of X.509 certs we will compare against.
127 * KLUDGE: this needs to be fleshed out a bit. We can do better
128 * than hard-coding the location of the cert key file.
130 me->certs = sk_X509_new_null();
132 fp = fopen(certfile, "r");
133 if (fp == NULL) {
134 warnx("Cannot open public key %s", certfile);
135 return 0;
138 if (verbose)
139 printf("Loading certificates from %s:\n", certfile);
141 while ((x509 = PEM_read_X509(fp, NULL, NULL, 0))) {
142 sk_X509_push(me->certs, x509);
144 switch (EVP_PKEY_type(X509_get_pubkey(x509)->type))
146 case EVP_PKEY_RSA:
147 me->has_rsa = 1;
148 break;
150 case EVP_PKEY_DSA:
151 me->has_dsa = 1;
152 break;
154 default:
155 warnx("Uknown certificate type");
156 return 0;
160 * By default, print the contents of the cert we matched so the
161 * user can decide if she is willing to accept a package from
162 * whoever signed this.
164 if (!quiet)
165 X509_print_fp(stdout, x509);
167 fclose(fp);
170 * Initialize the verification contexts for both RSA and DSA.
172 if (me->has_rsa) EVP_VerifyInit(&me->rsa_ctx, EVP_sha1());
173 if (me->has_dsa) EVP_VerifyInit(&me->dsa_ctx, EVP_dss1());
175 return me;
180 * "Add" another data block to an existing checker.
182 void
183 x509_add(arg, buffer, length)
184 void *arg;
185 const char *buffer;
186 size_t length;
188 struct x509_checker * me = arg;
190 if (me->has_rsa) EVP_VerifyUpdate(&me->rsa_ctx, buffer, length);
191 if (me->has_dsa) EVP_VerifyUpdate(&me->dsa_ctx, buffer, length);
196 * Finalize an existing checker and verify the signature matches one of the
197 * certs in our stack.
200 x509_sign_ok(arg)
201 void *arg;
203 struct x509_checker * n = arg;
204 X509 * x509;
205 EVP_PKEY * pkey;
206 EVP_MD_CTX * md_ctx;
207 int status;
209 if (verbose)
210 printf("\n\n-------\n\nChecking package signature:\n");
212 while ((x509 = sk_X509_pop(n->certs)) != NULL) {
214 * Get public key from cert.
216 pkey = X509_get_pubkey(x509);
217 if (pkey == NULL) {
218 warnx("Getting public key:");
219 ERR_print_errors_fp(stderr);
220 continue;
223 if (verbose)
224 X509_print_fp(stdout, x509);
226 switch (EVP_PKEY_type(pkey->type))
228 case EVP_PKEY_RSA:
229 md_ctx = &n->rsa_ctx;
230 break;
232 case EVP_PKEY_DSA:
233 md_ctx = &n->dsa_ctx;
234 break;
236 default:
237 break;
240 status = EVP_VerifyFinal(md_ctx,
241 n->signature->data,
242 n->signature->length,
243 pkey);
245 EVP_PKEY_free(pkey);
246 X509_free(x509);
248 if (status == 1) {
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);
256 return PKG_GOODSIG;
260 warnx("Verifying signature:");
261 ERR_print_errors_fp(stderr);
262 sk_X509_free(n->certs);
263 return PKG_BADSIG;
268 * Sign the specified filename into sign.
270 int
271 retrieve_x509_marker(filename, sign, userid)
272 const char * filename;
273 struct signature ** sign;
274 const char * userid;
276 struct signature * n;
277 struct mygzip_header h;
278 FILE * f, * keyf;
279 char buffer[1024];
280 ssize_t length;
281 int err;
282 int sig_len = 4096;
283 unsigned char * sig_buf;
284 EVP_MD_CTX md_ctx;
285 const EVP_MD * md_type;
286 EVP_PKEY * pkey;
288 char keyfile[PATH_MAX + 1] = KEYFILE;
290 key_from_name(keyfile, userkey);
292 f = fopen(filename, "r");
293 if (f == NULL) {
294 free(n);
295 return 0;
297 if (gzip_read_header(f, &h, sign) == GZIP_NOT_GZIP) {
298 warnx("File %s is not a gzip file\n", filename);
299 fclose(f);
300 free(n);
301 return 0;
305 * Sign the remaining data:
306 * Load just the crypto library error strings.
308 ERR_load_crypto_strings();
311 * Read private key.
313 keyf = fopen(keyfile, "r");
314 if (keyf == NULL)
316 warnx("Cannot open private key %s.", keyfile);
317 return 0;
320 pkey = PEM_read_PrivateKey(keyf, NULL, NULL, 0);
321 fclose(keyf);
323 if (pkey == NULL)
325 warnx("Reading private key %s:", keyfile);
326 ERR_print_errors_fp(stderr);
327 return 0;
331 * Do the signature. The remaining bytes of the GZIP file are the
332 * compressed tar image, which is what we are signing.
334 switch (EVP_PKEY_type(pkey->type))
336 case EVP_PKEY_RSA:
337 md_type = EVP_sha1();
338 printf("*** It's an RSA key.\n");
339 break;
341 case EVP_PKEY_DSA:
342 md_type = EVP_dss1();
343 printf("@@@ It's a DSA key, yippee!\n");
344 break;
346 default:
347 warnx("Uknown key type");
348 return 0;
351 EVP_SignInit(&md_ctx, md_type);
353 while ((length = fread(buffer, 1, sizeof buffer, f)) > 0)
354 EVP_SignUpdate(&md_ctx, buffer, length);
356 sig_buf = malloc(sig_len);
357 if (sig_buf == NULL) {
358 warnx("Cannot allocated %u bytes for signature buffer", sig_len);
359 return 0;
362 err = EVP_SignFinal(&md_ctx, sig_buf, &sig_len, pkey);
364 if (err != 1)
366 warnx("Creating signature:");
367 ERR_print_errors_fp(stderr);
368 return 0;
371 EVP_PKEY_free(pkey);
374 * Stuff the signature onto the head of the chain of signatures in
375 * the package.
377 n = malloc(sizeof *n);
378 if (n == NULL) {
379 warnx("Cannot allocate %u bytes for new signature", sizeof *n);
380 return 0;
382 n->data = sig_buf;
383 n->length = sig_len;
384 n->type = TAG_X509;
385 memcpy(n->tag, x509tag, sizeof x509tag);
386 sign_fill_tag(n);
387 n->next = *sign;
388 *sign = n;
391 * Report our success.
393 return 1;
397 static void
398 key_from_name(char * filename, const char * ident)
400 char * cp;
403 * If an alternate keyfile was specified, treat it as the name of an
404 * alternate private key with which to sign or verify the package.
406 if (ident) {
407 printf("Using alternate key/cert \"%s\".\n", ident);
408 if (strchr(ident, '/')) {
410 * The user specified a path, take it verbatim.
412 strncpy(filename, ident, PATH_MAX);
413 } else {
414 cp = dirname(filename);
415 if (cp == NULL) {
416 warnx("Key directory not correctly specified.");
417 return;
419 snprintf(filename, PATH_MAX, "%s/%s", cp, ident);
423 if (verbose)
424 printf("Key is \"%s\".\n", filename);