420 remove patch (sparse package) support from svr4 pkg
[illumos-gate.git] / usr / src / lib / libpkg / common / keystore.c
blob633c04b58e4641775f22458e762943019fa5b9b3
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Module: keystore.c
29 * Description: This module contains the structure definitions for processing
30 * package keystore files.
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <strings.h>
37 #include <libintl.h>
38 #include <time.h>
39 #include <ctype.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <openssl/evp.h>
43 #include <openssl/x509.h>
44 #include <openssl/pkcs12.h>
45 #include <openssl/asn1.h>
46 #include <openssl/pem.h>
47 #include <openssl/err.h>
48 #include <openssl/safestack.h>
49 #include <openssl/stack.h>
50 #include "p12lib.h"
51 #include "pkgerr.h"
52 #include "keystore.h"
53 #include "pkglib.h"
54 #include "pkglibmsgs.h"
56 typedef struct keystore_t {
57 boolean_t dirty;
58 boolean_t new;
59 char *path;
60 char *passphrase;
61 /* truststore handles */
62 int cafd;
63 STACK_OF(X509) *cacerts;
64 char *capath;
66 /* user certificate handles */
67 STACK_OF(X509) *clcerts;
68 char *clpath;
70 /* private key handles */
71 STACK_OF(EVP_PKEY) *pkeys;
72 char *keypath;
73 } keystore_t;
75 /* local routines */
76 static keystore_t *new_keystore(void);
77 static void free_keystore(keystore_t *);
78 static boolean_t verify_keystore_integrity(PKG_ERR *, keystore_t *);
79 static boolean_t check_password(PKCS12 *, char *);
80 static boolean_t resolve_paths(PKG_ERR *, char *, char *,
81 long, keystore_t *);
82 static boolean_t lock_keystore(PKG_ERR *, long, keystore_t *);
84 static boolean_t unlock_keystore(PKG_ERR *, keystore_t *);
85 static boolean_t read_keystore(PKG_ERR *, keystore_t *,
86 keystore_passphrase_cb);
87 static boolean_t write_keystore(PKG_ERR *, keystore_t *,
88 keystore_passphrase_cb);
89 static boolean_t write_keystore_file(PKG_ERR *, char *, PKCS12 *);
90 static boolean_t clear_keystore_file(PKG_ERR *, char *);
91 static PKCS12 *read_keystore_file(PKG_ERR *, char *);
92 static char *get_time_string(ASN1_TIME *);
94 /* locking routines */
95 static boolean_t restore_keystore_file(PKG_ERR *, char *);
96 static int file_lock(int, int, int);
97 static int file_unlock(int);
98 static boolean_t file_lock_test(int, int);
99 static boolean_t file_empty(char *);
100 static boolean_t get_keystore_passwd(PKG_ERR *err, PKCS12 *p12,
101 keystore_passphrase_cb cb, keystore_t *keystore);
102 static boolean_t wait_restore(int, char *, char *, char *);
104 #define KEYSTORE_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
106 /* wait on other keystore access for 1 minute before giving up */
107 #define LOCK_TIMEOUT 60
110 * print_certs - prints certificates out of a keystore, to a file.
112 * Arguments:
113 * err - Error object to append errors to
114 * keystore - Keystore on which to operate
115 * alias - Name of certificate to print, NULL means print all
116 * format - Format in which to print certificates
117 * outfile - Where to print certificates
119 * Returns:
120 * 0 - Success
121 * non-zero - Failure, errors added to err
124 print_certs(PKG_ERR *err, keystore_handle_t keystore_h, char *alias,
125 keystore_encoding_format_t format, FILE *outfile)
127 int i;
128 X509 *cert;
129 char *fname = NULL;
130 boolean_t found = B_FALSE;
131 keystore_t *keystore = keystore_h;
133 if (keystore->clcerts != NULL) {
134 /* print out each client cert */
135 for (i = 0; i < sk_X509_num(keystore->clcerts); i++) {
136 cert = sk_X509_value(keystore->clcerts, i);
137 (void) sunw_get_cert_fname(GETDO_COPY, cert,
138 &fname);
140 if (fname == NULL) {
141 /* no name recorded, keystore is corrupt */
142 pkgerr_add(err, PKGERR_CORRUPT,
143 gettext(ERR_KEYSTORE_NO_ALIAS),
144 get_subject_display_name(cert));
145 return (1);
148 if ((alias != NULL) && (!streq(alias, fname))) {
149 /* name does not match, skip it */
150 (void) OPENSSL_free(fname);
151 fname = NULL;
152 continue;
153 } else {
154 found = B_TRUE;
155 (void) print_cert(err, cert, format,
156 fname, B_FALSE, outfile);
157 (void) OPENSSL_free(fname);
158 fname = NULL;
163 if (fname != NULL) {
164 (void) OPENSSL_free(fname);
165 fname = NULL;
168 if (keystore->cacerts != NULL) {
169 /* print out each trusted cert */
170 for (i = 0; i < sk_X509_num(keystore->cacerts); i++) {
171 cert = sk_X509_value(keystore->cacerts, i);
172 (void) sunw_get_cert_fname(GETDO_COPY,
173 cert, &fname);
175 if (fname == NULL) {
176 /* no name recorded, keystore is corrupt */
177 pkgerr_add(err, PKGERR_CORRUPT,
178 gettext(ERR_KEYSTORE_NO_ALIAS),
179 get_subject_display_name(cert));
180 return (1);
183 if ((alias != NULL) && (!streq(alias, fname))) {
184 /* name does not match, skip it */
185 (void) OPENSSL_free(fname);
186 fname = NULL;
187 continue;
188 } else {
189 found = B_TRUE;
190 (void) print_cert(err, cert, format,
191 fname, B_TRUE, outfile);
192 (void) OPENSSL_free(fname);
193 fname = NULL;
198 if (fname != NULL) {
199 (void) OPENSSL_free(fname);
200 fname = NULL;
203 if (found) {
204 return (0);
205 } else {
206 /* no certs printed */
207 if (alias != NULL) {
208 pkgerr_add(err, PKGERR_NOALIASMATCH,
209 gettext(ERR_KEYSTORE_NOCERT),
210 alias, keystore->path);
211 } else {
212 pkgerr_add(err, PKGERR_NOPUBKEY,
213 gettext(ERR_KEYSTORE_NOPUBCERTS),
214 keystore->path);
215 pkgerr_add(err, PKGERR_NOCACERT,
216 gettext(ERR_KEYSTORE_NOCACERTS),
217 keystore->path);
219 return (1);
224 * print_cert - prints a single certificate, to a file
226 * Arguments:
227 * err - Error object to append errors to
228 * x - The certificate to print
229 * alias - Name of certificate to print
230 * format - Format in which to print certificate
231 * outfile - Where to print certificate
233 * Returns:
234 * 0 - Success
235 * non-zero - Failure, errors added to err
237 int print_cert(PKG_ERR *err, X509 *x,
238 keystore_encoding_format_t format, char *alias, boolean_t is_trusted,
239 FILE *outfile)
242 char *vdb_str;
243 char *vda_str;
244 char vd_str[ATTR_MAX];
245 int ret = 0;
246 char *cn_str, *icn_str, *typ_str;
247 char *tmp;
248 char *md5_fp;
249 char *sha1_fp;
250 int len;
252 /* need to localize the word "Fingerprint", hence these pointers */
253 char md5_label[ATTR_MAX];
254 char sha1_label[ATTR_MAX];
256 if (is_trusted) {
257 typ_str = gettext(MSG_KEYSTORE_TRUSTED);
258 } else {
259 typ_str = gettext(MSG_KEYSTORE_UNTRUSTED);
262 if ((cn_str = get_subject_display_name(x)) == NULL) {
263 cn_str = gettext(MSG_KEYSTORE_UNKNOWN);
266 if ((icn_str = get_issuer_display_name(x)) == NULL) {
267 icn_str = gettext(MSG_KEYSTORE_UNKNOWN);
270 vdb_str = xstrdup(get_time_string(X509_get_notBefore(x)));
271 vda_str = xstrdup(get_time_string(X509_get_notAfter(x)));
272 if (((len = snprintf(vd_str, ATTR_MAX, "<%s> - <%s>",
273 vdb_str, vda_str)) < 0) || (len >= ATTR_MAX)) {
274 pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), vdb_str);
275 ret = 1;
276 goto cleanup;
279 if ((tmp = get_fingerprint(x, EVP_md5())) == NULL) {
280 md5_fp = gettext(MSG_KEYSTORE_UNKNOWN);
281 } else {
283 * make a copy, otherwise the next call to get_fingerprint
284 * will overwrite this one
286 md5_fp = xstrdup(tmp);
289 if ((tmp = get_fingerprint(x, EVP_sha1())) == NULL) {
290 sha1_fp = gettext(MSG_KEYSTORE_UNKNOWN);
291 } else {
292 sha1_fp = xstrdup(tmp);
295 (void) snprintf(md5_label, ATTR_MAX, "%s %s",
296 OBJ_nid2sn(EVP_MD_type(EVP_md5())),
297 /* i18n: 14 characters max */
298 gettext(MSG_KEYSTORE_FP));
300 (void) snprintf(sha1_label, ATTR_MAX, "%s %s",
301 OBJ_nid2sn(EVP_MD_type(EVP_sha1())),
302 /* i18n: 14 characters max */
303 gettext(MSG_KEYSTORE_FP));
305 switch (format) {
306 case KEYSTORE_FORMAT_PEM:
307 (void) PEM_write_X509(outfile, x);
308 break;
309 case KEYSTORE_FORMAT_DER:
310 (void) i2d_X509_fp(outfile, x);
311 break;
312 case KEYSTORE_FORMAT_TEXT:
313 (void) fprintf(outfile, "%18s: %s\n",
314 /* i18n: 18 characters max */
315 gettext(MSG_KEYSTORE_AL), alias);
316 (void) fprintf(outfile, "%18s: %s\n",
317 /* i18n: 18 characters max */
318 gettext(MSG_KEYSTORE_CN), cn_str);
319 (void) fprintf(outfile, "%18s: %s\n",
320 /* i18n: 18 characters max */
321 gettext(MSG_KEYSTORE_TY), typ_str);
322 (void) fprintf(outfile, "%18s: %s\n",
323 /* i18n: 18 characters max */
324 gettext(MSG_KEYSTORE_IN), icn_str);
325 (void) fprintf(outfile, "%18s: %s\n",
326 /* i18n: 18 characters max */
327 gettext(MSG_KEYSTORE_VD), vd_str);
328 (void) fprintf(outfile, "%18s: %s\n", md5_label, md5_fp);
329 (void) fprintf(outfile, "%18s: %s\n", sha1_label, sha1_fp);
330 (void) fprintf(outfile, "\n");
331 break;
332 default:
333 pkgerr_add(err, PKGERR_INTERNAL,
334 gettext(ERR_KEYSTORE_INTERNAL),
335 __FILE__, __LINE__);
336 ret = 1;
337 goto cleanup;
340 cleanup:
341 if (md5_fp != NULL)
342 free(md5_fp);
343 if (sha1_fp != NULL)
344 free(sha1_fp);
345 if (vda_str != NULL)
346 free(vda_str);
347 if (vdb_str != NULL)
348 free(vdb_str);
349 return (ret);
353 * open_keystore - Initialize new keystore object for
354 * impending access.
356 * Arguments:
357 * err - Error object to append errors to
358 * keystore_file - Base filename or directory of keystore
359 * app - Application making request
360 * passwd - Password used to decrypt keystore
361 * flags - Control flags used to control access mode and behavior
362 * result - Resulting keystore object stored here on success
364 * Returns:
365 * 0 - Success - result contains a pointer to the opened keystore
366 * non-zero - Failure, errors added to err
369 open_keystore(PKG_ERR *err, char *keystore_file, char *app,
370 keystore_passphrase_cb cb, long flags, keystore_handle_t *result)
372 int ret = 0;
373 keystore_t *tmpstore;
375 tmpstore = new_keystore();
377 tmpstore->dirty = B_FALSE;
378 tmpstore->new = B_FALSE;
379 tmpstore->path = xstrdup(keystore_file);
381 if (!resolve_paths(err, keystore_file, app, flags, tmpstore)) {
382 /* unable to determine keystore paths */
383 pkgerr_add(err, PKGERR_CORRUPT, gettext(ERR_KEYSTORE_REPAIR),
384 keystore_file);
385 ret = 1;
386 goto cleanup;
389 if (!verify_keystore_integrity(err, tmpstore)) {
390 /* unable to repair keystore */
391 pkgerr_add(err, PKGERR_CORRUPT, gettext(ERR_KEYSTORE_REPAIR),
392 keystore_file);
393 ret = 1;
394 goto cleanup;
397 if (!lock_keystore(err, flags, tmpstore)) {
398 pkgerr_add(err, PKGERR_LOCKED, gettext(ERR_KEYSTORE_LOCKED),
399 keystore_file);
400 ret = 1;
401 goto cleanup;
404 /* now that we have locked the keystore, go ahead and read it */
405 if (!read_keystore(err, tmpstore, cb)) {
406 pkgerr_add(err, PKGERR_READ, gettext(ERR_PARSE),
407 keystore_file);
408 ret = 1;
409 goto cleanup;
412 *result = tmpstore;
413 tmpstore = NULL;
415 cleanup:
416 if (tmpstore != NULL)
417 free_keystore(tmpstore);
418 return (ret);
422 * new_keystore - Allocates and initializes a Keystore object
424 * Arguments:
425 * NONE
427 * Returns:
428 * NULL - out of memory
429 * otherwise, returns a pointer to the newly allocated object,
430 * which should be freed with free_keystore() when no longer
431 * needed.
433 static keystore_t
434 *new_keystore(void)
436 keystore_t *tmpstore;
438 if ((tmpstore = (keystore_t *)malloc(sizeof (keystore_t))) == NULL) {
439 return (NULL);
441 tmpstore->dirty = B_FALSE;
442 tmpstore->new = B_FALSE;
443 tmpstore->path = NULL;
444 tmpstore->passphrase = NULL;
445 tmpstore->cafd = -1;
446 tmpstore->cacerts = NULL;
447 tmpstore->capath = NULL;
448 tmpstore->clcerts = NULL;
449 tmpstore->clpath = NULL;
450 tmpstore->pkeys = NULL;
451 tmpstore->keypath = NULL;
453 return (tmpstore);
457 * free_keystore - Deallocates a Keystore object
459 * Arguments:
460 * keystore - The keystore to deallocate
462 * Returns:
463 * NONE
465 static void
466 free_keystore(keystore_t *keystore)
468 if (keystore->path != NULL)
469 free(keystore->path);
470 if (keystore->capath != NULL)
471 free(keystore->capath);
472 if (keystore->passphrase != NULL)
473 free(keystore->passphrase);
474 if (keystore->clpath != NULL)
475 free(keystore->clpath);
476 if (keystore->keypath != NULL)
477 free(keystore->keypath);
479 if (keystore->pkeys != NULL) {
480 sk_EVP_PKEY_pop_free(keystore->pkeys,
481 sunw_evp_pkey_free);
483 if (keystore->clcerts != NULL)
484 sk_X509_free(keystore->clcerts);
485 if (keystore->cacerts != NULL)
486 sk_X509_free(keystore->cacerts);
487 free(keystore);
491 * close_keystore - Writes keystore to disk if needed, then
492 * unlocks and closes keystore.
494 * Arguments:
495 * err - Error object to append errors to
496 * keystore - Keystore which should be closed
497 * passwd - Password used to encrypt keystore
499 * Returns:
500 * 0 - Success - keystore is committed to disk, and unlocked
501 * non-zero - Failure, errors added to err
504 close_keystore(PKG_ERR *err, keystore_handle_t keystore_h,
505 keystore_passphrase_cb cb)
507 int ret = 0;
508 keystore_t *keystore = keystore_h;
510 if (keystore->dirty) {
511 /* write out the keystore first */
512 if (!write_keystore(err, keystore, cb)) {
513 pkgerr_add(err, PKGERR_WRITE,
514 gettext(ERR_KEYSTORE_WRITE),
515 keystore->path);
516 ret = 1;
517 goto cleanup;
521 if (!unlock_keystore(err, keystore)) {
522 pkgerr_add(err, PKGERR_UNLOCK, gettext(ERR_KEYSTORE_UNLOCK),
523 keystore->path);
524 ret = 1;
525 goto cleanup;
528 free_keystore(keystore);
529 cleanup:
530 return (ret);
534 * merge_ca_cert - Adds a trusted certificate (trust anchor) to a keystore.
535 * certificate checked for validity dates and non-duplicity.
537 * Arguments:
538 * err - Error object to add errors to
539 * cacert - Certificate which to merge into keystore
540 * keystore - The keystore into which the certificate is merged
542 * Returns:
543 * 0 - Success - Certificate passes validity, and
544 * is merged into keystore
545 * non-zero - Failure, errors recorded in err
548 merge_ca_cert(PKG_ERR *err, X509 *cacert, keystore_handle_t keystore_h)
551 int ret = 0;
552 X509 *existing = NULL;
553 char *fname;
554 keystore_t *keystore = keystore_h;
556 /* check validity dates */
557 if (check_cert(err, cacert) != 0) {
558 ret = 1;
559 goto cleanup;
562 /* create the certificate's friendlyName */
563 fname = get_subject_display_name(cacert);
565 if (sunw_set_fname(fname, NULL, cacert) != 0) {
566 pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
567 ret = 1;
568 goto cleanup;
571 /* merge certificate into the keystore */
572 if (keystore->cacerts == NULL) {
573 /* no existing truststore, so make a new one */
574 if ((keystore->cacerts = sk_X509_new_null()) == NULL) {
575 pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
576 ret = 1;
577 goto cleanup;
579 } else {
580 /* existing truststore, make sure there's no duplicate */
581 if (sunw_find_fname(fname, NULL, keystore->cacerts,
582 NULL, &existing) < 0) {
583 pkgerr_add(err, PKGERR_INTERNAL,
584 gettext(ERR_KEYSTORE_INTERNAL),
585 __FILE__, __LINE__);
586 ERR_print_errors_fp(stderr);
587 ret = 1;
588 goto cleanup;
589 /* could not search properly! */
591 if (existing != NULL) {
592 /* whoops, found one already */
593 pkgerr_add(err, PKGERR_DUPLICATE,
594 gettext(ERR_KEYSTORE_DUPLICATECERT), fname);
595 ret = 1;
596 goto cleanup;
600 (void) sk_X509_push(keystore->cacerts, cacert);
601 keystore->dirty = B_TRUE;
602 cleanup:
603 if (existing != NULL)
604 X509_free(existing);
605 return (ret);
609 * find_key_cert_pair - Searches a keystore for a matching
610 * public key certificate and private key, given an alias.
612 * Arguments:
613 * err - Error object to add errors to
614 * ks - Keystore to search
615 * alias - Name to used to match certificate's alias
616 * key - Resulting key is placed here
617 * cert - Resulting cert is placed here
619 * Returns:
620 * 0 - Success - Matching cert/key pair placed in key and cert.
621 * non-zero - Failure, errors recorded in err
624 find_key_cert_pair(PKG_ERR *err, keystore_handle_t ks_h, char *alias,
625 EVP_PKEY **key, X509 **cert)
627 X509 *tmpcert = NULL;
628 EVP_PKEY *tmpkey = NULL;
629 int ret = 0;
630 int items_found;
631 keystore_t *ks = ks_h;
633 if (key == NULL || cert == NULL) {
634 pkgerr_add(err, PKGERR_NOPUBKEY,
635 gettext(ERR_KEYSTORE_NOPUBCERTS), ks->path);
636 ret = 1;
637 goto cleanup;
640 if (ks->clcerts == NULL) {
641 /* no public certs */
642 pkgerr_add(err, PKGERR_NOPUBKEY,
643 gettext(ERR_KEYSTORE_NOCERTS), ks->path);
644 ret = 1;
645 goto cleanup;
647 if (ks->pkeys == NULL) {
648 /* no private keys */
649 pkgerr_add(err, PKGERR_NOPRIVKEY,
650 gettext(ERR_KEYSTORE_NOKEYS), ks->path);
651 ret = 1;
652 goto cleanup;
655 /* try the easy case first */
656 if ((sk_EVP_PKEY_num(ks->pkeys) == 1) &&
657 (sk_X509_num(ks->clcerts) == 1)) {
658 tmpkey = sk_EVP_PKEY_value(ks->pkeys, 0);
659 tmpcert = sk_X509_value(ks->clcerts, 0);
660 if (sunw_check_keys(tmpcert, tmpkey)) {
662 * only one private key and public key cert, and they
663 * match, so use them
665 *key = tmpkey;
666 tmpkey = NULL;
667 *cert = tmpcert;
668 tmpcert = NULL;
669 goto cleanup;
673 /* Attempt to find the right pair given the alias */
674 items_found = sunw_find_fname(alias, ks->pkeys, ks->clcerts,
675 &tmpkey, &tmpcert);
677 if ((items_found < 0) ||
678 (items_found & (FOUND_PKEY | FOUND_CERT)) == 0) {
679 /* no key/cert pair found. bail. */
680 pkgerr_add(err, PKGERR_BADALIAS,
681 gettext(ERR_KEYSTORE_NOMATCH), alias);
682 ret = 1;
683 goto cleanup;
686 /* success */
687 *key = tmpkey;
688 tmpkey = NULL;
689 *cert = tmpcert;
690 tmpcert = NULL;
692 cleanup:
694 if (tmpcert != NULL)
695 (void) X509_free(tmpcert);
697 if (tmpkey != NULL)
698 sunw_evp_pkey_free(tmpkey);
700 return (ret);
704 * find_ca_certs - Searches a keystore for trusted certificates
706 * Arguments:
707 * err - Error object to add errors to
708 * ks - Keystore to search
709 * cacerts - resulting set of trusted certs are placed here
711 * Returns:
712 * 0 - Success - trusted cert list returned in cacerts
713 * non-zero - Failure, errors recorded in err
716 find_ca_certs(PKG_ERR *err, keystore_handle_t ks_h, STACK_OF(X509) **cacerts)
719 keystore_t *ks = ks_h;
721 /* easy */
722 if (cacerts == NULL) {
723 pkgerr_add(err, PKGERR_INTERNAL,
724 gettext(ERR_KEYSTORE_INTERNAL), __FILE__, __LINE__);
725 return (1);
728 *cacerts = ks->cacerts;
729 return (0);
733 * find_cl_certs - Searches a keystore for user certificates
735 * Arguments:
736 * err - Error object to add errors to
737 * ks - Keystore to search
738 * cacerts - resulting set of user certs are placed here
740 * No matching of any kind is performed.
741 * Returns:
742 * 0 - Success - trusted cert list returned in cacerts
743 * non-zero - Failure, errors recorded in err
745 /* ARGSUSED */
747 find_cl_certs(PKG_ERR *err, keystore_handle_t ks_h, STACK_OF(X509) **clcerts)
749 keystore_t *ks = ks_h;
751 /* easy */
752 *clcerts = ks->clcerts;
753 return (0);
758 * merge_cert_and_key - Adds a user certificate and matching
759 * private key to a keystore.
760 * certificate checked for validity dates and non-duplicity.
762 * Arguments:
763 * err - Error object to add errors to
764 * cert - Certificate which to merge into keystore
765 * key - matching private key to 'cert'
766 * alias - Name which to store the cert and key under
767 * keystore - The keystore into which the certificate is merged
769 * Returns:
770 * 0 - Success - Certificate passes validity, and
771 * is merged into keystore, along with key
772 * non-zero - Failure, errors recorded in err
775 merge_cert_and_key(PKG_ERR *err, X509 *cert, EVP_PKEY *key, char *alias,
776 keystore_handle_t keystore_h)
778 X509 *existingcert = NULL;
779 EVP_PKEY *existingkey = NULL;
780 int ret = 0;
781 keystore_t *keystore = keystore_h;
783 /* check validity dates */
784 if (check_cert(err, cert) != 0) {
785 ret = 1;
786 goto cleanup;
789 /* set the friendlyName of the key and cert to the supplied alias */
790 if (sunw_set_fname(alias, key, cert) != 0) {
791 pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
792 ret = 1;
793 goto cleanup;
796 /* merge certificate and key into the keystore */
797 if (keystore->clcerts == NULL) {
798 /* no existing truststore, so make a new one */
799 if ((keystore->clcerts = sk_X509_new_null()) == NULL) {
800 pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
801 ret = 1;
802 goto cleanup;
804 } else {
805 /* existing certstore, make sure there's no duplicate */
806 if (sunw_find_fname(alias, NULL, keystore->clcerts,
807 NULL, &existingcert) < 0) {
808 pkgerr_add(err, PKGERR_INTERNAL,
809 gettext(ERR_KEYSTORE_INTERNAL),
810 __FILE__, __LINE__);
811 ERR_print_errors_fp(stderr);
812 ret = 1;
813 goto cleanup;
814 /* could not search properly! */
816 if (existingcert != NULL) {
817 /* whoops, found one already */
818 pkgerr_add(err, PKGERR_DUPLICATE,
819 gettext(ERR_KEYSTORE_DUPLICATECERT), alias);
820 ret = 1;
821 goto cleanup;
825 if (keystore->pkeys == NULL) {
826 /* no existing keystore, so make a new one */
827 if ((keystore->pkeys = sk_EVP_PKEY_new_null()) == NULL) {
828 pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
829 ret = 1;
830 goto cleanup;
832 } else {
833 /* existing keystore, so make sure there's no duplicate entry */
834 if (sunw_find_fname(alias, keystore->pkeys, NULL,
835 &existingkey, NULL) < 0) {
836 pkgerr_add(err, PKGERR_INTERNAL,
837 gettext(ERR_KEYSTORE_INTERNAL),
838 __FILE__, __LINE__);
839 ERR_print_errors_fp(stderr);
840 ret = 1;
841 goto cleanup;
842 /* could not search properly! */
844 if (existingkey != NULL) {
845 /* whoops, found one already */
846 pkgerr_add(err, PKGERR_DUPLICATE,
847 gettext(ERR_KEYSTORE_DUPLICATEKEY), alias);
848 ret = 1;
849 goto cleanup;
853 (void) sk_X509_push(keystore->clcerts, cert);
854 (void) sk_EVP_PKEY_push(keystore->pkeys, key);
855 keystore->dirty = B_TRUE;
856 cleanup:
857 if (existingcert != NULL)
858 (void) X509_free(existingcert);
859 if (existingkey != NULL)
860 (void) sunw_evp_pkey_free(existingkey);
861 return (ret);
865 * delete_cert_and_keys - Deletes one or more certificates
866 * and matching private keys from a keystore.
868 * Arguments:
869 * err - Error object to add errors to
870 * ks - The keystore from which certs and keys are deleted
871 * alias - Name which to search for certificates and keys
872 * to delete
874 * Returns:
875 * 0 - Success - All trusted certs which match 'alias'
876 * are deleted. All user certificates
877 * which match 'alias' are deleted, along
878 * with the matching private key.
879 * non-zero - Failure, errors recorded in err
882 delete_cert_and_keys(PKG_ERR *err, keystore_handle_t ks_h, char *alias)
884 X509 *existingcert;
885 EVP_PKEY *existingkey;
886 int i;
887 char *fname = NULL;
888 boolean_t found = B_FALSE;
889 keystore_t *ks = ks_h;
891 /* delete any and all client certs with the supplied name */
892 if (ks->clcerts != NULL) {
893 for (i = 0; i < sk_X509_num(ks->clcerts); i++) {
894 existingcert = sk_X509_value(ks->clcerts, i);
895 if (sunw_get_cert_fname(GETDO_COPY,
896 existingcert, &fname) >= 0) {
897 if (streq(fname, alias)) {
898 /* match, so nuke it */
899 existingcert =
900 sk_X509_delete(ks->clcerts, i);
901 X509_free(existingcert);
902 existingcert = NULL;
903 found = B_TRUE;
905 (void) OPENSSL_free(fname);
906 fname = NULL;
909 if (sk_X509_num(ks->clcerts) <= 0) {
910 /* we deleted all the client certs */
911 sk_X509_free(ks->clcerts);
912 ks->clcerts = NULL;
916 /* and now the private keys */
917 if (ks->pkeys != NULL) {
918 for (i = 0; i < sk_EVP_PKEY_num(ks->pkeys); i++) {
919 existingkey = sk_EVP_PKEY_value(ks->pkeys, i);
920 if (sunw_get_pkey_fname(GETDO_COPY,
921 existingkey, &fname) >= 0) {
922 if (streq(fname, alias)) {
923 /* match, so nuke it */
924 existingkey =
925 sk_EVP_PKEY_delete(ks->pkeys, i);
926 sunw_evp_pkey_free(existingkey);
927 existingkey = NULL;
928 found = B_TRUE;
930 (void) OPENSSL_free(fname);
931 fname = NULL;
934 if (sk_EVP_PKEY_num(ks->pkeys) <= 0) {
935 /* we deleted all the private keys */
936 sk_EVP_PKEY_free(ks->pkeys);
937 ks->pkeys = NULL;
941 /* finally, remove any trust anchors that match */
943 if (ks->cacerts != NULL) {
944 for (i = 0; i < sk_X509_num(ks->cacerts); i++) {
945 existingcert = sk_X509_value(ks->cacerts, i);
946 if (sunw_get_cert_fname(GETDO_COPY,
947 existingcert, &fname) >= 0) {
948 if (streq(fname, alias)) {
949 /* match, so nuke it */
950 existingcert =
951 sk_X509_delete(ks->cacerts, i);
952 X509_free(existingcert);
953 existingcert = NULL;
954 found = B_TRUE;
956 (void) OPENSSL_free(fname);
957 fname = NULL;
960 if (sk_X509_num(ks->cacerts) <= 0) {
961 /* we deleted all the CA certs */
962 sk_X509_free(ks->cacerts);
963 ks->cacerts = NULL;
967 if (found) {
968 ks->dirty = B_TRUE;
969 return (0);
970 } else {
971 /* no certs or keys deleted */
972 pkgerr_add(err, PKGERR_NOALIASMATCH,
973 gettext(ERR_KEYSTORE_NOCERTKEY),
974 alias, ks->path);
975 return (1);
980 * check_cert - Checks certificate validity. This routine
981 * checks that the current time falls within the period
982 * of validity for the cert.
984 * Arguments:
985 * err - Error object to add errors to
986 * cert - The certificate to check
988 * Returns:
989 * 0 - Success - Certificate checks out
990 * non-zero - Failure, errors and reasons recorded in err
993 check_cert(PKG_ERR *err, X509 *cert)
995 char currtimestr[ATTR_MAX];
996 time_t currtime;
997 char *r;
998 /* get current time */
999 if ((currtime = time(NULL)) == (time_t)-1) {
1000 pkgerr_add(err, PKGERR_TIME, gettext(ERR_CURR_TIME));
1001 return (1);
1004 (void) strlcpy(currtimestr, ctime(&currtime), ATTR_MAX);
1006 /* trim whitespace from end of time string */
1007 for (r = (currtimestr + strlen(currtimestr) - 1); isspace(*r); r--) {
1008 *r = '\0';
1010 /* check validity of cert */
1011 switch (sunw_check_cert_times(CHK_BOTH, cert)) {
1012 case CHKERR_TIME_OK:
1013 /* Current time meets requested checks */
1014 break;
1015 case CHKERR_TIME_BEFORE_BAD:
1016 /* 'not before' field is invalid */
1017 case CHKERR_TIME_AFTER_BAD:
1018 /* 'not after' field is invalid */
1019 pkgerr_add(err, PKGERR_TIME, gettext(ERR_CERT_TIME_BAD));
1020 return (1);
1021 case CHKERR_TIME_IS_BEFORE:
1022 /* Current time is before 'not before' */
1023 case CHKERR_TIME_HAS_EXPIRED:
1025 * Ignore expiration time since the trust cert used to
1026 * verify the certs used to sign Sun patches is already
1027 * expired. Once the patches get resigned with the new
1028 * cert we will check expiration against the time the
1029 * patch was signed and not the time it is installed.
1031 return (0);
1032 default:
1033 pkgerr_add(err, PKGERR_INTERNAL,
1034 gettext(ERR_KEYSTORE_INTERNAL),
1035 __FILE__, __LINE__);
1036 return (1);
1039 /* all checks ok */
1040 return (0);
1044 * check_cert - Checks certificate validity. This routine
1045 * checks everything that check_cert checks, and additionally
1046 * verifies that the private key and corresponding public
1047 * key are indeed a pair.
1049 * Arguments:
1050 * err - Error object to add errors to
1051 * cert - The certificate to check
1052 * key - the key to check
1053 * Returns:
1054 * 0 - Success - Certificate checks out
1055 * non-zero - Failure, errors and reasons recorded in err
1058 check_cert_and_key(PKG_ERR *err, X509 *cert, EVP_PKEY *key)
1061 /* check validity dates */
1062 if (check_cert(err, cert) != 0) {
1063 return (1);
1066 /* check key pair match */
1067 if (sunw_check_keys(cert, key) == 0) {
1068 pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MISMATCHED_KEYS),
1069 get_subject_display_name(cert));
1070 return (1);
1073 /* all checks OK */
1074 return (0);
1077 /* ------------------ private functions ---------------------- */
1080 * verify_keystore_integrity - Searches for the remnants
1081 * of a failed or aborted keystore modification, and
1082 * cleans up the files, retstores the keystore to a known
1083 * state.
1085 * Arguments:
1086 * err - Error object to add errors to
1087 * keystore_file - Base directory or filename of keystore
1088 * app - Application making request
1090 * Returns:
1091 * 0 - Success - Keystore is restored, or untouched in the
1092 * case that cleanup was unnecessary
1093 * non-zero - Failure, errors and reasons recorded in err
1095 static boolean_t
1096 verify_keystore_integrity(PKG_ERR *err, keystore_t *keystore)
1098 if (keystore->capath != NULL) {
1099 if (!restore_keystore_file(err, keystore->capath)) {
1100 return (B_FALSE);
1103 if (keystore->clpath != NULL) {
1104 if (!restore_keystore_file(err, keystore->clpath)) {
1105 return (B_FALSE);
1108 if (keystore->keypath != NULL) {
1109 if (!restore_keystore_file(err, keystore->keypath)) {
1110 return (B_FALSE);
1113 return (B_TRUE);
1117 * restore_keystore_file - restores a keystore file to
1118 * a known state.
1120 * Keystore files can possibly be corrupted by a variety
1121 * of error conditions during reading/writing. This
1122 * routine, along with write_keystore_file, tries to
1123 * maintain keystore integrity by writing the files
1124 * out in a particular order, minimizing the time period
1125 * that the keystore is in an indeterminate state.
1127 * With the current implementation, there are some failures
1128 * that are wholly unrecoverable, such as disk corruption.
1129 * These routines attempt to minimize the risk, but not
1130 * eliminate it. When better, atomic operations are available
1131 * (such as a trued atabase with commit, rollback, and
1132 * guaranteed atomicity), this implementation should use that.
1134 * Arguments:
1135 * err - Error object to add errors to
1136 * keystore_file - keystore file path to restore.
1138 * Returns:
1139 * 0 - Success - Keystore file is restored, or untouched in the
1140 * case that cleanup was unnecessary
1141 * non-zero - Failure, errors and reasons recorded in err
1143 /* ARGSUSED */
1144 static boolean_t
1145 restore_keystore_file(PKG_ERR *err, char *keystore_file)
1147 char newpath[MAXPATHLEN];
1148 char backuppath[MAXPATHLEN];
1149 int newfd;
1150 struct stat buf;
1151 int len;
1153 if (((len = snprintf(newpath, MAXPATHLEN, "%s.new",
1154 keystore_file)) < 0) ||
1155 (len >= ATTR_MAX)) {
1156 pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), keystore_file);
1157 return (B_FALSE);
1160 if (((len = snprintf(backuppath, MAXPATHLEN, "%s.bak",
1161 keystore_file)) < 0) ||
1162 (len >= ATTR_MAX)) {
1163 pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), keystore_file);
1164 return (B_FALSE);
1167 if ((newfd = open(newpath, O_RDWR|O_NONBLOCK, 0)) != -1) {
1168 if (fstat(newfd, &buf) != -1) {
1169 if (S_ISREG(buf.st_mode)) {
1171 * restore the file, waiting on it
1172 * to be free for locking, or for
1173 * it to disappear
1175 if (!wait_restore(newfd, keystore_file,
1176 newpath, backuppath)) {
1177 pkgerr_add(err, PKGERR_WRITE,
1178 gettext(ERR_WRITE),
1179 newpath, strerror(errno));
1180 (void) close(newfd);
1181 return (B_FALSE);
1182 } else {
1183 return (B_TRUE);
1185 } else {
1186 /* "new" file is not a regular file */
1187 pkgerr_add(err, PKGERR_WRITE,
1188 gettext(ERR_NOT_REG), newpath);
1189 (void) close(newfd);
1190 return (B_FALSE);
1192 } else {
1193 /* couldn't stat "new" file */
1194 pkgerr_add(err, PKGERR_WRITE,
1195 gettext(ERR_WRITE), newpath,
1196 strerror(errno));
1197 (void) close(newfd);
1198 return (B_FALSE);
1200 } else {
1201 /* "new" file doesn't exist */
1202 return (B_TRUE);
1206 static boolean_t
1207 wait_restore(int newfd, char *keystore_file,
1208 char *origpath, char *backuppath)
1210 struct stat buf;
1211 FILE *newstream;
1212 PKCS12 *p12;
1214 (void) alarm(LOCK_TIMEOUT);
1215 if (file_lock(newfd, F_WRLCK, 1) == -1) {
1216 /* could not lock file */
1217 (void) alarm(0);
1218 return (B_FALSE);
1220 (void) alarm(0);
1222 if (fstat(newfd, &buf) != -1) {
1223 if (S_ISREG(buf.st_mode)) {
1225 * The new file still
1226 * exists, with no
1227 * owner. It must be
1228 * the result of an
1229 * aborted update.
1231 newstream = fdopen(newfd, "r");
1232 if ((p12 =
1233 d2i_PKCS12_fp(newstream,
1234 NULL)) != NULL) {
1236 * The file
1237 * appears
1238 * complete.
1239 * Replace the
1240 * exsisting
1241 * keystore
1242 * file with
1243 * this one
1245 (void) rename(keystore_file, backuppath);
1246 (void) rename(origpath, keystore_file);
1247 PKCS12_free(p12);
1248 } else {
1249 /* The file is not complete. Remove it */
1250 (void) remove(origpath);
1252 /* remove backup file */
1253 (void) remove(backuppath);
1254 (void) fclose(newstream);
1255 (void) close(newfd);
1256 return (B_TRUE);
1257 } else {
1259 * new file exists, but is not a
1260 * regular file
1262 (void) close(newfd);
1263 return (B_FALSE);
1265 } else {
1267 * could not stat file. Unless
1268 * the reason was that the file
1269 * is now gone, this is an error
1271 if (errno != ENOENT) {
1272 (void) close(newfd);
1273 return (B_FALSE);
1276 * otherwise, file is gone. The process
1277 * that held the lock must have
1278 * successfully cleaned up and
1279 * exited with a valid keystore
1280 * state
1282 (void) close(newfd);
1283 return (B_TRUE);
1288 * resolve_paths - figure out if we are dealing with a single-file
1289 * or multi-file keystore
1291 * The flags tell resolve_paths how to behave:
1293 * KEYSTORE_PATH_SOFT
1294 * If the keystore file does not exist at <base>/<app> then
1295 * use <base> as the path to the keystore. This can be used,
1296 * for example, to access an app-specific keystore iff it
1297 * exists, otherwise revert back to an app-generic keystore.
1299 * KEYSTORE_PATH_HARD
1300 * Always use the keystore located at <keystore_path>/<app>.
1301 * In read/write mode, if the files do not exist, then
1302 * they will be created. This is used to avoid falling
1303 * back to an app-generic keystore path when the app-specific
1304 * one does not exist.
1306 * Arguments:
1307 * err - Error object to add errors to
1308 * keystore_file - base keystore file path to lock
1309 * app - Application making requests
1310 * flags - Control flags (see above description)
1311 * keystore - object which is being locked
1313 * Returns:
1314 * B_TRUE - Success - Keystore file is locked, paths to
1315 * appropriate files placed in keystore.
1316 * B_FALSE - Failure, errors and reasons recorded in err
1318 static boolean_t
1319 resolve_paths(PKG_ERR *err, char *keystore_file, char *app,
1320 long flags, keystore_t *keystore)
1322 char storepath[PATH_MAX];
1323 struct stat buf;
1324 boolean_t multi = B_FALSE;
1325 int fd1, fd2, len;
1328 * figure out whether we are dealing with a single-file keystore
1329 * or a multi-file keystore
1331 if (app != NULL) {
1332 if (((len = snprintf(storepath, PATH_MAX, "%s/%s",
1333 keystore_file, app)) < 0) ||
1334 (len >= ATTR_MAX)) {
1335 pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN),
1336 keystore_file);
1337 return (B_FALSE);
1340 if (((fd1 = open(storepath, O_NONBLOCK|O_RDONLY)) == -1) ||
1341 (fstat(fd1, &buf) == -1) ||
1342 !S_ISDIR(buf.st_mode)) {
1344 * app-specific does not exist
1345 * fallback to app-generic, if flags say we can
1347 if ((flags & KEYSTORE_PATH_MASK) ==
1348 KEYSTORE_PATH_SOFT) {
1350 if (((fd2 = open(keystore_file,
1351 O_NONBLOCK|O_RDONLY)) != -1) &&
1352 (fstat(fd2, &buf) != -1)) {
1353 if (S_ISDIR(buf.st_mode)) {
1355 * app-generic dir
1356 * exists, so use it
1357 * as a multi-file
1358 * keystore
1360 multi = B_TRUE;
1361 app = NULL;
1362 } else if (S_ISREG(buf.st_mode)) {
1364 * app-generic file exists, so
1365 * use it as a single file ks
1367 multi = B_FALSE;
1368 app = NULL;
1373 if (fd1 != -1)
1374 (void) close(fd1);
1375 if (fd2 != -1)
1376 (void) close(fd2);
1377 } else {
1378 if (((fd1 = open(keystore_file,
1379 O_NONBLOCK|O_RDONLY)) != -1) &&
1380 (fstat(fd1, &buf) != -1) &&
1381 S_ISDIR(buf.st_mode)) {
1383 * app-generic dir exists, so use
1384 * it as a multi-file keystore
1386 multi = B_TRUE;
1388 if (fd1 != -1)
1389 (void) close(fd1);
1392 if (app != NULL) {
1393 /* app-specific keystore */
1394 (void) snprintf(storepath, PATH_MAX, "%s/%s/%s",
1395 keystore_file, app, TRUSTSTORE);
1396 keystore->capath = xstrdup(storepath);
1397 (void) snprintf(storepath, PATH_MAX, "%s/%s/%s",
1398 keystore_file, app, CERTSTORE);
1399 keystore->clpath = xstrdup(storepath);
1400 (void) snprintf(storepath, PATH_MAX, "%s/%s/%s",
1401 keystore_file, app, KEYSTORE);
1402 keystore->keypath = xstrdup(storepath);
1403 } else {
1404 /* app-generic keystore */
1405 if (!multi) {
1406 /* single-file app-generic keystore */
1407 keystore->capath = xstrdup(keystore_file);
1408 keystore->keypath = NULL;
1409 keystore->clpath = NULL;
1410 } else {
1411 /* multi-file app-generic keystore */
1412 (void) snprintf(storepath, PATH_MAX, "%s/%s",
1413 keystore_file, TRUSTSTORE);
1414 keystore->capath = xstrdup(storepath);
1415 (void) snprintf(storepath, PATH_MAX, "%s/%s",
1416 keystore_file, CERTSTORE);
1417 keystore->clpath = xstrdup(storepath);
1418 (void) snprintf(storepath, PATH_MAX, "%s/%s",
1419 keystore_file, KEYSTORE);
1420 keystore->keypath = xstrdup(storepath);
1424 return (B_TRUE);
1428 * lock_keystore - Locks a keystore for shared (read-only)
1429 * or exclusive (read-write) access.
1431 * The flags tell lock_keystore how to behave:
1433 * KEYSTORE_ACCESS_READONLY
1434 * opens keystore read-only. Attempts to modify results in an error
1436 * KEYSTORE_ACCESS_READWRITE
1437 * opens keystore read-write
1439 * KEYSTORE_PATH_SOFT
1440 * If the keystore file does not exist at <base>/<app> then
1441 * use <base> as the path to the keystore. This can be used,
1442 * for example, to access an app-specific keystore iff it
1443 * exists, otherwise revert back to an app-generic keystore.
1445 * KEYSTORE_PATH_HARD
1446 * Always use the keystore located at <keystore_path>/<app>.
1447 * In read/write mode, if the files do not exist, then
1448 * they will be created. This is used to avoid falling
1449 * back to an app-generic keystore path when the app-specific
1450 * one does not exist.
1452 * Arguments:
1453 * err - Error object to add errors to
1454 * flags - Control flags (see above description)
1455 * keystore - object which is being locked
1457 * Returns:
1458 * 0 - Success - Keystore file is locked, paths to
1459 * appropriate files placed in keystore.
1460 * non-zero - Failure, errors and reasons recorded in err
1462 static boolean_t
1463 lock_keystore(PKG_ERR *err, long flags, keystore_t *keystore)
1465 boolean_t ret = B_TRUE;
1466 struct stat buf;
1468 switch (flags & KEYSTORE_ACCESS_MASK) {
1469 case KEYSTORE_ACCESS_READONLY:
1470 if ((keystore->cafd =
1471 open(keystore->capath, O_NONBLOCK|O_RDONLY)) == -1) {
1472 if (errno == ENOENT) {
1474 * no keystore. try to create an
1475 * empty one so we can lock on it and
1476 * prevent others from gaining
1477 * exclusive access. It will be
1478 * deleted when the keystore is closed.
1480 if ((keystore->cafd =
1481 open(keystore->capath,
1482 O_NONBLOCK|O_RDWR|O_CREAT|O_EXCL,
1483 S_IRUSR|S_IWUSR)) == -1) {
1484 pkgerr_add(err, PKGERR_READ,
1485 gettext(ERR_NO_KEYSTORE),
1486 keystore->capath);
1487 ret = B_FALSE;
1488 goto cleanup;
1490 } else {
1491 pkgerr_add(err, PKGERR_READ,
1492 gettext(ERR_KEYSTORE_OPEN),
1493 keystore->capath, strerror(errno));
1494 ret = B_FALSE;
1495 goto cleanup;
1498 if (fstat(keystore->cafd, &buf) != -1) {
1499 if (S_ISREG(buf.st_mode)) {
1500 if (file_lock(keystore->cafd, F_RDLCK,
1501 0) == -1) {
1502 pkgerr_add(err, PKGERR_LOCKED,
1503 gettext(ERR_KEYSTORE_LOCKED_READ),
1504 keystore->capath);
1505 ret = B_FALSE;
1506 goto cleanup;
1508 } else {
1509 /* ca file not a regular file! */
1510 pkgerr_add(err, PKGERR_READ,
1511 gettext(ERR_NOT_REG),
1512 keystore->capath);
1513 ret = B_FALSE;
1514 goto cleanup;
1516 } else {
1517 pkgerr_add(err, PKGERR_READ,
1518 gettext(ERR_KEYSTORE_OPEN),
1519 keystore->capath, strerror(errno));
1520 ret = B_FALSE;
1521 goto cleanup;
1523 break;
1524 case KEYSTORE_ACCESS_READWRITE:
1526 if ((keystore->cafd = open(keystore->capath,
1527 O_RDWR|O_NONBLOCK)) == -1) {
1528 /* does not exist. try to create an empty one */
1529 if (errno == ENOENT) {
1530 if ((keystore->cafd =
1531 open(keystore->capath,
1532 O_NONBLOCK|O_RDWR|O_CREAT|O_EXCL,
1533 S_IRUSR|S_IWUSR)) == -1) {
1534 pkgerr_add(err, PKGERR_READ,
1535 gettext(ERR_KEYSTORE_WRITE),
1536 keystore->capath);
1537 ret = B_FALSE;
1538 goto cleanup;
1540 } else {
1541 pkgerr_add(err, PKGERR_READ,
1542 gettext(ERR_KEYSTORE_OPEN),
1543 keystore->capath, strerror(errno));
1544 ret = B_FALSE;
1545 goto cleanup;
1548 if (fstat(keystore->cafd, &buf) != -1) {
1549 if (S_ISREG(buf.st_mode)) {
1550 if (file_lock(keystore->cafd, F_WRLCK,
1551 0) == -1) {
1552 pkgerr_add(err, PKGERR_LOCKED,
1553 gettext(ERR_KEYSTORE_LOCKED),
1554 keystore->capath);
1555 ret = B_FALSE;
1556 goto cleanup;
1558 } else {
1559 /* ca file not a regular file! */
1560 pkgerr_add(err, PKGERR_READ,
1561 gettext(ERR_NOT_REG),
1562 keystore->capath);
1563 ret = B_FALSE;
1564 goto cleanup;
1566 } else {
1567 pkgerr_add(err, PKGERR_READ,
1568 gettext(ERR_KEYSTORE_OPEN),
1569 keystore->capath, strerror(errno));
1570 ret = B_FALSE;
1571 goto cleanup;
1574 break;
1575 default:
1576 pkgerr_add(err, PKGERR_INTERNAL,
1577 gettext(ERR_KEYSTORE_INTERNAL),
1578 __FILE__, __LINE__);
1579 ret = B_FALSE;
1580 goto cleanup;
1583 cleanup:
1584 if (!ret) {
1585 if (keystore->cafd > 0) {
1586 (void) file_unlock(keystore->cafd);
1587 (void) close(keystore->cafd);
1588 keystore->cafd = -1;
1591 if (keystore->capath != NULL)
1592 free(keystore->capath);
1593 if (keystore->clpath != NULL)
1594 free(keystore->clpath);
1595 if (keystore->keypath != NULL)
1596 free(keystore->keypath);
1597 keystore->capath = NULL;
1598 keystore->clpath = NULL;
1599 keystore->keypath = NULL;
1602 return (ret);
1606 * unlock_keystore - Unocks a keystore
1608 * Arguments:
1609 * err - Error object to add errors to
1610 * keystore - keystore object to unlock
1611 * Returns:
1612 * 0 - Success - Keystore files are unlocked, files are closed,
1613 * non-zero - Failure, errors and reasons recorded in err
1615 /* ARGSUSED */
1616 static boolean_t
1617 unlock_keystore(PKG_ERR *err, keystore_t *keystore)
1621 * Release lock on the CA file.
1622 * Delete file if it is empty
1624 if (file_empty(keystore->capath)) {
1625 (void) remove(keystore->capath);
1628 (void) file_unlock(keystore->cafd);
1629 (void) close(keystore->cafd);
1630 return (B_TRUE);
1634 * read_keystore - Reads keystore files of disk, parses
1635 * into internal structures.
1637 * Arguments:
1638 * err - Error object to add errors to
1639 * keystore - keystore object to read into
1640 * cb - callback to get password, if required
1641 * Returns:
1642 * 0 - Success - Keystore files are read, and placed
1643 * into keystore structure.
1644 * non-zero - Failure, errors and reasons recorded in err
1646 static boolean_t
1647 read_keystore(PKG_ERR *err, keystore_t *keystore, keystore_passphrase_cb cb)
1649 boolean_t ret = B_TRUE;
1650 PKCS12 *p12 = NULL;
1651 boolean_t ca_empty;
1652 boolean_t have_passwd = B_FALSE;
1653 boolean_t cl_empty = B_TRUE;
1654 boolean_t key_empty = B_TRUE;
1656 ca_empty = file_empty(keystore->capath);
1658 if (keystore->clpath != NULL)
1659 cl_empty = file_empty(keystore->clpath);
1660 if (keystore->keypath != NULL)
1661 key_empty = file_empty(keystore->keypath);
1663 if (ca_empty && cl_empty && key_empty) {
1664 keystore->new = B_TRUE;
1667 if (!ca_empty) {
1668 /* first read the ca file */
1669 if ((p12 = read_keystore_file(err,
1670 keystore->capath)) == NULL) {
1671 pkgerr_add(err, PKGERR_CORRUPT,
1672 gettext(ERR_KEYSTORE_CORRUPT), keystore->capath);
1673 ret = B_FALSE;
1674 goto cleanup;
1677 /* Get password, using callback if necessary */
1678 if (!have_passwd) {
1679 if (!get_keystore_passwd(err, p12, cb, keystore)) {
1680 ret = B_FALSE;
1681 goto cleanup;
1683 have_passwd = B_TRUE;
1686 /* decrypt and parse keystore file */
1687 if (sunw_PKCS12_contents(p12, keystore->passphrase,
1688 &keystore->pkeys, &keystore->cacerts) < 0) {
1689 /* could not parse the contents */
1690 pkgerr_add(err, PKGERR_CORRUPT,
1691 gettext(ERR_KEYSTORE_CORRUPT), keystore->capath);
1692 ret = B_FALSE;
1693 goto cleanup;
1696 PKCS12_free(p12);
1697 p12 = NULL;
1698 } else {
1701 * truststore is empty, so we don't have any trusted
1702 * certs
1704 keystore->cacerts = NULL;
1708 * if there is no cl file or key file, use the cl's and key's found
1709 * in the ca file
1711 if (keystore->clpath == NULL && !ca_empty) {
1712 if (sunw_split_certs(keystore->pkeys, keystore->cacerts,
1713 &keystore->clcerts, NULL) < 0) {
1714 pkgerr_add(err, PKGERR_CORRUPT,
1715 gettext(ERR_KEYSTORE_CORRUPT), keystore->capath);
1716 ret = B_FALSE;
1717 goto cleanup;
1719 } else {
1721 * files are in separate files. read keys out of the keystore
1722 * certs out of the certstore, if they are not empty
1724 if (!cl_empty) {
1725 if ((p12 = read_keystore_file(err,
1726 keystore->clpath)) == NULL) {
1727 pkgerr_add(err, PKGERR_CORRUPT,
1728 gettext(ERR_KEYSTORE_CORRUPT),
1729 keystore->clpath);
1730 ret = B_FALSE;
1731 goto cleanup;
1734 /* Get password, using callback if necessary */
1735 if (!have_passwd) {
1736 if (!get_keystore_passwd(err, p12, cb,
1737 keystore)) {
1738 ret = B_FALSE;
1739 goto cleanup;
1741 have_passwd = B_TRUE;
1744 if (check_password(p12,
1745 keystore->passphrase) == B_FALSE) {
1747 * password in client cert file
1748 * is different than
1749 * the one in the other files!
1751 pkgerr_add(err, PKGERR_BADPASS,
1752 gettext(ERR_MISMATCHPASS),
1753 keystore->clpath,
1754 keystore->capath, keystore->path);
1755 ret = B_FALSE;
1756 goto cleanup;
1759 if (sunw_PKCS12_contents(p12, keystore->passphrase,
1760 NULL, &keystore->clcerts) < 0) {
1761 /* could not parse the contents */
1762 pkgerr_add(err, PKGERR_CORRUPT,
1763 gettext(ERR_KEYSTORE_CORRUPT),
1764 keystore->clpath);
1765 ret = B_FALSE;
1766 goto cleanup;
1769 PKCS12_free(p12);
1770 p12 = NULL;
1771 } else {
1772 keystore->clcerts = NULL;
1775 if (!key_empty) {
1776 if ((p12 = read_keystore_file(err,
1777 keystore->keypath)) == NULL) {
1778 pkgerr_add(err, PKGERR_CORRUPT,
1779 gettext(ERR_KEYSTORE_CORRUPT),
1780 keystore->keypath);
1781 ret = B_FALSE;
1782 goto cleanup;
1785 /* Get password, using callback if necessary */
1786 if (!have_passwd) {
1787 if (!get_keystore_passwd(err, p12, cb,
1788 keystore)) {
1789 ret = B_FALSE;
1790 goto cleanup;
1792 have_passwd = B_TRUE;
1795 if (check_password(p12,
1796 keystore->passphrase) == B_FALSE) {
1797 pkgerr_add(err, PKGERR_BADPASS,
1798 gettext(ERR_MISMATCHPASS),
1799 keystore->keypath,
1800 keystore->capath, keystore->path);
1801 ret = B_FALSE;
1802 goto cleanup;
1805 if (sunw_PKCS12_contents(p12, keystore->passphrase,
1806 &keystore->pkeys, NULL) < 0) {
1807 /* could not parse the contents */
1808 pkgerr_add(err, PKGERR_CORRUPT,
1809 gettext(ERR_KEYSTORE_CORRUPT),
1810 keystore->keypath);
1811 ret = B_FALSE;
1812 goto cleanup;
1815 PKCS12_free(p12);
1816 p12 = NULL;
1817 } else {
1818 keystore->pkeys = NULL;
1822 cleanup:
1823 if (p12 != NULL)
1824 PKCS12_free(p12);
1825 return (ret);
1829 * get_keystore_password - retrieves pasword used to
1830 * decrypt PKCS12 structure.
1832 * Arguments:
1833 * err - Error object to add errors to
1834 * p12 - PKCS12 structure which returned password should
1835 * decrypt
1836 * cb - callback to collect password.
1837 * keystore - The keystore in which the PKCS12 structure
1838 * will eventually populate.
1839 * Returns:
1840 * B_TRUE - success.
1841 * keystore password is set in keystore->passphrase.
1842 * B_FALSE - failure, errors logged
1844 static boolean_t
1845 get_keystore_passwd(PKG_ERR *err, PKCS12 *p12, keystore_passphrase_cb cb,
1846 keystore_t *keystore)
1848 char *passwd;
1849 char passbuf[KEYSTORE_PASS_MAX + 1];
1850 keystore_passphrase_data data;
1852 /* see if no password is the right password */
1853 if (check_password(p12, "") == B_TRUE) {
1854 passwd = "";
1855 } else if (check_password(p12, NULL) == B_TRUE) {
1856 passwd = NULL;
1857 } else {
1858 /* oops, it's encrypted. get password */
1859 data.err = err;
1860 if (cb(passbuf, KEYSTORE_PASS_MAX, 0,
1861 &data) == -1) {
1862 /* could not get password */
1863 return (B_FALSE);
1866 if (check_password(p12, passbuf) == B_FALSE) {
1867 /* wrong password */
1868 pkgerr_add(err, PKGERR_BADPASS,
1869 gettext(ERR_BADPASS));
1870 return (B_FALSE);
1874 * make copy of password buffer, since it
1875 * goes away upon return
1877 passwd = xstrdup(passbuf);
1879 keystore->passphrase = passwd;
1880 return (B_TRUE);
1884 * write_keystore - Writes keystore files to disk
1886 * Arguments:
1887 * err - Error object to add errors to
1888 * keystore - keystore object to write from
1889 * passwd - password used to encrypt keystore
1890 * Returns:
1891 * 0 - Success - Keystore contents are written out to
1892 * the same locations as read from
1893 * non-zero - Failure, errors and reasons recorded in err
1895 static boolean_t
1896 write_keystore(PKG_ERR *err, keystore_t *keystore,
1897 keystore_passphrase_cb cb)
1899 PKCS12 *p12 = NULL;
1900 boolean_t ret = B_TRUE;
1901 keystore_passphrase_data data;
1902 char passbuf[KEYSTORE_PASS_MAX + 1];
1904 if (keystore->capath != NULL && keystore->clpath == NULL &&
1905 keystore->keypath == NULL) {
1908 * keystore is a file.
1909 * just write out a single file
1911 if ((keystore->pkeys == NULL) &&
1912 (keystore->clcerts == NULL) &&
1913 (keystore->cacerts == NULL)) {
1914 if (!clear_keystore_file(err, keystore->capath)) {
1916 * no keys or certs to write out, so
1917 * blank the ca file. we do not
1918 * delete it since it is used as a
1919 * lock by lock_keystore() in
1920 * subsequent invocations
1922 pkgerr_add(err, PKGERR_WRITE,
1923 gettext(ERR_KEYSTORE_WRITE),
1924 keystore->capath);
1925 ret = B_FALSE;
1926 goto cleanup;
1928 } else {
1930 * if the keystore is being created for the first time,
1931 * prompt for a passphrase for encryption
1933 if (keystore->new) {
1934 data.err = err;
1935 if (cb(passbuf, KEYSTORE_PASS_MAX,
1936 1, &data) == -1) {
1937 ret = B_FALSE;
1938 goto cleanup;
1940 } else {
1942 * use the one used when the keystore
1943 * was read
1945 (void) strlcpy(passbuf, keystore->passphrase,
1946 KEYSTORE_PASS_MAX);
1949 p12 = sunw_PKCS12_create(passbuf, keystore->pkeys,
1950 keystore->clcerts, keystore->cacerts);
1952 if (p12 == NULL) {
1953 pkgerr_add(err, PKGERR_WRITE,
1954 gettext(ERR_KEYSTORE_FORM),
1955 keystore->capath);
1956 ret = B_FALSE;
1957 goto cleanup;
1960 if (!write_keystore_file(err, keystore->capath, p12)) {
1961 pkgerr_add(err, PKGERR_WRITE,
1962 gettext(ERR_KEYSTORE_WRITE),
1963 keystore->capath);
1964 ret = B_FALSE;
1965 goto cleanup;
1969 } else {
1970 /* files are seprate. Do one at a time */
1973 * if the keystore is being created for the first time,
1974 * prompt for a passphrase for encryption
1976 if (keystore->new && ((keystore->pkeys != NULL) ||
1977 (keystore->clcerts != NULL) ||
1978 (keystore->cacerts != NULL))) {
1979 data.err = err;
1980 if (cb(passbuf, KEYSTORE_PASS_MAX,
1981 1, &data) == -1) {
1982 ret = B_FALSE;
1983 goto cleanup;
1985 } else {
1986 /* use the one used when the keystore was read */
1987 (void) strlcpy(passbuf, keystore->passphrase,
1988 KEYSTORE_PASS_MAX);
1991 /* do private keys first */
1992 if (keystore->pkeys != NULL) {
1993 p12 = sunw_PKCS12_create(passbuf, keystore->pkeys,
1994 NULL, NULL);
1996 if (p12 == NULL) {
1997 pkgerr_add(err, PKGERR_WRITE,
1998 gettext(ERR_KEYSTORE_FORM),
1999 keystore->keypath);
2000 ret = B_FALSE;
2001 goto cleanup;
2004 if (!write_keystore_file(err, keystore->keypath,
2005 p12)) {
2006 pkgerr_add(err, PKGERR_WRITE,
2007 gettext(ERR_KEYSTORE_WRITE),
2008 keystore->keypath);
2009 ret = B_FALSE;
2010 goto cleanup;
2013 PKCS12_free(p12);
2014 } else {
2015 if ((remove(keystore->keypath) != 0) &&
2016 (errno != ENOENT)) {
2017 pkgerr_add(err, PKGERR_WRITE,
2018 gettext(ERR_KEYSTORE_REMOVE),
2019 keystore->keypath);
2020 ret = B_FALSE;
2021 goto cleanup;
2025 /* do user certs next */
2026 if (keystore->clcerts != NULL) {
2027 p12 = sunw_PKCS12_create(passbuf, NULL,
2028 keystore->clcerts, NULL);
2030 if (p12 == NULL) {
2031 pkgerr_add(err, PKGERR_WRITE,
2032 gettext(ERR_KEYSTORE_FORM),
2033 keystore->clpath);
2034 ret = B_FALSE;
2035 goto cleanup;
2038 if (!write_keystore_file(err, keystore->clpath, p12)) {
2039 pkgerr_add(err, PKGERR_WRITE,
2040 gettext(ERR_KEYSTORE_WRITE),
2041 keystore->clpath);
2042 ret = B_FALSE;
2043 goto cleanup;
2046 PKCS12_free(p12);
2047 } else {
2048 if ((remove(keystore->clpath) != 0) &&
2049 (errno != ENOENT)) {
2050 pkgerr_add(err, PKGERR_WRITE,
2051 gettext(ERR_KEYSTORE_REMOVE),
2052 keystore->clpath);
2053 ret = B_FALSE;
2054 goto cleanup;
2059 /* finally do CA cert file */
2060 if (keystore->cacerts != NULL) {
2061 p12 = sunw_PKCS12_create(passbuf, NULL,
2062 NULL, keystore->cacerts);
2064 if (p12 == NULL) {
2065 pkgerr_add(err, PKGERR_WRITE,
2066 gettext(ERR_KEYSTORE_FORM),
2067 keystore->capath);
2068 ret = B_FALSE;
2069 goto cleanup;
2072 if (!write_keystore_file(err, keystore->capath, p12)) {
2073 pkgerr_add(err, PKGERR_WRITE,
2074 gettext(ERR_KEYSTORE_WRITE),
2075 keystore->capath);
2076 ret = B_FALSE;
2077 goto cleanup;
2080 PKCS12_free(p12);
2081 p12 = NULL;
2082 } else {
2084 * nothing to write out, so truncate the file
2085 * (it will be deleted during close_keystore)
2087 if (!clear_keystore_file(err, keystore->capath)) {
2088 pkgerr_add(err, PKGERR_WRITE,
2089 gettext(ERR_KEYSTORE_WRITE),
2090 keystore->capath);
2091 ret = B_FALSE;
2092 goto cleanup;
2097 cleanup:
2098 if (p12 != NULL)
2099 PKCS12_free(p12);
2101 return (ret);
2105 * clear_keystore_file - Clears (zeros out) a keystore file.
2107 * Arguments:
2108 * err - Error object to add errors to
2109 * dest - Path of keystore file to zero out.
2110 * Returns:
2111 * 0 - Success - Keystore file is truncated to zero length
2112 * non-zero - Failure, errors and reasons recorded in err
2114 static boolean_t
2115 clear_keystore_file(PKG_ERR *err, char *dest)
2117 int fd;
2118 struct stat buf;
2120 fd = open(dest, O_RDWR|O_NONBLOCK);
2121 if (fd == -1) {
2122 /* can't open for writing */
2123 pkgerr_add(err, PKGERR_WRITE, gettext(MSG_OPEN),
2124 errno);
2125 return (B_FALSE);
2128 if ((fstat(fd, &buf) == -1) || !S_ISREG(buf.st_mode)) {
2129 /* not a regular file */
2130 (void) close(fd);
2131 pkgerr_add(err, PKGERR_WRITE, gettext(ERR_NOT_REG),
2132 dest);
2133 return (B_FALSE);
2136 if (ftruncate(fd, 0) == -1) {
2137 (void) close(fd);
2138 pkgerr_add(err, PKGERR_WRITE, gettext(ERR_WRITE),
2139 dest, strerror(errno));
2140 return (B_FALSE);
2143 (void) close(fd);
2144 return (B_TRUE);
2148 * write_keystore_file - Writes keystore file to disk.
2150 * Keystore files can possibly be corrupted by a variety
2151 * of error conditions during reading/writing. This
2152 * routine, along with restore_keystore_file, tries to
2153 * maintain keystore integity by writing the files
2154 * out in a particular order, minimizing the time period
2155 * that the keystore is in an indeterminate state.
2157 * With the current implementation, there are some failures
2158 * that are wholly unrecoverable, such as disk corruption.
2159 * These routines attempt to minimize the risk, but not
2160 * eliminate it. When better, atomic operations are available
2161 * (such as a true database with commit, rollback, and
2162 * guaranteed atomicity), this implementation should use that.
2165 * Arguments:
2166 * err - Error object to add errors to
2167 * dest - Destination filename
2168 * contents - Contents to write to the file
2169 * Returns:
2170 * 0 - Success - Keystore contents are written out to
2171 * the destination.
2172 * non-zero - Failure, errors and reasons recorded in err
2174 static boolean_t
2175 write_keystore_file(PKG_ERR *err, char *dest, PKCS12 *contents)
2177 FILE *newfile = NULL;
2178 boolean_t ret = B_TRUE;
2179 char newpath[MAXPATHLEN];
2180 char backuppath[MAXPATHLEN];
2181 struct stat buf;
2182 int fd;
2184 (void) snprintf(newpath, MAXPATHLEN, "%s.new", dest);
2185 (void) snprintf(backuppath, MAXPATHLEN, "%s.bak", dest);
2187 if ((fd = open(newpath, O_CREAT|O_EXCL|O_WRONLY|O_NONBLOCK,
2188 S_IRUSR|S_IWUSR)) == -1) {
2189 pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2190 newpath, strerror(errno));
2191 ret = B_FALSE;
2192 goto cleanup;
2195 if (fstat(fd, &buf) == -1) {
2196 pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2197 newpath, strerror(errno));
2198 ret = B_FALSE;
2199 goto cleanup;
2202 if (!S_ISREG(buf.st_mode)) {
2203 pkgerr_add(err, PKGERR_READ, gettext(ERR_NOT_REG),
2204 newpath);
2205 ret = B_FALSE;
2206 goto cleanup;
2209 if ((newfile = fdopen(fd, "w")) == NULL) {
2210 pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2211 newpath, strerror(errno));
2212 ret = B_FALSE;
2213 goto cleanup;
2216 if (i2d_PKCS12_fp(newfile, contents) == 0) {
2217 pkgerr_add(err, PKGERR_WRITE, gettext(ERR_KEYSTORE_WRITE),
2218 newpath);
2219 ret = B_FALSE;
2220 goto cleanup;
2223 /* flush, then close */
2224 (void) fflush(newfile);
2225 (void) fclose(newfile);
2226 newfile = NULL;
2228 /* now back up the original file */
2229 (void) rename(dest, backuppath);
2231 /* put new one in its place */
2232 (void) rename(newpath, dest);
2234 /* remove backup */
2235 (void) remove(backuppath);
2237 cleanup:
2238 if (newfile != NULL)
2239 (void) fclose(newfile);
2240 if (fd != -1)
2241 (void) close(fd);
2243 return (ret);
2247 * read_keystore_file - Reads single keystore file
2248 * off disk in PKCS12 format.
2250 * Arguments:
2251 * err - Error object to add errors to
2252 * file - File path to read
2253 * Returns:
2254 * PKCS12 contents of file, or NULL if an error occurred.
2255 * errors recorded in 'err'.
2257 static PKCS12
2258 *read_keystore_file(PKG_ERR *err, char *file)
2260 int fd;
2261 struct stat buf;
2262 FILE *newfile;
2263 PKCS12 *p12 = NULL;
2265 if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
2266 pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2267 file, strerror(errno));
2268 goto cleanup;
2271 if (fstat(fd, &buf) == -1) {
2272 pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2273 file, strerror(errno));
2274 goto cleanup;
2277 if (!S_ISREG(buf.st_mode)) {
2278 pkgerr_add(err, PKGERR_READ, gettext(ERR_NOT_REG),
2279 file);
2280 goto cleanup;
2283 if ((newfile = fdopen(fd, "r")) == NULL) {
2284 pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2285 file, strerror(errno));
2286 goto cleanup;
2289 if ((p12 = d2i_PKCS12_fp(newfile, NULL)) == NULL) {
2290 pkgerr_add(err, PKGERR_CORRUPT,
2291 gettext(ERR_KEYSTORE_CORRUPT), file);
2292 goto cleanup;
2295 cleanup:
2296 if (newfile != NULL)
2297 (void) fclose(newfile);
2298 if (fd != -1)
2299 (void) close(fd);
2301 return (p12);
2306 * Locks the specified file.
2308 static int
2309 file_lock(int fd, int type, int wait)
2311 struct flock lock;
2313 lock.l_type = type;
2314 lock.l_start = 0;
2315 lock.l_whence = SEEK_SET;
2316 lock.l_len = 0;
2318 if (!wait) {
2319 if (file_lock_test(fd, type)) {
2321 * The caller would have to wait to get the
2322 * lock on this file.
2324 return (-1);
2328 return (fcntl(fd, F_SETLKW, &lock));
2332 * Returns FALSE if the file is not locked; TRUE
2333 * otherwise.
2335 static boolean_t
2336 file_lock_test(int fd, int type)
2338 struct flock lock;
2340 lock.l_type = type;
2341 lock.l_start = 0;
2342 lock.l_whence = SEEK_SET;
2343 lock.l_len = 0;
2345 if (fcntl(fd, F_GETLK, &lock) != -1) {
2346 if (lock.l_type != F_UNLCK) {
2348 * The caller would have to wait to get the
2349 * lock on this file.
2351 return (B_TRUE);
2356 * The file is not locked.
2358 return (B_FALSE);
2362 * Unlocks the specified file.
2364 static int
2365 file_unlock(int fd)
2367 struct flock lock;
2369 lock.l_type = F_UNLCK;
2370 lock.l_start = 0;
2371 lock.l_whence = SEEK_SET;
2372 lock.l_len = 0;
2374 return (fcntl(fd, F_SETLK, &lock));
2378 * Determines if file has a length of 0 or not
2380 static boolean_t
2381 file_empty(char *path)
2383 struct stat buf;
2385 /* file is empty if size = 0 or it doesn't exist */
2386 if (lstat(path, &buf) == 0) {
2387 if (buf.st_size == 0) {
2388 return (B_TRUE);
2390 } else {
2391 if (errno == ENOENT) {
2392 return (B_TRUE);
2396 return (B_FALSE);
2400 * Name: get_time_string
2401 * Description: Generates a human-readable string from an ASN1_TIME
2403 * Arguments: intime - The time to convert
2405 * Returns : A pointer to a static string representing the passed-in time.
2407 static char
2408 *get_time_string(ASN1_TIME *intime)
2411 static char time[ATTR_MAX];
2412 BIO *mem;
2413 char *p;
2415 if (intime == NULL) {
2416 return (NULL);
2418 if ((mem = BIO_new(BIO_s_mem())) == NULL) {
2419 return (NULL);
2422 if (ASN1_TIME_print(mem, intime) == 0) {
2423 (void) BIO_free(mem);
2424 return (NULL);
2427 if (BIO_gets(mem, time, ATTR_MAX) <= 0) {
2428 (void) BIO_free(mem);
2429 return (NULL);
2432 (void) BIO_free(mem);
2434 /* trim the end of the string */
2435 for (p = time + strlen(time) - 1; isspace(*p); p--) {
2436 *p = '\0';
2439 return (time);
2443 * check_password - do various password checks to see if the current password
2444 * will work or we need to prompt for a new one.
2446 * Arguments:
2447 * pass - password to check
2449 * Returns:
2450 * B_TRUE - Password is OK.
2451 * B_FALSE - Password not valid.
2453 static boolean_t
2454 check_password(PKCS12 *p12, char *pass)
2456 boolean_t ret = B_TRUE;
2459 * If password is zero length or NULL then try verifying both cases
2460 * to determine which password is correct. The reason for this is that
2461 * under PKCS#12 password based encryption no password and a zero
2462 * length password are two different things...
2465 /* Check the mac */
2466 if (pass == NULL || *pass == '\0') {
2467 if (PKCS12_verify_mac(p12, NULL, 0) == 0 &&
2468 PKCS12_verify_mac(p12, "", 0) == 0)
2469 ret = B_FALSE;
2470 } else if (PKCS12_verify_mac(p12, pass, -1) == 0) {
2471 ret = B_FALSE;
2473 return (ret);