1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <strings.h> 29 #include <stdarg.h> 30 #include <errno.h> 31 #include <libintl.h> 32 #include <sys/wanboot_impl.h> 33 34 #include "key_xdr.h" 35 #include "key_util.h" 36 37 /* 38 * Size of 'empty' pkcs12 key file (with no key in it) plus 1 39 * This is the minimum length for our RSA keys, because we 40 * only use RSA keys that are stored in PKCS12 format. 41 */ 42 #define PKCS12_MIN_LEN 76 43 44 /* 45 * Program name to be used by wbku_printerr() 46 */ 47 static const char *wbku_pname = NULL; 48 49 /* 50 * Note: must be kept in sync with codes in <key_util.h> 51 */ 52 static char *wbku_retmsgs[WBKU_NRET] = { 53 /* 0 WBKU_SUCCESS */ "Success", 54 /* 1 WBKU_INTERNAL_ERR */ "Internal error", 55 /* 2 WBKU_WRITE_ERR */ "Keystore write error", 56 /* 3 WBKU_NOKEY */ "Key does not exist in keystore", 57 /* 4 WBKU_BAD_KEYTYPE */ "Invalid keytype specified" 58 }; 59 60 /* 61 * Initialize library for calls to wbku_printerr(). 62 */ 63 void 64 wbku_errinit(const char *arg0) 65 { 66 wbku_pname = strrchr(arg0, '/'); 67 68 if (wbku_pname == NULL) 69 wbku_pname = arg0; 70 else 71 wbku_pname++; 72 } 73 74 /* 75 * Print an error message to standard error and optionally 76 * append a system error. 77 */ 78 /*PRINTFLIKE1*/ 79 void 80 wbku_printerr(const char *format, ...) 81 { 82 int err = errno; 83 va_list ap; 84 85 if (wbku_pname != NULL) 86 (void) fprintf(stderr, "%s: ", wbku_pname); 87 88 /* 89 * Note that gettext() is used in order to obtain the 90 * message from the consumer's domain. 91 */ 92 va_start(ap, format); 93 (void) vfprintf(stderr, gettext(format), ap); 94 va_end(ap); 95 96 if (strchr(format, '\n') == NULL) 97 (void) fprintf(stderr, ": %s\n", strerror(err)); 98 } 99 100 /* 101 * Return the appropriate message for a given WBKU return code. 102 */ 103 const char * 104 wbku_retmsg(wbku_retcode_t retcode) 105 { 106 if ((retcode < WBKU_SUCCESS) || (retcode >= WBKU_NRET)) 107 return (dgettext(TEXT_DOMAIN, "<unknown code>")); 108 109 return (dgettext(TEXT_DOMAIN, wbku_retmsgs[retcode])); 110 } 111 112 /* 113 * This routine is a simple helper routine that initializes a 114 * wbku_key_attr_t object. 115 */ 116 static void 117 wbku_keyattr_init(wbku_key_attr_t *attr, wbku_key_type_t type, uint_t atype, 118 uint_t len, uint_t minlen, uint_t maxlen, 119 char *str, char *oid, boolean_t (*keycheck)(const uint8_t *)) 120 { 121 attr->ka_type = type; 122 attr->ka_atype = atype; 123 attr->ka_len = len; 124 attr->ka_minlen = minlen; 125 attr->ka_maxlen = maxlen; 126 attr->ka_str = str; 127 attr->ka_oid = oid; 128 attr->ka_keycheck = keycheck; 129 } 130 131 132 /* 133 * This routine is used to build a key attribute structure of the type 134 * defined by 'str' and 'flag'. This structure, 'attr', is the common 135 * structure used by the utilities that defines the attributes of a 136 * specific key type. 137 * 138 * Returns: 139 * WBKU_SUCCESS or WBKU_BAD_KEYTYPE. 140 */ 141 wbku_retcode_t 142 wbku_str_to_keyattr(const char *str, wbku_key_attr_t *attr, uint_t flag) 143 { 144 if (str == NULL) 145 return (WBKU_BAD_KEYTYPE); 146 147 if (flag & WBKU_ENCR_KEY) { 148 if (strcmp(str, WBKU_KW_3DES) == 0) { 149 wbku_keyattr_init(attr, WBKU_KEY_3DES, 150 WBKU_ENCR_KEY, DES3_KEY_SIZE, DES3_KEY_SIZE, 151 DES3_KEY_SIZE, "3DES", WBKU_DES3_OID, 152 des3_keycheck); 153 return (WBKU_SUCCESS); 154 } 155 if (strcmp(str, WBKU_KW_AES_128) == 0) { 156 wbku_keyattr_init(attr, WBKU_KEY_AES_128, 157 WBKU_ENCR_KEY, AES_128_KEY_SIZE, AES_128_KEY_SIZE, 158 AES_128_KEY_SIZE, "AES", WBKU_AES_128_OID, NULL); 159 return (WBKU_SUCCESS); 160 } 161 if (strcmp(str, WBKU_KW_RSA) == 0) { 162 wbku_keyattr_init(attr, WBKU_KEY_RSA, 163 WBKU_ENCR_KEY, 0, PKCS12_MIN_LEN, 164 WBKU_MAX_KEYLEN, "RSA", WBKU_RSA_OID, NULL); 165 return (WBKU_SUCCESS); 166 } 167 } 168 if (flag & WBKU_HASH_KEY) { 169 if (strcmp(str, WBKU_KW_HMAC_SHA1) == 0) { 170 wbku_keyattr_init(attr, WBKU_KEY_HMAC_SHA1, 171 WBKU_HASH_KEY, WANBOOT_HMAC_KEY_SIZE, 172 WANBOOT_HMAC_KEY_SIZE, WANBOOT_HMAC_KEY_SIZE, 173 "HMAC/SHA1", WBKU_HMAC_SHA1_OID, NULL); 174 return (WBKU_SUCCESS); 175 } 176 } 177 return (WBKU_BAD_KEYTYPE); 178 } 179 180 /* 181 * This routine is used to search a key file (whose handle, fp, has been 182 * initialized by the caller) for the key of type 'ka'. The search is further 183 * constrained by the 'master' argument which is used to signify that the 184 * key being searched for is the master key. 185 * 186 * This routine may be used for a number of purposes: 187 * - Check for the existence of key of type foo. 188 * - Get the value for the key of type foo. 189 * - Return the file position of the key of type foo. 190 * 191 * To faciliate the uses above, both 'ppos' and 'ekey' will only be 192 * returned if they are not NULL pointers. 193 * 194 * Returns: 195 * WBKU_SUCCESS, WBKU_INTERNAL_ERR or WBKU_NOKEY. 196 */ 197 wbku_retcode_t 198 wbku_find_key(FILE *fp, fpos_t *ppos, wbku_key_attr_t *ka, uint8_t *ekey, 199 boolean_t master) 200 { 201 fpos_t pos; 202 XDR xdrs; 203 wbku_key keyobj; 204 int keyno; 205 int ret; 206 207 /* 208 * Always, start at the beginning. 209 */ 210 rewind(fp); 211 212 /* 213 * Initialize the XDR stream. 214 */ 215 xdrs.x_ops = NULL; 216 xdrstdio_create(&xdrs, fp, XDR_DECODE); 217 if (xdrs.x_ops == NULL) { 218 return (WBKU_INTERNAL_ERR); 219 } 220 221 /* 222 * The XDR routines may examine the content of the keyobj 223 * structure to determine whether or not to provide memory 224 * resources. Since XDR does not provide an init routine 225 * for XDR generated objects, it seems that the safest thing 226 * to do is to bzero() the object as a means of initialization. 227 */ 228 bzero(&keyobj, sizeof (keyobj)); 229 230 /* 231 * Read a key and check to see if matches the criteria. 232 */ 233 for (keyno = 0; !feof(fp); keyno++) { 234 235 /* 236 * Returning the file position is conditional. 237 */ 238 if (ppos != NULL) { 239 if (fgetpos(fp, &pos) != 0) { 240 ret = WBKU_INTERNAL_ERR; 241 break; 242 } 243 } 244 245 /* 246 * Read the key. Unfortuantely, XDR does not provide 247 * the ability to tell an EOF from some other IO error. 248 * Therefore, a faliure to read is assumed to be EOF. 249 */ 250 if (!xdr_wbku_key(&xdrs, &keyobj)) { 251 ret = WBKU_NOKEY; 252 break; 253 } 254 255 /* 256 * Check this key against the criteria. 257 */ 258 if ((strcmp(keyobj.wk_oid, ka->ka_oid) == 0) && 259 (keyobj.wk_master == master)) { 260 261 ka->ka_len = keyobj.wk_key_len; 262 263 /* 264 * Conditionally return the key value and file 265 * position. 266 */ 267 if (ekey != NULL) { 268 (void) memcpy(ekey, keyobj.wk_key_val, 269 ka->ka_len); 270 } 271 if (ppos != NULL) { 272 *ppos = pos; 273 } 274 275 xdr_free(xdr_wbku_key, (char *)&keyobj); 276 ret = WBKU_SUCCESS; 277 break; 278 } 279 xdr_free(xdr_wbku_key, (char *)&keyobj); 280 } 281 282 xdr_destroy(&xdrs); 283 return (ret); 284 } 285 286 /* 287 * This routine writes a key object to the key file at the location 288 * specified by the caller. 289 * 290 * Returns: 291 * WBKU_SUCCESS, WBKU_INTERNAL_ERR or WBKU_WRITE_ERR. 292 */ 293 wbku_retcode_t 294 wbku_write_key(FILE *fp, const fpos_t *ppos, const wbku_key_attr_t *ka, 295 uint8_t *rand_key, boolean_t master) 296 { 297 XDR xdrs; 298 wbku_key keyobj; 299 300 /* 301 * Set the file position as specified by the caller. 302 */ 303 if (fsetpos(fp, ppos) != 0) { 304 return (WBKU_INTERNAL_ERR); 305 } 306 307 /* 308 * Initialize the XDR stream. 309 */ 310 xdrs.x_ops = NULL; 311 xdrstdio_create(&xdrs, fp, XDR_ENCODE); 312 if (xdrs.x_ops == NULL) { 313 return (WBKU_INTERNAL_ERR); 314 } 315 316 /* 317 * Build the key object. 318 */ 319 keyobj.wk_master = master; 320 keyobj.wk_oid = ka->ka_oid; 321 keyobj.wk_key_len = ka->ka_len; 322 keyobj.wk_key_val = (char *)rand_key; 323 324 /* 325 * Write it. 326 */ 327 if (!xdr_wbku_key(&xdrs, &keyobj)) { 328 xdr_free(xdr_wbku_key, (char *)&keyobj); 329 xdr_destroy(&xdrs); 330 return (WBKU_WRITE_ERR); 331 } 332 333 /* 334 * Free the stream and return success. 335 */ 336 xdr_destroy(&xdrs); 337 return (WBKU_SUCCESS); 338 } 339 340 /* 341 * This routine reads the contents of one keystore file and copies it to 342 * another, omitting the key of the type defined by 'ka'. 343 * 344 * Returns: 345 * WBKU_SUCCESS, WBKU_INTERNAL_ERR or WBKU_WRITE_ERR. 346 */ 347 wbku_retcode_t 348 wbku_delete_key(FILE *from_fp, FILE *to_fp, const wbku_key_attr_t *ka) 349 { 350 XDR from_xdrs; 351 XDR to_xdrs; 352 wbku_key keyobj; 353 int keyno; 354 int ret; 355 356 /* 357 * Always, start at the beginning. 358 */ 359 rewind(from_fp); 360 rewind(to_fp); 361 362 /* 363 * Initialize the XDR streams. 364 */ 365 from_xdrs.x_ops = NULL; 366 xdrstdio_create(&from_xdrs, from_fp, XDR_DECODE); 367 if (from_xdrs.x_ops == NULL) { 368 return (WBKU_INTERNAL_ERR); 369 } 370 371 to_xdrs.x_ops = NULL; 372 xdrstdio_create(&to_xdrs, to_fp, XDR_ENCODE); 373 if (to_xdrs.x_ops == NULL) { 374 xdr_destroy(&from_xdrs); 375 return (WBKU_INTERNAL_ERR); 376 } 377 378 /* 379 * The XDR routines may examine the content of the keyobj 380 * structure to determine whether or not to provide memory 381 * resources. Since XDR does not provide an init routine 382 * for XDR generated objects, it seems that the safest thing 383 * to do is to bzero() the object as a means of initialization. 384 */ 385 bzero(&keyobj, sizeof (keyobj)); 386 387 /* 388 * Read a key and check to see if matches the criteria. 389 */ 390 ret = WBKU_SUCCESS; 391 for (keyno = 0; !feof(from_fp); keyno++) { 392 393 /* 394 * Read the key. Unfortuantely, XDR does not provide 395 * the ability to tell an EOF from some other IO error. 396 * Therefore, a faliure to read is assumed to be EOF. 397 */ 398 if (!xdr_wbku_key(&from_xdrs, &keyobj)) { 399 break; 400 } 401 402 /* 403 * If this isn't the key to skip, then write it. 404 */ 405 if (strcmp(keyobj.wk_oid, ka->ka_oid) != 0) { 406 /* 407 * Write this to the copy. 408 */ 409 if (!xdr_wbku_key(&to_xdrs, &keyobj)) { 410 xdr_free(xdr_wbku_key, (char *)&keyobj); 411 ret = WBKU_WRITE_ERR; 412 break; 413 } 414 415 } 416 417 xdr_free(xdr_wbku_key, (char *)&keyobj); 418 } 419 420 xdr_destroy(&from_xdrs); 421 xdr_destroy(&to_xdrs); 422 423 return (ret); 424 } 425