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

changeset 0
6474c204b198
     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 +}

mercurial