1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/ckfw/nssmkey/mobject.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1924 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "ckmk.h" 1.9 +#include "nssbase.h" 1.10 + 1.11 +#include "secdert.h" /* for DER_INTEGER */ 1.12 +#include "string.h" 1.13 + 1.14 +/* asn1 encoder (to build pkcs#8 blobs) */ 1.15 +#include <seccomon.h> 1.16 +#include <secitem.h> 1.17 +#include <blapit.h> 1.18 +#include <secoid.h> 1.19 +#include <secasn1.h> 1.20 + 1.21 +/* for importing the keys */ 1.22 +#include <CoreFoundation/CoreFoundation.h> 1.23 +#include <security/SecImportExport.h> 1.24 + 1.25 +/* 1.26 + * nssmkey/mobject.c 1.27 + * 1.28 + * This file implements the NSSCKMDObject object for the 1.29 + * "nssmkey" cryptoki module. 1.30 + */ 1.31 + 1.32 +const CK_ATTRIBUTE_TYPE certAttrs[] = { 1.33 + CKA_CLASS, 1.34 + CKA_TOKEN, 1.35 + CKA_PRIVATE, 1.36 + CKA_MODIFIABLE, 1.37 + CKA_LABEL, 1.38 + CKA_CERTIFICATE_TYPE, 1.39 + CKA_SUBJECT, 1.40 + CKA_ISSUER, 1.41 + CKA_SERIAL_NUMBER, 1.42 + CKA_VALUE 1.43 +}; 1.44 +const PRUint32 certAttrsCount = NSS_CKMK_ARRAY_SIZE(certAttrs); 1.45 + 1.46 +/* private keys, for now only support RSA */ 1.47 +const CK_ATTRIBUTE_TYPE privKeyAttrs[] = { 1.48 + CKA_CLASS, 1.49 + CKA_TOKEN, 1.50 + CKA_PRIVATE, 1.51 + CKA_MODIFIABLE, 1.52 + CKA_LABEL, 1.53 + CKA_KEY_TYPE, 1.54 + CKA_DERIVE, 1.55 + CKA_LOCAL, 1.56 + CKA_SUBJECT, 1.57 + CKA_SENSITIVE, 1.58 + CKA_DECRYPT, 1.59 + CKA_SIGN, 1.60 + CKA_SIGN_RECOVER, 1.61 + CKA_UNWRAP, 1.62 + CKA_EXTRACTABLE, 1.63 + CKA_ALWAYS_SENSITIVE, 1.64 + CKA_NEVER_EXTRACTABLE, 1.65 + CKA_MODULUS, 1.66 + CKA_PUBLIC_EXPONENT, 1.67 +}; 1.68 +const PRUint32 privKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(privKeyAttrs); 1.69 + 1.70 +/* public keys, for now only support RSA */ 1.71 +const CK_ATTRIBUTE_TYPE pubKeyAttrs[] = { 1.72 + CKA_CLASS, 1.73 + CKA_TOKEN, 1.74 + CKA_PRIVATE, 1.75 + CKA_MODIFIABLE, 1.76 + CKA_LABEL, 1.77 + CKA_KEY_TYPE, 1.78 + CKA_DERIVE, 1.79 + CKA_LOCAL, 1.80 + CKA_SUBJECT, 1.81 + CKA_ENCRYPT, 1.82 + CKA_VERIFY, 1.83 + CKA_VERIFY_RECOVER, 1.84 + CKA_WRAP, 1.85 + CKA_MODULUS, 1.86 + CKA_PUBLIC_EXPONENT, 1.87 +}; 1.88 +const PRUint32 pubKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(pubKeyAttrs); 1.89 +static const CK_BBOOL ck_true = CK_TRUE; 1.90 +static const CK_BBOOL ck_false = CK_FALSE; 1.91 +static const CK_CERTIFICATE_TYPE ckc_x509 = CKC_X_509; 1.92 +static const CK_KEY_TYPE ckk_rsa = CKK_RSA; 1.93 +static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE; 1.94 +static const CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY; 1.95 +static const CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY; 1.96 +static const NSSItem ckmk_trueItem = { 1.97 + (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL) }; 1.98 +static const NSSItem ckmk_falseItem = { 1.99 + (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) }; 1.100 +static const NSSItem ckmk_x509Item = { 1.101 + (void *)&ckc_x509, (PRUint32)sizeof(CK_CERTIFICATE_TYPE) }; 1.102 +static const NSSItem ckmk_rsaItem = { 1.103 + (void *)&ckk_rsa, (PRUint32)sizeof(CK_KEY_TYPE) }; 1.104 +static const NSSItem ckmk_certClassItem = { 1.105 + (void *)&cko_certificate, (PRUint32)sizeof(CK_OBJECT_CLASS) }; 1.106 +static const NSSItem ckmk_privKeyClassItem = { 1.107 + (void *)&cko_private_key, (PRUint32)sizeof(CK_OBJECT_CLASS) }; 1.108 +static const NSSItem ckmk_pubKeyClassItem = { 1.109 + (void *)&cko_public_key, (PRUint32)sizeof(CK_OBJECT_CLASS) }; 1.110 +static const NSSItem ckmk_emptyItem = { 1.111 + (void *)&ck_true, 0}; 1.112 + 1.113 +/* 1.114 + * these are utilities. The chould be moved to a new utilities file. 1.115 + */ 1.116 +#ifdef DEBUG 1.117 +static void 1.118 +itemdump(char *str, void *data, int size, CK_RV error) 1.119 +{ 1.120 + unsigned char *ptr = (unsigned char *)data; 1.121 + int i; 1.122 + fprintf(stderr,str); 1.123 + for (i=0; i < size; i++) { 1.124 + fprintf(stderr,"%02x ",(unsigned int) ptr[i]); 1.125 + } 1.126 + fprintf(stderr," (error = %d)\n", (int ) error); 1.127 +} 1.128 +#endif 1.129 + 1.130 +/* 1.131 + * unwrap a single DER value 1.132 + * now that we have util linked in, we should probably use 1.133 + * the ANS1_Decoder for this work... 1.134 + */ 1.135 +unsigned char * 1.136 +nss_ckmk_DERUnwrap 1.137 +( 1.138 + unsigned char *src, 1.139 + int size, 1.140 + int *outSize, 1.141 + unsigned char **next 1.142 +) 1.143 +{ 1.144 + unsigned char *start = src; 1.145 + unsigned int len = 0; 1.146 + 1.147 + /* initialize error condition return values */ 1.148 + *outSize = 0; 1.149 + if (next) { 1.150 + *next = src; 1.151 + } 1.152 + 1.153 + if (size < 2) { 1.154 + return start; 1.155 + } 1.156 + src ++ ; /* skip the tag -- should check it against an expected value! */ 1.157 + len = (unsigned) *src++; 1.158 + if (len & 0x80) { 1.159 + int count = len & 0x7f; 1.160 + len =0; 1.161 + 1.162 + if (count+2 > size) { 1.163 + return start; 1.164 + } 1.165 + while (count-- > 0) { 1.166 + len = (len << 8) | (unsigned) *src++; 1.167 + } 1.168 + } 1.169 + if (len + (src-start) > (unsigned int)size) { 1.170 + return start; 1.171 + } 1.172 + if (next) { 1.173 + *next = src+len; 1.174 + } 1.175 + *outSize = len; 1.176 + 1.177 + return src; 1.178 +} 1.179 + 1.180 +/* 1.181 + * get an attribute from a template. Value is returned in NSS item. 1.182 + * data for the item is owned by the template. 1.183 + */ 1.184 +CK_RV 1.185 +nss_ckmk_GetAttribute 1.186 +( 1.187 + CK_ATTRIBUTE_TYPE type, 1.188 + CK_ATTRIBUTE *template, 1.189 + CK_ULONG templateSize, 1.190 + NSSItem *item 1.191 +) 1.192 +{ 1.193 + CK_ULONG i; 1.194 + 1.195 + for (i=0; i < templateSize; i++) { 1.196 + if (template[i].type == type) { 1.197 + item->data = template[i].pValue; 1.198 + item->size = template[i].ulValueLen; 1.199 + return CKR_OK; 1.200 + } 1.201 + } 1.202 + return CKR_TEMPLATE_INCOMPLETE; 1.203 +} 1.204 + 1.205 +/* 1.206 + * get an attribute which is type CK_ULONG. 1.207 + */ 1.208 +CK_ULONG 1.209 +nss_ckmk_GetULongAttribute 1.210 +( 1.211 + CK_ATTRIBUTE_TYPE type, 1.212 + CK_ATTRIBUTE *template, 1.213 + CK_ULONG templateSize, 1.214 + CK_RV *pError 1.215 +) 1.216 +{ 1.217 + NSSItem item; 1.218 + 1.219 + *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item); 1.220 + if (CKR_OK != *pError) { 1.221 + return (CK_ULONG) 0; 1.222 + } 1.223 + if (item.size != sizeof(CK_ULONG)) { 1.224 + *pError = CKR_ATTRIBUTE_VALUE_INVALID; 1.225 + return (CK_ULONG) 0; 1.226 + } 1.227 + return *(CK_ULONG *)item.data; 1.228 +} 1.229 + 1.230 +/* 1.231 + * get an attribute which is type CK_BBOOL. 1.232 + */ 1.233 +CK_BBOOL 1.234 +nss_ckmk_GetBoolAttribute 1.235 +( 1.236 + CK_ATTRIBUTE_TYPE type, 1.237 + CK_ATTRIBUTE *template, 1.238 + CK_ULONG templateSize, 1.239 + CK_BBOOL defaultBool 1.240 +) 1.241 +{ 1.242 + NSSItem item; 1.243 + CK_RV error; 1.244 + 1.245 + error = nss_ckmk_GetAttribute(type, template, templateSize, &item); 1.246 + if (CKR_OK != error) { 1.247 + return defaultBool; 1.248 + } 1.249 + if (item.size != sizeof(CK_BBOOL)) { 1.250 + return defaultBool; 1.251 + } 1.252 + return *(CK_BBOOL *)item.data; 1.253 +} 1.254 + 1.255 +/* 1.256 + * get an attribute as a NULL terminated string. Caller is responsible to 1.257 + * free the string. 1.258 + */ 1.259 +char * 1.260 +nss_ckmk_GetStringAttribute 1.261 +( 1.262 + CK_ATTRIBUTE_TYPE type, 1.263 + CK_ATTRIBUTE *template, 1.264 + CK_ULONG templateSize, 1.265 + CK_RV *pError 1.266 +) 1.267 +{ 1.268 + NSSItem item; 1.269 + char *str; 1.270 + 1.271 + /* get the attribute */ 1.272 + *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item); 1.273 + if (CKR_OK != *pError) { 1.274 + return (char *)NULL; 1.275 + } 1.276 + /* make sure it is null terminated */ 1.277 + str = nss_ZNEWARRAY(NULL, char, item.size+1); 1.278 + if ((char *)NULL == str) { 1.279 + *pError = CKR_HOST_MEMORY; 1.280 + return (char *)NULL; 1.281 + } 1.282 + 1.283 + nsslibc_memcpy(str, item.data, item.size); 1.284 + str[item.size] = 0; 1.285 + 1.286 + return str; 1.287 +} 1.288 + 1.289 +/* 1.290 + * Apple doesn't seem to have a public interface to the DER encoder, 1.291 + * wip out a quick one for integers only (anything more complicated, 1.292 + * we should use one of the 3 in lib/util). -- especially since we 1.293 + * now link with it. 1.294 + */ 1.295 +static CK_RV 1.296 +ckmk_encodeInt(NSSItem *dest, void *src, int srcLen) 1.297 +{ 1.298 + int dataLen = srcLen; 1.299 + int lenLen = 1; 1.300 + int encLen; 1.301 + int isSigned = 0; 1.302 + int offset = 0; 1.303 + unsigned char *data = NULL; 1.304 + int i; 1.305 + 1.306 + if (*(unsigned char *)src & 0x80) { 1.307 + dataLen++; 1.308 + isSigned = 1; 1.309 + } 1.310 + 1.311 + /* calculate the length of the length specifier */ 1.312 + /* (NOTE: destroys dataLen value) */ 1.313 + if (dataLen > 0x7f) { 1.314 + do { 1.315 + lenLen++; 1.316 + dataLen >>= 8; 1.317 + } while (dataLen); 1.318 + } 1.319 + 1.320 + /* calculate our total length */ 1.321 + dataLen = isSigned + srcLen; 1.322 + encLen = 1 + lenLen + dataLen; 1.323 + data = nss_ZNEWARRAY(NULL, unsigned char, encLen); 1.324 + if ((unsigned char *)NULL == data) { 1.325 + return CKR_HOST_MEMORY; 1.326 + } 1.327 + data[0] = DER_INTEGER; 1.328 + if (1 == lenLen) { 1.329 + data[1] = dataLen; 1.330 + } else { 1.331 + data[1] = 0x80 + lenLen; 1.332 + for (i=0; i < lenLen; i++) { 1.333 + data[i+1] = ((dataLen >> ((lenLen-i-1)*8)) & 0xff); 1.334 + } 1.335 + } 1.336 + offset = lenLen+1; 1.337 + 1.338 + if (isSigned) { 1.339 + data[offset++] = 0; 1.340 + } 1.341 + nsslibc_memcpy(&data[offset], src, srcLen); 1.342 + dest->data = data; 1.343 + dest->size = encLen; 1.344 + return CKR_OK; 1.345 +} 1.346 + 1.347 + 1.348 +/* 1.349 + * Get a Keyring attribute. If content is set to true, then we get the 1.350 + * content, not the attribute. 1.351 + */ 1.352 +static CK_RV 1.353 +ckmk_GetCommonAttribute 1.354 +( 1.355 + ckmkInternalObject *io, 1.356 + SecItemAttr itemAttr, 1.357 + PRBool content, 1.358 + NSSItem *item, 1.359 + char *dbString 1.360 +) 1.361 +{ 1.362 + SecKeychainAttributeList *attrList = NULL; 1.363 + SecKeychainAttributeInfo attrInfo; 1.364 + PRUint32 len = 0; 1.365 + PRUint32 dataLen = 0; 1.366 + PRUint32 attrFormat = 0; 1.367 + void *dataVal = 0; 1.368 + void *out = NULL; 1.369 + CK_RV error = CKR_OK; 1.370 + OSStatus macErr; 1.371 + 1.372 + attrInfo.count = 1; 1.373 + attrInfo.tag = &itemAttr; 1.374 + attrInfo.format = &attrFormat; 1.375 + 1.376 + macErr = SecKeychainItemCopyAttributesAndData(io->u.item.itemRef, 1.377 + &attrInfo, NULL, &attrList, &len, &out); 1.378 + if (noErr != macErr) { 1.379 + CKMK_MACERR(dbString, macErr); 1.380 + return CKR_ATTRIBUTE_TYPE_INVALID; 1.381 + } 1.382 + dataLen = content ? len : attrList->attr->length; 1.383 + dataVal = content ? out : attrList->attr->data; 1.384 + 1.385 + /* Apple's documentation says this value is DER Encoded, but it clearly isn't 1.386 + * der encode it before we ship it back off to NSS 1.387 + */ 1.388 + if ( kSecSerialNumberItemAttr == itemAttr ) { 1.389 + error = ckmk_encodeInt(item, dataVal, dataLen); 1.390 + goto loser; /* logically 'done' if error == CKR_OK */ 1.391 + } 1.392 + item->data = nss_ZNEWARRAY(NULL, char, dataLen); 1.393 + if (NULL == item->data) { 1.394 + error = CKR_HOST_MEMORY; 1.395 + goto loser; 1.396 + } 1.397 + nsslibc_memcpy(item->data, dataVal, dataLen); 1.398 + item->size = dataLen; 1.399 + 1.400 +loser: 1.401 + SecKeychainItemFreeAttributesAndData(attrList, out); 1.402 + return error; 1.403 +} 1.404 + 1.405 +/* 1.406 + * change an attribute (does not operate on the content). 1.407 + */ 1.408 +static CK_RV 1.409 +ckmk_updateAttribute 1.410 +( 1.411 + SecKeychainItemRef itemRef, 1.412 + SecItemAttr itemAttr, 1.413 + void *data, 1.414 + PRUint32 len, 1.415 + char *dbString 1.416 +) 1.417 +{ 1.418 + SecKeychainAttributeList attrList; 1.419 + SecKeychainAttribute attrAttr; 1.420 + OSStatus macErr; 1.421 + CK_RV error = CKR_OK; 1.422 + 1.423 + attrList.count = 1; 1.424 + attrList.attr = &attrAttr; 1.425 + attrAttr.tag = itemAttr; 1.426 + attrAttr.data = data; 1.427 + attrAttr.length = len; 1.428 + macErr = SecKeychainItemModifyAttributesAndData(itemRef, &attrList, 0, NULL); 1.429 + if (noErr != macErr) { 1.430 + CKMK_MACERR(dbString, macErr); 1.431 + error = CKR_ATTRIBUTE_TYPE_INVALID; 1.432 + } 1.433 + return error; 1.434 +} 1.435 + 1.436 +/* 1.437 + * get an attribute (does not operate on the content) 1.438 + */ 1.439 +static CK_RV 1.440 +ckmk_GetDataAttribute 1.441 +( 1.442 + ckmkInternalObject *io, 1.443 + SecItemAttr itemAttr, 1.444 + NSSItem *item, 1.445 + char *dbString 1.446 +) 1.447 +{ 1.448 + return ckmk_GetCommonAttribute(io, itemAttr, PR_FALSE, item, dbString); 1.449 +} 1.450 + 1.451 +/* 1.452 + * get an attribute we know is a BOOL. 1.453 + */ 1.454 +static CK_RV 1.455 +ckmk_GetBoolAttribute 1.456 +( 1.457 + ckmkInternalObject *io, 1.458 + SecItemAttr itemAttr, 1.459 + NSSItem *item, 1.460 + char *dbString 1.461 +) 1.462 +{ 1.463 + SecKeychainAttribute attr; 1.464 + SecKeychainAttributeList attrList; 1.465 + CK_BBOOL *boolp = NULL; 1.466 + PRUint32 len = 0;; 1.467 + void *out = NULL; 1.468 + CK_RV error = CKR_OK; 1.469 + OSStatus macErr; 1.470 + 1.471 + attr.tag = itemAttr; 1.472 + attr.length = 0; 1.473 + attr.data = NULL; 1.474 + attrList.count = 1; 1.475 + attrList.attr = &attr; 1.476 + 1.477 + boolp = nss_ZNEW(NULL, CK_BBOOL); 1.478 + if ((CK_BBOOL *)NULL == boolp) { 1.479 + error = CKR_HOST_MEMORY; 1.480 + goto loser; 1.481 + } 1.482 + 1.483 + macErr = SecKeychainItemCopyContent(io->u.item.itemRef, NULL, 1.484 + &attrList, &len, &out); 1.485 + if (noErr != macErr) { 1.486 + CKMK_MACERR(dbString, macErr); 1.487 + error = CKR_ATTRIBUTE_TYPE_INVALID; 1.488 + goto loser; 1.489 + } 1.490 + if (sizeof(PRUint32) != attr.length) { 1.491 + error = CKR_ATTRIBUTE_TYPE_INVALID; 1.492 + goto loser; 1.493 + } 1.494 + *boolp = *(PRUint32 *)attr.data ? 1 : 0; 1.495 + item->data = boolp; 1.496 + boolp = NULL; 1.497 + item->size = sizeof(CK_BBOOL); 1.498 + 1.499 +loser: 1.500 + nss_ZFreeIf(boolp); 1.501 + SecKeychainItemFreeContent(&attrList, out); 1.502 + return error; 1.503 +} 1.504 + 1.505 + 1.506 +/* 1.507 + * macros for fetching attributes into a cache and returning the 1.508 + * appropriate value. These operate inside switch statements 1.509 + */ 1.510 +#define CKMK_HANDLE_ITEM(func, io, type, loc, item, error, str) \ 1.511 + if (0 == (item)->loc.size) { \ 1.512 + error = func(io, type, &(item)->loc, str); \ 1.513 + } \ 1.514 + return (CKR_OK == (error)) ? &(item)->loc : NULL; 1.515 + 1.516 +#define CKMK_HANDLE_OPT_ITEM(func, io, type, loc, item, error, str) \ 1.517 + if (0 == (item)->loc.size) { \ 1.518 + (void) func(io, type, &(item)->loc, str); \ 1.519 + } \ 1.520 + return &(item)->loc ; 1.521 + 1.522 +#define CKMK_HANDLE_BOOL_ITEM(io, type, loc, item, error, str) \ 1.523 + CKMK_HANDLE_ITEM(ckmk_GetBoolAttribute, io, type, loc, item, error, str) 1.524 +#define CKMK_HANDLE_DATA_ITEM(io, type, loc, item, error, str) \ 1.525 + CKMK_HANDLE_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str) 1.526 +#define CKMK_HANDLE_OPT_DATA_ITEM(io, type, loc, item, error, str) \ 1.527 + CKMK_HANDLE_OPT_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str) 1.528 + 1.529 +/* 1.530 + * fetch the unique identifier for each object type. 1.531 + */ 1.532 +static void 1.533 +ckmk_FetchHashKey 1.534 +( 1.535 + ckmkInternalObject *io 1.536 +) 1.537 +{ 1.538 + NSSItem *key = &io->hashKey; 1.539 + 1.540 + if (io->objClass == CKO_CERTIFICATE) { 1.541 + ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr, 1.542 + PR_TRUE, key, "Fetching HashKey (cert)"); 1.543 + } else { 1.544 + ckmk_GetCommonAttribute(io, kSecKeyLabel, 1.545 + PR_FALSE, key, "Fetching HashKey (key)"); 1.546 + } 1.547 +} 1.548 + 1.549 +/* 1.550 + * Apple mucks with the actual subject and issuer, so go fetch 1.551 + * the real ones ourselves. 1.552 + */ 1.553 +static void 1.554 +ckmk_fetchCert 1.555 +( 1.556 + ckmkInternalObject *io 1.557 +) 1.558 +{ 1.559 + CK_RV error; 1.560 + unsigned char * cert, *next; 1.561 + int certSize, thisEntrySize; 1.562 + 1.563 + error = ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr, PR_TRUE, 1.564 + &io->u.item.derCert, "Fetching Value (cert)"); 1.565 + if (CKR_OK != error) { 1.566 + return; 1.567 + } 1.568 + /* unwrap the cert bundle */ 1.569 + cert = nss_ckmk_DERUnwrap((unsigned char *)io->u.item.derCert.data, 1.570 + io->u.item.derCert.size, 1.571 + &certSize, NULL); 1.572 + /* unwrap the cert itself */ 1.573 + /* cert == certdata */ 1.574 + cert = nss_ckmk_DERUnwrap(cert, certSize, &certSize, NULL); 1.575 + 1.576 + /* skip the optional version */ 1.577 + if ((cert[0] & 0xa0) == 0xa0) { 1.578 + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); 1.579 + certSize -= next - cert; 1.580 + cert = next; 1.581 + } 1.582 + /* skip the serial number */ 1.583 + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); 1.584 + certSize -= next - cert; 1.585 + cert = next; 1.586 + 1.587 + /* skip the OID */ 1.588 + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); 1.589 + certSize -= next - cert; 1.590 + cert = next; 1.591 + 1.592 + /* save the (wrapped) issuer */ 1.593 + io->u.item.issuer.data = cert; 1.594 + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); 1.595 + io->u.item.issuer.size = next - cert; 1.596 + certSize -= io->u.item.issuer.size; 1.597 + cert = next; 1.598 + 1.599 + /* skip the OID */ 1.600 + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); 1.601 + certSize -= next - cert; 1.602 + cert = next; 1.603 + 1.604 + /* save the (wrapped) subject */ 1.605 + io->u.item.subject.data = cert; 1.606 + nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); 1.607 + io->u.item.subject.size = next - cert; 1.608 + certSize -= io->u.item.subject.size; 1.609 + cert = next; 1.610 +} 1.611 + 1.612 +static void 1.613 +ckmk_fetchModulus 1.614 +( 1.615 + ckmkInternalObject *io 1.616 +) 1.617 +{ 1.618 + NSSItem item; 1.619 + PRInt32 modLen; 1.620 + CK_RV error; 1.621 + 1.622 + /* we can't reliably get the modulus for private keys through CSSM (sigh). 1.623 + * For NSS this is OK because we really only use this to get the modulus 1.624 + * length (unless we are trying to get a public key from a private keys, 1.625 + * something CSSM ALSO does not do!). 1.626 + */ 1.627 + error = ckmk_GetDataAttribute(io, kSecKeyKeySizeInBits, &item, 1.628 + "Key Fetch Modulus"); 1.629 + if (CKR_OK != error) { 1.630 + return; 1.631 + } 1.632 + 1.633 + modLen = *(PRInt32 *)item.data; 1.634 + modLen = modLen/8; /* convert from bits to bytes */ 1.635 + 1.636 + nss_ZFreeIf(item.data); 1.637 + io->u.item.modulus.data = nss_ZNEWARRAY(NULL, char, modLen); 1.638 + if (NULL == io->u.item.modulus.data) { 1.639 + return; 1.640 + } 1.641 + *(char *)io->u.item.modulus.data = 0x80; /* fake NSS out or it will 1.642 + * drop the first byte */ 1.643 + io->u.item.modulus.size = modLen; 1.644 + return; 1.645 +} 1.646 + 1.647 +const NSSItem * 1.648 +ckmk_FetchCertAttribute 1.649 +( 1.650 + ckmkInternalObject *io, 1.651 + CK_ATTRIBUTE_TYPE type, 1.652 + CK_RV *pError 1.653 +) 1.654 +{ 1.655 + ckmkItemObject *item = &io->u.item; 1.656 + *pError = CKR_OK; 1.657 + switch(type) { 1.658 + case CKA_CLASS: 1.659 + return &ckmk_certClassItem; 1.660 + case CKA_TOKEN: 1.661 + case CKA_MODIFIABLE: 1.662 + return &ckmk_trueItem; 1.663 + case CKA_PRIVATE: 1.664 + return &ckmk_falseItem; 1.665 + case CKA_CERTIFICATE_TYPE: 1.666 + return &ckmk_x509Item; 1.667 + case CKA_LABEL: 1.668 + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecLabelItemAttr, label, item, *pError, 1.669 + "Cert:Label attr") 1.670 + case CKA_SUBJECT: 1.671 + /* OK, well apple does provide an subject and issuer attribute, but they 1.672 + * decided to cannonicalize that value. Probably a good move for them, 1.673 + * but makes it useless for most users of PKCS #11.. Get the real subject 1.674 + * from the certificate */ 1.675 + if (0 == item->derCert.size) { 1.676 + ckmk_fetchCert(io); 1.677 + } 1.678 + return &item->subject; 1.679 + case CKA_ISSUER: 1.680 + if (0 == item->derCert.size) { 1.681 + ckmk_fetchCert(io); 1.682 + } 1.683 + return &item->issuer; 1.684 + case CKA_SERIAL_NUMBER: 1.685 + CKMK_HANDLE_DATA_ITEM(io, kSecSerialNumberItemAttr, serial, item, *pError, 1.686 + "Cert:Serial Number attr") 1.687 + case CKA_VALUE: 1.688 + if (0 == item->derCert.size) { 1.689 + ckmk_fetchCert(io); 1.690 + } 1.691 + return &item->derCert; 1.692 + case CKA_ID: 1.693 + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecPublicKeyHashItemAttr, id, item, *pError, 1.694 + "Cert:ID attr") 1.695 + default: 1.696 + *pError = CKR_ATTRIBUTE_TYPE_INVALID; 1.697 + break; 1.698 + } 1.699 + return NULL; 1.700 +} 1.701 + 1.702 +const NSSItem * 1.703 +ckmk_FetchPubKeyAttribute 1.704 +( 1.705 + ckmkInternalObject *io, 1.706 + CK_ATTRIBUTE_TYPE type, 1.707 + CK_RV *pError 1.708 +) 1.709 +{ 1.710 + ckmkItemObject *item = &io->u.item; 1.711 + *pError = CKR_OK; 1.712 + 1.713 + switch(type) { 1.714 + case CKA_CLASS: 1.715 + return &ckmk_pubKeyClassItem; 1.716 + case CKA_TOKEN: 1.717 + case CKA_LOCAL: 1.718 + return &ckmk_trueItem; 1.719 + case CKA_KEY_TYPE: 1.720 + return &ckmk_rsaItem; 1.721 + case CKA_LABEL: 1.722 + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError, 1.723 + "PubKey:Label attr") 1.724 + case CKA_ENCRYPT: 1.725 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyEncrypt, encrypt, item, *pError, 1.726 + "PubKey:Encrypt attr") 1.727 + case CKA_VERIFY: 1.728 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerify, verify, item, *pError, 1.729 + "PubKey:Verify attr") 1.730 + case CKA_VERIFY_RECOVER: 1.731 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerifyRecover, verifyRecover, 1.732 + item, *pError, "PubKey:VerifyRecover attr") 1.733 + case CKA_PRIVATE: 1.734 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError, 1.735 + "PubKey:Private attr") 1.736 + case CKA_MODIFIABLE: 1.737 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError, 1.738 + "PubKey:Modify attr") 1.739 + case CKA_DERIVE: 1.740 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError, 1.741 + "PubKey:Derive attr") 1.742 + case CKA_WRAP: 1.743 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyWrap, wrap, item, *pError, 1.744 + "PubKey:Wrap attr") 1.745 + case CKA_SUBJECT: 1.746 + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError, 1.747 + "PubKey:Subect attr") 1.748 + case CKA_MODULUS: 1.749 + return &ckmk_emptyItem; 1.750 + case CKA_PUBLIC_EXPONENT: 1.751 + return &ckmk_emptyItem; 1.752 + case CKA_ID: 1.753 + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError, 1.754 + "PubKey:ID attr") 1.755 + default: 1.756 + *pError = CKR_ATTRIBUTE_TYPE_INVALID; 1.757 + break; 1.758 + } 1.759 + return NULL; 1.760 +} 1.761 + 1.762 +const NSSItem * 1.763 +ckmk_FetchPrivKeyAttribute 1.764 +( 1.765 + ckmkInternalObject *io, 1.766 + CK_ATTRIBUTE_TYPE type, 1.767 + CK_RV *pError 1.768 +) 1.769 +{ 1.770 + ckmkItemObject *item = &io->u.item; 1.771 + *pError = CKR_OK; 1.772 + 1.773 + switch(type) { 1.774 + case CKA_CLASS: 1.775 + return &ckmk_privKeyClassItem; 1.776 + case CKA_TOKEN: 1.777 + case CKA_LOCAL: 1.778 + return &ckmk_trueItem; 1.779 + case CKA_SENSITIVE: 1.780 + case CKA_EXTRACTABLE: /* will probably move in the future */ 1.781 + case CKA_ALWAYS_SENSITIVE: 1.782 + case CKA_NEVER_EXTRACTABLE: 1.783 + return &ckmk_falseItem; 1.784 + case CKA_KEY_TYPE: 1.785 + return &ckmk_rsaItem; 1.786 + case CKA_LABEL: 1.787 + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError, 1.788 + "PrivateKey:Label attr") 1.789 + case CKA_DECRYPT: 1.790 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDecrypt, decrypt, item, *pError, 1.791 + "PrivateKey:Decrypt attr") 1.792 + case CKA_SIGN: 1.793 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeySign, sign, item, *pError, 1.794 + "PrivateKey:Sign attr") 1.795 + case CKA_SIGN_RECOVER: 1.796 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeySignRecover, signRecover, item, *pError, 1.797 + "PrivateKey:Sign Recover attr") 1.798 + case CKA_PRIVATE: 1.799 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError, 1.800 + "PrivateKey:Private attr") 1.801 + case CKA_MODIFIABLE: 1.802 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError, 1.803 + "PrivateKey:Modify attr") 1.804 + case CKA_DERIVE: 1.805 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError, 1.806 + "PrivateKey:Derive attr") 1.807 + case CKA_UNWRAP: 1.808 + CKMK_HANDLE_BOOL_ITEM(io, kSecKeyUnwrap, unwrap, item, *pError, 1.809 + "PrivateKey:Unwrap attr") 1.810 + case CKA_SUBJECT: 1.811 + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError, 1.812 + "PrivateKey:Subject attr") 1.813 + case CKA_MODULUS: 1.814 + if (0 == item->modulus.size) { 1.815 + ckmk_fetchModulus(io); 1.816 + } 1.817 + return &item->modulus; 1.818 + case CKA_PUBLIC_EXPONENT: 1.819 + return &ckmk_emptyItem; 1.820 +#ifdef notdef 1.821 + /* the following are sensitive attributes. We could implement them for 1.822 + * sensitive keys using the key export function, but it's better to 1.823 + * just support wrap through this token. That will more reliably allow us 1.824 + * to export any private key that is truly exportable. 1.825 + */ 1.826 + case CKA_PRIVATE_EXPONENT: 1.827 + CKMK_HANDLE_DATA_ITEM(io, kSecPrivateExponentItemAttr, privateExponent, 1.828 + item, *pError) 1.829 + case CKA_PRIME_1: 1.830 + CKMK_HANDLE_DATA_ITEM(io, kSecPrime1ItemAttr, prime1, item, *pError) 1.831 + case CKA_PRIME_2: 1.832 + CKMK_HANDLE_DATA_ITEM(io, kSecPrime2ItemAttr, prime2, item, *pError) 1.833 + case CKA_EXPONENT_1: 1.834 + CKMK_HANDLE_DATA_ITEM(io, kSecExponent1ItemAttr, exponent1, item, *pError) 1.835 + case CKA_EXPONENT_2: 1.836 + CKMK_HANDLE_DATA_ITEM(io, kSecExponent2ItemAttr, exponent2, item, *pError) 1.837 + case CKA_COEFFICIENT: 1.838 + CKMK_HANDLE_DATA_ITEM(io, kSecCoefficientItemAttr, coefficient, 1.839 + item, *pError) 1.840 +#endif 1.841 + case CKA_ID: 1.842 + CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError, 1.843 + "PrivateKey:ID attr") 1.844 + default: 1.845 + *pError = CKR_ATTRIBUTE_TYPE_INVALID; 1.846 + return NULL; 1.847 + } 1.848 +} 1.849 + 1.850 +const NSSItem * 1.851 +nss_ckmk_FetchAttribute 1.852 +( 1.853 + ckmkInternalObject *io, 1.854 + CK_ATTRIBUTE_TYPE type, 1.855 + CK_RV *pError 1.856 +) 1.857 +{ 1.858 + CK_ULONG i; 1.859 + const NSSItem * value = NULL; 1.860 + 1.861 + if (io->type == ckmkRaw) { 1.862 + for( i = 0; i < io->u.raw.n; i++ ) { 1.863 + if( type == io->u.raw.types[i] ) { 1.864 + return &io->u.raw.items[i]; 1.865 + } 1.866 + } 1.867 + *pError = CKR_ATTRIBUTE_TYPE_INVALID; 1.868 + return NULL; 1.869 + } 1.870 + /* deal with the common attributes */ 1.871 + switch (io->objClass) { 1.872 + case CKO_CERTIFICATE: 1.873 + value = ckmk_FetchCertAttribute(io, type, pError); 1.874 + break; 1.875 + case CKO_PRIVATE_KEY: 1.876 + value = ckmk_FetchPrivKeyAttribute(io, type, pError); 1.877 + break; 1.878 + case CKO_PUBLIC_KEY: 1.879 + value = ckmk_FetchPubKeyAttribute(io, type, pError); 1.880 + break; 1.881 + default: 1.882 + *pError = CKR_OBJECT_HANDLE_INVALID; 1.883 + return NULL; 1.884 + } 1.885 + 1.886 +#ifdef DEBUG 1.887 + if (CKA_ID == type) { 1.888 + itemdump("id: ", value->data, value->size, *pError); 1.889 + } 1.890 +#endif 1.891 + return value; 1.892 +} 1.893 + 1.894 +static void 1.895 +ckmk_removeObjectFromHash 1.896 +( 1.897 + ckmkInternalObject *io 1.898 +); 1.899 + 1.900 +/* 1.901 + * 1.902 + * These are the MSObject functions we need to implement 1.903 + * 1.904 + * Finalize - unneeded (actually we should clean up the hashtables) 1.905 + * Destroy 1.906 + * IsTokenObject - CK_TRUE 1.907 + * GetAttributeCount 1.908 + * GetAttributeTypes 1.909 + * GetAttributeSize 1.910 + * GetAttribute 1.911 + * SetAttribute 1.912 + * GetObjectSize 1.913 + */ 1.914 + 1.915 +static CK_RV 1.916 +ckmk_mdObject_Destroy 1.917 +( 1.918 + NSSCKMDObject *mdObject, 1.919 + NSSCKFWObject *fwObject, 1.920 + NSSCKMDSession *mdSession, 1.921 + NSSCKFWSession *fwSession, 1.922 + NSSCKMDToken *mdToken, 1.923 + NSSCKFWToken *fwToken, 1.924 + NSSCKMDInstance *mdInstance, 1.925 + NSSCKFWInstance *fwInstance 1.926 +) 1.927 +{ 1.928 + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; 1.929 + OSStatus macErr; 1.930 + 1.931 + if (ckmkRaw == io->type) { 1.932 + /* there is not 'object write protected' error, use the next best thing */ 1.933 + return CKR_TOKEN_WRITE_PROTECTED; 1.934 + } 1.935 + 1.936 + /* This API is done well. The following 4 lines are the complete apple 1.937 + * specific part of this implementation */ 1.938 + macErr = SecKeychainItemDelete(io->u.item.itemRef); 1.939 + if (noErr != macErr) { 1.940 + CKMK_MACERR("Delete object", macErr); 1.941 + } 1.942 + 1.943 + /* remove it from the hash */ 1.944 + ckmk_removeObjectFromHash(io); 1.945 + 1.946 + /* free the puppy.. */ 1.947 + nss_ckmk_DestroyInternalObject(io); 1.948 + 1.949 + return CKR_OK; 1.950 +} 1.951 + 1.952 +static CK_BBOOL 1.953 +ckmk_mdObject_IsTokenObject 1.954 +( 1.955 + NSSCKMDObject *mdObject, 1.956 + NSSCKFWObject *fwObject, 1.957 + NSSCKMDSession *mdSession, 1.958 + NSSCKFWSession *fwSession, 1.959 + NSSCKMDToken *mdToken, 1.960 + NSSCKFWToken *fwToken, 1.961 + NSSCKMDInstance *mdInstance, 1.962 + NSSCKFWInstance *fwInstance 1.963 +) 1.964 +{ 1.965 + return CK_TRUE; 1.966 +} 1.967 + 1.968 +static CK_ULONG 1.969 +ckmk_mdObject_GetAttributeCount 1.970 +( 1.971 + NSSCKMDObject *mdObject, 1.972 + NSSCKFWObject *fwObject, 1.973 + NSSCKMDSession *mdSession, 1.974 + NSSCKFWSession *fwSession, 1.975 + NSSCKMDToken *mdToken, 1.976 + NSSCKFWToken *fwToken, 1.977 + NSSCKMDInstance *mdInstance, 1.978 + NSSCKFWInstance *fwInstance, 1.979 + CK_RV *pError 1.980 +) 1.981 +{ 1.982 + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; 1.983 + 1.984 + if (ckmkRaw == io->type) { 1.985 + return io->u.raw.n; 1.986 + } 1.987 + switch (io->objClass) { 1.988 + case CKO_CERTIFICATE: 1.989 + return certAttrsCount; 1.990 + case CKO_PUBLIC_KEY: 1.991 + return pubKeyAttrsCount; 1.992 + case CKO_PRIVATE_KEY: 1.993 + return privKeyAttrsCount; 1.994 + default: 1.995 + break; 1.996 + } 1.997 + return 0; 1.998 +} 1.999 + 1.1000 +static CK_RV 1.1001 +ckmk_mdObject_GetAttributeTypes 1.1002 +( 1.1003 + NSSCKMDObject *mdObject, 1.1004 + NSSCKFWObject *fwObject, 1.1005 + NSSCKMDSession *mdSession, 1.1006 + NSSCKFWSession *fwSession, 1.1007 + NSSCKMDToken *mdToken, 1.1008 + NSSCKFWToken *fwToken, 1.1009 + NSSCKMDInstance *mdInstance, 1.1010 + NSSCKFWInstance *fwInstance, 1.1011 + CK_ATTRIBUTE_TYPE_PTR typeArray, 1.1012 + CK_ULONG ulCount 1.1013 +) 1.1014 +{ 1.1015 + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; 1.1016 + CK_ULONG i; 1.1017 + CK_RV error = CKR_OK; 1.1018 + const CK_ATTRIBUTE_TYPE *attrs = NULL; 1.1019 + CK_ULONG size = ckmk_mdObject_GetAttributeCount( 1.1020 + mdObject, fwObject, mdSession, fwSession, 1.1021 + mdToken, fwToken, mdInstance, fwInstance, &error); 1.1022 + 1.1023 + if( size != ulCount ) { 1.1024 + return CKR_BUFFER_TOO_SMALL; 1.1025 + } 1.1026 + if (io->type == ckmkRaw) { 1.1027 + attrs = io->u.raw.types; 1.1028 + } else switch(io->objClass) { 1.1029 + case CKO_CERTIFICATE: 1.1030 + attrs = certAttrs; 1.1031 + break; 1.1032 + case CKO_PUBLIC_KEY: 1.1033 + attrs = pubKeyAttrs; 1.1034 + break; 1.1035 + case CKO_PRIVATE_KEY: 1.1036 + attrs = privKeyAttrs; 1.1037 + break; 1.1038 + default: 1.1039 + return CKR_OK; 1.1040 + } 1.1041 + 1.1042 + for( i = 0; i < size; i++) { 1.1043 + typeArray[i] = attrs[i]; 1.1044 + } 1.1045 + 1.1046 + return CKR_OK; 1.1047 +} 1.1048 + 1.1049 +static CK_ULONG 1.1050 +ckmk_mdObject_GetAttributeSize 1.1051 +( 1.1052 + NSSCKMDObject *mdObject, 1.1053 + NSSCKFWObject *fwObject, 1.1054 + NSSCKMDSession *mdSession, 1.1055 + NSSCKFWSession *fwSession, 1.1056 + NSSCKMDToken *mdToken, 1.1057 + NSSCKFWToken *fwToken, 1.1058 + NSSCKMDInstance *mdInstance, 1.1059 + NSSCKFWInstance *fwInstance, 1.1060 + CK_ATTRIBUTE_TYPE attribute, 1.1061 + CK_RV *pError 1.1062 +) 1.1063 +{ 1.1064 + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; 1.1065 + 1.1066 + const NSSItem *b; 1.1067 + 1.1068 + b = nss_ckmk_FetchAttribute(io, attribute, pError); 1.1069 + 1.1070 + if ((const NSSItem *)NULL == b) { 1.1071 + return 0; 1.1072 + } 1.1073 + return b->size; 1.1074 +} 1.1075 + 1.1076 +static CK_RV 1.1077 +ckmk_mdObject_SetAttribute 1.1078 +( 1.1079 + NSSCKMDObject *mdObject, 1.1080 + NSSCKFWObject *fwObject, 1.1081 + NSSCKMDSession *mdSession, 1.1082 + NSSCKFWSession *fwSession, 1.1083 + NSSCKMDToken *mdToken, 1.1084 + NSSCKFWToken *fwToken, 1.1085 + NSSCKMDInstance *mdInstance, 1.1086 + NSSCKFWInstance *fwInstance, 1.1087 + CK_ATTRIBUTE_TYPE attribute, 1.1088 + NSSItem *value 1.1089 +) 1.1090 +{ 1.1091 + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; 1.1092 + SecKeychainItemRef itemRef; 1.1093 + 1.1094 + if (io->type == ckmkRaw) { 1.1095 + return CKR_TOKEN_WRITE_PROTECTED; 1.1096 + } 1.1097 + itemRef = io->u.item.itemRef; 1.1098 + 1.1099 + switch (io->objClass) { 1.1100 + case CKO_PRIVATE_KEY: 1.1101 + case CKO_PUBLIC_KEY: 1.1102 + switch (attribute) { 1.1103 + case CKA_ID: 1.1104 + ckmk_updateAttribute(itemRef, kSecKeyLabel, 1.1105 + value->data, value->size, "Set Attr Key ID"); 1.1106 +#ifdef DEBUG 1.1107 + itemdump("key id: ", value->data, value->size, CKR_OK); 1.1108 +#endif 1.1109 + break; 1.1110 + case CKA_LABEL: 1.1111 + ckmk_updateAttribute(itemRef, kSecKeyPrintName, value->data, 1.1112 + value->size, "Set Attr Key Label"); 1.1113 + break; 1.1114 + default: 1.1115 + break; 1.1116 + } 1.1117 + break; 1.1118 + 1.1119 + case CKO_CERTIFICATE: 1.1120 + switch (attribute) { 1.1121 + case CKA_ID: 1.1122 + ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr, 1.1123 + value->data, value->size, "Set Attr Cert ID"); 1.1124 + break; 1.1125 + case CKA_LABEL: 1.1126 + ckmk_updateAttribute(itemRef, kSecLabelItemAttr, value->data, 1.1127 + value->size, "Set Attr Cert Label"); 1.1128 + break; 1.1129 + default: 1.1130 + break; 1.1131 + } 1.1132 + break; 1.1133 + 1.1134 + default: 1.1135 + break; 1.1136 + } 1.1137 + return CKR_OK; 1.1138 +} 1.1139 + 1.1140 +static NSSCKFWItem 1.1141 +ckmk_mdObject_GetAttribute 1.1142 +( 1.1143 + NSSCKMDObject *mdObject, 1.1144 + NSSCKFWObject *fwObject, 1.1145 + NSSCKMDSession *mdSession, 1.1146 + NSSCKFWSession *fwSession, 1.1147 + NSSCKMDToken *mdToken, 1.1148 + NSSCKFWToken *fwToken, 1.1149 + NSSCKMDInstance *mdInstance, 1.1150 + NSSCKFWInstance *fwInstance, 1.1151 + CK_ATTRIBUTE_TYPE attribute, 1.1152 + CK_RV *pError 1.1153 +) 1.1154 +{ 1.1155 + NSSCKFWItem mdItem; 1.1156 + ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; 1.1157 + 1.1158 + mdItem.needsFreeing = PR_FALSE; 1.1159 + mdItem.item = (NSSItem*)nss_ckmk_FetchAttribute(io, attribute, pError); 1.1160 + 1.1161 + 1.1162 + return mdItem; 1.1163 +} 1.1164 + 1.1165 +static CK_ULONG 1.1166 +ckmk_mdObject_GetObjectSize 1.1167 +( 1.1168 + NSSCKMDObject *mdObject, 1.1169 + NSSCKFWObject *fwObject, 1.1170 + NSSCKMDSession *mdSession, 1.1171 + NSSCKFWSession *fwSession, 1.1172 + NSSCKMDToken *mdToken, 1.1173 + NSSCKFWToken *fwToken, 1.1174 + NSSCKMDInstance *mdInstance, 1.1175 + NSSCKFWInstance *fwInstance, 1.1176 + CK_RV *pError 1.1177 +) 1.1178 +{ 1.1179 + CK_ULONG rv = 1; 1.1180 + 1.1181 + /* size is irrelevant to this token */ 1.1182 + return rv; 1.1183 +} 1.1184 + 1.1185 +static const NSSCKMDObject 1.1186 +ckmk_prototype_mdObject = { 1.1187 + (void *)NULL, /* etc */ 1.1188 + NULL, /* Finalize */ 1.1189 + ckmk_mdObject_Destroy, 1.1190 + ckmk_mdObject_IsTokenObject, 1.1191 + ckmk_mdObject_GetAttributeCount, 1.1192 + ckmk_mdObject_GetAttributeTypes, 1.1193 + ckmk_mdObject_GetAttributeSize, 1.1194 + ckmk_mdObject_GetAttribute, 1.1195 + NULL, /* FreeAttribute */ 1.1196 + ckmk_mdObject_SetAttribute, 1.1197 + ckmk_mdObject_GetObjectSize, 1.1198 + (void *)NULL /* null terminator */ 1.1199 +}; 1.1200 + 1.1201 +static nssHash *ckmkInternalObjectHash = NULL; 1.1202 + 1.1203 +NSS_IMPLEMENT NSSCKMDObject * 1.1204 +nss_ckmk_CreateMDObject 1.1205 +( 1.1206 + NSSArena *arena, 1.1207 + ckmkInternalObject *io, 1.1208 + CK_RV *pError 1.1209 +) 1.1210 +{ 1.1211 + if ((nssHash *)NULL == ckmkInternalObjectHash) { 1.1212 + ckmkInternalObjectHash = nssHash_CreateItem(NULL, 10); 1.1213 + } 1.1214 + if (ckmkItem == io->type) { 1.1215 + /* the hash key, not a cryptographic key */ 1.1216 + NSSItem *key = &io->hashKey; 1.1217 + ckmkInternalObject *old_o = NULL; 1.1218 + 1.1219 + if (key->size == 0) { 1.1220 + ckmk_FetchHashKey(io); 1.1221 + } 1.1222 + old_o = (ckmkInternalObject *) 1.1223 + nssHash_Lookup(ckmkInternalObjectHash, key); 1.1224 + if (!old_o) { 1.1225 + nssHash_Add(ckmkInternalObjectHash, key, io); 1.1226 + } else if (old_o != io) { 1.1227 + nss_ckmk_DestroyInternalObject(io); 1.1228 + io = old_o; 1.1229 + } 1.1230 + } 1.1231 + 1.1232 + if ( (void*)NULL == io->mdObject.etc) { 1.1233 + (void) nsslibc_memcpy(&io->mdObject,&ckmk_prototype_mdObject, 1.1234 + sizeof(ckmk_prototype_mdObject)); 1.1235 + io->mdObject.etc = (void *)io; 1.1236 + } 1.1237 + return &io->mdObject; 1.1238 +} 1.1239 + 1.1240 +static void 1.1241 +ckmk_removeObjectFromHash 1.1242 +( 1.1243 + ckmkInternalObject *io 1.1244 +) 1.1245 +{ 1.1246 + NSSItem *key = &io->hashKey; 1.1247 + 1.1248 + if ((nssHash *)NULL == ckmkInternalObjectHash) { 1.1249 + return; 1.1250 + } 1.1251 + if (key->size == 0) { 1.1252 + ckmk_FetchHashKey(io); 1.1253 + } 1.1254 + nssHash_Remove(ckmkInternalObjectHash, key); 1.1255 + return; 1.1256 +} 1.1257 + 1.1258 + 1.1259 +void 1.1260 +nss_ckmk_DestroyInternalObject 1.1261 +( 1.1262 + ckmkInternalObject *io 1.1263 +) 1.1264 +{ 1.1265 + switch (io->type) { 1.1266 + case ckmkRaw: 1.1267 + return; 1.1268 + case ckmkItem: 1.1269 + nss_ZFreeIf(io->u.item.modify.data); 1.1270 + nss_ZFreeIf(io->u.item.private.data); 1.1271 + nss_ZFreeIf(io->u.item.encrypt.data); 1.1272 + nss_ZFreeIf(io->u.item.decrypt.data); 1.1273 + nss_ZFreeIf(io->u.item.derive.data); 1.1274 + nss_ZFreeIf(io->u.item.sign.data); 1.1275 + nss_ZFreeIf(io->u.item.signRecover.data); 1.1276 + nss_ZFreeIf(io->u.item.verify.data); 1.1277 + nss_ZFreeIf(io->u.item.verifyRecover.data); 1.1278 + nss_ZFreeIf(io->u.item.wrap.data); 1.1279 + nss_ZFreeIf(io->u.item.unwrap.data); 1.1280 + nss_ZFreeIf(io->u.item.label.data); 1.1281 + /*nss_ZFreeIf(io->u.item.subject.data); */ 1.1282 + /*nss_ZFreeIf(io->u.item.issuer.data); */ 1.1283 + nss_ZFreeIf(io->u.item.serial.data); 1.1284 + nss_ZFreeIf(io->u.item.modulus.data); 1.1285 + nss_ZFreeIf(io->u.item.exponent.data); 1.1286 + nss_ZFreeIf(io->u.item.privateExponent.data); 1.1287 + nss_ZFreeIf(io->u.item.prime1.data); 1.1288 + nss_ZFreeIf(io->u.item.prime2.data); 1.1289 + nss_ZFreeIf(io->u.item.exponent1.data); 1.1290 + nss_ZFreeIf(io->u.item.exponent2.data); 1.1291 + nss_ZFreeIf(io->u.item.coefficient.data); 1.1292 + break; 1.1293 + } 1.1294 + nss_ZFreeIf(io); 1.1295 + return; 1.1296 +} 1.1297 + 1.1298 + 1.1299 +static ckmkInternalObject * 1.1300 +nss_ckmk_NewInternalObject 1.1301 +( 1.1302 + CK_OBJECT_CLASS objClass, 1.1303 + SecKeychainItemRef itemRef, 1.1304 + SecItemClass itemClass, 1.1305 + CK_RV *pError 1.1306 +) 1.1307 +{ 1.1308 + ckmkInternalObject *io = nss_ZNEW(NULL, ckmkInternalObject); 1.1309 + 1.1310 + if ((ckmkInternalObject *)NULL == io) { 1.1311 + *pError = CKR_HOST_MEMORY; 1.1312 + return io; 1.1313 + } 1.1314 + io->type = ckmkItem; 1.1315 + io->objClass = objClass; 1.1316 + io->u.item.itemRef = itemRef; 1.1317 + io->u.item.itemClass = itemClass; 1.1318 + return io; 1.1319 +} 1.1320 + 1.1321 +/* 1.1322 + * Apple doesn't alway have a default keyChain set by the OS, use the 1.1323 + * SearchList to try to find one. 1.1324 + */ 1.1325 +static CK_RV 1.1326 +ckmk_GetSafeDefaultKeychain 1.1327 +( 1.1328 + SecKeychainRef *keychainRef 1.1329 +) 1.1330 +{ 1.1331 + OSStatus macErr; 1.1332 + CFArrayRef searchList = 0; 1.1333 + CK_RV error = CKR_OK; 1.1334 + 1.1335 + macErr = SecKeychainCopyDefault(keychainRef); 1.1336 + if (noErr != macErr) { 1.1337 + int searchCount = 0; 1.1338 + if (errSecNoDefaultKeychain != macErr) { 1.1339 + CKMK_MACERR("Getting default key chain", macErr); 1.1340 + error = CKR_GENERAL_ERROR; 1.1341 + goto loser; 1.1342 + } 1.1343 + /* ok, we don't have a default key chain, find one */ 1.1344 + macErr = SecKeychainCopySearchList(&searchList); 1.1345 + if (noErr != macErr) { 1.1346 + CKMK_MACERR("failed to find a keyring searchList", macErr); 1.1347 + error = CKR_DEVICE_REMOVED; 1.1348 + goto loser; 1.1349 + } 1.1350 + searchCount = CFArrayGetCount(searchList); 1.1351 + if (searchCount < 1) { 1.1352 + error = CKR_DEVICE_REMOVED; 1.1353 + goto loser; 1.1354 + } 1.1355 + *keychainRef = 1.1356 + (SecKeychainRef)CFRetain(CFArrayGetValueAtIndex(searchList, 0)); 1.1357 + if (0 == *keychainRef) { 1.1358 + error = CKR_DEVICE_REMOVED; 1.1359 + goto loser; 1.1360 + } 1.1361 + /* should we set it as default? */ 1.1362 + } 1.1363 +loser: 1.1364 + if (0 != searchList) { 1.1365 + CFRelease(searchList); 1.1366 + } 1.1367 + return error; 1.1368 +} 1.1369 +static ckmkInternalObject * 1.1370 +nss_ckmk_CreateCertificate 1.1371 +( 1.1372 + NSSCKFWSession *fwSession, 1.1373 + CK_ATTRIBUTE_PTR pTemplate, 1.1374 + CK_ULONG ulAttributeCount, 1.1375 + CK_RV *pError 1.1376 +) 1.1377 +{ 1.1378 + NSSItem value; 1.1379 + ckmkInternalObject *io = NULL; 1.1380 + OSStatus macErr; 1.1381 + SecCertificateRef certRef; 1.1382 + SecKeychainItemRef itemRef; 1.1383 + SecKeychainRef keychainRef; 1.1384 + CSSM_DATA certData; 1.1385 + 1.1386 + *pError = nss_ckmk_GetAttribute(CKA_VALUE, pTemplate, 1.1387 + ulAttributeCount, &value); 1.1388 + if (CKR_OK != *pError) { 1.1389 + goto loser; 1.1390 + } 1.1391 + 1.1392 + certData.Data = value.data; 1.1393 + certData.Length = value.size; 1.1394 + macErr = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, 1.1395 + CSSM_CERT_ENCODING_BER, &certRef); 1.1396 + if (noErr != macErr) { 1.1397 + CKMK_MACERR("Create cert from data Failed", macErr); 1.1398 + *pError = CKR_GENERAL_ERROR; /* need to map macErr */ 1.1399 + goto loser; 1.1400 + } 1.1401 + 1.1402 + *pError = ckmk_GetSafeDefaultKeychain(&keychainRef); 1.1403 + if (CKR_OK != *pError) { 1.1404 + goto loser; 1.1405 + } 1.1406 + 1.1407 + macErr = SecCertificateAddToKeychain( certRef, keychainRef); 1.1408 + itemRef = (SecKeychainItemRef) certRef; 1.1409 + if (errSecDuplicateItem != macErr) { 1.1410 + NSSItem keyID = { NULL, 0 }; 1.1411 + char *nickname = NULL; 1.1412 + CK_RV dummy; 1.1413 + 1.1414 + if (noErr != macErr) { 1.1415 + CKMK_MACERR("Add cert to keychain Failed", macErr); 1.1416 + *pError = CKR_GENERAL_ERROR; /* need to map macErr */ 1.1417 + goto loser; 1.1418 + } 1.1419 + /* these two are optional */ 1.1420 + nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate, 1.1421 + ulAttributeCount, &dummy); 1.1422 + /* we've added a new one, update the attributes in the key ring */ 1.1423 + if (nickname) { 1.1424 + ckmk_updateAttribute(itemRef, kSecLabelItemAttr, nickname, 1.1425 + strlen(nickname)+1, "Modify Cert Label"); 1.1426 + nss_ZFreeIf(nickname); 1.1427 + } 1.1428 + dummy = nss_ckmk_GetAttribute(CKA_ID, pTemplate, 1.1429 + ulAttributeCount, &keyID); 1.1430 + if (CKR_OK == dummy) { 1.1431 + dummy = ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr, 1.1432 + keyID.data, keyID.size, "Modify Cert ID"); 1.1433 + } 1.1434 + } 1.1435 + 1.1436 + io = nss_ckmk_NewInternalObject(CKO_CERTIFICATE, itemRef, 1.1437 + kSecCertificateItemClass, pError); 1.1438 + if ((ckmkInternalObject *)NULL != io) { 1.1439 + itemRef = 0; 1.1440 + } 1.1441 + 1.1442 +loser: 1.1443 + if (0 != itemRef) { 1.1444 + CFRelease(itemRef); 1.1445 + } 1.1446 + if (0 != keychainRef) { 1.1447 + CFRelease(keychainRef); 1.1448 + } 1.1449 + 1.1450 + return io; 1.1451 +} 1.1452 + 1.1453 +/* 1.1454 + * PKCS #8 attributes 1.1455 + */ 1.1456 +struct ckmk_AttributeStr { 1.1457 + SECItem attrType; 1.1458 + SECItem *attrValue; 1.1459 +}; 1.1460 +typedef struct ckmk_AttributeStr ckmk_Attribute; 1.1461 + 1.1462 +/* 1.1463 +** A PKCS#8 private key info object 1.1464 +*/ 1.1465 +struct PrivateKeyInfoStr { 1.1466 + PLArenaPool *arena; 1.1467 + SECItem version; 1.1468 + SECAlgorithmID algorithm; 1.1469 + SECItem privateKey; 1.1470 + ckmk_Attribute **attributes; 1.1471 +}; 1.1472 +typedef struct PrivateKeyInfoStr PrivateKeyInfo; 1.1473 + 1.1474 +const SEC_ASN1Template ckmk_RSAPrivateKeyTemplate[] = { 1.1475 + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey) }, 1.1476 + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,version) }, 1.1477 + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,modulus) }, 1.1478 + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,publicExponent) }, 1.1479 + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,privateExponent) }, 1.1480 + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,prime1) }, 1.1481 + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,prime2) }, 1.1482 + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,exponent1) }, 1.1483 + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,exponent2) }, 1.1484 + { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,coefficient) }, 1.1485 + { 0 } 1.1486 +}; 1.1487 + 1.1488 +const SEC_ASN1Template ckmk_AttributeTemplate[] = { 1.1489 + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ckmk_Attribute) }, 1.1490 + { SEC_ASN1_OBJECT_ID, offsetof(ckmk_Attribute, attrType) }, 1.1491 + { SEC_ASN1_SET_OF, offsetof(ckmk_Attribute, attrValue), 1.1492 + SEC_AnyTemplate }, 1.1493 + { 0 } 1.1494 +}; 1.1495 + 1.1496 +const SEC_ASN1Template ckmk_SetOfAttributeTemplate[] = { 1.1497 + { SEC_ASN1_SET_OF, 0, ckmk_AttributeTemplate }, 1.1498 +}; 1.1499 + 1.1500 +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 1.1501 + 1.1502 +/* ASN1 Templates for new decoder/encoder */ 1.1503 +const SEC_ASN1Template ckmk_PrivateKeyInfoTemplate[] = { 1.1504 + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PrivateKeyInfo) }, 1.1505 + { SEC_ASN1_INTEGER, offsetof(PrivateKeyInfo,version) }, 1.1506 + { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(PrivateKeyInfo,algorithm), 1.1507 + SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 1.1508 + { SEC_ASN1_OCTET_STRING, offsetof(PrivateKeyInfo,privateKey) }, 1.1509 + { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, 1.1510 + offsetof(PrivateKeyInfo, attributes), ckmk_SetOfAttributeTemplate }, 1.1511 + { 0 } 1.1512 +}; 1.1513 + 1.1514 +#define CKMK_PRIVATE_KEY_INFO_VERSION 0 1.1515 +static CK_RV 1.1516 +ckmk_CreateRSAKeyBlob 1.1517 +( 1.1518 + RSAPrivateKey *lk, 1.1519 + NSSItem *keyBlob 1.1520 +) 1.1521 +{ 1.1522 + PrivateKeyInfo *pki = NULL; 1.1523 + PLArenaPool *arena = NULL; 1.1524 + SECOidTag algorithm = SEC_OID_UNKNOWN; 1.1525 + void *dummy; 1.1526 + SECStatus rv; 1.1527 + SECItem *encodedKey = NULL; 1.1528 + CK_RV error = CKR_OK; 1.1529 + 1.1530 + arena = PORT_NewArena(2048); /* XXX different size? */ 1.1531 + if(!arena) { 1.1532 + error = CKR_HOST_MEMORY; 1.1533 + goto loser; 1.1534 + } 1.1535 + 1.1536 + pki = (PrivateKeyInfo*)PORT_ArenaZAlloc(arena, sizeof(PrivateKeyInfo)); 1.1537 + if(!pki) { 1.1538 + error = CKR_HOST_MEMORY; 1.1539 + goto loser; 1.1540 + } 1.1541 + pki->arena = arena; 1.1542 + 1.1543 + dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk, 1.1544 + ckmk_RSAPrivateKeyTemplate); 1.1545 + algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION; 1.1546 + 1.1547 + if (!dummy) { 1.1548 + error = CKR_DEVICE_ERROR; /* should map NSS SECError */ 1.1549 + goto loser; 1.1550 + } 1.1551 + 1.1552 + rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm, 1.1553 + (SECItem*)NULL); 1.1554 + if (rv != SECSuccess) { 1.1555 + error = CKR_DEVICE_ERROR; /* should map NSS SECError */ 1.1556 + goto loser; 1.1557 + } 1.1558 + 1.1559 + dummy = SEC_ASN1EncodeInteger(arena, &pki->version, 1.1560 + CKMK_PRIVATE_KEY_INFO_VERSION); 1.1561 + if (!dummy) { 1.1562 + error = CKR_DEVICE_ERROR; /* should map NSS SECError */ 1.1563 + goto loser; 1.1564 + } 1.1565 + 1.1566 + encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki, 1.1567 + ckmk_PrivateKeyInfoTemplate); 1.1568 + if (!encodedKey) { 1.1569 + error = CKR_DEVICE_ERROR; 1.1570 + goto loser; 1.1571 + } 1.1572 + 1.1573 + keyBlob->data = nss_ZNEWARRAY(NULL, char, encodedKey->len); 1.1574 + if (NULL == keyBlob->data) { 1.1575 + error = CKR_HOST_MEMORY; 1.1576 + goto loser; 1.1577 + } 1.1578 + nsslibc_memcpy(keyBlob->data, encodedKey->data, encodedKey->len); 1.1579 + keyBlob->size = encodedKey->len; 1.1580 + 1.1581 +loser: 1.1582 + if(arena) { 1.1583 + PORT_FreeArena(arena, PR_TRUE); 1.1584 + } 1.1585 + if (encodedKey) { 1.1586 + SECITEM_FreeItem(encodedKey, PR_TRUE); 1.1587 + } 1.1588 + 1.1589 + return error; 1.1590 +} 1.1591 +/* 1.1592 + * There MUST be a better way to do this. For now, find the key based on the 1.1593 + * default name Apple gives it once we import. 1.1594 + */ 1.1595 +#define IMPORTED_NAME "Imported Private Key" 1.1596 +static CK_RV 1.1597 +ckmk_FindImportedKey 1.1598 +( 1.1599 + SecKeychainRef keychainRef, 1.1600 + SecItemClass itemClass, 1.1601 + SecKeychainItemRef *outItemRef 1.1602 +) 1.1603 +{ 1.1604 + OSStatus macErr; 1.1605 + SecKeychainSearchRef searchRef = 0; 1.1606 + SecKeychainItemRef newItemRef; 1.1607 + 1.1608 + macErr = SecKeychainSearchCreateFromAttributes(keychainRef, itemClass, 1.1609 + NULL, &searchRef); 1.1610 + if (noErr != macErr) { 1.1611 + CKMK_MACERR("Can't search for Key", macErr); 1.1612 + return CKR_GENERAL_ERROR; 1.1613 + } 1.1614 + while (noErr == SecKeychainSearchCopyNext(searchRef, &newItemRef)) { 1.1615 + SecKeychainAttributeList *attrList = NULL; 1.1616 + SecKeychainAttributeInfo attrInfo; 1.1617 + SecItemAttr itemAttr = kSecKeyPrintName; 1.1618 + PRUint32 attrFormat = 0; 1.1619 + OSStatus macErr; 1.1620 + 1.1621 + attrInfo.count = 1; 1.1622 + attrInfo.tag = &itemAttr; 1.1623 + attrInfo.format = &attrFormat; 1.1624 + 1.1625 + macErr = SecKeychainItemCopyAttributesAndData(newItemRef, 1.1626 + &attrInfo, NULL, &attrList, NULL, NULL); 1.1627 + if (noErr == macErr) { 1.1628 + if (nsslibc_memcmp(attrList->attr->data, IMPORTED_NAME, 1.1629 + attrList->attr->length, NULL) == 0) { 1.1630 + *outItemRef = newItemRef; 1.1631 + CFRelease (searchRef); 1.1632 + SecKeychainItemFreeAttributesAndData(attrList, NULL); 1.1633 + return CKR_OK; 1.1634 + } 1.1635 + SecKeychainItemFreeAttributesAndData(attrList, NULL); 1.1636 + } 1.1637 + CFRelease(newItemRef); 1.1638 + } 1.1639 + CFRelease (searchRef); 1.1640 + return CKR_GENERAL_ERROR; /* we can come up with something better! */ 1.1641 +} 1.1642 + 1.1643 +static ckmkInternalObject * 1.1644 +nss_ckmk_CreatePrivateKey 1.1645 +( 1.1646 + NSSCKFWSession *fwSession, 1.1647 + CK_ATTRIBUTE_PTR pTemplate, 1.1648 + CK_ULONG ulAttributeCount, 1.1649 + CK_RV *pError 1.1650 +) 1.1651 +{ 1.1652 + NSSItem attribute; 1.1653 + RSAPrivateKey lk; 1.1654 + NSSItem keyID; 1.1655 + char *nickname = NULL; 1.1656 + ckmkInternalObject *io = NULL; 1.1657 + CK_KEY_TYPE keyType; 1.1658 + OSStatus macErr; 1.1659 + SecKeychainItemRef itemRef = 0; 1.1660 + NSSItem keyBlob = { NULL, 0 }; 1.1661 + CFDataRef dataRef = 0; 1.1662 + SecExternalFormat inputFormat = kSecFormatBSAFE; 1.1663 + /*SecExternalFormat inputFormat = kSecFormatOpenSSL; */ 1.1664 + SecExternalItemType itemType = kSecItemTypePrivateKey; 1.1665 + SecKeyImportExportParameters keyParams ; 1.1666 + SecKeychainRef targetKeychain = 0; 1.1667 + unsigned char zero = 0; 1.1668 + CK_RV error; 1.1669 + 1.1670 + keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; 1.1671 + keyParams.flags = 0; 1.1672 + keyParams.passphrase = 0; 1.1673 + keyParams.alertTitle = 0; 1.1674 + keyParams.alertPrompt = 0; 1.1675 + keyParams.accessRef = 0; /* default */ 1.1676 + keyParams.keyUsage = 0; /* will get filled in */ 1.1677 + keyParams.keyAttributes = CSSM_KEYATTR_PERMANENT; /* will get filled in */ 1.1678 + keyType = nss_ckmk_GetULongAttribute 1.1679 + (CKA_KEY_TYPE, pTemplate, ulAttributeCount, pError); 1.1680 + if (CKR_OK != *pError) { 1.1681 + return (ckmkInternalObject *)NULL; 1.1682 + } 1.1683 + if (CKK_RSA != keyType) { 1.1684 + *pError = CKR_ATTRIBUTE_VALUE_INVALID; 1.1685 + return (ckmkInternalObject *)NULL; 1.1686 + } 1.1687 + if (nss_ckmk_GetBoolAttribute(CKA_DECRYPT, 1.1688 + pTemplate, ulAttributeCount, CK_TRUE)) { 1.1689 + keyParams.keyUsage |= CSSM_KEYUSE_DECRYPT; 1.1690 + } 1.1691 + if (nss_ckmk_GetBoolAttribute(CKA_UNWRAP, 1.1692 + pTemplate, ulAttributeCount, CK_TRUE)) { 1.1693 + keyParams.keyUsage |= CSSM_KEYUSE_UNWRAP; 1.1694 + } 1.1695 + if (nss_ckmk_GetBoolAttribute(CKA_SIGN, 1.1696 + pTemplate, ulAttributeCount, CK_TRUE)) { 1.1697 + keyParams.keyUsage |= CSSM_KEYUSE_SIGN; 1.1698 + } 1.1699 + if (nss_ckmk_GetBoolAttribute(CKA_DERIVE, 1.1700 + pTemplate, ulAttributeCount, CK_FALSE)) { 1.1701 + keyParams.keyUsage |= CSSM_KEYUSE_DERIVE; 1.1702 + } 1.1703 + if (nss_ckmk_GetBoolAttribute(CKA_SENSITIVE, 1.1704 + pTemplate, ulAttributeCount, CK_TRUE)) { 1.1705 + keyParams.keyAttributes |= CSSM_KEYATTR_SENSITIVE; 1.1706 + } 1.1707 + if (nss_ckmk_GetBoolAttribute(CKA_EXTRACTABLE, 1.1708 + pTemplate, ulAttributeCount, CK_TRUE)) { 1.1709 + keyParams.keyAttributes |= CSSM_KEYATTR_EXTRACTABLE; 1.1710 + } 1.1711 + 1.1712 + lk.version.type = siUnsignedInteger; 1.1713 + lk.version.data = &zero; 1.1714 + lk.version.len = 1; 1.1715 + 1.1716 + *pError = nss_ckmk_GetAttribute(CKA_MODULUS, pTemplate, 1.1717 + ulAttributeCount, &attribute); 1.1718 + if (CKR_OK != *pError) { 1.1719 + return (ckmkInternalObject *)NULL; 1.1720 + } 1.1721 + lk.modulus.type = siUnsignedInteger; 1.1722 + lk.modulus.data = attribute.data; 1.1723 + lk.modulus.len = attribute.size; 1.1724 + 1.1725 + *pError = nss_ckmk_GetAttribute(CKA_PUBLIC_EXPONENT, pTemplate, 1.1726 + ulAttributeCount, &attribute); 1.1727 + if (CKR_OK != *pError) { 1.1728 + return (ckmkInternalObject *)NULL; 1.1729 + } 1.1730 + lk.publicExponent.type = siUnsignedInteger; 1.1731 + lk.publicExponent.data = attribute.data; 1.1732 + lk.publicExponent.len = attribute.size; 1.1733 + 1.1734 + *pError = nss_ckmk_GetAttribute(CKA_PRIVATE_EXPONENT, pTemplate, 1.1735 + ulAttributeCount, &attribute); 1.1736 + if (CKR_OK != *pError) { 1.1737 + return (ckmkInternalObject *)NULL; 1.1738 + } 1.1739 + lk.privateExponent.type = siUnsignedInteger; 1.1740 + lk.privateExponent.data = attribute.data; 1.1741 + lk.privateExponent.len = attribute.size; 1.1742 + 1.1743 + *pError = nss_ckmk_GetAttribute(CKA_PRIME_1, pTemplate, 1.1744 + ulAttributeCount, &attribute); 1.1745 + if (CKR_OK != *pError) { 1.1746 + return (ckmkInternalObject *)NULL; 1.1747 + } 1.1748 + lk.prime1.type = siUnsignedInteger; 1.1749 + lk.prime1.data = attribute.data; 1.1750 + lk.prime1.len = attribute.size; 1.1751 + 1.1752 + *pError = nss_ckmk_GetAttribute(CKA_PRIME_2, pTemplate, 1.1753 + ulAttributeCount, &attribute); 1.1754 + if (CKR_OK != *pError) { 1.1755 + return (ckmkInternalObject *)NULL; 1.1756 + } 1.1757 + lk.prime2.type = siUnsignedInteger; 1.1758 + lk.prime2.data = attribute.data; 1.1759 + lk.prime2.len = attribute.size; 1.1760 + 1.1761 + *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_1, pTemplate, 1.1762 + ulAttributeCount, &attribute); 1.1763 + if (CKR_OK != *pError) { 1.1764 + return (ckmkInternalObject *)NULL; 1.1765 + } 1.1766 + lk.exponent1.type = siUnsignedInteger; 1.1767 + lk.exponent1.data = attribute.data; 1.1768 + lk.exponent1.len = attribute.size; 1.1769 + 1.1770 + *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_2, pTemplate, 1.1771 + ulAttributeCount, &attribute); 1.1772 + if (CKR_OK != *pError) { 1.1773 + return (ckmkInternalObject *)NULL; 1.1774 + } 1.1775 + lk.exponent2.type = siUnsignedInteger; 1.1776 + lk.exponent2.data = attribute.data; 1.1777 + lk.exponent2.len = attribute.size; 1.1778 + 1.1779 + *pError = nss_ckmk_GetAttribute(CKA_COEFFICIENT, pTemplate, 1.1780 + ulAttributeCount, &attribute); 1.1781 + if (CKR_OK != *pError) { 1.1782 + return (ckmkInternalObject *)NULL; 1.1783 + } 1.1784 + lk.coefficient.type = siUnsignedInteger; 1.1785 + lk.coefficient.data = attribute.data; 1.1786 + lk.coefficient.len = attribute.size; 1.1787 + 1.1788 + /* ASN1 Encode the pkcs8 structure... look at softoken to see how this 1.1789 + * is done... */ 1.1790 + error = ckmk_CreateRSAKeyBlob(&lk, &keyBlob); 1.1791 + if (CKR_OK != error) { 1.1792 + goto loser; 1.1793 + } 1.1794 + 1.1795 + dataRef = CFDataCreate(NULL, (UInt8 *)keyBlob.data, keyBlob.size); 1.1796 + if (0 == dataRef) { 1.1797 + *pError = CKR_HOST_MEMORY; 1.1798 + goto loser; 1.1799 + } 1.1800 + 1.1801 + *pError == ckmk_GetSafeDefaultKeychain(&targetKeychain); 1.1802 + if (CKR_OK != *pError) { 1.1803 + goto loser; 1.1804 + } 1.1805 + 1.1806 + 1.1807 + /* the itemArray that is returned is useless. the item does not 1.1808 + * is 'not on the key chain' so none of the modify calls work on it. 1.1809 + * It also has a key that isn't the same key as the one in the actual 1.1810 + * key chain. In short it isn't the item we want, and it gives us zero 1.1811 + * information about the item we want, so don't even bother with it... 1.1812 + */ 1.1813 + macErr = SecKeychainItemImport(dataRef, NULL, &inputFormat, &itemType, 0, 1.1814 + &keyParams, targetKeychain, NULL); 1.1815 + if (noErr != macErr) { 1.1816 + CKMK_MACERR("Import Private Key", macErr); 1.1817 + *pError = CKR_GENERAL_ERROR; 1.1818 + goto loser; 1.1819 + } 1.1820 + 1.1821 + *pError = ckmk_FindImportedKey(targetKeychain, 1.1822 + CSSM_DL_DB_RECORD_PRIVATE_KEY, 1.1823 + &itemRef); 1.1824 + if (CKR_OK != *pError) { 1.1825 +#ifdef DEBUG 1.1826 + fprintf(stderr,"couldn't find key in keychain \n"); 1.1827 +#endif 1.1828 + goto loser; 1.1829 + } 1.1830 + 1.1831 + 1.1832 + /* set the CKA_ID and the CKA_LABEL */ 1.1833 + error = nss_ckmk_GetAttribute(CKA_ID, pTemplate, 1.1834 + ulAttributeCount, &keyID); 1.1835 + if (CKR_OK == error) { 1.1836 + error = ckmk_updateAttribute(itemRef, kSecKeyLabel, 1.1837 + keyID.data, keyID.size, "Modify Key ID"); 1.1838 +#ifdef DEBUG 1.1839 + itemdump("key id: ", keyID.data, keyID.size, error); 1.1840 +#endif 1.1841 + } 1.1842 + nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate, 1.1843 + ulAttributeCount, &error); 1.1844 + if (nickname) { 1.1845 + ckmk_updateAttribute(itemRef, kSecKeyPrintName, nickname, 1.1846 + strlen(nickname)+1, "Modify Key Label"); 1.1847 + } else { 1.1848 +#define DEFAULT_NICKNAME "NSS Imported Key" 1.1849 + ckmk_updateAttribute(itemRef, kSecKeyPrintName, DEFAULT_NICKNAME, 1.1850 + sizeof(DEFAULT_NICKNAME), "Modify Key Label"); 1.1851 + } 1.1852 + 1.1853 + io = nss_ckmk_NewInternalObject(CKO_PRIVATE_KEY, itemRef, 1.1854 + CSSM_DL_DB_RECORD_PRIVATE_KEY, pError); 1.1855 + if ((ckmkInternalObject *)NULL == io) { 1.1856 + CFRelease(itemRef); 1.1857 + } 1.1858 + 1.1859 + return io; 1.1860 + 1.1861 +loser: 1.1862 + /* free the key blob */ 1.1863 + if (keyBlob.data) { 1.1864 + nss_ZFreeIf(keyBlob.data); 1.1865 + } 1.1866 + if (0 != targetKeychain) { 1.1867 + CFRelease(targetKeychain); 1.1868 + } 1.1869 + if (0 != dataRef) { 1.1870 + CFRelease(dataRef); 1.1871 + } 1.1872 + return io; 1.1873 +} 1.1874 + 1.1875 + 1.1876 +NSS_EXTERN NSSCKMDObject * 1.1877 +nss_ckmk_CreateObject 1.1878 +( 1.1879 + NSSCKFWSession *fwSession, 1.1880 + CK_ATTRIBUTE_PTR pTemplate, 1.1881 + CK_ULONG ulAttributeCount, 1.1882 + CK_RV *pError 1.1883 +) 1.1884 +{ 1.1885 + CK_OBJECT_CLASS objClass; 1.1886 + ckmkInternalObject *io; 1.1887 + CK_BBOOL isToken; 1.1888 + 1.1889 + /* 1.1890 + * only create token objects 1.1891 + */ 1.1892 + isToken = nss_ckmk_GetBoolAttribute(CKA_TOKEN, pTemplate, 1.1893 + ulAttributeCount, CK_FALSE); 1.1894 + if (!isToken) { 1.1895 + *pError = CKR_ATTRIBUTE_VALUE_INVALID; 1.1896 + return (NSSCKMDObject *) NULL; 1.1897 + } 1.1898 + 1.1899 + /* 1.1900 + * only create keys and certs. 1.1901 + */ 1.1902 + objClass = nss_ckmk_GetULongAttribute(CKA_CLASS, pTemplate, 1.1903 + ulAttributeCount, pError); 1.1904 + if (CKR_OK != *pError) { 1.1905 + return (NSSCKMDObject *) NULL; 1.1906 + } 1.1907 +#ifdef notdef 1.1908 + if (objClass == CKO_PUBLIC_KEY) { 1.1909 + return CKR_OK; /* fake public key creation, happens as a side effect of 1.1910 + * private key creation */ 1.1911 + } 1.1912 +#endif 1.1913 + if (objClass == CKO_CERTIFICATE) { 1.1914 + io = nss_ckmk_CreateCertificate(fwSession, pTemplate, 1.1915 + ulAttributeCount, pError); 1.1916 + } else if (objClass == CKO_PRIVATE_KEY) { 1.1917 + io = nss_ckmk_CreatePrivateKey(fwSession, pTemplate, 1.1918 + ulAttributeCount, pError); 1.1919 + } else { 1.1920 + *pError = CKR_ATTRIBUTE_VALUE_INVALID; 1.1921 + } 1.1922 + 1.1923 + if ((ckmkInternalObject *)NULL == io) { 1.1924 + return (NSSCKMDObject *) NULL; 1.1925 + } 1.1926 + return nss_ckmk_CreateMDObject(NULL, io, pError); 1.1927 +}