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/x509.c,v 1.4 2004/07/30 06: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
);