/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include "key_xdr.h" #include "key_util.h" /* * Size of 'empty' pkcs12 key file (with no key in it) plus 1 * This is the minimum length for our RSA keys, because we * only use RSA keys that are stored in PKCS12 format. */ #define PKCS12_MIN_LEN 76 /* * Program name to be used by wbku_printerr() */ static const char *wbku_pname = NULL; /* * Note: must be kept in sync with codes in */ static char *wbku_retmsgs[WBKU_NRET] = { /* 0 WBKU_SUCCESS */ "Success", /* 1 WBKU_INTERNAL_ERR */ "Internal error", /* 2 WBKU_WRITE_ERR */ "Keystore write error", /* 3 WBKU_NOKEY */ "Key does not exist in keystore", /* 4 WBKU_BAD_KEYTYPE */ "Invalid keytype specified" }; /* * Initialize library for calls to wbku_printerr(). */ void wbku_errinit(const char *arg0) { wbku_pname = strrchr(arg0, '/'); if (wbku_pname == NULL) wbku_pname = arg0; else wbku_pname++; } /* * Print an error message to standard error and optionally * append a system error. */ /*PRINTFLIKE1*/ void wbku_printerr(const char *format, ...) { int err = errno; va_list ap; if (wbku_pname != NULL) (void) fprintf(stderr, "%s: ", wbku_pname); /* * Note that gettext() is used in order to obtain the * message from the consumer's domain. */ va_start(ap, format); (void) vfprintf(stderr, gettext(format), ap); va_end(ap); if (strchr(format, '\n') == NULL) (void) fprintf(stderr, ": %s\n", strerror(err)); } /* * Return the appropriate message for a given WBKU return code. */ const char * wbku_retmsg(wbku_retcode_t retcode) { if ((retcode < WBKU_SUCCESS) || (retcode >= WBKU_NRET)) return (dgettext(TEXT_DOMAIN, "")); return (dgettext(TEXT_DOMAIN, wbku_retmsgs[retcode])); } /* * This routine is a simple helper routine that initializes a * wbku_key_attr_t object. */ static void wbku_keyattr_init(wbku_key_attr_t *attr, wbku_key_type_t type, uint_t atype, uint_t len, uint_t minlen, uint_t maxlen, char *str, char *oid, boolean_t (*keycheck)(const uint8_t *)) { attr->ka_type = type; attr->ka_atype = atype; attr->ka_len = len; attr->ka_minlen = minlen; attr->ka_maxlen = maxlen; attr->ka_str = str; attr->ka_oid = oid; attr->ka_keycheck = keycheck; } /* * This routine is used to build a key attribute structure of the type * defined by 'str' and 'flag'. This structure, 'attr', is the common * structure used by the utilities that defines the attributes of a * specific key type. * * Returns: * WBKU_SUCCESS or WBKU_BAD_KEYTYPE. */ wbku_retcode_t wbku_str_to_keyattr(const char *str, wbku_key_attr_t *attr, uint_t flag) { if (str == NULL) return (WBKU_BAD_KEYTYPE); if (flag & WBKU_ENCR_KEY) { if (strcmp(str, WBKU_KW_3DES) == 0) { wbku_keyattr_init(attr, WBKU_KEY_3DES, WBKU_ENCR_KEY, DES3_KEY_SIZE, DES3_KEY_SIZE, DES3_KEY_SIZE, "3DES", WBKU_DES3_OID, des3_keycheck); return (WBKU_SUCCESS); } if (strcmp(str, WBKU_KW_AES_128) == 0) { wbku_keyattr_init(attr, WBKU_KEY_AES_128, WBKU_ENCR_KEY, AES_128_KEY_SIZE, AES_128_KEY_SIZE, AES_128_KEY_SIZE, "AES", WBKU_AES_128_OID, NULL); return (WBKU_SUCCESS); } if (strcmp(str, WBKU_KW_RSA) == 0) { wbku_keyattr_init(attr, WBKU_KEY_RSA, WBKU_ENCR_KEY, 0, PKCS12_MIN_LEN, WBKU_MAX_KEYLEN, "RSA", WBKU_RSA_OID, NULL); return (WBKU_SUCCESS); } } if (flag & WBKU_HASH_KEY) { if (strcmp(str, WBKU_KW_HMAC_SHA1) == 0) { wbku_keyattr_init(attr, WBKU_KEY_HMAC_SHA1, WBKU_HASH_KEY, WANBOOT_HMAC_KEY_SIZE, WANBOOT_HMAC_KEY_SIZE, WANBOOT_HMAC_KEY_SIZE, "HMAC/SHA1", WBKU_HMAC_SHA1_OID, NULL); return (WBKU_SUCCESS); } } return (WBKU_BAD_KEYTYPE); } /* * This routine is used to search a key file (whose handle, fp, has been * initialized by the caller) for the key of type 'ka'. The search is further * constrained by the 'master' argument which is used to signify that the * key being searched for is the master key. * * This routine may be used for a number of purposes: * - Check for the existence of key of type foo. * - Get the value for the key of type foo. * - Return the file position of the key of type foo. * * To faciliate the uses above, both 'ppos' and 'ekey' will only be * returned if they are not NULL pointers. * * Returns: * WBKU_SUCCESS, WBKU_INTERNAL_ERR or WBKU_NOKEY. */ wbku_retcode_t wbku_find_key(FILE *fp, fpos_t *ppos, wbku_key_attr_t *ka, uint8_t *ekey, boolean_t master) { fpos_t pos; XDR xdrs; wbku_key keyobj; int keyno; int ret; /* * Always, start at the beginning. */ rewind(fp); /* * Initialize the XDR stream. */ xdrs.x_ops = NULL; xdrstdio_create(&xdrs, fp, XDR_DECODE); if (xdrs.x_ops == NULL) { return (WBKU_INTERNAL_ERR); } /* * The XDR routines may examine the content of the keyobj * structure to determine whether or not to provide memory * resources. Since XDR does not provide an init routine * for XDR generated objects, it seems that the safest thing * to do is to bzero() the object as a means of initialization. */ bzero(&keyobj, sizeof (keyobj)); /* * Read a key and check to see if matches the criteria. */ for (keyno = 0; !feof(fp); keyno++) { /* * Returning the file position is conditional. */ if (ppos != NULL) { if (fgetpos(fp, &pos) != 0) { ret = WBKU_INTERNAL_ERR; break; } } /* * Read the key. Unfortuantely, XDR does not provide * the ability to tell an EOF from some other IO error. * Therefore, a faliure to read is assumed to be EOF. */ if (!xdr_wbku_key(&xdrs, &keyobj)) { ret = WBKU_NOKEY; break; } /* * Check this key against the criteria. */ if ((strcmp(keyobj.wk_oid, ka->ka_oid) == 0) && (keyobj.wk_master == master)) { ka->ka_len = keyobj.wk_key_len; /* * Conditionally return the key value and file * position. */ if (ekey != NULL) { (void) memcpy(ekey, keyobj.wk_key_val, ka->ka_len); } if (ppos != NULL) { *ppos = pos; } xdr_free(xdr_wbku_key, (char *)&keyobj); ret = WBKU_SUCCESS; break; } xdr_free(xdr_wbku_key, (char *)&keyobj); } xdr_destroy(&xdrs); return (ret); } /* * This routine writes a key object to the key file at the location * specified by the caller. * * Returns: * WBKU_SUCCESS, WBKU_INTERNAL_ERR or WBKU_WRITE_ERR. */ wbku_retcode_t wbku_write_key(FILE *fp, const fpos_t *ppos, const wbku_key_attr_t *ka, uint8_t *rand_key, boolean_t master) { XDR xdrs; wbku_key keyobj; /* * Set the file position as specified by the caller. */ if (fsetpos(fp, ppos) != 0) { return (WBKU_INTERNAL_ERR); } /* * Initialize the XDR stream. */ xdrs.x_ops = NULL; xdrstdio_create(&xdrs, fp, XDR_ENCODE); if (xdrs.x_ops == NULL) { return (WBKU_INTERNAL_ERR); } /* * Build the key object. */ keyobj.wk_master = master; keyobj.wk_oid = ka->ka_oid; keyobj.wk_key_len = ka->ka_len; keyobj.wk_key_val = (char *)rand_key; /* * Write it. */ if (!xdr_wbku_key(&xdrs, &keyobj)) { xdr_free(xdr_wbku_key, (char *)&keyobj); xdr_destroy(&xdrs); return (WBKU_WRITE_ERR); } /* * Free the stream and return success. */ xdr_destroy(&xdrs); return (WBKU_SUCCESS); } /* * This routine reads the contents of one keystore file and copies it to * another, omitting the key of the type defined by 'ka'. * * Returns: * WBKU_SUCCESS, WBKU_INTERNAL_ERR or WBKU_WRITE_ERR. */ wbku_retcode_t wbku_delete_key(FILE *from_fp, FILE *to_fp, const wbku_key_attr_t *ka) { XDR from_xdrs; XDR to_xdrs; wbku_key keyobj; int keyno; int ret; /* * Always, start at the beginning. */ rewind(from_fp); rewind(to_fp); /* * Initialize the XDR streams. */ from_xdrs.x_ops = NULL; xdrstdio_create(&from_xdrs, from_fp, XDR_DECODE); if (from_xdrs.x_ops == NULL) { return (WBKU_INTERNAL_ERR); } to_xdrs.x_ops = NULL; xdrstdio_create(&to_xdrs, to_fp, XDR_ENCODE); if (to_xdrs.x_ops == NULL) { xdr_destroy(&from_xdrs); return (WBKU_INTERNAL_ERR); } /* * The XDR routines may examine the content of the keyobj * structure to determine whether or not to provide memory * resources. Since XDR does not provide an init routine * for XDR generated objects, it seems that the safest thing * to do is to bzero() the object as a means of initialization. */ bzero(&keyobj, sizeof (keyobj)); /* * Read a key and check to see if matches the criteria. */ ret = WBKU_SUCCESS; for (keyno = 0; !feof(from_fp); keyno++) { /* * Read the key. Unfortuantely, XDR does not provide * the ability to tell an EOF from some other IO error. * Therefore, a faliure to read is assumed to be EOF. */ if (!xdr_wbku_key(&from_xdrs, &keyobj)) { break; } /* * If this isn't the key to skip, then write it. */ if (strcmp(keyobj.wk_oid, ka->ka_oid) != 0) { /* * Write this to the copy. */ if (!xdr_wbku_key(&to_xdrs, &keyobj)) { xdr_free(xdr_wbku_key, (char *)&keyobj); ret = WBKU_WRITE_ERR; break; } } xdr_free(xdr_wbku_key, (char *)&keyobj); } xdr_destroy(&from_xdrs); xdr_destroy(&to_xdrs); return (ret); }