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.4 2004/06/29 19:06:42 eik Exp $
27 * $DragonFly: src/usr.sbin/pkg_install/sign/Attic/x509.c,v 1.4 2004/07/30 04:46:14 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;
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);
106 me = malloc(sizeof *me);
108 warn("Cannot allocate x509_checker");
112 me->filename = filename;
113 me->signature = sign;
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");
134 warnx("Cannot open public key %s", certfile);
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))
155 warnx("Uknown certificate type");
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.
165 X509_print_fp(stdout, x509);
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());
180 * "Add" another data block to an existing checker.
183 x509_add(arg, buffer, 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.
203 struct x509_checker * n = arg;
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);
218 warnx("Getting public key:");
219 ERR_print_errors_fp(stderr);
224 X509_print_fp(stdout, x509);
226 switch (EVP_PKEY_type(pkey->type))
229 md_ctx = &n->rsa_ctx;
233 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;
285 const EVP_MD * md_type;
288 char keyfile[PATH_MAX + 1] = KEYFILE;
290 key_from_name(keyfile, userkey);
292 f = fopen(filename, "r");
297 if (gzip_read_header(f, &h, sign) == GZIP_NOT_GZIP) {
298 warnx("File %s is not a gzip file\n", filename);
305 * Sign the remaining data:
306 * Load just the crypto library error strings.
308 ERR_load_crypto_strings();
313 keyf = fopen(keyfile, "r");
316 warnx("Cannot open private key %s.", keyfile);
320 pkey = PEM_read_PrivateKey(keyf, NULL, NULL, 0);
325 warnx("Reading private key %s:", keyfile);
326 ERR_print_errors_fp(stderr);
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))
337 md_type = EVP_sha1();
338 printf("*** It's an RSA key.\n");
342 md_type = EVP_dss1();
343 printf("@@@ It's a DSA key, yippee!\n");
347 warnx("Uknown key type");
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);
362 err = EVP_SignFinal(&md_ctx, sig_buf, &sig_len, pkey);
366 warnx("Creating signature:");
367 ERR_print_errors_fp(stderr);
374 * Stuff the signature onto the head of the chain of signatures in
377 n = malloc(sizeof *n);
379 warnx("Cannot allocate %u bytes for new signature", sizeof *n);
385 memcpy(n->tag, x509tag, sizeof x509tag);
391 * Report our success.
398 key_from_name(char * filename, const char * ident)
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.
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);
414 cp = dirname(filename);
416 warnx("Key directory not correctly specified.");
419 snprintf(filename, PATH_MAX, "%s/%s", cp, ident);
424 printf("Key is \"%s\".\n", filename);