michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "ckmk.h" michael@0: #include "nssbase.h" michael@0: michael@0: #include "secdert.h" /* for DER_INTEGER */ michael@0: #include "string.h" michael@0: michael@0: /* asn1 encoder (to build pkcs#8 blobs) */ michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: /* for importing the keys */ michael@0: #include michael@0: #include michael@0: michael@0: /* michael@0: * nssmkey/mobject.c michael@0: * michael@0: * This file implements the NSSCKMDObject object for the michael@0: * "nssmkey" cryptoki module. michael@0: */ michael@0: michael@0: const CK_ATTRIBUTE_TYPE certAttrs[] = { michael@0: CKA_CLASS, michael@0: CKA_TOKEN, michael@0: CKA_PRIVATE, michael@0: CKA_MODIFIABLE, michael@0: CKA_LABEL, michael@0: CKA_CERTIFICATE_TYPE, michael@0: CKA_SUBJECT, michael@0: CKA_ISSUER, michael@0: CKA_SERIAL_NUMBER, michael@0: CKA_VALUE michael@0: }; michael@0: const PRUint32 certAttrsCount = NSS_CKMK_ARRAY_SIZE(certAttrs); michael@0: michael@0: /* private keys, for now only support RSA */ michael@0: const CK_ATTRIBUTE_TYPE privKeyAttrs[] = { michael@0: CKA_CLASS, michael@0: CKA_TOKEN, michael@0: CKA_PRIVATE, michael@0: CKA_MODIFIABLE, michael@0: CKA_LABEL, michael@0: CKA_KEY_TYPE, michael@0: CKA_DERIVE, michael@0: CKA_LOCAL, michael@0: CKA_SUBJECT, michael@0: CKA_SENSITIVE, michael@0: CKA_DECRYPT, michael@0: CKA_SIGN, michael@0: CKA_SIGN_RECOVER, michael@0: CKA_UNWRAP, michael@0: CKA_EXTRACTABLE, michael@0: CKA_ALWAYS_SENSITIVE, michael@0: CKA_NEVER_EXTRACTABLE, michael@0: CKA_MODULUS, michael@0: CKA_PUBLIC_EXPONENT, michael@0: }; michael@0: const PRUint32 privKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(privKeyAttrs); michael@0: michael@0: /* public keys, for now only support RSA */ michael@0: const CK_ATTRIBUTE_TYPE pubKeyAttrs[] = { michael@0: CKA_CLASS, michael@0: CKA_TOKEN, michael@0: CKA_PRIVATE, michael@0: CKA_MODIFIABLE, michael@0: CKA_LABEL, michael@0: CKA_KEY_TYPE, michael@0: CKA_DERIVE, michael@0: CKA_LOCAL, michael@0: CKA_SUBJECT, michael@0: CKA_ENCRYPT, michael@0: CKA_VERIFY, michael@0: CKA_VERIFY_RECOVER, michael@0: CKA_WRAP, michael@0: CKA_MODULUS, michael@0: CKA_PUBLIC_EXPONENT, michael@0: }; michael@0: const PRUint32 pubKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(pubKeyAttrs); michael@0: static const CK_BBOOL ck_true = CK_TRUE; michael@0: static const CK_BBOOL ck_false = CK_FALSE; michael@0: static const CK_CERTIFICATE_TYPE ckc_x509 = CKC_X_509; michael@0: static const CK_KEY_TYPE ckk_rsa = CKK_RSA; michael@0: static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE; michael@0: static const CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY; michael@0: static const CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY; michael@0: static const NSSItem ckmk_trueItem = { michael@0: (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL) }; michael@0: static const NSSItem ckmk_falseItem = { michael@0: (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) }; michael@0: static const NSSItem ckmk_x509Item = { michael@0: (void *)&ckc_x509, (PRUint32)sizeof(CK_CERTIFICATE_TYPE) }; michael@0: static const NSSItem ckmk_rsaItem = { michael@0: (void *)&ckk_rsa, (PRUint32)sizeof(CK_KEY_TYPE) }; michael@0: static const NSSItem ckmk_certClassItem = { michael@0: (void *)&cko_certificate, (PRUint32)sizeof(CK_OBJECT_CLASS) }; michael@0: static const NSSItem ckmk_privKeyClassItem = { michael@0: (void *)&cko_private_key, (PRUint32)sizeof(CK_OBJECT_CLASS) }; michael@0: static const NSSItem ckmk_pubKeyClassItem = { michael@0: (void *)&cko_public_key, (PRUint32)sizeof(CK_OBJECT_CLASS) }; michael@0: static const NSSItem ckmk_emptyItem = { michael@0: (void *)&ck_true, 0}; michael@0: michael@0: /* michael@0: * these are utilities. The chould be moved to a new utilities file. michael@0: */ michael@0: #ifdef DEBUG michael@0: static void michael@0: itemdump(char *str, void *data, int size, CK_RV error) michael@0: { michael@0: unsigned char *ptr = (unsigned char *)data; michael@0: int i; michael@0: fprintf(stderr,str); michael@0: for (i=0; i < size; i++) { michael@0: fprintf(stderr,"%02x ",(unsigned int) ptr[i]); michael@0: } michael@0: fprintf(stderr," (error = %d)\n", (int ) error); michael@0: } michael@0: #endif michael@0: michael@0: /* michael@0: * unwrap a single DER value michael@0: * now that we have util linked in, we should probably use michael@0: * the ANS1_Decoder for this work... michael@0: */ michael@0: unsigned char * michael@0: nss_ckmk_DERUnwrap michael@0: ( michael@0: unsigned char *src, michael@0: int size, michael@0: int *outSize, michael@0: unsigned char **next michael@0: ) michael@0: { michael@0: unsigned char *start = src; michael@0: unsigned int len = 0; michael@0: michael@0: /* initialize error condition return values */ michael@0: *outSize = 0; michael@0: if (next) { michael@0: *next = src; michael@0: } michael@0: michael@0: if (size < 2) { michael@0: return start; michael@0: } michael@0: src ++ ; /* skip the tag -- should check it against an expected value! */ michael@0: len = (unsigned) *src++; michael@0: if (len & 0x80) { michael@0: int count = len & 0x7f; michael@0: len =0; michael@0: michael@0: if (count+2 > size) { michael@0: return start; michael@0: } michael@0: while (count-- > 0) { michael@0: len = (len << 8) | (unsigned) *src++; michael@0: } michael@0: } michael@0: if (len + (src-start) > (unsigned int)size) { michael@0: return start; michael@0: } michael@0: if (next) { michael@0: *next = src+len; michael@0: } michael@0: *outSize = len; michael@0: michael@0: return src; michael@0: } michael@0: michael@0: /* michael@0: * get an attribute from a template. Value is returned in NSS item. michael@0: * data for the item is owned by the template. michael@0: */ michael@0: CK_RV michael@0: nss_ckmk_GetAttribute michael@0: ( michael@0: CK_ATTRIBUTE_TYPE type, michael@0: CK_ATTRIBUTE *template, michael@0: CK_ULONG templateSize, michael@0: NSSItem *item michael@0: ) michael@0: { michael@0: CK_ULONG i; michael@0: michael@0: for (i=0; i < templateSize; i++) { michael@0: if (template[i].type == type) { michael@0: item->data = template[i].pValue; michael@0: item->size = template[i].ulValueLen; michael@0: return CKR_OK; michael@0: } michael@0: } michael@0: return CKR_TEMPLATE_INCOMPLETE; michael@0: } michael@0: michael@0: /* michael@0: * get an attribute which is type CK_ULONG. michael@0: */ michael@0: CK_ULONG michael@0: nss_ckmk_GetULongAttribute michael@0: ( michael@0: CK_ATTRIBUTE_TYPE type, michael@0: CK_ATTRIBUTE *template, michael@0: CK_ULONG templateSize, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: NSSItem item; michael@0: michael@0: *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item); michael@0: if (CKR_OK != *pError) { michael@0: return (CK_ULONG) 0; michael@0: } michael@0: if (item.size != sizeof(CK_ULONG)) { michael@0: *pError = CKR_ATTRIBUTE_VALUE_INVALID; michael@0: return (CK_ULONG) 0; michael@0: } michael@0: return *(CK_ULONG *)item.data; michael@0: } michael@0: michael@0: /* michael@0: * get an attribute which is type CK_BBOOL. michael@0: */ michael@0: CK_BBOOL michael@0: nss_ckmk_GetBoolAttribute michael@0: ( michael@0: CK_ATTRIBUTE_TYPE type, michael@0: CK_ATTRIBUTE *template, michael@0: CK_ULONG templateSize, michael@0: CK_BBOOL defaultBool michael@0: ) michael@0: { michael@0: NSSItem item; michael@0: CK_RV error; michael@0: michael@0: error = nss_ckmk_GetAttribute(type, template, templateSize, &item); michael@0: if (CKR_OK != error) { michael@0: return defaultBool; michael@0: } michael@0: if (item.size != sizeof(CK_BBOOL)) { michael@0: return defaultBool; michael@0: } michael@0: return *(CK_BBOOL *)item.data; michael@0: } michael@0: michael@0: /* michael@0: * get an attribute as a NULL terminated string. Caller is responsible to michael@0: * free the string. michael@0: */ michael@0: char * michael@0: nss_ckmk_GetStringAttribute michael@0: ( michael@0: CK_ATTRIBUTE_TYPE type, michael@0: CK_ATTRIBUTE *template, michael@0: CK_ULONG templateSize, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: NSSItem item; michael@0: char *str; michael@0: michael@0: /* get the attribute */ michael@0: *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item); michael@0: if (CKR_OK != *pError) { michael@0: return (char *)NULL; michael@0: } michael@0: /* make sure it is null terminated */ michael@0: str = nss_ZNEWARRAY(NULL, char, item.size+1); michael@0: if ((char *)NULL == str) { michael@0: *pError = CKR_HOST_MEMORY; michael@0: return (char *)NULL; michael@0: } michael@0: michael@0: nsslibc_memcpy(str, item.data, item.size); michael@0: str[item.size] = 0; michael@0: michael@0: return str; michael@0: } michael@0: michael@0: /* michael@0: * Apple doesn't seem to have a public interface to the DER encoder, michael@0: * wip out a quick one for integers only (anything more complicated, michael@0: * we should use one of the 3 in lib/util). -- especially since we michael@0: * now link with it. michael@0: */ michael@0: static CK_RV michael@0: ckmk_encodeInt(NSSItem *dest, void *src, int srcLen) michael@0: { michael@0: int dataLen = srcLen; michael@0: int lenLen = 1; michael@0: int encLen; michael@0: int isSigned = 0; michael@0: int offset = 0; michael@0: unsigned char *data = NULL; michael@0: int i; michael@0: michael@0: if (*(unsigned char *)src & 0x80) { michael@0: dataLen++; michael@0: isSigned = 1; michael@0: } michael@0: michael@0: /* calculate the length of the length specifier */ michael@0: /* (NOTE: destroys dataLen value) */ michael@0: if (dataLen > 0x7f) { michael@0: do { michael@0: lenLen++; michael@0: dataLen >>= 8; michael@0: } while (dataLen); michael@0: } michael@0: michael@0: /* calculate our total length */ michael@0: dataLen = isSigned + srcLen; michael@0: encLen = 1 + lenLen + dataLen; michael@0: data = nss_ZNEWARRAY(NULL, unsigned char, encLen); michael@0: if ((unsigned char *)NULL == data) { michael@0: return CKR_HOST_MEMORY; michael@0: } michael@0: data[0] = DER_INTEGER; michael@0: if (1 == lenLen) { michael@0: data[1] = dataLen; michael@0: } else { michael@0: data[1] = 0x80 + lenLen; michael@0: for (i=0; i < lenLen; i++) { michael@0: data[i+1] = ((dataLen >> ((lenLen-i-1)*8)) & 0xff); michael@0: } michael@0: } michael@0: offset = lenLen+1; michael@0: michael@0: if (isSigned) { michael@0: data[offset++] = 0; michael@0: } michael@0: nsslibc_memcpy(&data[offset], src, srcLen); michael@0: dest->data = data; michael@0: dest->size = encLen; michael@0: return CKR_OK; michael@0: } michael@0: michael@0: michael@0: /* michael@0: * Get a Keyring attribute. If content is set to true, then we get the michael@0: * content, not the attribute. michael@0: */ michael@0: static CK_RV michael@0: ckmk_GetCommonAttribute michael@0: ( michael@0: ckmkInternalObject *io, michael@0: SecItemAttr itemAttr, michael@0: PRBool content, michael@0: NSSItem *item, michael@0: char *dbString michael@0: ) michael@0: { michael@0: SecKeychainAttributeList *attrList = NULL; michael@0: SecKeychainAttributeInfo attrInfo; michael@0: PRUint32 len = 0; michael@0: PRUint32 dataLen = 0; michael@0: PRUint32 attrFormat = 0; michael@0: void *dataVal = 0; michael@0: void *out = NULL; michael@0: CK_RV error = CKR_OK; michael@0: OSStatus macErr; michael@0: michael@0: attrInfo.count = 1; michael@0: attrInfo.tag = &itemAttr; michael@0: attrInfo.format = &attrFormat; michael@0: michael@0: macErr = SecKeychainItemCopyAttributesAndData(io->u.item.itemRef, michael@0: &attrInfo, NULL, &attrList, &len, &out); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR(dbString, macErr); michael@0: return CKR_ATTRIBUTE_TYPE_INVALID; michael@0: } michael@0: dataLen = content ? len : attrList->attr->length; michael@0: dataVal = content ? out : attrList->attr->data; michael@0: michael@0: /* Apple's documentation says this value is DER Encoded, but it clearly isn't michael@0: * der encode it before we ship it back off to NSS michael@0: */ michael@0: if ( kSecSerialNumberItemAttr == itemAttr ) { michael@0: error = ckmk_encodeInt(item, dataVal, dataLen); michael@0: goto loser; /* logically 'done' if error == CKR_OK */ michael@0: } michael@0: item->data = nss_ZNEWARRAY(NULL, char, dataLen); michael@0: if (NULL == item->data) { michael@0: error = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: nsslibc_memcpy(item->data, dataVal, dataLen); michael@0: item->size = dataLen; michael@0: michael@0: loser: michael@0: SecKeychainItemFreeAttributesAndData(attrList, out); michael@0: return error; michael@0: } michael@0: michael@0: /* michael@0: * change an attribute (does not operate on the content). michael@0: */ michael@0: static CK_RV michael@0: ckmk_updateAttribute michael@0: ( michael@0: SecKeychainItemRef itemRef, michael@0: SecItemAttr itemAttr, michael@0: void *data, michael@0: PRUint32 len, michael@0: char *dbString michael@0: ) michael@0: { michael@0: SecKeychainAttributeList attrList; michael@0: SecKeychainAttribute attrAttr; michael@0: OSStatus macErr; michael@0: CK_RV error = CKR_OK; michael@0: michael@0: attrList.count = 1; michael@0: attrList.attr = &attrAttr; michael@0: attrAttr.tag = itemAttr; michael@0: attrAttr.data = data; michael@0: attrAttr.length = len; michael@0: macErr = SecKeychainItemModifyAttributesAndData(itemRef, &attrList, 0, NULL); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR(dbString, macErr); michael@0: error = CKR_ATTRIBUTE_TYPE_INVALID; michael@0: } michael@0: return error; michael@0: } michael@0: michael@0: /* michael@0: * get an attribute (does not operate on the content) michael@0: */ michael@0: static CK_RV michael@0: ckmk_GetDataAttribute michael@0: ( michael@0: ckmkInternalObject *io, michael@0: SecItemAttr itemAttr, michael@0: NSSItem *item, michael@0: char *dbString michael@0: ) michael@0: { michael@0: return ckmk_GetCommonAttribute(io, itemAttr, PR_FALSE, item, dbString); michael@0: } michael@0: michael@0: /* michael@0: * get an attribute we know is a BOOL. michael@0: */ michael@0: static CK_RV michael@0: ckmk_GetBoolAttribute michael@0: ( michael@0: ckmkInternalObject *io, michael@0: SecItemAttr itemAttr, michael@0: NSSItem *item, michael@0: char *dbString michael@0: ) michael@0: { michael@0: SecKeychainAttribute attr; michael@0: SecKeychainAttributeList attrList; michael@0: CK_BBOOL *boolp = NULL; michael@0: PRUint32 len = 0;; michael@0: void *out = NULL; michael@0: CK_RV error = CKR_OK; michael@0: OSStatus macErr; michael@0: michael@0: attr.tag = itemAttr; michael@0: attr.length = 0; michael@0: attr.data = NULL; michael@0: attrList.count = 1; michael@0: attrList.attr = &attr; michael@0: michael@0: boolp = nss_ZNEW(NULL, CK_BBOOL); michael@0: if ((CK_BBOOL *)NULL == boolp) { michael@0: error = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: michael@0: macErr = SecKeychainItemCopyContent(io->u.item.itemRef, NULL, michael@0: &attrList, &len, &out); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR(dbString, macErr); michael@0: error = CKR_ATTRIBUTE_TYPE_INVALID; michael@0: goto loser; michael@0: } michael@0: if (sizeof(PRUint32) != attr.length) { michael@0: error = CKR_ATTRIBUTE_TYPE_INVALID; michael@0: goto loser; michael@0: } michael@0: *boolp = *(PRUint32 *)attr.data ? 1 : 0; michael@0: item->data = boolp; michael@0: boolp = NULL; michael@0: item->size = sizeof(CK_BBOOL); michael@0: michael@0: loser: michael@0: nss_ZFreeIf(boolp); michael@0: SecKeychainItemFreeContent(&attrList, out); michael@0: return error; michael@0: } michael@0: michael@0: michael@0: /* michael@0: * macros for fetching attributes into a cache and returning the michael@0: * appropriate value. These operate inside switch statements michael@0: */ michael@0: #define CKMK_HANDLE_ITEM(func, io, type, loc, item, error, str) \ michael@0: if (0 == (item)->loc.size) { \ michael@0: error = func(io, type, &(item)->loc, str); \ michael@0: } \ michael@0: return (CKR_OK == (error)) ? &(item)->loc : NULL; michael@0: michael@0: #define CKMK_HANDLE_OPT_ITEM(func, io, type, loc, item, error, str) \ michael@0: if (0 == (item)->loc.size) { \ michael@0: (void) func(io, type, &(item)->loc, str); \ michael@0: } \ michael@0: return &(item)->loc ; michael@0: michael@0: #define CKMK_HANDLE_BOOL_ITEM(io, type, loc, item, error, str) \ michael@0: CKMK_HANDLE_ITEM(ckmk_GetBoolAttribute, io, type, loc, item, error, str) michael@0: #define CKMK_HANDLE_DATA_ITEM(io, type, loc, item, error, str) \ michael@0: CKMK_HANDLE_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str) michael@0: #define CKMK_HANDLE_OPT_DATA_ITEM(io, type, loc, item, error, str) \ michael@0: CKMK_HANDLE_OPT_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str) michael@0: michael@0: /* michael@0: * fetch the unique identifier for each object type. michael@0: */ michael@0: static void michael@0: ckmk_FetchHashKey michael@0: ( michael@0: ckmkInternalObject *io michael@0: ) michael@0: { michael@0: NSSItem *key = &io->hashKey; michael@0: michael@0: if (io->objClass == CKO_CERTIFICATE) { michael@0: ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr, michael@0: PR_TRUE, key, "Fetching HashKey (cert)"); michael@0: } else { michael@0: ckmk_GetCommonAttribute(io, kSecKeyLabel, michael@0: PR_FALSE, key, "Fetching HashKey (key)"); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * Apple mucks with the actual subject and issuer, so go fetch michael@0: * the real ones ourselves. michael@0: */ michael@0: static void michael@0: ckmk_fetchCert michael@0: ( michael@0: ckmkInternalObject *io michael@0: ) michael@0: { michael@0: CK_RV error; michael@0: unsigned char * cert, *next; michael@0: int certSize, thisEntrySize; michael@0: michael@0: error = ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr, PR_TRUE, michael@0: &io->u.item.derCert, "Fetching Value (cert)"); michael@0: if (CKR_OK != error) { michael@0: return; michael@0: } michael@0: /* unwrap the cert bundle */ michael@0: cert = nss_ckmk_DERUnwrap((unsigned char *)io->u.item.derCert.data, michael@0: io->u.item.derCert.size, michael@0: &certSize, NULL); michael@0: /* unwrap the cert itself */ michael@0: /* cert == certdata */ michael@0: cert = nss_ckmk_DERUnwrap(cert, certSize, &certSize, NULL); michael@0: michael@0: /* skip the optional version */ michael@0: if ((cert[0] & 0xa0) == 0xa0) { michael@0: nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); michael@0: certSize -= next - cert; michael@0: cert = next; michael@0: } michael@0: /* skip the serial number */ michael@0: nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); michael@0: certSize -= next - cert; michael@0: cert = next; michael@0: michael@0: /* skip the OID */ michael@0: nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); michael@0: certSize -= next - cert; michael@0: cert = next; michael@0: michael@0: /* save the (wrapped) issuer */ michael@0: io->u.item.issuer.data = cert; michael@0: nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); michael@0: io->u.item.issuer.size = next - cert; michael@0: certSize -= io->u.item.issuer.size; michael@0: cert = next; michael@0: michael@0: /* skip the OID */ michael@0: nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); michael@0: certSize -= next - cert; michael@0: cert = next; michael@0: michael@0: /* save the (wrapped) subject */ michael@0: io->u.item.subject.data = cert; michael@0: nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); michael@0: io->u.item.subject.size = next - cert; michael@0: certSize -= io->u.item.subject.size; michael@0: cert = next; michael@0: } michael@0: michael@0: static void michael@0: ckmk_fetchModulus michael@0: ( michael@0: ckmkInternalObject *io michael@0: ) michael@0: { michael@0: NSSItem item; michael@0: PRInt32 modLen; michael@0: CK_RV error; michael@0: michael@0: /* we can't reliably get the modulus for private keys through CSSM (sigh). michael@0: * For NSS this is OK because we really only use this to get the modulus michael@0: * length (unless we are trying to get a public key from a private keys, michael@0: * something CSSM ALSO does not do!). michael@0: */ michael@0: error = ckmk_GetDataAttribute(io, kSecKeyKeySizeInBits, &item, michael@0: "Key Fetch Modulus"); michael@0: if (CKR_OK != error) { michael@0: return; michael@0: } michael@0: michael@0: modLen = *(PRInt32 *)item.data; michael@0: modLen = modLen/8; /* convert from bits to bytes */ michael@0: michael@0: nss_ZFreeIf(item.data); michael@0: io->u.item.modulus.data = nss_ZNEWARRAY(NULL, char, modLen); michael@0: if (NULL == io->u.item.modulus.data) { michael@0: return; michael@0: } michael@0: *(char *)io->u.item.modulus.data = 0x80; /* fake NSS out or it will michael@0: * drop the first byte */ michael@0: io->u.item.modulus.size = modLen; michael@0: return; michael@0: } michael@0: michael@0: const NSSItem * michael@0: ckmk_FetchCertAttribute michael@0: ( michael@0: ckmkInternalObject *io, michael@0: CK_ATTRIBUTE_TYPE type, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: ckmkItemObject *item = &io->u.item; michael@0: *pError = CKR_OK; michael@0: switch(type) { michael@0: case CKA_CLASS: michael@0: return &ckmk_certClassItem; michael@0: case CKA_TOKEN: michael@0: case CKA_MODIFIABLE: michael@0: return &ckmk_trueItem; michael@0: case CKA_PRIVATE: michael@0: return &ckmk_falseItem; michael@0: case CKA_CERTIFICATE_TYPE: michael@0: return &ckmk_x509Item; michael@0: case CKA_LABEL: michael@0: CKMK_HANDLE_OPT_DATA_ITEM(io, kSecLabelItemAttr, label, item, *pError, michael@0: "Cert:Label attr") michael@0: case CKA_SUBJECT: michael@0: /* OK, well apple does provide an subject and issuer attribute, but they michael@0: * decided to cannonicalize that value. Probably a good move for them, michael@0: * but makes it useless for most users of PKCS #11.. Get the real subject michael@0: * from the certificate */ michael@0: if (0 == item->derCert.size) { michael@0: ckmk_fetchCert(io); michael@0: } michael@0: return &item->subject; michael@0: case CKA_ISSUER: michael@0: if (0 == item->derCert.size) { michael@0: ckmk_fetchCert(io); michael@0: } michael@0: return &item->issuer; michael@0: case CKA_SERIAL_NUMBER: michael@0: CKMK_HANDLE_DATA_ITEM(io, kSecSerialNumberItemAttr, serial, item, *pError, michael@0: "Cert:Serial Number attr") michael@0: case CKA_VALUE: michael@0: if (0 == item->derCert.size) { michael@0: ckmk_fetchCert(io); michael@0: } michael@0: return &item->derCert; michael@0: case CKA_ID: michael@0: CKMK_HANDLE_OPT_DATA_ITEM(io, kSecPublicKeyHashItemAttr, id, item, *pError, michael@0: "Cert:ID attr") michael@0: default: michael@0: *pError = CKR_ATTRIBUTE_TYPE_INVALID; michael@0: break; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: const NSSItem * michael@0: ckmk_FetchPubKeyAttribute michael@0: ( michael@0: ckmkInternalObject *io, michael@0: CK_ATTRIBUTE_TYPE type, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: ckmkItemObject *item = &io->u.item; michael@0: *pError = CKR_OK; michael@0: michael@0: switch(type) { michael@0: case CKA_CLASS: michael@0: return &ckmk_pubKeyClassItem; michael@0: case CKA_TOKEN: michael@0: case CKA_LOCAL: michael@0: return &ckmk_trueItem; michael@0: case CKA_KEY_TYPE: michael@0: return &ckmk_rsaItem; michael@0: case CKA_LABEL: michael@0: CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError, michael@0: "PubKey:Label attr") michael@0: case CKA_ENCRYPT: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyEncrypt, encrypt, item, *pError, michael@0: "PubKey:Encrypt attr") michael@0: case CKA_VERIFY: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerify, verify, item, *pError, michael@0: "PubKey:Verify attr") michael@0: case CKA_VERIFY_RECOVER: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerifyRecover, verifyRecover, michael@0: item, *pError, "PubKey:VerifyRecover attr") michael@0: case CKA_PRIVATE: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError, michael@0: "PubKey:Private attr") michael@0: case CKA_MODIFIABLE: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError, michael@0: "PubKey:Modify attr") michael@0: case CKA_DERIVE: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError, michael@0: "PubKey:Derive attr") michael@0: case CKA_WRAP: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyWrap, wrap, item, *pError, michael@0: "PubKey:Wrap attr") michael@0: case CKA_SUBJECT: michael@0: CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError, michael@0: "PubKey:Subect attr") michael@0: case CKA_MODULUS: michael@0: return &ckmk_emptyItem; michael@0: case CKA_PUBLIC_EXPONENT: michael@0: return &ckmk_emptyItem; michael@0: case CKA_ID: michael@0: CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError, michael@0: "PubKey:ID attr") michael@0: default: michael@0: *pError = CKR_ATTRIBUTE_TYPE_INVALID; michael@0: break; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: const NSSItem * michael@0: ckmk_FetchPrivKeyAttribute michael@0: ( michael@0: ckmkInternalObject *io, michael@0: CK_ATTRIBUTE_TYPE type, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: ckmkItemObject *item = &io->u.item; michael@0: *pError = CKR_OK; michael@0: michael@0: switch(type) { michael@0: case CKA_CLASS: michael@0: return &ckmk_privKeyClassItem; michael@0: case CKA_TOKEN: michael@0: case CKA_LOCAL: michael@0: return &ckmk_trueItem; michael@0: case CKA_SENSITIVE: michael@0: case CKA_EXTRACTABLE: /* will probably move in the future */ michael@0: case CKA_ALWAYS_SENSITIVE: michael@0: case CKA_NEVER_EXTRACTABLE: michael@0: return &ckmk_falseItem; michael@0: case CKA_KEY_TYPE: michael@0: return &ckmk_rsaItem; michael@0: case CKA_LABEL: michael@0: CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError, michael@0: "PrivateKey:Label attr") michael@0: case CKA_DECRYPT: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDecrypt, decrypt, item, *pError, michael@0: "PrivateKey:Decrypt attr") michael@0: case CKA_SIGN: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeySign, sign, item, *pError, michael@0: "PrivateKey:Sign attr") michael@0: case CKA_SIGN_RECOVER: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeySignRecover, signRecover, item, *pError, michael@0: "PrivateKey:Sign Recover attr") michael@0: case CKA_PRIVATE: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError, michael@0: "PrivateKey:Private attr") michael@0: case CKA_MODIFIABLE: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError, michael@0: "PrivateKey:Modify attr") michael@0: case CKA_DERIVE: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError, michael@0: "PrivateKey:Derive attr") michael@0: case CKA_UNWRAP: michael@0: CKMK_HANDLE_BOOL_ITEM(io, kSecKeyUnwrap, unwrap, item, *pError, michael@0: "PrivateKey:Unwrap attr") michael@0: case CKA_SUBJECT: michael@0: CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError, michael@0: "PrivateKey:Subject attr") michael@0: case CKA_MODULUS: michael@0: if (0 == item->modulus.size) { michael@0: ckmk_fetchModulus(io); michael@0: } michael@0: return &item->modulus; michael@0: case CKA_PUBLIC_EXPONENT: michael@0: return &ckmk_emptyItem; michael@0: #ifdef notdef michael@0: /* the following are sensitive attributes. We could implement them for michael@0: * sensitive keys using the key export function, but it's better to michael@0: * just support wrap through this token. That will more reliably allow us michael@0: * to export any private key that is truly exportable. michael@0: */ michael@0: case CKA_PRIVATE_EXPONENT: michael@0: CKMK_HANDLE_DATA_ITEM(io, kSecPrivateExponentItemAttr, privateExponent, michael@0: item, *pError) michael@0: case CKA_PRIME_1: michael@0: CKMK_HANDLE_DATA_ITEM(io, kSecPrime1ItemAttr, prime1, item, *pError) michael@0: case CKA_PRIME_2: michael@0: CKMK_HANDLE_DATA_ITEM(io, kSecPrime2ItemAttr, prime2, item, *pError) michael@0: case CKA_EXPONENT_1: michael@0: CKMK_HANDLE_DATA_ITEM(io, kSecExponent1ItemAttr, exponent1, item, *pError) michael@0: case CKA_EXPONENT_2: michael@0: CKMK_HANDLE_DATA_ITEM(io, kSecExponent2ItemAttr, exponent2, item, *pError) michael@0: case CKA_COEFFICIENT: michael@0: CKMK_HANDLE_DATA_ITEM(io, kSecCoefficientItemAttr, coefficient, michael@0: item, *pError) michael@0: #endif michael@0: case CKA_ID: michael@0: CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError, michael@0: "PrivateKey:ID attr") michael@0: default: michael@0: *pError = CKR_ATTRIBUTE_TYPE_INVALID; michael@0: return NULL; michael@0: } michael@0: } michael@0: michael@0: const NSSItem * michael@0: nss_ckmk_FetchAttribute michael@0: ( michael@0: ckmkInternalObject *io, michael@0: CK_ATTRIBUTE_TYPE type, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: CK_ULONG i; michael@0: const NSSItem * value = NULL; michael@0: michael@0: if (io->type == ckmkRaw) { michael@0: for( i = 0; i < io->u.raw.n; i++ ) { michael@0: if( type == io->u.raw.types[i] ) { michael@0: return &io->u.raw.items[i]; michael@0: } michael@0: } michael@0: *pError = CKR_ATTRIBUTE_TYPE_INVALID; michael@0: return NULL; michael@0: } michael@0: /* deal with the common attributes */ michael@0: switch (io->objClass) { michael@0: case CKO_CERTIFICATE: michael@0: value = ckmk_FetchCertAttribute(io, type, pError); michael@0: break; michael@0: case CKO_PRIVATE_KEY: michael@0: value = ckmk_FetchPrivKeyAttribute(io, type, pError); michael@0: break; michael@0: case CKO_PUBLIC_KEY: michael@0: value = ckmk_FetchPubKeyAttribute(io, type, pError); michael@0: break; michael@0: default: michael@0: *pError = CKR_OBJECT_HANDLE_INVALID; michael@0: return NULL; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: if (CKA_ID == type) { michael@0: itemdump("id: ", value->data, value->size, *pError); michael@0: } michael@0: #endif michael@0: return value; michael@0: } michael@0: michael@0: static void michael@0: ckmk_removeObjectFromHash michael@0: ( michael@0: ckmkInternalObject *io michael@0: ); michael@0: michael@0: /* michael@0: * michael@0: * These are the MSObject functions we need to implement michael@0: * michael@0: * Finalize - unneeded (actually we should clean up the hashtables) michael@0: * Destroy michael@0: * IsTokenObject - CK_TRUE michael@0: * GetAttributeCount michael@0: * GetAttributeTypes michael@0: * GetAttributeSize michael@0: * GetAttribute michael@0: * SetAttribute michael@0: * GetObjectSize michael@0: */ michael@0: michael@0: static CK_RV michael@0: ckmk_mdObject_Destroy michael@0: ( michael@0: NSSCKMDObject *mdObject, michael@0: NSSCKFWObject *fwObject, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance michael@0: ) michael@0: { michael@0: ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; michael@0: OSStatus macErr; michael@0: michael@0: if (ckmkRaw == io->type) { michael@0: /* there is not 'object write protected' error, use the next best thing */ michael@0: return CKR_TOKEN_WRITE_PROTECTED; michael@0: } michael@0: michael@0: /* This API is done well. The following 4 lines are the complete apple michael@0: * specific part of this implementation */ michael@0: macErr = SecKeychainItemDelete(io->u.item.itemRef); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR("Delete object", macErr); michael@0: } michael@0: michael@0: /* remove it from the hash */ michael@0: ckmk_removeObjectFromHash(io); michael@0: michael@0: /* free the puppy.. */ michael@0: nss_ckmk_DestroyInternalObject(io); michael@0: michael@0: return CKR_OK; michael@0: } michael@0: michael@0: static CK_BBOOL michael@0: ckmk_mdObject_IsTokenObject michael@0: ( michael@0: NSSCKMDObject *mdObject, michael@0: NSSCKFWObject *fwObject, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance michael@0: ) michael@0: { michael@0: return CK_TRUE; michael@0: } michael@0: michael@0: static CK_ULONG michael@0: ckmk_mdObject_GetAttributeCount michael@0: ( michael@0: NSSCKMDObject *mdObject, michael@0: NSSCKFWObject *fwObject, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; michael@0: michael@0: if (ckmkRaw == io->type) { michael@0: return io->u.raw.n; michael@0: } michael@0: switch (io->objClass) { michael@0: case CKO_CERTIFICATE: michael@0: return certAttrsCount; michael@0: case CKO_PUBLIC_KEY: michael@0: return pubKeyAttrsCount; michael@0: case CKO_PRIVATE_KEY: michael@0: return privKeyAttrsCount; michael@0: default: michael@0: break; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: static CK_RV michael@0: ckmk_mdObject_GetAttributeTypes michael@0: ( michael@0: NSSCKMDObject *mdObject, michael@0: NSSCKFWObject *fwObject, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: CK_ATTRIBUTE_TYPE_PTR typeArray, michael@0: CK_ULONG ulCount michael@0: ) michael@0: { michael@0: ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; michael@0: CK_ULONG i; michael@0: CK_RV error = CKR_OK; michael@0: const CK_ATTRIBUTE_TYPE *attrs = NULL; michael@0: CK_ULONG size = ckmk_mdObject_GetAttributeCount( michael@0: mdObject, fwObject, mdSession, fwSession, michael@0: mdToken, fwToken, mdInstance, fwInstance, &error); michael@0: michael@0: if( size != ulCount ) { michael@0: return CKR_BUFFER_TOO_SMALL; michael@0: } michael@0: if (io->type == ckmkRaw) { michael@0: attrs = io->u.raw.types; michael@0: } else switch(io->objClass) { michael@0: case CKO_CERTIFICATE: michael@0: attrs = certAttrs; michael@0: break; michael@0: case CKO_PUBLIC_KEY: michael@0: attrs = pubKeyAttrs; michael@0: break; michael@0: case CKO_PRIVATE_KEY: michael@0: attrs = privKeyAttrs; michael@0: break; michael@0: default: michael@0: return CKR_OK; michael@0: } michael@0: michael@0: for( i = 0; i < size; i++) { michael@0: typeArray[i] = attrs[i]; michael@0: } michael@0: michael@0: return CKR_OK; michael@0: } michael@0: michael@0: static CK_ULONG michael@0: ckmk_mdObject_GetAttributeSize michael@0: ( michael@0: NSSCKMDObject *mdObject, michael@0: NSSCKFWObject *fwObject, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: CK_ATTRIBUTE_TYPE attribute, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; michael@0: michael@0: const NSSItem *b; michael@0: michael@0: b = nss_ckmk_FetchAttribute(io, attribute, pError); michael@0: michael@0: if ((const NSSItem *)NULL == b) { michael@0: return 0; michael@0: } michael@0: return b->size; michael@0: } michael@0: michael@0: static CK_RV michael@0: ckmk_mdObject_SetAttribute michael@0: ( michael@0: NSSCKMDObject *mdObject, michael@0: NSSCKFWObject *fwObject, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: CK_ATTRIBUTE_TYPE attribute, michael@0: NSSItem *value michael@0: ) michael@0: { michael@0: ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; michael@0: SecKeychainItemRef itemRef; michael@0: michael@0: if (io->type == ckmkRaw) { michael@0: return CKR_TOKEN_WRITE_PROTECTED; michael@0: } michael@0: itemRef = io->u.item.itemRef; michael@0: michael@0: switch (io->objClass) { michael@0: case CKO_PRIVATE_KEY: michael@0: case CKO_PUBLIC_KEY: michael@0: switch (attribute) { michael@0: case CKA_ID: michael@0: ckmk_updateAttribute(itemRef, kSecKeyLabel, michael@0: value->data, value->size, "Set Attr Key ID"); michael@0: #ifdef DEBUG michael@0: itemdump("key id: ", value->data, value->size, CKR_OK); michael@0: #endif michael@0: break; michael@0: case CKA_LABEL: michael@0: ckmk_updateAttribute(itemRef, kSecKeyPrintName, value->data, michael@0: value->size, "Set Attr Key Label"); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: break; michael@0: michael@0: case CKO_CERTIFICATE: michael@0: switch (attribute) { michael@0: case CKA_ID: michael@0: ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr, michael@0: value->data, value->size, "Set Attr Cert ID"); michael@0: break; michael@0: case CKA_LABEL: michael@0: ckmk_updateAttribute(itemRef, kSecLabelItemAttr, value->data, michael@0: value->size, "Set Attr Cert Label"); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: break; michael@0: } michael@0: return CKR_OK; michael@0: } michael@0: michael@0: static NSSCKFWItem michael@0: ckmk_mdObject_GetAttribute michael@0: ( michael@0: NSSCKMDObject *mdObject, michael@0: NSSCKFWObject *fwObject, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: CK_ATTRIBUTE_TYPE attribute, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: NSSCKFWItem mdItem; michael@0: ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; michael@0: michael@0: mdItem.needsFreeing = PR_FALSE; michael@0: mdItem.item = (NSSItem*)nss_ckmk_FetchAttribute(io, attribute, pError); michael@0: michael@0: michael@0: return mdItem; michael@0: } michael@0: michael@0: static CK_ULONG michael@0: ckmk_mdObject_GetObjectSize michael@0: ( michael@0: NSSCKMDObject *mdObject, michael@0: NSSCKFWObject *fwObject, michael@0: NSSCKMDSession *mdSession, michael@0: NSSCKFWSession *fwSession, michael@0: NSSCKMDToken *mdToken, michael@0: NSSCKFWToken *fwToken, michael@0: NSSCKMDInstance *mdInstance, michael@0: NSSCKFWInstance *fwInstance, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: CK_ULONG rv = 1; michael@0: michael@0: /* size is irrelevant to this token */ michael@0: return rv; michael@0: } michael@0: michael@0: static const NSSCKMDObject michael@0: ckmk_prototype_mdObject = { michael@0: (void *)NULL, /* etc */ michael@0: NULL, /* Finalize */ michael@0: ckmk_mdObject_Destroy, michael@0: ckmk_mdObject_IsTokenObject, michael@0: ckmk_mdObject_GetAttributeCount, michael@0: ckmk_mdObject_GetAttributeTypes, michael@0: ckmk_mdObject_GetAttributeSize, michael@0: ckmk_mdObject_GetAttribute, michael@0: NULL, /* FreeAttribute */ michael@0: ckmk_mdObject_SetAttribute, michael@0: ckmk_mdObject_GetObjectSize, michael@0: (void *)NULL /* null terminator */ michael@0: }; michael@0: michael@0: static nssHash *ckmkInternalObjectHash = NULL; michael@0: michael@0: NSS_IMPLEMENT NSSCKMDObject * michael@0: nss_ckmk_CreateMDObject michael@0: ( michael@0: NSSArena *arena, michael@0: ckmkInternalObject *io, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: if ((nssHash *)NULL == ckmkInternalObjectHash) { michael@0: ckmkInternalObjectHash = nssHash_CreateItem(NULL, 10); michael@0: } michael@0: if (ckmkItem == io->type) { michael@0: /* the hash key, not a cryptographic key */ michael@0: NSSItem *key = &io->hashKey; michael@0: ckmkInternalObject *old_o = NULL; michael@0: michael@0: if (key->size == 0) { michael@0: ckmk_FetchHashKey(io); michael@0: } michael@0: old_o = (ckmkInternalObject *) michael@0: nssHash_Lookup(ckmkInternalObjectHash, key); michael@0: if (!old_o) { michael@0: nssHash_Add(ckmkInternalObjectHash, key, io); michael@0: } else if (old_o != io) { michael@0: nss_ckmk_DestroyInternalObject(io); michael@0: io = old_o; michael@0: } michael@0: } michael@0: michael@0: if ( (void*)NULL == io->mdObject.etc) { michael@0: (void) nsslibc_memcpy(&io->mdObject,&ckmk_prototype_mdObject, michael@0: sizeof(ckmk_prototype_mdObject)); michael@0: io->mdObject.etc = (void *)io; michael@0: } michael@0: return &io->mdObject; michael@0: } michael@0: michael@0: static void michael@0: ckmk_removeObjectFromHash michael@0: ( michael@0: ckmkInternalObject *io michael@0: ) michael@0: { michael@0: NSSItem *key = &io->hashKey; michael@0: michael@0: if ((nssHash *)NULL == ckmkInternalObjectHash) { michael@0: return; michael@0: } michael@0: if (key->size == 0) { michael@0: ckmk_FetchHashKey(io); michael@0: } michael@0: nssHash_Remove(ckmkInternalObjectHash, key); michael@0: return; michael@0: } michael@0: michael@0: michael@0: void michael@0: nss_ckmk_DestroyInternalObject michael@0: ( michael@0: ckmkInternalObject *io michael@0: ) michael@0: { michael@0: switch (io->type) { michael@0: case ckmkRaw: michael@0: return; michael@0: case ckmkItem: michael@0: nss_ZFreeIf(io->u.item.modify.data); michael@0: nss_ZFreeIf(io->u.item.private.data); michael@0: nss_ZFreeIf(io->u.item.encrypt.data); michael@0: nss_ZFreeIf(io->u.item.decrypt.data); michael@0: nss_ZFreeIf(io->u.item.derive.data); michael@0: nss_ZFreeIf(io->u.item.sign.data); michael@0: nss_ZFreeIf(io->u.item.signRecover.data); michael@0: nss_ZFreeIf(io->u.item.verify.data); michael@0: nss_ZFreeIf(io->u.item.verifyRecover.data); michael@0: nss_ZFreeIf(io->u.item.wrap.data); michael@0: nss_ZFreeIf(io->u.item.unwrap.data); michael@0: nss_ZFreeIf(io->u.item.label.data); michael@0: /*nss_ZFreeIf(io->u.item.subject.data); */ michael@0: /*nss_ZFreeIf(io->u.item.issuer.data); */ michael@0: nss_ZFreeIf(io->u.item.serial.data); michael@0: nss_ZFreeIf(io->u.item.modulus.data); michael@0: nss_ZFreeIf(io->u.item.exponent.data); michael@0: nss_ZFreeIf(io->u.item.privateExponent.data); michael@0: nss_ZFreeIf(io->u.item.prime1.data); michael@0: nss_ZFreeIf(io->u.item.prime2.data); michael@0: nss_ZFreeIf(io->u.item.exponent1.data); michael@0: nss_ZFreeIf(io->u.item.exponent2.data); michael@0: nss_ZFreeIf(io->u.item.coefficient.data); michael@0: break; michael@0: } michael@0: nss_ZFreeIf(io); michael@0: return; michael@0: } michael@0: michael@0: michael@0: static ckmkInternalObject * michael@0: nss_ckmk_NewInternalObject michael@0: ( michael@0: CK_OBJECT_CLASS objClass, michael@0: SecKeychainItemRef itemRef, michael@0: SecItemClass itemClass, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: ckmkInternalObject *io = nss_ZNEW(NULL, ckmkInternalObject); michael@0: michael@0: if ((ckmkInternalObject *)NULL == io) { michael@0: *pError = CKR_HOST_MEMORY; michael@0: return io; michael@0: } michael@0: io->type = ckmkItem; michael@0: io->objClass = objClass; michael@0: io->u.item.itemRef = itemRef; michael@0: io->u.item.itemClass = itemClass; michael@0: return io; michael@0: } michael@0: michael@0: /* michael@0: * Apple doesn't alway have a default keyChain set by the OS, use the michael@0: * SearchList to try to find one. michael@0: */ michael@0: static CK_RV michael@0: ckmk_GetSafeDefaultKeychain michael@0: ( michael@0: SecKeychainRef *keychainRef michael@0: ) michael@0: { michael@0: OSStatus macErr; michael@0: CFArrayRef searchList = 0; michael@0: CK_RV error = CKR_OK; michael@0: michael@0: macErr = SecKeychainCopyDefault(keychainRef); michael@0: if (noErr != macErr) { michael@0: int searchCount = 0; michael@0: if (errSecNoDefaultKeychain != macErr) { michael@0: CKMK_MACERR("Getting default key chain", macErr); michael@0: error = CKR_GENERAL_ERROR; michael@0: goto loser; michael@0: } michael@0: /* ok, we don't have a default key chain, find one */ michael@0: macErr = SecKeychainCopySearchList(&searchList); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR("failed to find a keyring searchList", macErr); michael@0: error = CKR_DEVICE_REMOVED; michael@0: goto loser; michael@0: } michael@0: searchCount = CFArrayGetCount(searchList); michael@0: if (searchCount < 1) { michael@0: error = CKR_DEVICE_REMOVED; michael@0: goto loser; michael@0: } michael@0: *keychainRef = michael@0: (SecKeychainRef)CFRetain(CFArrayGetValueAtIndex(searchList, 0)); michael@0: if (0 == *keychainRef) { michael@0: error = CKR_DEVICE_REMOVED; michael@0: goto loser; michael@0: } michael@0: /* should we set it as default? */ michael@0: } michael@0: loser: michael@0: if (0 != searchList) { michael@0: CFRelease(searchList); michael@0: } michael@0: return error; michael@0: } michael@0: static ckmkInternalObject * michael@0: nss_ckmk_CreateCertificate michael@0: ( michael@0: NSSCKFWSession *fwSession, michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: NSSItem value; michael@0: ckmkInternalObject *io = NULL; michael@0: OSStatus macErr; michael@0: SecCertificateRef certRef; michael@0: SecKeychainItemRef itemRef; michael@0: SecKeychainRef keychainRef; michael@0: CSSM_DATA certData; michael@0: michael@0: *pError = nss_ckmk_GetAttribute(CKA_VALUE, pTemplate, michael@0: ulAttributeCount, &value); michael@0: if (CKR_OK != *pError) { michael@0: goto loser; michael@0: } michael@0: michael@0: certData.Data = value.data; michael@0: certData.Length = value.size; michael@0: macErr = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, michael@0: CSSM_CERT_ENCODING_BER, &certRef); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR("Create cert from data Failed", macErr); michael@0: *pError = CKR_GENERAL_ERROR; /* need to map macErr */ michael@0: goto loser; michael@0: } michael@0: michael@0: *pError = ckmk_GetSafeDefaultKeychain(&keychainRef); michael@0: if (CKR_OK != *pError) { michael@0: goto loser; michael@0: } michael@0: michael@0: macErr = SecCertificateAddToKeychain( certRef, keychainRef); michael@0: itemRef = (SecKeychainItemRef) certRef; michael@0: if (errSecDuplicateItem != macErr) { michael@0: NSSItem keyID = { NULL, 0 }; michael@0: char *nickname = NULL; michael@0: CK_RV dummy; michael@0: michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR("Add cert to keychain Failed", macErr); michael@0: *pError = CKR_GENERAL_ERROR; /* need to map macErr */ michael@0: goto loser; michael@0: } michael@0: /* these two are optional */ michael@0: nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate, michael@0: ulAttributeCount, &dummy); michael@0: /* we've added a new one, update the attributes in the key ring */ michael@0: if (nickname) { michael@0: ckmk_updateAttribute(itemRef, kSecLabelItemAttr, nickname, michael@0: strlen(nickname)+1, "Modify Cert Label"); michael@0: nss_ZFreeIf(nickname); michael@0: } michael@0: dummy = nss_ckmk_GetAttribute(CKA_ID, pTemplate, michael@0: ulAttributeCount, &keyID); michael@0: if (CKR_OK == dummy) { michael@0: dummy = ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr, michael@0: keyID.data, keyID.size, "Modify Cert ID"); michael@0: } michael@0: } michael@0: michael@0: io = nss_ckmk_NewInternalObject(CKO_CERTIFICATE, itemRef, michael@0: kSecCertificateItemClass, pError); michael@0: if ((ckmkInternalObject *)NULL != io) { michael@0: itemRef = 0; michael@0: } michael@0: michael@0: loser: michael@0: if (0 != itemRef) { michael@0: CFRelease(itemRef); michael@0: } michael@0: if (0 != keychainRef) { michael@0: CFRelease(keychainRef); michael@0: } michael@0: michael@0: return io; michael@0: } michael@0: michael@0: /* michael@0: * PKCS #8 attributes michael@0: */ michael@0: struct ckmk_AttributeStr { michael@0: SECItem attrType; michael@0: SECItem *attrValue; michael@0: }; michael@0: typedef struct ckmk_AttributeStr ckmk_Attribute; michael@0: michael@0: /* michael@0: ** A PKCS#8 private key info object michael@0: */ michael@0: struct PrivateKeyInfoStr { michael@0: PLArenaPool *arena; michael@0: SECItem version; michael@0: SECAlgorithmID algorithm; michael@0: SECItem privateKey; michael@0: ckmk_Attribute **attributes; michael@0: }; michael@0: typedef struct PrivateKeyInfoStr PrivateKeyInfo; michael@0: michael@0: const SEC_ASN1Template ckmk_RSAPrivateKeyTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey) }, michael@0: { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,version) }, michael@0: { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,modulus) }, michael@0: { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,publicExponent) }, michael@0: { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,privateExponent) }, michael@0: { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,prime1) }, michael@0: { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,prime2) }, michael@0: { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,exponent1) }, michael@0: { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,exponent2) }, michael@0: { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,coefficient) }, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template ckmk_AttributeTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ckmk_Attribute) }, michael@0: { SEC_ASN1_OBJECT_ID, offsetof(ckmk_Attribute, attrType) }, michael@0: { SEC_ASN1_SET_OF, offsetof(ckmk_Attribute, attrValue), michael@0: SEC_AnyTemplate }, michael@0: { 0 } michael@0: }; michael@0: michael@0: const SEC_ASN1Template ckmk_SetOfAttributeTemplate[] = { michael@0: { SEC_ASN1_SET_OF, 0, ckmk_AttributeTemplate }, michael@0: }; michael@0: michael@0: SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) michael@0: michael@0: /* ASN1 Templates for new decoder/encoder */ michael@0: const SEC_ASN1Template ckmk_PrivateKeyInfoTemplate[] = { michael@0: { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PrivateKeyInfo) }, michael@0: { SEC_ASN1_INTEGER, offsetof(PrivateKeyInfo,version) }, michael@0: { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(PrivateKeyInfo,algorithm), michael@0: SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, michael@0: { SEC_ASN1_OCTET_STRING, offsetof(PrivateKeyInfo,privateKey) }, michael@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, michael@0: offsetof(PrivateKeyInfo, attributes), ckmk_SetOfAttributeTemplate }, michael@0: { 0 } michael@0: }; michael@0: michael@0: #define CKMK_PRIVATE_KEY_INFO_VERSION 0 michael@0: static CK_RV michael@0: ckmk_CreateRSAKeyBlob michael@0: ( michael@0: RSAPrivateKey *lk, michael@0: NSSItem *keyBlob michael@0: ) michael@0: { michael@0: PrivateKeyInfo *pki = NULL; michael@0: PLArenaPool *arena = NULL; michael@0: SECOidTag algorithm = SEC_OID_UNKNOWN; michael@0: void *dummy; michael@0: SECStatus rv; michael@0: SECItem *encodedKey = NULL; michael@0: CK_RV error = CKR_OK; michael@0: michael@0: arena = PORT_NewArena(2048); /* XXX different size? */ michael@0: if(!arena) { michael@0: error = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: michael@0: pki = (PrivateKeyInfo*)PORT_ArenaZAlloc(arena, sizeof(PrivateKeyInfo)); michael@0: if(!pki) { michael@0: error = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: pki->arena = arena; michael@0: michael@0: dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk, michael@0: ckmk_RSAPrivateKeyTemplate); michael@0: algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION; michael@0: michael@0: if (!dummy) { michael@0: error = CKR_DEVICE_ERROR; /* should map NSS SECError */ michael@0: goto loser; michael@0: } michael@0: michael@0: rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm, michael@0: (SECItem*)NULL); michael@0: if (rv != SECSuccess) { michael@0: error = CKR_DEVICE_ERROR; /* should map NSS SECError */ michael@0: goto loser; michael@0: } michael@0: michael@0: dummy = SEC_ASN1EncodeInteger(arena, &pki->version, michael@0: CKMK_PRIVATE_KEY_INFO_VERSION); michael@0: if (!dummy) { michael@0: error = CKR_DEVICE_ERROR; /* should map NSS SECError */ michael@0: goto loser; michael@0: } michael@0: michael@0: encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki, michael@0: ckmk_PrivateKeyInfoTemplate); michael@0: if (!encodedKey) { michael@0: error = CKR_DEVICE_ERROR; michael@0: goto loser; michael@0: } michael@0: michael@0: keyBlob->data = nss_ZNEWARRAY(NULL, char, encodedKey->len); michael@0: if (NULL == keyBlob->data) { michael@0: error = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: nsslibc_memcpy(keyBlob->data, encodedKey->data, encodedKey->len); michael@0: keyBlob->size = encodedKey->len; michael@0: michael@0: loser: michael@0: if(arena) { michael@0: PORT_FreeArena(arena, PR_TRUE); michael@0: } michael@0: if (encodedKey) { michael@0: SECITEM_FreeItem(encodedKey, PR_TRUE); michael@0: } michael@0: michael@0: return error; michael@0: } michael@0: /* michael@0: * There MUST be a better way to do this. For now, find the key based on the michael@0: * default name Apple gives it once we import. michael@0: */ michael@0: #define IMPORTED_NAME "Imported Private Key" michael@0: static CK_RV michael@0: ckmk_FindImportedKey michael@0: ( michael@0: SecKeychainRef keychainRef, michael@0: SecItemClass itemClass, michael@0: SecKeychainItemRef *outItemRef michael@0: ) michael@0: { michael@0: OSStatus macErr; michael@0: SecKeychainSearchRef searchRef = 0; michael@0: SecKeychainItemRef newItemRef; michael@0: michael@0: macErr = SecKeychainSearchCreateFromAttributes(keychainRef, itemClass, michael@0: NULL, &searchRef); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR("Can't search for Key", macErr); michael@0: return CKR_GENERAL_ERROR; michael@0: } michael@0: while (noErr == SecKeychainSearchCopyNext(searchRef, &newItemRef)) { michael@0: SecKeychainAttributeList *attrList = NULL; michael@0: SecKeychainAttributeInfo attrInfo; michael@0: SecItemAttr itemAttr = kSecKeyPrintName; michael@0: PRUint32 attrFormat = 0; michael@0: OSStatus macErr; michael@0: michael@0: attrInfo.count = 1; michael@0: attrInfo.tag = &itemAttr; michael@0: attrInfo.format = &attrFormat; michael@0: michael@0: macErr = SecKeychainItemCopyAttributesAndData(newItemRef, michael@0: &attrInfo, NULL, &attrList, NULL, NULL); michael@0: if (noErr == macErr) { michael@0: if (nsslibc_memcmp(attrList->attr->data, IMPORTED_NAME, michael@0: attrList->attr->length, NULL) == 0) { michael@0: *outItemRef = newItemRef; michael@0: CFRelease (searchRef); michael@0: SecKeychainItemFreeAttributesAndData(attrList, NULL); michael@0: return CKR_OK; michael@0: } michael@0: SecKeychainItemFreeAttributesAndData(attrList, NULL); michael@0: } michael@0: CFRelease(newItemRef); michael@0: } michael@0: CFRelease (searchRef); michael@0: return CKR_GENERAL_ERROR; /* we can come up with something better! */ michael@0: } michael@0: michael@0: static ckmkInternalObject * michael@0: nss_ckmk_CreatePrivateKey michael@0: ( michael@0: NSSCKFWSession *fwSession, michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: NSSItem attribute; michael@0: RSAPrivateKey lk; michael@0: NSSItem keyID; michael@0: char *nickname = NULL; michael@0: ckmkInternalObject *io = NULL; michael@0: CK_KEY_TYPE keyType; michael@0: OSStatus macErr; michael@0: SecKeychainItemRef itemRef = 0; michael@0: NSSItem keyBlob = { NULL, 0 }; michael@0: CFDataRef dataRef = 0; michael@0: SecExternalFormat inputFormat = kSecFormatBSAFE; michael@0: /*SecExternalFormat inputFormat = kSecFormatOpenSSL; */ michael@0: SecExternalItemType itemType = kSecItemTypePrivateKey; michael@0: SecKeyImportExportParameters keyParams ; michael@0: SecKeychainRef targetKeychain = 0; michael@0: unsigned char zero = 0; michael@0: CK_RV error; michael@0: michael@0: keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; michael@0: keyParams.flags = 0; michael@0: keyParams.passphrase = 0; michael@0: keyParams.alertTitle = 0; michael@0: keyParams.alertPrompt = 0; michael@0: keyParams.accessRef = 0; /* default */ michael@0: keyParams.keyUsage = 0; /* will get filled in */ michael@0: keyParams.keyAttributes = CSSM_KEYATTR_PERMANENT; /* will get filled in */ michael@0: keyType = nss_ckmk_GetULongAttribute michael@0: (CKA_KEY_TYPE, pTemplate, ulAttributeCount, pError); michael@0: if (CKR_OK != *pError) { michael@0: return (ckmkInternalObject *)NULL; michael@0: } michael@0: if (CKK_RSA != keyType) { michael@0: *pError = CKR_ATTRIBUTE_VALUE_INVALID; michael@0: return (ckmkInternalObject *)NULL; michael@0: } michael@0: if (nss_ckmk_GetBoolAttribute(CKA_DECRYPT, michael@0: pTemplate, ulAttributeCount, CK_TRUE)) { michael@0: keyParams.keyUsage |= CSSM_KEYUSE_DECRYPT; michael@0: } michael@0: if (nss_ckmk_GetBoolAttribute(CKA_UNWRAP, michael@0: pTemplate, ulAttributeCount, CK_TRUE)) { michael@0: keyParams.keyUsage |= CSSM_KEYUSE_UNWRAP; michael@0: } michael@0: if (nss_ckmk_GetBoolAttribute(CKA_SIGN, michael@0: pTemplate, ulAttributeCount, CK_TRUE)) { michael@0: keyParams.keyUsage |= CSSM_KEYUSE_SIGN; michael@0: } michael@0: if (nss_ckmk_GetBoolAttribute(CKA_DERIVE, michael@0: pTemplate, ulAttributeCount, CK_FALSE)) { michael@0: keyParams.keyUsage |= CSSM_KEYUSE_DERIVE; michael@0: } michael@0: if (nss_ckmk_GetBoolAttribute(CKA_SENSITIVE, michael@0: pTemplate, ulAttributeCount, CK_TRUE)) { michael@0: keyParams.keyAttributes |= CSSM_KEYATTR_SENSITIVE; michael@0: } michael@0: if (nss_ckmk_GetBoolAttribute(CKA_EXTRACTABLE, michael@0: pTemplate, ulAttributeCount, CK_TRUE)) { michael@0: keyParams.keyAttributes |= CSSM_KEYATTR_EXTRACTABLE; michael@0: } michael@0: michael@0: lk.version.type = siUnsignedInteger; michael@0: lk.version.data = &zero; michael@0: lk.version.len = 1; michael@0: michael@0: *pError = nss_ckmk_GetAttribute(CKA_MODULUS, pTemplate, michael@0: ulAttributeCount, &attribute); michael@0: if (CKR_OK != *pError) { michael@0: return (ckmkInternalObject *)NULL; michael@0: } michael@0: lk.modulus.type = siUnsignedInteger; michael@0: lk.modulus.data = attribute.data; michael@0: lk.modulus.len = attribute.size; michael@0: michael@0: *pError = nss_ckmk_GetAttribute(CKA_PUBLIC_EXPONENT, pTemplate, michael@0: ulAttributeCount, &attribute); michael@0: if (CKR_OK != *pError) { michael@0: return (ckmkInternalObject *)NULL; michael@0: } michael@0: lk.publicExponent.type = siUnsignedInteger; michael@0: lk.publicExponent.data = attribute.data; michael@0: lk.publicExponent.len = attribute.size; michael@0: michael@0: *pError = nss_ckmk_GetAttribute(CKA_PRIVATE_EXPONENT, pTemplate, michael@0: ulAttributeCount, &attribute); michael@0: if (CKR_OK != *pError) { michael@0: return (ckmkInternalObject *)NULL; michael@0: } michael@0: lk.privateExponent.type = siUnsignedInteger; michael@0: lk.privateExponent.data = attribute.data; michael@0: lk.privateExponent.len = attribute.size; michael@0: michael@0: *pError = nss_ckmk_GetAttribute(CKA_PRIME_1, pTemplate, michael@0: ulAttributeCount, &attribute); michael@0: if (CKR_OK != *pError) { michael@0: return (ckmkInternalObject *)NULL; michael@0: } michael@0: lk.prime1.type = siUnsignedInteger; michael@0: lk.prime1.data = attribute.data; michael@0: lk.prime1.len = attribute.size; michael@0: michael@0: *pError = nss_ckmk_GetAttribute(CKA_PRIME_2, pTemplate, michael@0: ulAttributeCount, &attribute); michael@0: if (CKR_OK != *pError) { michael@0: return (ckmkInternalObject *)NULL; michael@0: } michael@0: lk.prime2.type = siUnsignedInteger; michael@0: lk.prime2.data = attribute.data; michael@0: lk.prime2.len = attribute.size; michael@0: michael@0: *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_1, pTemplate, michael@0: ulAttributeCount, &attribute); michael@0: if (CKR_OK != *pError) { michael@0: return (ckmkInternalObject *)NULL; michael@0: } michael@0: lk.exponent1.type = siUnsignedInteger; michael@0: lk.exponent1.data = attribute.data; michael@0: lk.exponent1.len = attribute.size; michael@0: michael@0: *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_2, pTemplate, michael@0: ulAttributeCount, &attribute); michael@0: if (CKR_OK != *pError) { michael@0: return (ckmkInternalObject *)NULL; michael@0: } michael@0: lk.exponent2.type = siUnsignedInteger; michael@0: lk.exponent2.data = attribute.data; michael@0: lk.exponent2.len = attribute.size; michael@0: michael@0: *pError = nss_ckmk_GetAttribute(CKA_COEFFICIENT, pTemplate, michael@0: ulAttributeCount, &attribute); michael@0: if (CKR_OK != *pError) { michael@0: return (ckmkInternalObject *)NULL; michael@0: } michael@0: lk.coefficient.type = siUnsignedInteger; michael@0: lk.coefficient.data = attribute.data; michael@0: lk.coefficient.len = attribute.size; michael@0: michael@0: /* ASN1 Encode the pkcs8 structure... look at softoken to see how this michael@0: * is done... */ michael@0: error = ckmk_CreateRSAKeyBlob(&lk, &keyBlob); michael@0: if (CKR_OK != error) { michael@0: goto loser; michael@0: } michael@0: michael@0: dataRef = CFDataCreate(NULL, (UInt8 *)keyBlob.data, keyBlob.size); michael@0: if (0 == dataRef) { michael@0: *pError = CKR_HOST_MEMORY; michael@0: goto loser; michael@0: } michael@0: michael@0: *pError == ckmk_GetSafeDefaultKeychain(&targetKeychain); michael@0: if (CKR_OK != *pError) { michael@0: goto loser; michael@0: } michael@0: michael@0: michael@0: /* the itemArray that is returned is useless. the item does not michael@0: * is 'not on the key chain' so none of the modify calls work on it. michael@0: * It also has a key that isn't the same key as the one in the actual michael@0: * key chain. In short it isn't the item we want, and it gives us zero michael@0: * information about the item we want, so don't even bother with it... michael@0: */ michael@0: macErr = SecKeychainItemImport(dataRef, NULL, &inputFormat, &itemType, 0, michael@0: &keyParams, targetKeychain, NULL); michael@0: if (noErr != macErr) { michael@0: CKMK_MACERR("Import Private Key", macErr); michael@0: *pError = CKR_GENERAL_ERROR; michael@0: goto loser; michael@0: } michael@0: michael@0: *pError = ckmk_FindImportedKey(targetKeychain, michael@0: CSSM_DL_DB_RECORD_PRIVATE_KEY, michael@0: &itemRef); michael@0: if (CKR_OK != *pError) { michael@0: #ifdef DEBUG michael@0: fprintf(stderr,"couldn't find key in keychain \n"); michael@0: #endif michael@0: goto loser; michael@0: } michael@0: michael@0: michael@0: /* set the CKA_ID and the CKA_LABEL */ michael@0: error = nss_ckmk_GetAttribute(CKA_ID, pTemplate, michael@0: ulAttributeCount, &keyID); michael@0: if (CKR_OK == error) { michael@0: error = ckmk_updateAttribute(itemRef, kSecKeyLabel, michael@0: keyID.data, keyID.size, "Modify Key ID"); michael@0: #ifdef DEBUG michael@0: itemdump("key id: ", keyID.data, keyID.size, error); michael@0: #endif michael@0: } michael@0: nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate, michael@0: ulAttributeCount, &error); michael@0: if (nickname) { michael@0: ckmk_updateAttribute(itemRef, kSecKeyPrintName, nickname, michael@0: strlen(nickname)+1, "Modify Key Label"); michael@0: } else { michael@0: #define DEFAULT_NICKNAME "NSS Imported Key" michael@0: ckmk_updateAttribute(itemRef, kSecKeyPrintName, DEFAULT_NICKNAME, michael@0: sizeof(DEFAULT_NICKNAME), "Modify Key Label"); michael@0: } michael@0: michael@0: io = nss_ckmk_NewInternalObject(CKO_PRIVATE_KEY, itemRef, michael@0: CSSM_DL_DB_RECORD_PRIVATE_KEY, pError); michael@0: if ((ckmkInternalObject *)NULL == io) { michael@0: CFRelease(itemRef); michael@0: } michael@0: michael@0: return io; michael@0: michael@0: loser: michael@0: /* free the key blob */ michael@0: if (keyBlob.data) { michael@0: nss_ZFreeIf(keyBlob.data); michael@0: } michael@0: if (0 != targetKeychain) { michael@0: CFRelease(targetKeychain); michael@0: } michael@0: if (0 != dataRef) { michael@0: CFRelease(dataRef); michael@0: } michael@0: return io; michael@0: } michael@0: michael@0: michael@0: NSS_EXTERN NSSCKMDObject * michael@0: nss_ckmk_CreateObject michael@0: ( michael@0: NSSCKFWSession *fwSession, michael@0: CK_ATTRIBUTE_PTR pTemplate, michael@0: CK_ULONG ulAttributeCount, michael@0: CK_RV *pError michael@0: ) michael@0: { michael@0: CK_OBJECT_CLASS objClass; michael@0: ckmkInternalObject *io; michael@0: CK_BBOOL isToken; michael@0: michael@0: /* michael@0: * only create token objects michael@0: */ michael@0: isToken = nss_ckmk_GetBoolAttribute(CKA_TOKEN, pTemplate, michael@0: ulAttributeCount, CK_FALSE); michael@0: if (!isToken) { michael@0: *pError = CKR_ATTRIBUTE_VALUE_INVALID; michael@0: return (NSSCKMDObject *) NULL; michael@0: } michael@0: michael@0: /* michael@0: * only create keys and certs. michael@0: */ michael@0: objClass = nss_ckmk_GetULongAttribute(CKA_CLASS, pTemplate, michael@0: ulAttributeCount, pError); michael@0: if (CKR_OK != *pError) { michael@0: return (NSSCKMDObject *) NULL; michael@0: } michael@0: #ifdef notdef michael@0: if (objClass == CKO_PUBLIC_KEY) { michael@0: return CKR_OK; /* fake public key creation, happens as a side effect of michael@0: * private key creation */ michael@0: } michael@0: #endif michael@0: if (objClass == CKO_CERTIFICATE) { michael@0: io = nss_ckmk_CreateCertificate(fwSession, pTemplate, michael@0: ulAttributeCount, pError); michael@0: } else if (objClass == CKO_PRIVATE_KEY) { michael@0: io = nss_ckmk_CreatePrivateKey(fwSession, pTemplate, michael@0: ulAttributeCount, pError); michael@0: } else { michael@0: *pError = CKR_ATTRIBUTE_VALUE_INVALID; michael@0: } michael@0: michael@0: if ((ckmkInternalObject *)NULL == io) { michael@0: return (NSSCKMDObject *) NULL; michael@0: } michael@0: return nss_ckmk_CreateMDObject(NULL, io, pError); michael@0: }