Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 | } |