security/nss/lib/ckfw/nssmkey/mobject.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "ckmk.h"
michael@0 6 #include "nssbase.h"
michael@0 7
michael@0 8 #include "secdert.h" /* for DER_INTEGER */
michael@0 9 #include "string.h"
michael@0 10
michael@0 11 /* asn1 encoder (to build pkcs#8 blobs) */
michael@0 12 #include <seccomon.h>
michael@0 13 #include <secitem.h>
michael@0 14 #include <blapit.h>
michael@0 15 #include <secoid.h>
michael@0 16 #include <secasn1.h>
michael@0 17
michael@0 18 /* for importing the keys */
michael@0 19 #include <CoreFoundation/CoreFoundation.h>
michael@0 20 #include <security/SecImportExport.h>
michael@0 21
michael@0 22 /*
michael@0 23 * nssmkey/mobject.c
michael@0 24 *
michael@0 25 * This file implements the NSSCKMDObject object for the
michael@0 26 * "nssmkey" cryptoki module.
michael@0 27 */
michael@0 28
michael@0 29 const CK_ATTRIBUTE_TYPE certAttrs[] = {
michael@0 30 CKA_CLASS,
michael@0 31 CKA_TOKEN,
michael@0 32 CKA_PRIVATE,
michael@0 33 CKA_MODIFIABLE,
michael@0 34 CKA_LABEL,
michael@0 35 CKA_CERTIFICATE_TYPE,
michael@0 36 CKA_SUBJECT,
michael@0 37 CKA_ISSUER,
michael@0 38 CKA_SERIAL_NUMBER,
michael@0 39 CKA_VALUE
michael@0 40 };
michael@0 41 const PRUint32 certAttrsCount = NSS_CKMK_ARRAY_SIZE(certAttrs);
michael@0 42
michael@0 43 /* private keys, for now only support RSA */
michael@0 44 const CK_ATTRIBUTE_TYPE privKeyAttrs[] = {
michael@0 45 CKA_CLASS,
michael@0 46 CKA_TOKEN,
michael@0 47 CKA_PRIVATE,
michael@0 48 CKA_MODIFIABLE,
michael@0 49 CKA_LABEL,
michael@0 50 CKA_KEY_TYPE,
michael@0 51 CKA_DERIVE,
michael@0 52 CKA_LOCAL,
michael@0 53 CKA_SUBJECT,
michael@0 54 CKA_SENSITIVE,
michael@0 55 CKA_DECRYPT,
michael@0 56 CKA_SIGN,
michael@0 57 CKA_SIGN_RECOVER,
michael@0 58 CKA_UNWRAP,
michael@0 59 CKA_EXTRACTABLE,
michael@0 60 CKA_ALWAYS_SENSITIVE,
michael@0 61 CKA_NEVER_EXTRACTABLE,
michael@0 62 CKA_MODULUS,
michael@0 63 CKA_PUBLIC_EXPONENT,
michael@0 64 };
michael@0 65 const PRUint32 privKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(privKeyAttrs);
michael@0 66
michael@0 67 /* public keys, for now only support RSA */
michael@0 68 const CK_ATTRIBUTE_TYPE pubKeyAttrs[] = {
michael@0 69 CKA_CLASS,
michael@0 70 CKA_TOKEN,
michael@0 71 CKA_PRIVATE,
michael@0 72 CKA_MODIFIABLE,
michael@0 73 CKA_LABEL,
michael@0 74 CKA_KEY_TYPE,
michael@0 75 CKA_DERIVE,
michael@0 76 CKA_LOCAL,
michael@0 77 CKA_SUBJECT,
michael@0 78 CKA_ENCRYPT,
michael@0 79 CKA_VERIFY,
michael@0 80 CKA_VERIFY_RECOVER,
michael@0 81 CKA_WRAP,
michael@0 82 CKA_MODULUS,
michael@0 83 CKA_PUBLIC_EXPONENT,
michael@0 84 };
michael@0 85 const PRUint32 pubKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(pubKeyAttrs);
michael@0 86 static const CK_BBOOL ck_true = CK_TRUE;
michael@0 87 static const CK_BBOOL ck_false = CK_FALSE;
michael@0 88 static const CK_CERTIFICATE_TYPE ckc_x509 = CKC_X_509;
michael@0 89 static const CK_KEY_TYPE ckk_rsa = CKK_RSA;
michael@0 90 static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE;
michael@0 91 static const CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY;
michael@0 92 static const CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY;
michael@0 93 static const NSSItem ckmk_trueItem = {
michael@0 94 (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL) };
michael@0 95 static const NSSItem ckmk_falseItem = {
michael@0 96 (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) };
michael@0 97 static const NSSItem ckmk_x509Item = {
michael@0 98 (void *)&ckc_x509, (PRUint32)sizeof(CK_CERTIFICATE_TYPE) };
michael@0 99 static const NSSItem ckmk_rsaItem = {
michael@0 100 (void *)&ckk_rsa, (PRUint32)sizeof(CK_KEY_TYPE) };
michael@0 101 static const NSSItem ckmk_certClassItem = {
michael@0 102 (void *)&cko_certificate, (PRUint32)sizeof(CK_OBJECT_CLASS) };
michael@0 103 static const NSSItem ckmk_privKeyClassItem = {
michael@0 104 (void *)&cko_private_key, (PRUint32)sizeof(CK_OBJECT_CLASS) };
michael@0 105 static const NSSItem ckmk_pubKeyClassItem = {
michael@0 106 (void *)&cko_public_key, (PRUint32)sizeof(CK_OBJECT_CLASS) };
michael@0 107 static const NSSItem ckmk_emptyItem = {
michael@0 108 (void *)&ck_true, 0};
michael@0 109
michael@0 110 /*
michael@0 111 * these are utilities. The chould be moved to a new utilities file.
michael@0 112 */
michael@0 113 #ifdef DEBUG
michael@0 114 static void
michael@0 115 itemdump(char *str, void *data, int size, CK_RV error)
michael@0 116 {
michael@0 117 unsigned char *ptr = (unsigned char *)data;
michael@0 118 int i;
michael@0 119 fprintf(stderr,str);
michael@0 120 for (i=0; i < size; i++) {
michael@0 121 fprintf(stderr,"%02x ",(unsigned int) ptr[i]);
michael@0 122 }
michael@0 123 fprintf(stderr," (error = %d)\n", (int ) error);
michael@0 124 }
michael@0 125 #endif
michael@0 126
michael@0 127 /*
michael@0 128 * unwrap a single DER value
michael@0 129 * now that we have util linked in, we should probably use
michael@0 130 * the ANS1_Decoder for this work...
michael@0 131 */
michael@0 132 unsigned char *
michael@0 133 nss_ckmk_DERUnwrap
michael@0 134 (
michael@0 135 unsigned char *src,
michael@0 136 int size,
michael@0 137 int *outSize,
michael@0 138 unsigned char **next
michael@0 139 )
michael@0 140 {
michael@0 141 unsigned char *start = src;
michael@0 142 unsigned int len = 0;
michael@0 143
michael@0 144 /* initialize error condition return values */
michael@0 145 *outSize = 0;
michael@0 146 if (next) {
michael@0 147 *next = src;
michael@0 148 }
michael@0 149
michael@0 150 if (size < 2) {
michael@0 151 return start;
michael@0 152 }
michael@0 153 src ++ ; /* skip the tag -- should check it against an expected value! */
michael@0 154 len = (unsigned) *src++;
michael@0 155 if (len & 0x80) {
michael@0 156 int count = len & 0x7f;
michael@0 157 len =0;
michael@0 158
michael@0 159 if (count+2 > size) {
michael@0 160 return start;
michael@0 161 }
michael@0 162 while (count-- > 0) {
michael@0 163 len = (len << 8) | (unsigned) *src++;
michael@0 164 }
michael@0 165 }
michael@0 166 if (len + (src-start) > (unsigned int)size) {
michael@0 167 return start;
michael@0 168 }
michael@0 169 if (next) {
michael@0 170 *next = src+len;
michael@0 171 }
michael@0 172 *outSize = len;
michael@0 173
michael@0 174 return src;
michael@0 175 }
michael@0 176
michael@0 177 /*
michael@0 178 * get an attribute from a template. Value is returned in NSS item.
michael@0 179 * data for the item is owned by the template.
michael@0 180 */
michael@0 181 CK_RV
michael@0 182 nss_ckmk_GetAttribute
michael@0 183 (
michael@0 184 CK_ATTRIBUTE_TYPE type,
michael@0 185 CK_ATTRIBUTE *template,
michael@0 186 CK_ULONG templateSize,
michael@0 187 NSSItem *item
michael@0 188 )
michael@0 189 {
michael@0 190 CK_ULONG i;
michael@0 191
michael@0 192 for (i=0; i < templateSize; i++) {
michael@0 193 if (template[i].type == type) {
michael@0 194 item->data = template[i].pValue;
michael@0 195 item->size = template[i].ulValueLen;
michael@0 196 return CKR_OK;
michael@0 197 }
michael@0 198 }
michael@0 199 return CKR_TEMPLATE_INCOMPLETE;
michael@0 200 }
michael@0 201
michael@0 202 /*
michael@0 203 * get an attribute which is type CK_ULONG.
michael@0 204 */
michael@0 205 CK_ULONG
michael@0 206 nss_ckmk_GetULongAttribute
michael@0 207 (
michael@0 208 CK_ATTRIBUTE_TYPE type,
michael@0 209 CK_ATTRIBUTE *template,
michael@0 210 CK_ULONG templateSize,
michael@0 211 CK_RV *pError
michael@0 212 )
michael@0 213 {
michael@0 214 NSSItem item;
michael@0 215
michael@0 216 *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item);
michael@0 217 if (CKR_OK != *pError) {
michael@0 218 return (CK_ULONG) 0;
michael@0 219 }
michael@0 220 if (item.size != sizeof(CK_ULONG)) {
michael@0 221 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 222 return (CK_ULONG) 0;
michael@0 223 }
michael@0 224 return *(CK_ULONG *)item.data;
michael@0 225 }
michael@0 226
michael@0 227 /*
michael@0 228 * get an attribute which is type CK_BBOOL.
michael@0 229 */
michael@0 230 CK_BBOOL
michael@0 231 nss_ckmk_GetBoolAttribute
michael@0 232 (
michael@0 233 CK_ATTRIBUTE_TYPE type,
michael@0 234 CK_ATTRIBUTE *template,
michael@0 235 CK_ULONG templateSize,
michael@0 236 CK_BBOOL defaultBool
michael@0 237 )
michael@0 238 {
michael@0 239 NSSItem item;
michael@0 240 CK_RV error;
michael@0 241
michael@0 242 error = nss_ckmk_GetAttribute(type, template, templateSize, &item);
michael@0 243 if (CKR_OK != error) {
michael@0 244 return defaultBool;
michael@0 245 }
michael@0 246 if (item.size != sizeof(CK_BBOOL)) {
michael@0 247 return defaultBool;
michael@0 248 }
michael@0 249 return *(CK_BBOOL *)item.data;
michael@0 250 }
michael@0 251
michael@0 252 /*
michael@0 253 * get an attribute as a NULL terminated string. Caller is responsible to
michael@0 254 * free the string.
michael@0 255 */
michael@0 256 char *
michael@0 257 nss_ckmk_GetStringAttribute
michael@0 258 (
michael@0 259 CK_ATTRIBUTE_TYPE type,
michael@0 260 CK_ATTRIBUTE *template,
michael@0 261 CK_ULONG templateSize,
michael@0 262 CK_RV *pError
michael@0 263 )
michael@0 264 {
michael@0 265 NSSItem item;
michael@0 266 char *str;
michael@0 267
michael@0 268 /* get the attribute */
michael@0 269 *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item);
michael@0 270 if (CKR_OK != *pError) {
michael@0 271 return (char *)NULL;
michael@0 272 }
michael@0 273 /* make sure it is null terminated */
michael@0 274 str = nss_ZNEWARRAY(NULL, char, item.size+1);
michael@0 275 if ((char *)NULL == str) {
michael@0 276 *pError = CKR_HOST_MEMORY;
michael@0 277 return (char *)NULL;
michael@0 278 }
michael@0 279
michael@0 280 nsslibc_memcpy(str, item.data, item.size);
michael@0 281 str[item.size] = 0;
michael@0 282
michael@0 283 return str;
michael@0 284 }
michael@0 285
michael@0 286 /*
michael@0 287 * Apple doesn't seem to have a public interface to the DER encoder,
michael@0 288 * wip out a quick one for integers only (anything more complicated,
michael@0 289 * we should use one of the 3 in lib/util). -- especially since we
michael@0 290 * now link with it.
michael@0 291 */
michael@0 292 static CK_RV
michael@0 293 ckmk_encodeInt(NSSItem *dest, void *src, int srcLen)
michael@0 294 {
michael@0 295 int dataLen = srcLen;
michael@0 296 int lenLen = 1;
michael@0 297 int encLen;
michael@0 298 int isSigned = 0;
michael@0 299 int offset = 0;
michael@0 300 unsigned char *data = NULL;
michael@0 301 int i;
michael@0 302
michael@0 303 if (*(unsigned char *)src & 0x80) {
michael@0 304 dataLen++;
michael@0 305 isSigned = 1;
michael@0 306 }
michael@0 307
michael@0 308 /* calculate the length of the length specifier */
michael@0 309 /* (NOTE: destroys dataLen value) */
michael@0 310 if (dataLen > 0x7f) {
michael@0 311 do {
michael@0 312 lenLen++;
michael@0 313 dataLen >>= 8;
michael@0 314 } while (dataLen);
michael@0 315 }
michael@0 316
michael@0 317 /* calculate our total length */
michael@0 318 dataLen = isSigned + srcLen;
michael@0 319 encLen = 1 + lenLen + dataLen;
michael@0 320 data = nss_ZNEWARRAY(NULL, unsigned char, encLen);
michael@0 321 if ((unsigned char *)NULL == data) {
michael@0 322 return CKR_HOST_MEMORY;
michael@0 323 }
michael@0 324 data[0] = DER_INTEGER;
michael@0 325 if (1 == lenLen) {
michael@0 326 data[1] = dataLen;
michael@0 327 } else {
michael@0 328 data[1] = 0x80 + lenLen;
michael@0 329 for (i=0; i < lenLen; i++) {
michael@0 330 data[i+1] = ((dataLen >> ((lenLen-i-1)*8)) & 0xff);
michael@0 331 }
michael@0 332 }
michael@0 333 offset = lenLen+1;
michael@0 334
michael@0 335 if (isSigned) {
michael@0 336 data[offset++] = 0;
michael@0 337 }
michael@0 338 nsslibc_memcpy(&data[offset], src, srcLen);
michael@0 339 dest->data = data;
michael@0 340 dest->size = encLen;
michael@0 341 return CKR_OK;
michael@0 342 }
michael@0 343
michael@0 344
michael@0 345 /*
michael@0 346 * Get a Keyring attribute. If content is set to true, then we get the
michael@0 347 * content, not the attribute.
michael@0 348 */
michael@0 349 static CK_RV
michael@0 350 ckmk_GetCommonAttribute
michael@0 351 (
michael@0 352 ckmkInternalObject *io,
michael@0 353 SecItemAttr itemAttr,
michael@0 354 PRBool content,
michael@0 355 NSSItem *item,
michael@0 356 char *dbString
michael@0 357 )
michael@0 358 {
michael@0 359 SecKeychainAttributeList *attrList = NULL;
michael@0 360 SecKeychainAttributeInfo attrInfo;
michael@0 361 PRUint32 len = 0;
michael@0 362 PRUint32 dataLen = 0;
michael@0 363 PRUint32 attrFormat = 0;
michael@0 364 void *dataVal = 0;
michael@0 365 void *out = NULL;
michael@0 366 CK_RV error = CKR_OK;
michael@0 367 OSStatus macErr;
michael@0 368
michael@0 369 attrInfo.count = 1;
michael@0 370 attrInfo.tag = &itemAttr;
michael@0 371 attrInfo.format = &attrFormat;
michael@0 372
michael@0 373 macErr = SecKeychainItemCopyAttributesAndData(io->u.item.itemRef,
michael@0 374 &attrInfo, NULL, &attrList, &len, &out);
michael@0 375 if (noErr != macErr) {
michael@0 376 CKMK_MACERR(dbString, macErr);
michael@0 377 return CKR_ATTRIBUTE_TYPE_INVALID;
michael@0 378 }
michael@0 379 dataLen = content ? len : attrList->attr->length;
michael@0 380 dataVal = content ? out : attrList->attr->data;
michael@0 381
michael@0 382 /* Apple's documentation says this value is DER Encoded, but it clearly isn't
michael@0 383 * der encode it before we ship it back off to NSS
michael@0 384 */
michael@0 385 if ( kSecSerialNumberItemAttr == itemAttr ) {
michael@0 386 error = ckmk_encodeInt(item, dataVal, dataLen);
michael@0 387 goto loser; /* logically 'done' if error == CKR_OK */
michael@0 388 }
michael@0 389 item->data = nss_ZNEWARRAY(NULL, char, dataLen);
michael@0 390 if (NULL == item->data) {
michael@0 391 error = CKR_HOST_MEMORY;
michael@0 392 goto loser;
michael@0 393 }
michael@0 394 nsslibc_memcpy(item->data, dataVal, dataLen);
michael@0 395 item->size = dataLen;
michael@0 396
michael@0 397 loser:
michael@0 398 SecKeychainItemFreeAttributesAndData(attrList, out);
michael@0 399 return error;
michael@0 400 }
michael@0 401
michael@0 402 /*
michael@0 403 * change an attribute (does not operate on the content).
michael@0 404 */
michael@0 405 static CK_RV
michael@0 406 ckmk_updateAttribute
michael@0 407 (
michael@0 408 SecKeychainItemRef itemRef,
michael@0 409 SecItemAttr itemAttr,
michael@0 410 void *data,
michael@0 411 PRUint32 len,
michael@0 412 char *dbString
michael@0 413 )
michael@0 414 {
michael@0 415 SecKeychainAttributeList attrList;
michael@0 416 SecKeychainAttribute attrAttr;
michael@0 417 OSStatus macErr;
michael@0 418 CK_RV error = CKR_OK;
michael@0 419
michael@0 420 attrList.count = 1;
michael@0 421 attrList.attr = &attrAttr;
michael@0 422 attrAttr.tag = itemAttr;
michael@0 423 attrAttr.data = data;
michael@0 424 attrAttr.length = len;
michael@0 425 macErr = SecKeychainItemModifyAttributesAndData(itemRef, &attrList, 0, NULL);
michael@0 426 if (noErr != macErr) {
michael@0 427 CKMK_MACERR(dbString, macErr);
michael@0 428 error = CKR_ATTRIBUTE_TYPE_INVALID;
michael@0 429 }
michael@0 430 return error;
michael@0 431 }
michael@0 432
michael@0 433 /*
michael@0 434 * get an attribute (does not operate on the content)
michael@0 435 */
michael@0 436 static CK_RV
michael@0 437 ckmk_GetDataAttribute
michael@0 438 (
michael@0 439 ckmkInternalObject *io,
michael@0 440 SecItemAttr itemAttr,
michael@0 441 NSSItem *item,
michael@0 442 char *dbString
michael@0 443 )
michael@0 444 {
michael@0 445 return ckmk_GetCommonAttribute(io, itemAttr, PR_FALSE, item, dbString);
michael@0 446 }
michael@0 447
michael@0 448 /*
michael@0 449 * get an attribute we know is a BOOL.
michael@0 450 */
michael@0 451 static CK_RV
michael@0 452 ckmk_GetBoolAttribute
michael@0 453 (
michael@0 454 ckmkInternalObject *io,
michael@0 455 SecItemAttr itemAttr,
michael@0 456 NSSItem *item,
michael@0 457 char *dbString
michael@0 458 )
michael@0 459 {
michael@0 460 SecKeychainAttribute attr;
michael@0 461 SecKeychainAttributeList attrList;
michael@0 462 CK_BBOOL *boolp = NULL;
michael@0 463 PRUint32 len = 0;;
michael@0 464 void *out = NULL;
michael@0 465 CK_RV error = CKR_OK;
michael@0 466 OSStatus macErr;
michael@0 467
michael@0 468 attr.tag = itemAttr;
michael@0 469 attr.length = 0;
michael@0 470 attr.data = NULL;
michael@0 471 attrList.count = 1;
michael@0 472 attrList.attr = &attr;
michael@0 473
michael@0 474 boolp = nss_ZNEW(NULL, CK_BBOOL);
michael@0 475 if ((CK_BBOOL *)NULL == boolp) {
michael@0 476 error = CKR_HOST_MEMORY;
michael@0 477 goto loser;
michael@0 478 }
michael@0 479
michael@0 480 macErr = SecKeychainItemCopyContent(io->u.item.itemRef, NULL,
michael@0 481 &attrList, &len, &out);
michael@0 482 if (noErr != macErr) {
michael@0 483 CKMK_MACERR(dbString, macErr);
michael@0 484 error = CKR_ATTRIBUTE_TYPE_INVALID;
michael@0 485 goto loser;
michael@0 486 }
michael@0 487 if (sizeof(PRUint32) != attr.length) {
michael@0 488 error = CKR_ATTRIBUTE_TYPE_INVALID;
michael@0 489 goto loser;
michael@0 490 }
michael@0 491 *boolp = *(PRUint32 *)attr.data ? 1 : 0;
michael@0 492 item->data = boolp;
michael@0 493 boolp = NULL;
michael@0 494 item->size = sizeof(CK_BBOOL);
michael@0 495
michael@0 496 loser:
michael@0 497 nss_ZFreeIf(boolp);
michael@0 498 SecKeychainItemFreeContent(&attrList, out);
michael@0 499 return error;
michael@0 500 }
michael@0 501
michael@0 502
michael@0 503 /*
michael@0 504 * macros for fetching attributes into a cache and returning the
michael@0 505 * appropriate value. These operate inside switch statements
michael@0 506 */
michael@0 507 #define CKMK_HANDLE_ITEM(func, io, type, loc, item, error, str) \
michael@0 508 if (0 == (item)->loc.size) { \
michael@0 509 error = func(io, type, &(item)->loc, str); \
michael@0 510 } \
michael@0 511 return (CKR_OK == (error)) ? &(item)->loc : NULL;
michael@0 512
michael@0 513 #define CKMK_HANDLE_OPT_ITEM(func, io, type, loc, item, error, str) \
michael@0 514 if (0 == (item)->loc.size) { \
michael@0 515 (void) func(io, type, &(item)->loc, str); \
michael@0 516 } \
michael@0 517 return &(item)->loc ;
michael@0 518
michael@0 519 #define CKMK_HANDLE_BOOL_ITEM(io, type, loc, item, error, str) \
michael@0 520 CKMK_HANDLE_ITEM(ckmk_GetBoolAttribute, io, type, loc, item, error, str)
michael@0 521 #define CKMK_HANDLE_DATA_ITEM(io, type, loc, item, error, str) \
michael@0 522 CKMK_HANDLE_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str)
michael@0 523 #define CKMK_HANDLE_OPT_DATA_ITEM(io, type, loc, item, error, str) \
michael@0 524 CKMK_HANDLE_OPT_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str)
michael@0 525
michael@0 526 /*
michael@0 527 * fetch the unique identifier for each object type.
michael@0 528 */
michael@0 529 static void
michael@0 530 ckmk_FetchHashKey
michael@0 531 (
michael@0 532 ckmkInternalObject *io
michael@0 533 )
michael@0 534 {
michael@0 535 NSSItem *key = &io->hashKey;
michael@0 536
michael@0 537 if (io->objClass == CKO_CERTIFICATE) {
michael@0 538 ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr,
michael@0 539 PR_TRUE, key, "Fetching HashKey (cert)");
michael@0 540 } else {
michael@0 541 ckmk_GetCommonAttribute(io, kSecKeyLabel,
michael@0 542 PR_FALSE, key, "Fetching HashKey (key)");
michael@0 543 }
michael@0 544 }
michael@0 545
michael@0 546 /*
michael@0 547 * Apple mucks with the actual subject and issuer, so go fetch
michael@0 548 * the real ones ourselves.
michael@0 549 */
michael@0 550 static void
michael@0 551 ckmk_fetchCert
michael@0 552 (
michael@0 553 ckmkInternalObject *io
michael@0 554 )
michael@0 555 {
michael@0 556 CK_RV error;
michael@0 557 unsigned char * cert, *next;
michael@0 558 int certSize, thisEntrySize;
michael@0 559
michael@0 560 error = ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr, PR_TRUE,
michael@0 561 &io->u.item.derCert, "Fetching Value (cert)");
michael@0 562 if (CKR_OK != error) {
michael@0 563 return;
michael@0 564 }
michael@0 565 /* unwrap the cert bundle */
michael@0 566 cert = nss_ckmk_DERUnwrap((unsigned char *)io->u.item.derCert.data,
michael@0 567 io->u.item.derCert.size,
michael@0 568 &certSize, NULL);
michael@0 569 /* unwrap the cert itself */
michael@0 570 /* cert == certdata */
michael@0 571 cert = nss_ckmk_DERUnwrap(cert, certSize, &certSize, NULL);
michael@0 572
michael@0 573 /* skip the optional version */
michael@0 574 if ((cert[0] & 0xa0) == 0xa0) {
michael@0 575 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
michael@0 576 certSize -= next - cert;
michael@0 577 cert = next;
michael@0 578 }
michael@0 579 /* skip the serial number */
michael@0 580 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
michael@0 581 certSize -= next - cert;
michael@0 582 cert = next;
michael@0 583
michael@0 584 /* skip the OID */
michael@0 585 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
michael@0 586 certSize -= next - cert;
michael@0 587 cert = next;
michael@0 588
michael@0 589 /* save the (wrapped) issuer */
michael@0 590 io->u.item.issuer.data = cert;
michael@0 591 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
michael@0 592 io->u.item.issuer.size = next - cert;
michael@0 593 certSize -= io->u.item.issuer.size;
michael@0 594 cert = next;
michael@0 595
michael@0 596 /* skip the OID */
michael@0 597 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
michael@0 598 certSize -= next - cert;
michael@0 599 cert = next;
michael@0 600
michael@0 601 /* save the (wrapped) subject */
michael@0 602 io->u.item.subject.data = cert;
michael@0 603 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next);
michael@0 604 io->u.item.subject.size = next - cert;
michael@0 605 certSize -= io->u.item.subject.size;
michael@0 606 cert = next;
michael@0 607 }
michael@0 608
michael@0 609 static void
michael@0 610 ckmk_fetchModulus
michael@0 611 (
michael@0 612 ckmkInternalObject *io
michael@0 613 )
michael@0 614 {
michael@0 615 NSSItem item;
michael@0 616 PRInt32 modLen;
michael@0 617 CK_RV error;
michael@0 618
michael@0 619 /* we can't reliably get the modulus for private keys through CSSM (sigh).
michael@0 620 * For NSS this is OK because we really only use this to get the modulus
michael@0 621 * length (unless we are trying to get a public key from a private keys,
michael@0 622 * something CSSM ALSO does not do!).
michael@0 623 */
michael@0 624 error = ckmk_GetDataAttribute(io, kSecKeyKeySizeInBits, &item,
michael@0 625 "Key Fetch Modulus");
michael@0 626 if (CKR_OK != error) {
michael@0 627 return;
michael@0 628 }
michael@0 629
michael@0 630 modLen = *(PRInt32 *)item.data;
michael@0 631 modLen = modLen/8; /* convert from bits to bytes */
michael@0 632
michael@0 633 nss_ZFreeIf(item.data);
michael@0 634 io->u.item.modulus.data = nss_ZNEWARRAY(NULL, char, modLen);
michael@0 635 if (NULL == io->u.item.modulus.data) {
michael@0 636 return;
michael@0 637 }
michael@0 638 *(char *)io->u.item.modulus.data = 0x80; /* fake NSS out or it will
michael@0 639 * drop the first byte */
michael@0 640 io->u.item.modulus.size = modLen;
michael@0 641 return;
michael@0 642 }
michael@0 643
michael@0 644 const NSSItem *
michael@0 645 ckmk_FetchCertAttribute
michael@0 646 (
michael@0 647 ckmkInternalObject *io,
michael@0 648 CK_ATTRIBUTE_TYPE type,
michael@0 649 CK_RV *pError
michael@0 650 )
michael@0 651 {
michael@0 652 ckmkItemObject *item = &io->u.item;
michael@0 653 *pError = CKR_OK;
michael@0 654 switch(type) {
michael@0 655 case CKA_CLASS:
michael@0 656 return &ckmk_certClassItem;
michael@0 657 case CKA_TOKEN:
michael@0 658 case CKA_MODIFIABLE:
michael@0 659 return &ckmk_trueItem;
michael@0 660 case CKA_PRIVATE:
michael@0 661 return &ckmk_falseItem;
michael@0 662 case CKA_CERTIFICATE_TYPE:
michael@0 663 return &ckmk_x509Item;
michael@0 664 case CKA_LABEL:
michael@0 665 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecLabelItemAttr, label, item, *pError,
michael@0 666 "Cert:Label attr")
michael@0 667 case CKA_SUBJECT:
michael@0 668 /* OK, well apple does provide an subject and issuer attribute, but they
michael@0 669 * decided to cannonicalize that value. Probably a good move for them,
michael@0 670 * but makes it useless for most users of PKCS #11.. Get the real subject
michael@0 671 * from the certificate */
michael@0 672 if (0 == item->derCert.size) {
michael@0 673 ckmk_fetchCert(io);
michael@0 674 }
michael@0 675 return &item->subject;
michael@0 676 case CKA_ISSUER:
michael@0 677 if (0 == item->derCert.size) {
michael@0 678 ckmk_fetchCert(io);
michael@0 679 }
michael@0 680 return &item->issuer;
michael@0 681 case CKA_SERIAL_NUMBER:
michael@0 682 CKMK_HANDLE_DATA_ITEM(io, kSecSerialNumberItemAttr, serial, item, *pError,
michael@0 683 "Cert:Serial Number attr")
michael@0 684 case CKA_VALUE:
michael@0 685 if (0 == item->derCert.size) {
michael@0 686 ckmk_fetchCert(io);
michael@0 687 }
michael@0 688 return &item->derCert;
michael@0 689 case CKA_ID:
michael@0 690 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecPublicKeyHashItemAttr, id, item, *pError,
michael@0 691 "Cert:ID attr")
michael@0 692 default:
michael@0 693 *pError = CKR_ATTRIBUTE_TYPE_INVALID;
michael@0 694 break;
michael@0 695 }
michael@0 696 return NULL;
michael@0 697 }
michael@0 698
michael@0 699 const NSSItem *
michael@0 700 ckmk_FetchPubKeyAttribute
michael@0 701 (
michael@0 702 ckmkInternalObject *io,
michael@0 703 CK_ATTRIBUTE_TYPE type,
michael@0 704 CK_RV *pError
michael@0 705 )
michael@0 706 {
michael@0 707 ckmkItemObject *item = &io->u.item;
michael@0 708 *pError = CKR_OK;
michael@0 709
michael@0 710 switch(type) {
michael@0 711 case CKA_CLASS:
michael@0 712 return &ckmk_pubKeyClassItem;
michael@0 713 case CKA_TOKEN:
michael@0 714 case CKA_LOCAL:
michael@0 715 return &ckmk_trueItem;
michael@0 716 case CKA_KEY_TYPE:
michael@0 717 return &ckmk_rsaItem;
michael@0 718 case CKA_LABEL:
michael@0 719 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError,
michael@0 720 "PubKey:Label attr")
michael@0 721 case CKA_ENCRYPT:
michael@0 722 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyEncrypt, encrypt, item, *pError,
michael@0 723 "PubKey:Encrypt attr")
michael@0 724 case CKA_VERIFY:
michael@0 725 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerify, verify, item, *pError,
michael@0 726 "PubKey:Verify attr")
michael@0 727 case CKA_VERIFY_RECOVER:
michael@0 728 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerifyRecover, verifyRecover,
michael@0 729 item, *pError, "PubKey:VerifyRecover attr")
michael@0 730 case CKA_PRIVATE:
michael@0 731 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError,
michael@0 732 "PubKey:Private attr")
michael@0 733 case CKA_MODIFIABLE:
michael@0 734 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError,
michael@0 735 "PubKey:Modify attr")
michael@0 736 case CKA_DERIVE:
michael@0 737 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError,
michael@0 738 "PubKey:Derive attr")
michael@0 739 case CKA_WRAP:
michael@0 740 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyWrap, wrap, item, *pError,
michael@0 741 "PubKey:Wrap attr")
michael@0 742 case CKA_SUBJECT:
michael@0 743 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError,
michael@0 744 "PubKey:Subect attr")
michael@0 745 case CKA_MODULUS:
michael@0 746 return &ckmk_emptyItem;
michael@0 747 case CKA_PUBLIC_EXPONENT:
michael@0 748 return &ckmk_emptyItem;
michael@0 749 case CKA_ID:
michael@0 750 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError,
michael@0 751 "PubKey:ID attr")
michael@0 752 default:
michael@0 753 *pError = CKR_ATTRIBUTE_TYPE_INVALID;
michael@0 754 break;
michael@0 755 }
michael@0 756 return NULL;
michael@0 757 }
michael@0 758
michael@0 759 const NSSItem *
michael@0 760 ckmk_FetchPrivKeyAttribute
michael@0 761 (
michael@0 762 ckmkInternalObject *io,
michael@0 763 CK_ATTRIBUTE_TYPE type,
michael@0 764 CK_RV *pError
michael@0 765 )
michael@0 766 {
michael@0 767 ckmkItemObject *item = &io->u.item;
michael@0 768 *pError = CKR_OK;
michael@0 769
michael@0 770 switch(type) {
michael@0 771 case CKA_CLASS:
michael@0 772 return &ckmk_privKeyClassItem;
michael@0 773 case CKA_TOKEN:
michael@0 774 case CKA_LOCAL:
michael@0 775 return &ckmk_trueItem;
michael@0 776 case CKA_SENSITIVE:
michael@0 777 case CKA_EXTRACTABLE: /* will probably move in the future */
michael@0 778 case CKA_ALWAYS_SENSITIVE:
michael@0 779 case CKA_NEVER_EXTRACTABLE:
michael@0 780 return &ckmk_falseItem;
michael@0 781 case CKA_KEY_TYPE:
michael@0 782 return &ckmk_rsaItem;
michael@0 783 case CKA_LABEL:
michael@0 784 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError,
michael@0 785 "PrivateKey:Label attr")
michael@0 786 case CKA_DECRYPT:
michael@0 787 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDecrypt, decrypt, item, *pError,
michael@0 788 "PrivateKey:Decrypt attr")
michael@0 789 case CKA_SIGN:
michael@0 790 CKMK_HANDLE_BOOL_ITEM(io, kSecKeySign, sign, item, *pError,
michael@0 791 "PrivateKey:Sign attr")
michael@0 792 case CKA_SIGN_RECOVER:
michael@0 793 CKMK_HANDLE_BOOL_ITEM(io, kSecKeySignRecover, signRecover, item, *pError,
michael@0 794 "PrivateKey:Sign Recover attr")
michael@0 795 case CKA_PRIVATE:
michael@0 796 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError,
michael@0 797 "PrivateKey:Private attr")
michael@0 798 case CKA_MODIFIABLE:
michael@0 799 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError,
michael@0 800 "PrivateKey:Modify attr")
michael@0 801 case CKA_DERIVE:
michael@0 802 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError,
michael@0 803 "PrivateKey:Derive attr")
michael@0 804 case CKA_UNWRAP:
michael@0 805 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyUnwrap, unwrap, item, *pError,
michael@0 806 "PrivateKey:Unwrap attr")
michael@0 807 case CKA_SUBJECT:
michael@0 808 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError,
michael@0 809 "PrivateKey:Subject attr")
michael@0 810 case CKA_MODULUS:
michael@0 811 if (0 == item->modulus.size) {
michael@0 812 ckmk_fetchModulus(io);
michael@0 813 }
michael@0 814 return &item->modulus;
michael@0 815 case CKA_PUBLIC_EXPONENT:
michael@0 816 return &ckmk_emptyItem;
michael@0 817 #ifdef notdef
michael@0 818 /* the following are sensitive attributes. We could implement them for
michael@0 819 * sensitive keys using the key export function, but it's better to
michael@0 820 * just support wrap through this token. That will more reliably allow us
michael@0 821 * to export any private key that is truly exportable.
michael@0 822 */
michael@0 823 case CKA_PRIVATE_EXPONENT:
michael@0 824 CKMK_HANDLE_DATA_ITEM(io, kSecPrivateExponentItemAttr, privateExponent,
michael@0 825 item, *pError)
michael@0 826 case CKA_PRIME_1:
michael@0 827 CKMK_HANDLE_DATA_ITEM(io, kSecPrime1ItemAttr, prime1, item, *pError)
michael@0 828 case CKA_PRIME_2:
michael@0 829 CKMK_HANDLE_DATA_ITEM(io, kSecPrime2ItemAttr, prime2, item, *pError)
michael@0 830 case CKA_EXPONENT_1:
michael@0 831 CKMK_HANDLE_DATA_ITEM(io, kSecExponent1ItemAttr, exponent1, item, *pError)
michael@0 832 case CKA_EXPONENT_2:
michael@0 833 CKMK_HANDLE_DATA_ITEM(io, kSecExponent2ItemAttr, exponent2, item, *pError)
michael@0 834 case CKA_COEFFICIENT:
michael@0 835 CKMK_HANDLE_DATA_ITEM(io, kSecCoefficientItemAttr, coefficient,
michael@0 836 item, *pError)
michael@0 837 #endif
michael@0 838 case CKA_ID:
michael@0 839 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError,
michael@0 840 "PrivateKey:ID attr")
michael@0 841 default:
michael@0 842 *pError = CKR_ATTRIBUTE_TYPE_INVALID;
michael@0 843 return NULL;
michael@0 844 }
michael@0 845 }
michael@0 846
michael@0 847 const NSSItem *
michael@0 848 nss_ckmk_FetchAttribute
michael@0 849 (
michael@0 850 ckmkInternalObject *io,
michael@0 851 CK_ATTRIBUTE_TYPE type,
michael@0 852 CK_RV *pError
michael@0 853 )
michael@0 854 {
michael@0 855 CK_ULONG i;
michael@0 856 const NSSItem * value = NULL;
michael@0 857
michael@0 858 if (io->type == ckmkRaw) {
michael@0 859 for( i = 0; i < io->u.raw.n; i++ ) {
michael@0 860 if( type == io->u.raw.types[i] ) {
michael@0 861 return &io->u.raw.items[i];
michael@0 862 }
michael@0 863 }
michael@0 864 *pError = CKR_ATTRIBUTE_TYPE_INVALID;
michael@0 865 return NULL;
michael@0 866 }
michael@0 867 /* deal with the common attributes */
michael@0 868 switch (io->objClass) {
michael@0 869 case CKO_CERTIFICATE:
michael@0 870 value = ckmk_FetchCertAttribute(io, type, pError);
michael@0 871 break;
michael@0 872 case CKO_PRIVATE_KEY:
michael@0 873 value = ckmk_FetchPrivKeyAttribute(io, type, pError);
michael@0 874 break;
michael@0 875 case CKO_PUBLIC_KEY:
michael@0 876 value = ckmk_FetchPubKeyAttribute(io, type, pError);
michael@0 877 break;
michael@0 878 default:
michael@0 879 *pError = CKR_OBJECT_HANDLE_INVALID;
michael@0 880 return NULL;
michael@0 881 }
michael@0 882
michael@0 883 #ifdef DEBUG
michael@0 884 if (CKA_ID == type) {
michael@0 885 itemdump("id: ", value->data, value->size, *pError);
michael@0 886 }
michael@0 887 #endif
michael@0 888 return value;
michael@0 889 }
michael@0 890
michael@0 891 static void
michael@0 892 ckmk_removeObjectFromHash
michael@0 893 (
michael@0 894 ckmkInternalObject *io
michael@0 895 );
michael@0 896
michael@0 897 /*
michael@0 898 *
michael@0 899 * These are the MSObject functions we need to implement
michael@0 900 *
michael@0 901 * Finalize - unneeded (actually we should clean up the hashtables)
michael@0 902 * Destroy
michael@0 903 * IsTokenObject - CK_TRUE
michael@0 904 * GetAttributeCount
michael@0 905 * GetAttributeTypes
michael@0 906 * GetAttributeSize
michael@0 907 * GetAttribute
michael@0 908 * SetAttribute
michael@0 909 * GetObjectSize
michael@0 910 */
michael@0 911
michael@0 912 static CK_RV
michael@0 913 ckmk_mdObject_Destroy
michael@0 914 (
michael@0 915 NSSCKMDObject *mdObject,
michael@0 916 NSSCKFWObject *fwObject,
michael@0 917 NSSCKMDSession *mdSession,
michael@0 918 NSSCKFWSession *fwSession,
michael@0 919 NSSCKMDToken *mdToken,
michael@0 920 NSSCKFWToken *fwToken,
michael@0 921 NSSCKMDInstance *mdInstance,
michael@0 922 NSSCKFWInstance *fwInstance
michael@0 923 )
michael@0 924 {
michael@0 925 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
michael@0 926 OSStatus macErr;
michael@0 927
michael@0 928 if (ckmkRaw == io->type) {
michael@0 929 /* there is not 'object write protected' error, use the next best thing */
michael@0 930 return CKR_TOKEN_WRITE_PROTECTED;
michael@0 931 }
michael@0 932
michael@0 933 /* This API is done well. The following 4 lines are the complete apple
michael@0 934 * specific part of this implementation */
michael@0 935 macErr = SecKeychainItemDelete(io->u.item.itemRef);
michael@0 936 if (noErr != macErr) {
michael@0 937 CKMK_MACERR("Delete object", macErr);
michael@0 938 }
michael@0 939
michael@0 940 /* remove it from the hash */
michael@0 941 ckmk_removeObjectFromHash(io);
michael@0 942
michael@0 943 /* free the puppy.. */
michael@0 944 nss_ckmk_DestroyInternalObject(io);
michael@0 945
michael@0 946 return CKR_OK;
michael@0 947 }
michael@0 948
michael@0 949 static CK_BBOOL
michael@0 950 ckmk_mdObject_IsTokenObject
michael@0 951 (
michael@0 952 NSSCKMDObject *mdObject,
michael@0 953 NSSCKFWObject *fwObject,
michael@0 954 NSSCKMDSession *mdSession,
michael@0 955 NSSCKFWSession *fwSession,
michael@0 956 NSSCKMDToken *mdToken,
michael@0 957 NSSCKFWToken *fwToken,
michael@0 958 NSSCKMDInstance *mdInstance,
michael@0 959 NSSCKFWInstance *fwInstance
michael@0 960 )
michael@0 961 {
michael@0 962 return CK_TRUE;
michael@0 963 }
michael@0 964
michael@0 965 static CK_ULONG
michael@0 966 ckmk_mdObject_GetAttributeCount
michael@0 967 (
michael@0 968 NSSCKMDObject *mdObject,
michael@0 969 NSSCKFWObject *fwObject,
michael@0 970 NSSCKMDSession *mdSession,
michael@0 971 NSSCKFWSession *fwSession,
michael@0 972 NSSCKMDToken *mdToken,
michael@0 973 NSSCKFWToken *fwToken,
michael@0 974 NSSCKMDInstance *mdInstance,
michael@0 975 NSSCKFWInstance *fwInstance,
michael@0 976 CK_RV *pError
michael@0 977 )
michael@0 978 {
michael@0 979 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
michael@0 980
michael@0 981 if (ckmkRaw == io->type) {
michael@0 982 return io->u.raw.n;
michael@0 983 }
michael@0 984 switch (io->objClass) {
michael@0 985 case CKO_CERTIFICATE:
michael@0 986 return certAttrsCount;
michael@0 987 case CKO_PUBLIC_KEY:
michael@0 988 return pubKeyAttrsCount;
michael@0 989 case CKO_PRIVATE_KEY:
michael@0 990 return privKeyAttrsCount;
michael@0 991 default:
michael@0 992 break;
michael@0 993 }
michael@0 994 return 0;
michael@0 995 }
michael@0 996
michael@0 997 static CK_RV
michael@0 998 ckmk_mdObject_GetAttributeTypes
michael@0 999 (
michael@0 1000 NSSCKMDObject *mdObject,
michael@0 1001 NSSCKFWObject *fwObject,
michael@0 1002 NSSCKMDSession *mdSession,
michael@0 1003 NSSCKFWSession *fwSession,
michael@0 1004 NSSCKMDToken *mdToken,
michael@0 1005 NSSCKFWToken *fwToken,
michael@0 1006 NSSCKMDInstance *mdInstance,
michael@0 1007 NSSCKFWInstance *fwInstance,
michael@0 1008 CK_ATTRIBUTE_TYPE_PTR typeArray,
michael@0 1009 CK_ULONG ulCount
michael@0 1010 )
michael@0 1011 {
michael@0 1012 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
michael@0 1013 CK_ULONG i;
michael@0 1014 CK_RV error = CKR_OK;
michael@0 1015 const CK_ATTRIBUTE_TYPE *attrs = NULL;
michael@0 1016 CK_ULONG size = ckmk_mdObject_GetAttributeCount(
michael@0 1017 mdObject, fwObject, mdSession, fwSession,
michael@0 1018 mdToken, fwToken, mdInstance, fwInstance, &error);
michael@0 1019
michael@0 1020 if( size != ulCount ) {
michael@0 1021 return CKR_BUFFER_TOO_SMALL;
michael@0 1022 }
michael@0 1023 if (io->type == ckmkRaw) {
michael@0 1024 attrs = io->u.raw.types;
michael@0 1025 } else switch(io->objClass) {
michael@0 1026 case CKO_CERTIFICATE:
michael@0 1027 attrs = certAttrs;
michael@0 1028 break;
michael@0 1029 case CKO_PUBLIC_KEY:
michael@0 1030 attrs = pubKeyAttrs;
michael@0 1031 break;
michael@0 1032 case CKO_PRIVATE_KEY:
michael@0 1033 attrs = privKeyAttrs;
michael@0 1034 break;
michael@0 1035 default:
michael@0 1036 return CKR_OK;
michael@0 1037 }
michael@0 1038
michael@0 1039 for( i = 0; i < size; i++) {
michael@0 1040 typeArray[i] = attrs[i];
michael@0 1041 }
michael@0 1042
michael@0 1043 return CKR_OK;
michael@0 1044 }
michael@0 1045
michael@0 1046 static CK_ULONG
michael@0 1047 ckmk_mdObject_GetAttributeSize
michael@0 1048 (
michael@0 1049 NSSCKMDObject *mdObject,
michael@0 1050 NSSCKFWObject *fwObject,
michael@0 1051 NSSCKMDSession *mdSession,
michael@0 1052 NSSCKFWSession *fwSession,
michael@0 1053 NSSCKMDToken *mdToken,
michael@0 1054 NSSCKFWToken *fwToken,
michael@0 1055 NSSCKMDInstance *mdInstance,
michael@0 1056 NSSCKFWInstance *fwInstance,
michael@0 1057 CK_ATTRIBUTE_TYPE attribute,
michael@0 1058 CK_RV *pError
michael@0 1059 )
michael@0 1060 {
michael@0 1061 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
michael@0 1062
michael@0 1063 const NSSItem *b;
michael@0 1064
michael@0 1065 b = nss_ckmk_FetchAttribute(io, attribute, pError);
michael@0 1066
michael@0 1067 if ((const NSSItem *)NULL == b) {
michael@0 1068 return 0;
michael@0 1069 }
michael@0 1070 return b->size;
michael@0 1071 }
michael@0 1072
michael@0 1073 static CK_RV
michael@0 1074 ckmk_mdObject_SetAttribute
michael@0 1075 (
michael@0 1076 NSSCKMDObject *mdObject,
michael@0 1077 NSSCKFWObject *fwObject,
michael@0 1078 NSSCKMDSession *mdSession,
michael@0 1079 NSSCKFWSession *fwSession,
michael@0 1080 NSSCKMDToken *mdToken,
michael@0 1081 NSSCKFWToken *fwToken,
michael@0 1082 NSSCKMDInstance *mdInstance,
michael@0 1083 NSSCKFWInstance *fwInstance,
michael@0 1084 CK_ATTRIBUTE_TYPE attribute,
michael@0 1085 NSSItem *value
michael@0 1086 )
michael@0 1087 {
michael@0 1088 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
michael@0 1089 SecKeychainItemRef itemRef;
michael@0 1090
michael@0 1091 if (io->type == ckmkRaw) {
michael@0 1092 return CKR_TOKEN_WRITE_PROTECTED;
michael@0 1093 }
michael@0 1094 itemRef = io->u.item.itemRef;
michael@0 1095
michael@0 1096 switch (io->objClass) {
michael@0 1097 case CKO_PRIVATE_KEY:
michael@0 1098 case CKO_PUBLIC_KEY:
michael@0 1099 switch (attribute) {
michael@0 1100 case CKA_ID:
michael@0 1101 ckmk_updateAttribute(itemRef, kSecKeyLabel,
michael@0 1102 value->data, value->size, "Set Attr Key ID");
michael@0 1103 #ifdef DEBUG
michael@0 1104 itemdump("key id: ", value->data, value->size, CKR_OK);
michael@0 1105 #endif
michael@0 1106 break;
michael@0 1107 case CKA_LABEL:
michael@0 1108 ckmk_updateAttribute(itemRef, kSecKeyPrintName, value->data,
michael@0 1109 value->size, "Set Attr Key Label");
michael@0 1110 break;
michael@0 1111 default:
michael@0 1112 break;
michael@0 1113 }
michael@0 1114 break;
michael@0 1115
michael@0 1116 case CKO_CERTIFICATE:
michael@0 1117 switch (attribute) {
michael@0 1118 case CKA_ID:
michael@0 1119 ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr,
michael@0 1120 value->data, value->size, "Set Attr Cert ID");
michael@0 1121 break;
michael@0 1122 case CKA_LABEL:
michael@0 1123 ckmk_updateAttribute(itemRef, kSecLabelItemAttr, value->data,
michael@0 1124 value->size, "Set Attr Cert Label");
michael@0 1125 break;
michael@0 1126 default:
michael@0 1127 break;
michael@0 1128 }
michael@0 1129 break;
michael@0 1130
michael@0 1131 default:
michael@0 1132 break;
michael@0 1133 }
michael@0 1134 return CKR_OK;
michael@0 1135 }
michael@0 1136
michael@0 1137 static NSSCKFWItem
michael@0 1138 ckmk_mdObject_GetAttribute
michael@0 1139 (
michael@0 1140 NSSCKMDObject *mdObject,
michael@0 1141 NSSCKFWObject *fwObject,
michael@0 1142 NSSCKMDSession *mdSession,
michael@0 1143 NSSCKFWSession *fwSession,
michael@0 1144 NSSCKMDToken *mdToken,
michael@0 1145 NSSCKFWToken *fwToken,
michael@0 1146 NSSCKMDInstance *mdInstance,
michael@0 1147 NSSCKFWInstance *fwInstance,
michael@0 1148 CK_ATTRIBUTE_TYPE attribute,
michael@0 1149 CK_RV *pError
michael@0 1150 )
michael@0 1151 {
michael@0 1152 NSSCKFWItem mdItem;
michael@0 1153 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc;
michael@0 1154
michael@0 1155 mdItem.needsFreeing = PR_FALSE;
michael@0 1156 mdItem.item = (NSSItem*)nss_ckmk_FetchAttribute(io, attribute, pError);
michael@0 1157
michael@0 1158
michael@0 1159 return mdItem;
michael@0 1160 }
michael@0 1161
michael@0 1162 static CK_ULONG
michael@0 1163 ckmk_mdObject_GetObjectSize
michael@0 1164 (
michael@0 1165 NSSCKMDObject *mdObject,
michael@0 1166 NSSCKFWObject *fwObject,
michael@0 1167 NSSCKMDSession *mdSession,
michael@0 1168 NSSCKFWSession *fwSession,
michael@0 1169 NSSCKMDToken *mdToken,
michael@0 1170 NSSCKFWToken *fwToken,
michael@0 1171 NSSCKMDInstance *mdInstance,
michael@0 1172 NSSCKFWInstance *fwInstance,
michael@0 1173 CK_RV *pError
michael@0 1174 )
michael@0 1175 {
michael@0 1176 CK_ULONG rv = 1;
michael@0 1177
michael@0 1178 /* size is irrelevant to this token */
michael@0 1179 return rv;
michael@0 1180 }
michael@0 1181
michael@0 1182 static const NSSCKMDObject
michael@0 1183 ckmk_prototype_mdObject = {
michael@0 1184 (void *)NULL, /* etc */
michael@0 1185 NULL, /* Finalize */
michael@0 1186 ckmk_mdObject_Destroy,
michael@0 1187 ckmk_mdObject_IsTokenObject,
michael@0 1188 ckmk_mdObject_GetAttributeCount,
michael@0 1189 ckmk_mdObject_GetAttributeTypes,
michael@0 1190 ckmk_mdObject_GetAttributeSize,
michael@0 1191 ckmk_mdObject_GetAttribute,
michael@0 1192 NULL, /* FreeAttribute */
michael@0 1193 ckmk_mdObject_SetAttribute,
michael@0 1194 ckmk_mdObject_GetObjectSize,
michael@0 1195 (void *)NULL /* null terminator */
michael@0 1196 };
michael@0 1197
michael@0 1198 static nssHash *ckmkInternalObjectHash = NULL;
michael@0 1199
michael@0 1200 NSS_IMPLEMENT NSSCKMDObject *
michael@0 1201 nss_ckmk_CreateMDObject
michael@0 1202 (
michael@0 1203 NSSArena *arena,
michael@0 1204 ckmkInternalObject *io,
michael@0 1205 CK_RV *pError
michael@0 1206 )
michael@0 1207 {
michael@0 1208 if ((nssHash *)NULL == ckmkInternalObjectHash) {
michael@0 1209 ckmkInternalObjectHash = nssHash_CreateItem(NULL, 10);
michael@0 1210 }
michael@0 1211 if (ckmkItem == io->type) {
michael@0 1212 /* the hash key, not a cryptographic key */
michael@0 1213 NSSItem *key = &io->hashKey;
michael@0 1214 ckmkInternalObject *old_o = NULL;
michael@0 1215
michael@0 1216 if (key->size == 0) {
michael@0 1217 ckmk_FetchHashKey(io);
michael@0 1218 }
michael@0 1219 old_o = (ckmkInternalObject *)
michael@0 1220 nssHash_Lookup(ckmkInternalObjectHash, key);
michael@0 1221 if (!old_o) {
michael@0 1222 nssHash_Add(ckmkInternalObjectHash, key, io);
michael@0 1223 } else if (old_o != io) {
michael@0 1224 nss_ckmk_DestroyInternalObject(io);
michael@0 1225 io = old_o;
michael@0 1226 }
michael@0 1227 }
michael@0 1228
michael@0 1229 if ( (void*)NULL == io->mdObject.etc) {
michael@0 1230 (void) nsslibc_memcpy(&io->mdObject,&ckmk_prototype_mdObject,
michael@0 1231 sizeof(ckmk_prototype_mdObject));
michael@0 1232 io->mdObject.etc = (void *)io;
michael@0 1233 }
michael@0 1234 return &io->mdObject;
michael@0 1235 }
michael@0 1236
michael@0 1237 static void
michael@0 1238 ckmk_removeObjectFromHash
michael@0 1239 (
michael@0 1240 ckmkInternalObject *io
michael@0 1241 )
michael@0 1242 {
michael@0 1243 NSSItem *key = &io->hashKey;
michael@0 1244
michael@0 1245 if ((nssHash *)NULL == ckmkInternalObjectHash) {
michael@0 1246 return;
michael@0 1247 }
michael@0 1248 if (key->size == 0) {
michael@0 1249 ckmk_FetchHashKey(io);
michael@0 1250 }
michael@0 1251 nssHash_Remove(ckmkInternalObjectHash, key);
michael@0 1252 return;
michael@0 1253 }
michael@0 1254
michael@0 1255
michael@0 1256 void
michael@0 1257 nss_ckmk_DestroyInternalObject
michael@0 1258 (
michael@0 1259 ckmkInternalObject *io
michael@0 1260 )
michael@0 1261 {
michael@0 1262 switch (io->type) {
michael@0 1263 case ckmkRaw:
michael@0 1264 return;
michael@0 1265 case ckmkItem:
michael@0 1266 nss_ZFreeIf(io->u.item.modify.data);
michael@0 1267 nss_ZFreeIf(io->u.item.private.data);
michael@0 1268 nss_ZFreeIf(io->u.item.encrypt.data);
michael@0 1269 nss_ZFreeIf(io->u.item.decrypt.data);
michael@0 1270 nss_ZFreeIf(io->u.item.derive.data);
michael@0 1271 nss_ZFreeIf(io->u.item.sign.data);
michael@0 1272 nss_ZFreeIf(io->u.item.signRecover.data);
michael@0 1273 nss_ZFreeIf(io->u.item.verify.data);
michael@0 1274 nss_ZFreeIf(io->u.item.verifyRecover.data);
michael@0 1275 nss_ZFreeIf(io->u.item.wrap.data);
michael@0 1276 nss_ZFreeIf(io->u.item.unwrap.data);
michael@0 1277 nss_ZFreeIf(io->u.item.label.data);
michael@0 1278 /*nss_ZFreeIf(io->u.item.subject.data); */
michael@0 1279 /*nss_ZFreeIf(io->u.item.issuer.data); */
michael@0 1280 nss_ZFreeIf(io->u.item.serial.data);
michael@0 1281 nss_ZFreeIf(io->u.item.modulus.data);
michael@0 1282 nss_ZFreeIf(io->u.item.exponent.data);
michael@0 1283 nss_ZFreeIf(io->u.item.privateExponent.data);
michael@0 1284 nss_ZFreeIf(io->u.item.prime1.data);
michael@0 1285 nss_ZFreeIf(io->u.item.prime2.data);
michael@0 1286 nss_ZFreeIf(io->u.item.exponent1.data);
michael@0 1287 nss_ZFreeIf(io->u.item.exponent2.data);
michael@0 1288 nss_ZFreeIf(io->u.item.coefficient.data);
michael@0 1289 break;
michael@0 1290 }
michael@0 1291 nss_ZFreeIf(io);
michael@0 1292 return;
michael@0 1293 }
michael@0 1294
michael@0 1295
michael@0 1296 static ckmkInternalObject *
michael@0 1297 nss_ckmk_NewInternalObject
michael@0 1298 (
michael@0 1299 CK_OBJECT_CLASS objClass,
michael@0 1300 SecKeychainItemRef itemRef,
michael@0 1301 SecItemClass itemClass,
michael@0 1302 CK_RV *pError
michael@0 1303 )
michael@0 1304 {
michael@0 1305 ckmkInternalObject *io = nss_ZNEW(NULL, ckmkInternalObject);
michael@0 1306
michael@0 1307 if ((ckmkInternalObject *)NULL == io) {
michael@0 1308 *pError = CKR_HOST_MEMORY;
michael@0 1309 return io;
michael@0 1310 }
michael@0 1311 io->type = ckmkItem;
michael@0 1312 io->objClass = objClass;
michael@0 1313 io->u.item.itemRef = itemRef;
michael@0 1314 io->u.item.itemClass = itemClass;
michael@0 1315 return io;
michael@0 1316 }
michael@0 1317
michael@0 1318 /*
michael@0 1319 * Apple doesn't alway have a default keyChain set by the OS, use the
michael@0 1320 * SearchList to try to find one.
michael@0 1321 */
michael@0 1322 static CK_RV
michael@0 1323 ckmk_GetSafeDefaultKeychain
michael@0 1324 (
michael@0 1325 SecKeychainRef *keychainRef
michael@0 1326 )
michael@0 1327 {
michael@0 1328 OSStatus macErr;
michael@0 1329 CFArrayRef searchList = 0;
michael@0 1330 CK_RV error = CKR_OK;
michael@0 1331
michael@0 1332 macErr = SecKeychainCopyDefault(keychainRef);
michael@0 1333 if (noErr != macErr) {
michael@0 1334 int searchCount = 0;
michael@0 1335 if (errSecNoDefaultKeychain != macErr) {
michael@0 1336 CKMK_MACERR("Getting default key chain", macErr);
michael@0 1337 error = CKR_GENERAL_ERROR;
michael@0 1338 goto loser;
michael@0 1339 }
michael@0 1340 /* ok, we don't have a default key chain, find one */
michael@0 1341 macErr = SecKeychainCopySearchList(&searchList);
michael@0 1342 if (noErr != macErr) {
michael@0 1343 CKMK_MACERR("failed to find a keyring searchList", macErr);
michael@0 1344 error = CKR_DEVICE_REMOVED;
michael@0 1345 goto loser;
michael@0 1346 }
michael@0 1347 searchCount = CFArrayGetCount(searchList);
michael@0 1348 if (searchCount < 1) {
michael@0 1349 error = CKR_DEVICE_REMOVED;
michael@0 1350 goto loser;
michael@0 1351 }
michael@0 1352 *keychainRef =
michael@0 1353 (SecKeychainRef)CFRetain(CFArrayGetValueAtIndex(searchList, 0));
michael@0 1354 if (0 == *keychainRef) {
michael@0 1355 error = CKR_DEVICE_REMOVED;
michael@0 1356 goto loser;
michael@0 1357 }
michael@0 1358 /* should we set it as default? */
michael@0 1359 }
michael@0 1360 loser:
michael@0 1361 if (0 != searchList) {
michael@0 1362 CFRelease(searchList);
michael@0 1363 }
michael@0 1364 return error;
michael@0 1365 }
michael@0 1366 static ckmkInternalObject *
michael@0 1367 nss_ckmk_CreateCertificate
michael@0 1368 (
michael@0 1369 NSSCKFWSession *fwSession,
michael@0 1370 CK_ATTRIBUTE_PTR pTemplate,
michael@0 1371 CK_ULONG ulAttributeCount,
michael@0 1372 CK_RV *pError
michael@0 1373 )
michael@0 1374 {
michael@0 1375 NSSItem value;
michael@0 1376 ckmkInternalObject *io = NULL;
michael@0 1377 OSStatus macErr;
michael@0 1378 SecCertificateRef certRef;
michael@0 1379 SecKeychainItemRef itemRef;
michael@0 1380 SecKeychainRef keychainRef;
michael@0 1381 CSSM_DATA certData;
michael@0 1382
michael@0 1383 *pError = nss_ckmk_GetAttribute(CKA_VALUE, pTemplate,
michael@0 1384 ulAttributeCount, &value);
michael@0 1385 if (CKR_OK != *pError) {
michael@0 1386 goto loser;
michael@0 1387 }
michael@0 1388
michael@0 1389 certData.Data = value.data;
michael@0 1390 certData.Length = value.size;
michael@0 1391 macErr = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3,
michael@0 1392 CSSM_CERT_ENCODING_BER, &certRef);
michael@0 1393 if (noErr != macErr) {
michael@0 1394 CKMK_MACERR("Create cert from data Failed", macErr);
michael@0 1395 *pError = CKR_GENERAL_ERROR; /* need to map macErr */
michael@0 1396 goto loser;
michael@0 1397 }
michael@0 1398
michael@0 1399 *pError = ckmk_GetSafeDefaultKeychain(&keychainRef);
michael@0 1400 if (CKR_OK != *pError) {
michael@0 1401 goto loser;
michael@0 1402 }
michael@0 1403
michael@0 1404 macErr = SecCertificateAddToKeychain( certRef, keychainRef);
michael@0 1405 itemRef = (SecKeychainItemRef) certRef;
michael@0 1406 if (errSecDuplicateItem != macErr) {
michael@0 1407 NSSItem keyID = { NULL, 0 };
michael@0 1408 char *nickname = NULL;
michael@0 1409 CK_RV dummy;
michael@0 1410
michael@0 1411 if (noErr != macErr) {
michael@0 1412 CKMK_MACERR("Add cert to keychain Failed", macErr);
michael@0 1413 *pError = CKR_GENERAL_ERROR; /* need to map macErr */
michael@0 1414 goto loser;
michael@0 1415 }
michael@0 1416 /* these two are optional */
michael@0 1417 nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate,
michael@0 1418 ulAttributeCount, &dummy);
michael@0 1419 /* we've added a new one, update the attributes in the key ring */
michael@0 1420 if (nickname) {
michael@0 1421 ckmk_updateAttribute(itemRef, kSecLabelItemAttr, nickname,
michael@0 1422 strlen(nickname)+1, "Modify Cert Label");
michael@0 1423 nss_ZFreeIf(nickname);
michael@0 1424 }
michael@0 1425 dummy = nss_ckmk_GetAttribute(CKA_ID, pTemplate,
michael@0 1426 ulAttributeCount, &keyID);
michael@0 1427 if (CKR_OK == dummy) {
michael@0 1428 dummy = ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr,
michael@0 1429 keyID.data, keyID.size, "Modify Cert ID");
michael@0 1430 }
michael@0 1431 }
michael@0 1432
michael@0 1433 io = nss_ckmk_NewInternalObject(CKO_CERTIFICATE, itemRef,
michael@0 1434 kSecCertificateItemClass, pError);
michael@0 1435 if ((ckmkInternalObject *)NULL != io) {
michael@0 1436 itemRef = 0;
michael@0 1437 }
michael@0 1438
michael@0 1439 loser:
michael@0 1440 if (0 != itemRef) {
michael@0 1441 CFRelease(itemRef);
michael@0 1442 }
michael@0 1443 if (0 != keychainRef) {
michael@0 1444 CFRelease(keychainRef);
michael@0 1445 }
michael@0 1446
michael@0 1447 return io;
michael@0 1448 }
michael@0 1449
michael@0 1450 /*
michael@0 1451 * PKCS #8 attributes
michael@0 1452 */
michael@0 1453 struct ckmk_AttributeStr {
michael@0 1454 SECItem attrType;
michael@0 1455 SECItem *attrValue;
michael@0 1456 };
michael@0 1457 typedef struct ckmk_AttributeStr ckmk_Attribute;
michael@0 1458
michael@0 1459 /*
michael@0 1460 ** A PKCS#8 private key info object
michael@0 1461 */
michael@0 1462 struct PrivateKeyInfoStr {
michael@0 1463 PLArenaPool *arena;
michael@0 1464 SECItem version;
michael@0 1465 SECAlgorithmID algorithm;
michael@0 1466 SECItem privateKey;
michael@0 1467 ckmk_Attribute **attributes;
michael@0 1468 };
michael@0 1469 typedef struct PrivateKeyInfoStr PrivateKeyInfo;
michael@0 1470
michael@0 1471 const SEC_ASN1Template ckmk_RSAPrivateKeyTemplate[] = {
michael@0 1472 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey) },
michael@0 1473 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,version) },
michael@0 1474 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,modulus) },
michael@0 1475 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,publicExponent) },
michael@0 1476 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,privateExponent) },
michael@0 1477 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,prime1) },
michael@0 1478 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,prime2) },
michael@0 1479 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,exponent1) },
michael@0 1480 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,exponent2) },
michael@0 1481 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,coefficient) },
michael@0 1482 { 0 }
michael@0 1483 };
michael@0 1484
michael@0 1485 const SEC_ASN1Template ckmk_AttributeTemplate[] = {
michael@0 1486 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ckmk_Attribute) },
michael@0 1487 { SEC_ASN1_OBJECT_ID, offsetof(ckmk_Attribute, attrType) },
michael@0 1488 { SEC_ASN1_SET_OF, offsetof(ckmk_Attribute, attrValue),
michael@0 1489 SEC_AnyTemplate },
michael@0 1490 { 0 }
michael@0 1491 };
michael@0 1492
michael@0 1493 const SEC_ASN1Template ckmk_SetOfAttributeTemplate[] = {
michael@0 1494 { SEC_ASN1_SET_OF, 0, ckmk_AttributeTemplate },
michael@0 1495 };
michael@0 1496
michael@0 1497 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
michael@0 1498
michael@0 1499 /* ASN1 Templates for new decoder/encoder */
michael@0 1500 const SEC_ASN1Template ckmk_PrivateKeyInfoTemplate[] = {
michael@0 1501 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PrivateKeyInfo) },
michael@0 1502 { SEC_ASN1_INTEGER, offsetof(PrivateKeyInfo,version) },
michael@0 1503 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(PrivateKeyInfo,algorithm),
michael@0 1504 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
michael@0 1505 { SEC_ASN1_OCTET_STRING, offsetof(PrivateKeyInfo,privateKey) },
michael@0 1506 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
michael@0 1507 offsetof(PrivateKeyInfo, attributes), ckmk_SetOfAttributeTemplate },
michael@0 1508 { 0 }
michael@0 1509 };
michael@0 1510
michael@0 1511 #define CKMK_PRIVATE_KEY_INFO_VERSION 0
michael@0 1512 static CK_RV
michael@0 1513 ckmk_CreateRSAKeyBlob
michael@0 1514 (
michael@0 1515 RSAPrivateKey *lk,
michael@0 1516 NSSItem *keyBlob
michael@0 1517 )
michael@0 1518 {
michael@0 1519 PrivateKeyInfo *pki = NULL;
michael@0 1520 PLArenaPool *arena = NULL;
michael@0 1521 SECOidTag algorithm = SEC_OID_UNKNOWN;
michael@0 1522 void *dummy;
michael@0 1523 SECStatus rv;
michael@0 1524 SECItem *encodedKey = NULL;
michael@0 1525 CK_RV error = CKR_OK;
michael@0 1526
michael@0 1527 arena = PORT_NewArena(2048); /* XXX different size? */
michael@0 1528 if(!arena) {
michael@0 1529 error = CKR_HOST_MEMORY;
michael@0 1530 goto loser;
michael@0 1531 }
michael@0 1532
michael@0 1533 pki = (PrivateKeyInfo*)PORT_ArenaZAlloc(arena, sizeof(PrivateKeyInfo));
michael@0 1534 if(!pki) {
michael@0 1535 error = CKR_HOST_MEMORY;
michael@0 1536 goto loser;
michael@0 1537 }
michael@0 1538 pki->arena = arena;
michael@0 1539
michael@0 1540 dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
michael@0 1541 ckmk_RSAPrivateKeyTemplate);
michael@0 1542 algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION;
michael@0 1543
michael@0 1544 if (!dummy) {
michael@0 1545 error = CKR_DEVICE_ERROR; /* should map NSS SECError */
michael@0 1546 goto loser;
michael@0 1547 }
michael@0 1548
michael@0 1549 rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm,
michael@0 1550 (SECItem*)NULL);
michael@0 1551 if (rv != SECSuccess) {
michael@0 1552 error = CKR_DEVICE_ERROR; /* should map NSS SECError */
michael@0 1553 goto loser;
michael@0 1554 }
michael@0 1555
michael@0 1556 dummy = SEC_ASN1EncodeInteger(arena, &pki->version,
michael@0 1557 CKMK_PRIVATE_KEY_INFO_VERSION);
michael@0 1558 if (!dummy) {
michael@0 1559 error = CKR_DEVICE_ERROR; /* should map NSS SECError */
michael@0 1560 goto loser;
michael@0 1561 }
michael@0 1562
michael@0 1563 encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki,
michael@0 1564 ckmk_PrivateKeyInfoTemplate);
michael@0 1565 if (!encodedKey) {
michael@0 1566 error = CKR_DEVICE_ERROR;
michael@0 1567 goto loser;
michael@0 1568 }
michael@0 1569
michael@0 1570 keyBlob->data = nss_ZNEWARRAY(NULL, char, encodedKey->len);
michael@0 1571 if (NULL == keyBlob->data) {
michael@0 1572 error = CKR_HOST_MEMORY;
michael@0 1573 goto loser;
michael@0 1574 }
michael@0 1575 nsslibc_memcpy(keyBlob->data, encodedKey->data, encodedKey->len);
michael@0 1576 keyBlob->size = encodedKey->len;
michael@0 1577
michael@0 1578 loser:
michael@0 1579 if(arena) {
michael@0 1580 PORT_FreeArena(arena, PR_TRUE);
michael@0 1581 }
michael@0 1582 if (encodedKey) {
michael@0 1583 SECITEM_FreeItem(encodedKey, PR_TRUE);
michael@0 1584 }
michael@0 1585
michael@0 1586 return error;
michael@0 1587 }
michael@0 1588 /*
michael@0 1589 * There MUST be a better way to do this. For now, find the key based on the
michael@0 1590 * default name Apple gives it once we import.
michael@0 1591 */
michael@0 1592 #define IMPORTED_NAME "Imported Private Key"
michael@0 1593 static CK_RV
michael@0 1594 ckmk_FindImportedKey
michael@0 1595 (
michael@0 1596 SecKeychainRef keychainRef,
michael@0 1597 SecItemClass itemClass,
michael@0 1598 SecKeychainItemRef *outItemRef
michael@0 1599 )
michael@0 1600 {
michael@0 1601 OSStatus macErr;
michael@0 1602 SecKeychainSearchRef searchRef = 0;
michael@0 1603 SecKeychainItemRef newItemRef;
michael@0 1604
michael@0 1605 macErr = SecKeychainSearchCreateFromAttributes(keychainRef, itemClass,
michael@0 1606 NULL, &searchRef);
michael@0 1607 if (noErr != macErr) {
michael@0 1608 CKMK_MACERR("Can't search for Key", macErr);
michael@0 1609 return CKR_GENERAL_ERROR;
michael@0 1610 }
michael@0 1611 while (noErr == SecKeychainSearchCopyNext(searchRef, &newItemRef)) {
michael@0 1612 SecKeychainAttributeList *attrList = NULL;
michael@0 1613 SecKeychainAttributeInfo attrInfo;
michael@0 1614 SecItemAttr itemAttr = kSecKeyPrintName;
michael@0 1615 PRUint32 attrFormat = 0;
michael@0 1616 OSStatus macErr;
michael@0 1617
michael@0 1618 attrInfo.count = 1;
michael@0 1619 attrInfo.tag = &itemAttr;
michael@0 1620 attrInfo.format = &attrFormat;
michael@0 1621
michael@0 1622 macErr = SecKeychainItemCopyAttributesAndData(newItemRef,
michael@0 1623 &attrInfo, NULL, &attrList, NULL, NULL);
michael@0 1624 if (noErr == macErr) {
michael@0 1625 if (nsslibc_memcmp(attrList->attr->data, IMPORTED_NAME,
michael@0 1626 attrList->attr->length, NULL) == 0) {
michael@0 1627 *outItemRef = newItemRef;
michael@0 1628 CFRelease (searchRef);
michael@0 1629 SecKeychainItemFreeAttributesAndData(attrList, NULL);
michael@0 1630 return CKR_OK;
michael@0 1631 }
michael@0 1632 SecKeychainItemFreeAttributesAndData(attrList, NULL);
michael@0 1633 }
michael@0 1634 CFRelease(newItemRef);
michael@0 1635 }
michael@0 1636 CFRelease (searchRef);
michael@0 1637 return CKR_GENERAL_ERROR; /* we can come up with something better! */
michael@0 1638 }
michael@0 1639
michael@0 1640 static ckmkInternalObject *
michael@0 1641 nss_ckmk_CreatePrivateKey
michael@0 1642 (
michael@0 1643 NSSCKFWSession *fwSession,
michael@0 1644 CK_ATTRIBUTE_PTR pTemplate,
michael@0 1645 CK_ULONG ulAttributeCount,
michael@0 1646 CK_RV *pError
michael@0 1647 )
michael@0 1648 {
michael@0 1649 NSSItem attribute;
michael@0 1650 RSAPrivateKey lk;
michael@0 1651 NSSItem keyID;
michael@0 1652 char *nickname = NULL;
michael@0 1653 ckmkInternalObject *io = NULL;
michael@0 1654 CK_KEY_TYPE keyType;
michael@0 1655 OSStatus macErr;
michael@0 1656 SecKeychainItemRef itemRef = 0;
michael@0 1657 NSSItem keyBlob = { NULL, 0 };
michael@0 1658 CFDataRef dataRef = 0;
michael@0 1659 SecExternalFormat inputFormat = kSecFormatBSAFE;
michael@0 1660 /*SecExternalFormat inputFormat = kSecFormatOpenSSL; */
michael@0 1661 SecExternalItemType itemType = kSecItemTypePrivateKey;
michael@0 1662 SecKeyImportExportParameters keyParams ;
michael@0 1663 SecKeychainRef targetKeychain = 0;
michael@0 1664 unsigned char zero = 0;
michael@0 1665 CK_RV error;
michael@0 1666
michael@0 1667 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
michael@0 1668 keyParams.flags = 0;
michael@0 1669 keyParams.passphrase = 0;
michael@0 1670 keyParams.alertTitle = 0;
michael@0 1671 keyParams.alertPrompt = 0;
michael@0 1672 keyParams.accessRef = 0; /* default */
michael@0 1673 keyParams.keyUsage = 0; /* will get filled in */
michael@0 1674 keyParams.keyAttributes = CSSM_KEYATTR_PERMANENT; /* will get filled in */
michael@0 1675 keyType = nss_ckmk_GetULongAttribute
michael@0 1676 (CKA_KEY_TYPE, pTemplate, ulAttributeCount, pError);
michael@0 1677 if (CKR_OK != *pError) {
michael@0 1678 return (ckmkInternalObject *)NULL;
michael@0 1679 }
michael@0 1680 if (CKK_RSA != keyType) {
michael@0 1681 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 1682 return (ckmkInternalObject *)NULL;
michael@0 1683 }
michael@0 1684 if (nss_ckmk_GetBoolAttribute(CKA_DECRYPT,
michael@0 1685 pTemplate, ulAttributeCount, CK_TRUE)) {
michael@0 1686 keyParams.keyUsage |= CSSM_KEYUSE_DECRYPT;
michael@0 1687 }
michael@0 1688 if (nss_ckmk_GetBoolAttribute(CKA_UNWRAP,
michael@0 1689 pTemplate, ulAttributeCount, CK_TRUE)) {
michael@0 1690 keyParams.keyUsage |= CSSM_KEYUSE_UNWRAP;
michael@0 1691 }
michael@0 1692 if (nss_ckmk_GetBoolAttribute(CKA_SIGN,
michael@0 1693 pTemplate, ulAttributeCount, CK_TRUE)) {
michael@0 1694 keyParams.keyUsage |= CSSM_KEYUSE_SIGN;
michael@0 1695 }
michael@0 1696 if (nss_ckmk_GetBoolAttribute(CKA_DERIVE,
michael@0 1697 pTemplate, ulAttributeCount, CK_FALSE)) {
michael@0 1698 keyParams.keyUsage |= CSSM_KEYUSE_DERIVE;
michael@0 1699 }
michael@0 1700 if (nss_ckmk_GetBoolAttribute(CKA_SENSITIVE,
michael@0 1701 pTemplate, ulAttributeCount, CK_TRUE)) {
michael@0 1702 keyParams.keyAttributes |= CSSM_KEYATTR_SENSITIVE;
michael@0 1703 }
michael@0 1704 if (nss_ckmk_GetBoolAttribute(CKA_EXTRACTABLE,
michael@0 1705 pTemplate, ulAttributeCount, CK_TRUE)) {
michael@0 1706 keyParams.keyAttributes |= CSSM_KEYATTR_EXTRACTABLE;
michael@0 1707 }
michael@0 1708
michael@0 1709 lk.version.type = siUnsignedInteger;
michael@0 1710 lk.version.data = &zero;
michael@0 1711 lk.version.len = 1;
michael@0 1712
michael@0 1713 *pError = nss_ckmk_GetAttribute(CKA_MODULUS, pTemplate,
michael@0 1714 ulAttributeCount, &attribute);
michael@0 1715 if (CKR_OK != *pError) {
michael@0 1716 return (ckmkInternalObject *)NULL;
michael@0 1717 }
michael@0 1718 lk.modulus.type = siUnsignedInteger;
michael@0 1719 lk.modulus.data = attribute.data;
michael@0 1720 lk.modulus.len = attribute.size;
michael@0 1721
michael@0 1722 *pError = nss_ckmk_GetAttribute(CKA_PUBLIC_EXPONENT, pTemplate,
michael@0 1723 ulAttributeCount, &attribute);
michael@0 1724 if (CKR_OK != *pError) {
michael@0 1725 return (ckmkInternalObject *)NULL;
michael@0 1726 }
michael@0 1727 lk.publicExponent.type = siUnsignedInteger;
michael@0 1728 lk.publicExponent.data = attribute.data;
michael@0 1729 lk.publicExponent.len = attribute.size;
michael@0 1730
michael@0 1731 *pError = nss_ckmk_GetAttribute(CKA_PRIVATE_EXPONENT, pTemplate,
michael@0 1732 ulAttributeCount, &attribute);
michael@0 1733 if (CKR_OK != *pError) {
michael@0 1734 return (ckmkInternalObject *)NULL;
michael@0 1735 }
michael@0 1736 lk.privateExponent.type = siUnsignedInteger;
michael@0 1737 lk.privateExponent.data = attribute.data;
michael@0 1738 lk.privateExponent.len = attribute.size;
michael@0 1739
michael@0 1740 *pError = nss_ckmk_GetAttribute(CKA_PRIME_1, pTemplate,
michael@0 1741 ulAttributeCount, &attribute);
michael@0 1742 if (CKR_OK != *pError) {
michael@0 1743 return (ckmkInternalObject *)NULL;
michael@0 1744 }
michael@0 1745 lk.prime1.type = siUnsignedInteger;
michael@0 1746 lk.prime1.data = attribute.data;
michael@0 1747 lk.prime1.len = attribute.size;
michael@0 1748
michael@0 1749 *pError = nss_ckmk_GetAttribute(CKA_PRIME_2, pTemplate,
michael@0 1750 ulAttributeCount, &attribute);
michael@0 1751 if (CKR_OK != *pError) {
michael@0 1752 return (ckmkInternalObject *)NULL;
michael@0 1753 }
michael@0 1754 lk.prime2.type = siUnsignedInteger;
michael@0 1755 lk.prime2.data = attribute.data;
michael@0 1756 lk.prime2.len = attribute.size;
michael@0 1757
michael@0 1758 *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_1, pTemplate,
michael@0 1759 ulAttributeCount, &attribute);
michael@0 1760 if (CKR_OK != *pError) {
michael@0 1761 return (ckmkInternalObject *)NULL;
michael@0 1762 }
michael@0 1763 lk.exponent1.type = siUnsignedInteger;
michael@0 1764 lk.exponent1.data = attribute.data;
michael@0 1765 lk.exponent1.len = attribute.size;
michael@0 1766
michael@0 1767 *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_2, pTemplate,
michael@0 1768 ulAttributeCount, &attribute);
michael@0 1769 if (CKR_OK != *pError) {
michael@0 1770 return (ckmkInternalObject *)NULL;
michael@0 1771 }
michael@0 1772 lk.exponent2.type = siUnsignedInteger;
michael@0 1773 lk.exponent2.data = attribute.data;
michael@0 1774 lk.exponent2.len = attribute.size;
michael@0 1775
michael@0 1776 *pError = nss_ckmk_GetAttribute(CKA_COEFFICIENT, pTemplate,
michael@0 1777 ulAttributeCount, &attribute);
michael@0 1778 if (CKR_OK != *pError) {
michael@0 1779 return (ckmkInternalObject *)NULL;
michael@0 1780 }
michael@0 1781 lk.coefficient.type = siUnsignedInteger;
michael@0 1782 lk.coefficient.data = attribute.data;
michael@0 1783 lk.coefficient.len = attribute.size;
michael@0 1784
michael@0 1785 /* ASN1 Encode the pkcs8 structure... look at softoken to see how this
michael@0 1786 * is done... */
michael@0 1787 error = ckmk_CreateRSAKeyBlob(&lk, &keyBlob);
michael@0 1788 if (CKR_OK != error) {
michael@0 1789 goto loser;
michael@0 1790 }
michael@0 1791
michael@0 1792 dataRef = CFDataCreate(NULL, (UInt8 *)keyBlob.data, keyBlob.size);
michael@0 1793 if (0 == dataRef) {
michael@0 1794 *pError = CKR_HOST_MEMORY;
michael@0 1795 goto loser;
michael@0 1796 }
michael@0 1797
michael@0 1798 *pError == ckmk_GetSafeDefaultKeychain(&targetKeychain);
michael@0 1799 if (CKR_OK != *pError) {
michael@0 1800 goto loser;
michael@0 1801 }
michael@0 1802
michael@0 1803
michael@0 1804 /* the itemArray that is returned is useless. the item does not
michael@0 1805 * is 'not on the key chain' so none of the modify calls work on it.
michael@0 1806 * It also has a key that isn't the same key as the one in the actual
michael@0 1807 * key chain. In short it isn't the item we want, and it gives us zero
michael@0 1808 * information about the item we want, so don't even bother with it...
michael@0 1809 */
michael@0 1810 macErr = SecKeychainItemImport(dataRef, NULL, &inputFormat, &itemType, 0,
michael@0 1811 &keyParams, targetKeychain, NULL);
michael@0 1812 if (noErr != macErr) {
michael@0 1813 CKMK_MACERR("Import Private Key", macErr);
michael@0 1814 *pError = CKR_GENERAL_ERROR;
michael@0 1815 goto loser;
michael@0 1816 }
michael@0 1817
michael@0 1818 *pError = ckmk_FindImportedKey(targetKeychain,
michael@0 1819 CSSM_DL_DB_RECORD_PRIVATE_KEY,
michael@0 1820 &itemRef);
michael@0 1821 if (CKR_OK != *pError) {
michael@0 1822 #ifdef DEBUG
michael@0 1823 fprintf(stderr,"couldn't find key in keychain \n");
michael@0 1824 #endif
michael@0 1825 goto loser;
michael@0 1826 }
michael@0 1827
michael@0 1828
michael@0 1829 /* set the CKA_ID and the CKA_LABEL */
michael@0 1830 error = nss_ckmk_GetAttribute(CKA_ID, pTemplate,
michael@0 1831 ulAttributeCount, &keyID);
michael@0 1832 if (CKR_OK == error) {
michael@0 1833 error = ckmk_updateAttribute(itemRef, kSecKeyLabel,
michael@0 1834 keyID.data, keyID.size, "Modify Key ID");
michael@0 1835 #ifdef DEBUG
michael@0 1836 itemdump("key id: ", keyID.data, keyID.size, error);
michael@0 1837 #endif
michael@0 1838 }
michael@0 1839 nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate,
michael@0 1840 ulAttributeCount, &error);
michael@0 1841 if (nickname) {
michael@0 1842 ckmk_updateAttribute(itemRef, kSecKeyPrintName, nickname,
michael@0 1843 strlen(nickname)+1, "Modify Key Label");
michael@0 1844 } else {
michael@0 1845 #define DEFAULT_NICKNAME "NSS Imported Key"
michael@0 1846 ckmk_updateAttribute(itemRef, kSecKeyPrintName, DEFAULT_NICKNAME,
michael@0 1847 sizeof(DEFAULT_NICKNAME), "Modify Key Label");
michael@0 1848 }
michael@0 1849
michael@0 1850 io = nss_ckmk_NewInternalObject(CKO_PRIVATE_KEY, itemRef,
michael@0 1851 CSSM_DL_DB_RECORD_PRIVATE_KEY, pError);
michael@0 1852 if ((ckmkInternalObject *)NULL == io) {
michael@0 1853 CFRelease(itemRef);
michael@0 1854 }
michael@0 1855
michael@0 1856 return io;
michael@0 1857
michael@0 1858 loser:
michael@0 1859 /* free the key blob */
michael@0 1860 if (keyBlob.data) {
michael@0 1861 nss_ZFreeIf(keyBlob.data);
michael@0 1862 }
michael@0 1863 if (0 != targetKeychain) {
michael@0 1864 CFRelease(targetKeychain);
michael@0 1865 }
michael@0 1866 if (0 != dataRef) {
michael@0 1867 CFRelease(dataRef);
michael@0 1868 }
michael@0 1869 return io;
michael@0 1870 }
michael@0 1871
michael@0 1872
michael@0 1873 NSS_EXTERN NSSCKMDObject *
michael@0 1874 nss_ckmk_CreateObject
michael@0 1875 (
michael@0 1876 NSSCKFWSession *fwSession,
michael@0 1877 CK_ATTRIBUTE_PTR pTemplate,
michael@0 1878 CK_ULONG ulAttributeCount,
michael@0 1879 CK_RV *pError
michael@0 1880 )
michael@0 1881 {
michael@0 1882 CK_OBJECT_CLASS objClass;
michael@0 1883 ckmkInternalObject *io;
michael@0 1884 CK_BBOOL isToken;
michael@0 1885
michael@0 1886 /*
michael@0 1887 * only create token objects
michael@0 1888 */
michael@0 1889 isToken = nss_ckmk_GetBoolAttribute(CKA_TOKEN, pTemplate,
michael@0 1890 ulAttributeCount, CK_FALSE);
michael@0 1891 if (!isToken) {
michael@0 1892 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 1893 return (NSSCKMDObject *) NULL;
michael@0 1894 }
michael@0 1895
michael@0 1896 /*
michael@0 1897 * only create keys and certs.
michael@0 1898 */
michael@0 1899 objClass = nss_ckmk_GetULongAttribute(CKA_CLASS, pTemplate,
michael@0 1900 ulAttributeCount, pError);
michael@0 1901 if (CKR_OK != *pError) {
michael@0 1902 return (NSSCKMDObject *) NULL;
michael@0 1903 }
michael@0 1904 #ifdef notdef
michael@0 1905 if (objClass == CKO_PUBLIC_KEY) {
michael@0 1906 return CKR_OK; /* fake public key creation, happens as a side effect of
michael@0 1907 * private key creation */
michael@0 1908 }
michael@0 1909 #endif
michael@0 1910 if (objClass == CKO_CERTIFICATE) {
michael@0 1911 io = nss_ckmk_CreateCertificate(fwSession, pTemplate,
michael@0 1912 ulAttributeCount, pError);
michael@0 1913 } else if (objClass == CKO_PRIVATE_KEY) {
michael@0 1914 io = nss_ckmk_CreatePrivateKey(fwSession, pTemplate,
michael@0 1915 ulAttributeCount, pError);
michael@0 1916 } else {
michael@0 1917 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
michael@0 1918 }
michael@0 1919
michael@0 1920 if ((ckmkInternalObject *)NULL == io) {
michael@0 1921 return (NSSCKMDObject *) NULL;
michael@0 1922 }
michael@0 1923 return nss_ckmk_CreateMDObject(NULL, io, pError);
michael@0 1924 }

mercurial