diff options
Diffstat (limited to 'pobject.c')
-rw-r--r-- | pobject.c | 1175 |
1 files changed, 1175 insertions, 0 deletions
diff --git a/pobject.c b/pobject.c new file mode 100644 index 0000000..2fcc9c8 --- /dev/null +++ b/pobject.c @@ -0,0 +1,1175 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Rob Crittenden (rcritten@redhat.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ckpem.h" +#include "secasn1.h" +#include "certt.h" +#include "pk11pub.h" + +/* + * pobject.c + * + * This file implements the NSSCKMDObject object for the + * "PEM objects" cryptoki module. + */ + +NSS_EXTERN_DATA pemInternalObject **gobj; +NSS_EXTERN_DATA int pem_nobjs; +NSS_EXTERN_DATA int token_needsLogin[NUM_SLOTS]; + +#define PEM_ITEM_CHUNK 512 +#define PUT_Object(obj,err) \ + { \ + if (count >= size) { \ + gobj = gobj ? \ + nss_ZREALLOCARRAY(gobj, pemInternalObject *, \ + (size+PEM_ITEM_CHUNK) ) : \ + nss_ZNEWARRAY(NULL, pemInternalObject *, \ + (size+PEM_ITEM_CHUNK) ) ; \ + if ((pemInternalObject **)NULL == gobj) { \ + err = CKR_HOST_MEMORY; \ + goto loser; \ + } \ + size += PEM_ITEM_CHUNK; \ + } \ + (gobj)[ count ] = (obj); \ + count++; \ + } + +const CK_ATTRIBUTE_TYPE certAttrs[] = { + CKA_CLASS, + CKA_TOKEN, + CKA_PRIVATE, + CKA_MODIFIABLE, + CKA_LABEL, + CKA_CERTIFICATE_TYPE, + CKA_SUBJECT, + CKA_ISSUER, + CKA_SERIAL_NUMBER, + CKA_VALUE +}; +const PRUint32 certAttrsCount = NSS_PEM_ARRAY_SIZE(certAttrs); + +/* private keys, for now only support RSA */ +const CK_ATTRIBUTE_TYPE privKeyAttrs[] = { + CKA_CLASS, + CKA_TOKEN, + CKA_PRIVATE, + CKA_MODIFIABLE, + CKA_LABEL, + CKA_KEY_TYPE, + CKA_DERIVE, + CKA_LOCAL, + CKA_SUBJECT, + CKA_SENSITIVE, + CKA_DECRYPT, + CKA_SIGN, + CKA_SIGN_RECOVER, + CKA_UNWRAP, + CKA_EXTRACTABLE, + CKA_ALWAYS_SENSITIVE, + CKA_NEVER_EXTRACTABLE, + CKA_MODULUS, + CKA_PUBLIC_EXPONENT, +}; +const PRUint32 privKeyAttrsCount = NSS_PEM_ARRAY_SIZE(privKeyAttrs); + +/* public keys, for now only support RSA */ +const CK_ATTRIBUTE_TYPE pubKeyAttrs[] = { + CKA_CLASS, + CKA_TOKEN, + CKA_PRIVATE, + CKA_MODIFIABLE, + CKA_LABEL, + CKA_KEY_TYPE, + CKA_DERIVE, + CKA_LOCAL, + CKA_SUBJECT, + CKA_ENCRYPT, + CKA_VERIFY, + CKA_VERIFY_RECOVER, + CKA_WRAP, + CKA_MODULUS, + CKA_PUBLIC_EXPONENT, +}; +const PRUint32 pubKeyAttrsCount = NSS_PEM_ARRAY_SIZE(pubKeyAttrs); + +/* Trust */ +const CK_ATTRIBUTE_TYPE trustAttrs[] = { + CKA_CLASS, + CKA_TOKEN, + CKA_LABEL, + CKA_CERT_SHA1_HASH, + CKA_CERT_MD5_HASH, + CKA_ISSUER, + CKA_SUBJECT, + CKA_TRUST_SERVER_AUTH, + CKA_TRUST_CLIENT_AUTH, + CKA_TRUST_EMAIL_PROTECTION, + CKA_TRUST_CODE_SIGNING +}; +const PRUint32 trustAttrsCount = NSS_PEM_ARRAY_SIZE(trustAttrs); + +static const CK_BBOOL ck_true = CK_TRUE; +static const CK_BBOOL ck_false = CK_FALSE; +static const CK_CERTIFICATE_TYPE ckc_x509 = CKC_X_509; +static const CK_KEY_TYPE ckk_rsa = CKK_RSA; +static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE; +static const CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY; +static const CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY; +static const CK_OBJECT_CLASS cko_trust = CKO_NETSCAPE_TRUST; +static const CK_TRUST ckt_netscape_trusted = CKT_NETSCAPE_TRUSTED_DELEGATOR; +static const NSSItem pem_trueItem = { + (void *) &ck_true, (PRUint32) sizeof(CK_BBOOL) +}; +static const NSSItem pem_falseItem = { + (void *) &ck_false, (PRUint32) sizeof(CK_BBOOL) +}; +static const NSSItem pem_x509Item = { + (void *) &ckc_x509, (PRUint32) sizeof(CKC_X_509) +}; +static const NSSItem pem_rsaItem = { + (void *) &ckk_rsa, (PRUint32) sizeof(CK_KEY_TYPE) +}; +static const NSSItem pem_certClassItem = { + (void *) &cko_certificate, (PRUint32) sizeof(CK_OBJECT_CLASS) +}; +static const NSSItem pem_privKeyClassItem = { + (void *) &cko_private_key, (PRUint32) sizeof(CK_OBJECT_CLASS) +}; +static const NSSItem pem_pubKeyClassItem = { + (void *) &cko_public_key, (PRUint32) sizeof(CK_OBJECT_CLASS) +}; +static const NSSItem pem_trustClassItem = { + (void *) &cko_trust, (PRUint32) sizeof(CK_OBJECT_CLASS) +}; +static const NSSItem pem_emptyItem = { + (void *) &ck_true, 0 +}; +static const NSSItem pem_trusted = { + (void *) &ckt_netscape_trusted, (PRUint32) sizeof(CK_TRUST) +}; + +/* + * Template for skipping a subitem. + * + * Note that it only makes sense to use this for decoding (when you want + * to decode something where you are only interested in one or two of + * the fields); you cannot encode a SKIP! + */ +const SEC_ASN1Template SEC_SkipTemplate[] = { + {SEC_ASN1_SKIP} +}; + +/* + * Find the subjectName in a DER encoded certificate + */ +const SEC_ASN1Template SEC_CertSubjectTemplate[] = { + {SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(SECItem)} , + {SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | + SEC_ASN1_CONTEXT_SPECIFIC | 0, + 0, SEC_SkipTemplate} , /* version */ + {SEC_ASN1_SKIP}, /* serial number */ + {SEC_ASN1_SKIP}, /* signature algorithm */ + {SEC_ASN1_SKIP}, /* issuer */ + {SEC_ASN1_SKIP}, /* validity */ + {SEC_ASN1_ANY, 0, NULL}, /* subject */ + {SEC_ASN1_SKIP_REST}, + {0} +}; + +void +pem_FetchLabel +( + pemInternalObject * io +) +{ + pemCertObject *co = &io->u.cert; + + co->label.data = io->nickname; + co->label.size = strlen(io->nickname); +} + +const NSSItem +*pem_FetchCertAttribute +( + pemInternalObject * io, + CK_ATTRIBUTE_TYPE type +) +{ + switch (type) { + case CKA_CLASS: + plog(" fetch cert CKA_CLASS\n"); + return &pem_certClassItem; + case CKA_TOKEN: + plog(" fetch cert CKA_TOKEN\n"); + return &pem_trueItem; + case CKA_PRIVATE: + return &pem_falseItem; + case CKA_CERTIFICATE_TYPE: + plog(" fetch cert CKA_CERTIFICATE_TYPE\n"); + return &pem_x509Item; + case CKA_LABEL: + if (0 == io->u.cert.label.size) { + pem_FetchLabel(io); + } + plog(" fetch cert CKA_LABEL %s\n", io->u.cert.label.data); + return &io->u.cert.label; + case CKA_SUBJECT: + plog(" fetch cert CKA_SUBJECT size %d\n", io->u.cert.subject.size); + return &io->u.cert.subject; + case CKA_ISSUER: + plog(" fetch cert CKA_ISSUER size %d\n", io->u.cert.issuer.size); + return &io->u.cert.issuer; + case CKA_SERIAL_NUMBER: + plog(" fetch cert CKA_SERIAL_NUMBER size %d value %08x\n", io->u.cert.serial.size, io->u.cert.serial.data); + return &io->u.cert.serial; + case CKA_VALUE: + if (0 == io->u.cert.derCert.size) { + io->u.cert.derCert.data = io->derCert->data; + io->u.cert.derCert.size = io->derCert->len; + } + plog(" fetch cert CKA_VALUE\n"); + return &io->u.cert.derCert; + case CKA_ID: + plog(" fetch cert CKA_ID val=%s size=%d\n", (char *) io->id.data, + io->id.size); + return &io->id; + case CKA_TRUSTED: + plog(" fetch cert CKA_TRUSTED: returning NULL\n"); + return NULL; + default: + plog(" fetching cert unknown type %d\n", type); + break; + } + return NULL; +} + +const NSSItem * +pem_FetchPrivKeyAttribute +( + pemInternalObject * io, + CK_ATTRIBUTE_TYPE type +) +{ + PRBool isCertType = (pemCert == io->type); + pemKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key; + + switch (type) { + case CKA_CLASS: + return &pem_privKeyClassItem; + case CKA_TOKEN: + case CKA_LOCAL: + case CKA_SIGN: + case CKA_DECRYPT: + case CKA_SIGN_RECOVER: + return &pem_trueItem; + case CKA_SENSITIVE: + case CKA_PRIVATE: /* should move in the future */ + case CKA_MODIFIABLE: + case CKA_DERIVE: + case CKA_UNWRAP: + case CKA_EXTRACTABLE: /* will probably move in the future */ + case CKA_ALWAYS_SENSITIVE: + case CKA_NEVER_EXTRACTABLE: + return &pem_falseItem; + case CKA_KEY_TYPE: + return &pem_rsaItem; + case CKA_LABEL: + if (!isCertType) { + return &pem_emptyItem; + } + if (0 == io->u.cert.label.size) { + pem_FetchLabel(io); + } + plog(" fetch key CKA_LABEL %s\n", io->u.cert.label.data); + return &io->u.cert.label; + case CKA_SUBJECT: + if (!isCertType) { + return &pem_emptyItem; + } + plog(" fetch key CKA_SUBJECT %s\n", io->u.cert.label.data); + return &io->u.cert.subject; + case CKA_MODULUS: + if (0 == kp->modulus.size) { + pem_PopulateModulusExponent(io); + } + plog(" fetch key CKA_MODULUS\n"); + return &kp->modulus; + case CKA_PUBLIC_EXPONENT: + if (0 == kp->modulus.size) { + pem_PopulateModulusExponent(io); + } + plog(" fetch key CKA_PUBLIC_EXPONENT\n"); + return &kp->exponent; + case CKA_PRIVATE_EXPONENT: + if (0 == kp->privateExponent.size) { + pem_PopulateModulusExponent(io); + } + plog(" fetch key CKA_PRIVATE_EXPONENT\n"); + return &kp->privateExponent; + case CKA_PRIME_1: + if (0 == kp->prime1.size) { + pem_PopulateModulusExponent(io); + } + plog(" fetch key CKA_PRIME_1\n"); + return &kp->prime1; + case CKA_PRIME_2: + if (0 == kp->prime2.size) { + pem_PopulateModulusExponent(io); + } + plog(" fetch key CKA_PRIME_2\n"); + return &kp->prime2; + case CKA_EXPONENT_1: + if (0 == kp->exponent1.size) { + pem_PopulateModulusExponent(io); + } + plog(" fetch key CKA_EXPONENT_1\n"); + return &kp->exponent1; + case CKA_EXPONENT_2: + if (0 == kp->exponent2.size) { + pem_PopulateModulusExponent(io); + } + plog(" fetch key CKA_EXPONENT_2\n"); + return &kp->exponent2; + case CKA_COEFFICIENT: + if (0 == kp->coefficient.size) { + pem_PopulateModulusExponent(io); + } + plog(" fetch key CKA_COEFFICIENT_2\n"); + return &kp->coefficient; + case CKA_ID: + plog(" fetch key CKA_ID val=%s size=%d\n", (char *) io->id.data, + io->id.size); + return &io->id; + default: + return NULL; + } +} + +const NSSItem * +pem_FetchPubKeyAttribute +( + pemInternalObject * io, + CK_ATTRIBUTE_TYPE type +) +{ + PRBool isCertType = (pemCert == io->type); + pemKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key; + + switch (type) { + case CKA_CLASS: + return &pem_pubKeyClassItem; + case CKA_TOKEN: + case CKA_LOCAL: + case CKA_ENCRYPT: + case CKA_VERIFY: + case CKA_VERIFY_RECOVER: + return &pem_trueItem; + case CKA_PRIVATE: + case CKA_MODIFIABLE: + case CKA_DERIVE: + case CKA_WRAP: + return &pem_falseItem; + case CKA_KEY_TYPE: + return &pem_rsaItem; + case CKA_LABEL: + if (!isCertType) { + return &pem_emptyItem; + } + if (0 == io->u.cert.label.size) { + pem_FetchLabel(io); + } + return &io->u.cert.label; + case CKA_SUBJECT: + if (!isCertType) { + return &pem_emptyItem; + } + return &io->u.cert.subject; + case CKA_MODULUS: + if (0 == kp->modulus.size) { + pem_PopulateModulusExponent(io); + } + return &kp->modulus; + case CKA_PUBLIC_EXPONENT: + if (0 == kp->modulus.size) { + pem_PopulateModulusExponent(io); + } + return &kp->exponent; + case CKA_ID: + return &io->id; + default: + break; + } + return NULL; +} + +const NSSItem * +pem_FetchTrustAttribute +( + pemInternalObject * io, + CK_ATTRIBUTE_TYPE type +) +{ + static NSSItem hash; + SECStatus rv; + + switch (type) { + case CKA_CLASS: + return &pem_trustClassItem; + case CKA_TOKEN: + return &pem_trueItem; + case CKA_PRIVATE: + return &pem_falseItem; + case CKA_CERTIFICATE_TYPE: + return &pem_x509Item; + case CKA_LABEL: + if (0 == io->u.cert.label.size) { + pem_FetchLabel(io); + } + plog(" fetch trust CKA_LABEL %s\n", io->u.cert.label.data); + return &io->u.cert.label; + case CKA_SUBJECT: + plog(" fetch trust CKA_SUBJECT\n"); + return NULL; + case CKA_ISSUER: + plog(" fetch trust CKA_ISSUER\n"); + return &io->u.cert.issuer; + case CKA_SERIAL_NUMBER: + plog(" fetch trust CKA_SERIAL_NUMBER size %d value %08x\n", io->u.cert.serial.size, io->u.cert.serial.data); + return &io->u.cert.serial; + case CKA_VALUE: + return &pem_trueItem; + case CKA_ID: + plog(" fetch trust CKA_ID val=%s size=%d\n", (char *) io->id.data, + io->id.size); + return &io->id; + case CKA_TRUSTED: + return &pem_trusted; + case CKA_TRUST_SERVER_AUTH: + return &pem_trusted; + case CKA_TRUST_CLIENT_AUTH: + return &pem_trusted; + case CKA_TRUST_CODE_SIGNING: + return &pem_trusted; + case CKA_TRUST_EMAIL_PROTECTION: + return &pem_trusted; + case CKA_TRUST_IPSEC_END_SYSTEM: + return &pem_trusted; + case CKA_TRUST_IPSEC_TUNNEL: + return &pem_trusted; + case CKA_TRUST_IPSEC_USER: + return &pem_trusted; + case CKA_TRUST_TIME_STAMPING: + return &pem_trusted; + case CKA_TRUST_STEP_UP_APPROVED: + return &pem_falseItem; + case CKA_CERT_SHA1_HASH: + hash.size = 0; + hash.data = NULL; + nsslibc_memset(io->u.cert.sha1_hash, 0, SHA1_LENGTH); + rv = SHA1_HashBuf(io->u.cert.sha1_hash, io->derCert->data, + io->derCert->len); + if (rv == SECSuccess) { + hash.data = io->u.cert.sha1_hash; + hash.size = sizeof(io->u.cert.sha1_hash); + } + return &hash; + case CKA_CERT_MD5_HASH: + hash.size = 0; + hash.data = NULL; + nsslibc_memset(io->u.cert.sha1_hash, 0, MD5_LENGTH); + rv = MD5_HashBuf(io->u.cert.sha1_hash, io->derCert->data, + io->derCert->len); + if (rv == SECSuccess) { + hash.data = io->u.cert.sha1_hash; + hash.size = sizeof(io->u.cert.sha1_hash); + } + return &hash; + default: + return &pem_trusted; + break; + } + return NULL; +} + +const NSSItem * +pem_FetchAttribute +( + pemInternalObject * io, + CK_ATTRIBUTE_TYPE type +) +{ + CK_ULONG i; + + if (io->type == pemRaw) { + for (i = 0; i < io->u.raw.n; i++) { + if (type == io->u.raw.types[i]) { + return &io->u.raw.items[i]; + } + } + return NULL; + } + /* deal with the common attributes */ + switch (io->objClass) { + case CKO_CERTIFICATE: + return pem_FetchCertAttribute(io, type); + case CKO_PRIVATE_KEY: + return pem_FetchPrivKeyAttribute(io, type); + case CKO_NETSCAPE_TRUST: + return pem_FetchTrustAttribute(io, type); + case CKO_PUBLIC_KEY: + return pem_FetchPubKeyAttribute(io, type); + } + return NULL; +} + +void +pem_DestroyInternalObject +( + pemInternalObject * io +) +{ + switch (io->type) { + case pemRaw: + return; + case pemCert: + nss_ZFreeIf(io->u.cert.labelData); + nss_ZFreeIf(io->u.cert.key.privateKey); + nss_ZFreeIf(io->u.cert.key.pubKey); + nss_ZFreeIf(io->idData); + nss_ZFreeIf(io->nickname); + nss_ZFreeIf(io->derCert); + if (io->u.cert.subject.size > 0) { + PR_Free(io->u.cert.subject.data); + } + if (io->u.cert.issuer.size > 0) { + PR_Free(io->u.cert.issuer.data); + } + if (io->u.cert.serial.size > 0) { + PR_Free(io->u.cert.serial.data); + } + break; + case pemBareKey: + nss_ZFreeIf(io->u.key.key.privateKey); + nss_ZFreeIf(io->u.key.key.pubKey); + nss_ZFreeIf(io->idData); + nss_ZFreeIf(io->nickname); + nss_ZFreeIf(io->derCert); + + /* strdup'd in ReadDERFromFile */ + if (io->u.key.ivstring) + free(io->u.key.ivstring); + break; + case pemTrust: + nss_ZFreeIf(io->idData); + nss_ZFreeIf(io->nickname); + nss_ZFreeIf(io->derCert); + } + nss_ZFreeIf(io); + return; +} + +/* + * Finalize - unneeded + * Destroy - CKR_SESSION_READ_ONLY + * IsTokenObject - CK_TRUE + * GetAttributeCount + * GetAttributeTypes + * GetAttributeSize + * GetAttribute + * SetAttribute - unneeded + * GetObjectSize + */ + +static CK_RV +pem_mdObject_Destroy +( + NSSCKMDObject * mdObject, + NSSCKFWObject * fwObject, + NSSCKMDSession * mdSession, + NSSCKFWSession * fwSession, + NSSCKMDToken * mdToken, + NSSCKFWToken * fwToken, + NSSCKMDInstance * mdInstance, + NSSCKFWInstance * fwInstance +) +{ + pemInternalObject *io = (pemInternalObject *) mdObject->etc; + + pem_DestroyInternalObject(io); + return CKR_OK; +} + +static CK_BBOOL +pem_mdObject_IsTokenObject +( + NSSCKMDObject * mdObject, + NSSCKFWObject * fwObject, + NSSCKMDSession * mdSession, + NSSCKFWSession * fwSession, + NSSCKMDToken * mdToken, + NSSCKFWToken * fwToken, + NSSCKMDInstance * mdInstance, + NSSCKFWInstance * fwInstance +) +{ + return CK_TRUE; +} + +static CK_ULONG +pem_mdObject_GetAttributeCount +( + NSSCKMDObject * mdObject, + NSSCKFWObject * fwObject, + NSSCKMDSession * mdSession, + NSSCKFWSession * fwSession, + NSSCKMDToken * mdToken, + NSSCKFWToken * fwToken, + NSSCKMDInstance * mdInstance, + NSSCKFWInstance * fwInstance, + CK_RV * pError +) +{ + pemInternalObject *io = (pemInternalObject *) mdObject->etc; + + if (pemRaw == io->type) { + return io->u.raw.n; + } + switch (io->objClass) { + case CKO_CERTIFICATE: + return certAttrsCount; + case CKO_PUBLIC_KEY: + return pubKeyAttrsCount; + case CKO_PRIVATE_KEY: + return privKeyAttrsCount; + case CKO_NETSCAPE_TRUST: + return trustAttrsCount; + default: + break; + } + return 0; +} + +static CK_RV +pem_mdObject_GetAttributeTypes +( + NSSCKMDObject * mdObject, + NSSCKFWObject * fwObject, + NSSCKMDSession * mdSession, + NSSCKFWSession * fwSession, + NSSCKMDToken * mdToken, + NSSCKFWToken * fwToken, + NSSCKMDInstance * mdInstance, + NSSCKFWInstance * fwInstance, + CK_ATTRIBUTE_TYPE_PTR typeArray, + CK_ULONG ulCount +) +{ + pemInternalObject *io = (pemInternalObject *) mdObject->etc; + CK_ULONG i; + CK_RV error = CKR_OK; + const CK_ATTRIBUTE_TYPE *attrs = NULL; + CK_ULONG size = + pem_mdObject_GetAttributeCount(mdObject, fwObject, mdSession, + fwSession, mdToken, fwToken, mdInstance, + fwInstance, &error); + + if (size != ulCount) { + return CKR_BUFFER_TOO_SMALL; + } + if (io->type == pemRaw) { + attrs = io->u.raw.types; + } else + switch (io->objClass) { + case CKO_CERTIFICATE: + attrs = certAttrs; + break; + case CKO_PUBLIC_KEY: + attrs = pubKeyAttrs; + break; + case CKO_PRIVATE_KEY: + attrs = privKeyAttrs; + break; + default: + return CKR_OK; + } + + for (i = 0; i < size; i++) { + typeArray[i] = attrs[i]; + } + + return CKR_OK; +} + +static CK_ULONG +pem_mdObject_GetAttributeSize +( + NSSCKMDObject * mdObject, + NSSCKFWObject * fwObject, + NSSCKMDSession * mdSession, + NSSCKFWSession * fwSession, + NSSCKMDToken * mdToken, + NSSCKFWToken * fwToken, + NSSCKMDInstance * mdInstance, + NSSCKFWInstance * fwInstance, + CK_ATTRIBUTE_TYPE attribute, + CK_RV * pError +) +{ + pemInternalObject *io = (pemInternalObject *) mdObject->etc; + + const NSSItem *b; + + b = pem_FetchAttribute(io, attribute); + + if ((const NSSItem *) NULL == b) { + *pError = CKR_ATTRIBUTE_TYPE_INVALID; + return 0; + } + return b->size; +} + +static NSSCKFWItem +pem_mdObject_GetAttribute +( + NSSCKMDObject * mdObject, + NSSCKFWObject * fwObject, + NSSCKMDSession * mdSession, + NSSCKFWSession * fwSession, + NSSCKMDToken * mdToken, + NSSCKFWToken * fwToken, + NSSCKMDInstance * mdInstance, + NSSCKFWInstance * fwInstance, + CK_ATTRIBUTE_TYPE attribute, + CK_RV * pError +) +{ + NSSCKFWItem mdItem; + pemInternalObject *io = (pemInternalObject *) mdObject->etc; + + mdItem.needsFreeing = PR_FALSE; + mdItem.item = (NSSItem *) pem_FetchAttribute(io, attribute); + + if ((NSSItem *) NULL == mdItem.item) { + *pError = CKR_ATTRIBUTE_TYPE_INVALID; + } + + return mdItem; +} + +/* + * get an attribute from a template. Value is returned in NSS item. + * data for the item is owned by the template. + */ +CK_RV +pem_GetAttribute +( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE * template, + CK_ULONG templateSize, + NSSItem * item +) +{ + CK_ULONG i; + + for (i = 0; i < templateSize; i++) { + if (template[i].type == type) { + item->data = template[i].pValue; + item->size = template[i].ulValueLen; + return CKR_OK; + } + } + return CKR_TEMPLATE_INCOMPLETE; +} + +/* + * get an attribute which is type CK_ULONG. + */ +CK_ULONG +pem_GetULongAttribute +( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE * template, + CK_ULONG templateSize, + CK_RV * pError +) +{ + NSSItem item; + + *pError = pem_GetAttribute(type, template, templateSize, &item); + if (CKR_OK != *pError) { + return (CK_ULONG) 0; + } + if (item.size != sizeof(CK_ULONG)) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + return (CK_ULONG) 0; + } + return *(CK_ULONG *) item.data; +} + +/* + * get an attribute which is type CK_BBOOL. + */ +CK_BBOOL +pem_GetBoolAttribute +( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE * template, + CK_ULONG templateSize, + CK_RV * pError +) +{ + NSSItem item; + + *pError = pem_GetAttribute(type, template, templateSize, &item); + if (CKR_OK != *pError) { + return (CK_BBOOL) 0; + } + if (item.size != sizeof(CK_BBOOL)) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + return (CK_BBOOL) 0; + } + return *(CK_BBOOL *) item.data; +} + +/* + * Get a string attribute. Caller needs to free this. + */ +char * +pem_GetStringAttribute +( + CK_ATTRIBUTE_TYPE type, + CK_ATTRIBUTE * template, + CK_ULONG templateSize, + CK_RV * pError +) +{ + NSSItem item; + char *str; + + /* get the attribute */ + *pError = pem_GetAttribute(type, template, templateSize, &item); + if (CKR_OK != *pError) { + return (char *) NULL; + } + /* make sure it is null terminated */ + str = nss_ZNEWARRAY(NULL, char, item.size + 1); + if ((char *) NULL == str) { + *pError = CKR_HOST_MEMORY; + return (char *) NULL; + } + + nsslibc_memcpy(str, item.data, item.size); + str[item.size] = 0; + + return str; +} + +static CK_ULONG +pem_mdObject_GetObjectSize +( + NSSCKMDObject * mdObject, + NSSCKFWObject * fwObject, + NSSCKMDSession * mdSession, + NSSCKFWSession * fwSession, + NSSCKMDToken * mdToken, + NSSCKFWToken * fwToken, + NSSCKMDInstance * mdInstance, + NSSCKFWInstance * fwInstance, + CK_RV * pError +) +{ + pemInternalObject *io = (pemInternalObject *) mdObject->etc; + CK_ULONG rv = 1; + + /* size is irrelevant to this token */ + return rv; +} + +static const NSSCKMDObject +pem_prototype_mdObject = { + (void *) NULL, /* etc */ + NULL, /* Finalize */ + pem_mdObject_Destroy, + pem_mdObject_IsTokenObject, + pem_mdObject_GetAttributeCount, + pem_mdObject_GetAttributeTypes, + pem_mdObject_GetAttributeSize, + pem_mdObject_GetAttribute, + NULL, /* FreeAttribute */ + NULL, /* SetAttribute */ + pem_mdObject_GetObjectSize, + (void *) NULL /* null terminator */ +}; + +NSS_IMPLEMENT NSSCKMDObject * +pem_CreateMDObject +( + NSSArena * arena, + pemInternalObject * io, + CK_RV * pError +) +{ + if ((void *) NULL == io->mdObject.etc) { + (void) nsslibc_memcpy(&io->mdObject, &pem_prototype_mdObject, + sizeof(pem_prototype_mdObject)); + io->mdObject.etc = (void *) io; + } + + return &io->mdObject; +} + +/* + * Each object has an identifier. For a certificate and key pair this id + * needs to be the same so we use the right combination. If the target object + * is a key we first look to see if its certificate was already added and if + * so, use that id. The same thing is done when a key is added. + */ +NSS_EXTERN NSSCKMDObject * +pem_CreateObject +( + NSSCKFWInstance * fwInstance, + NSSCKFWSession * fwSession, + NSSCKMDToken * mdToken, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulAttributeCount, + CK_RV * pError +) +{ + CK_OBJECT_CLASS objClass; + pemInternalObject *io = NULL; + CK_BBOOL isToken; + NSSCKFWSlot *fwSlot; + CK_SLOT_ID slotID; + CK_BBOOL cacert; + char *filename; + SECItem **derlist = NULL; + int nobjs, i; + int objid, count, size; + pemToken *token; + int cipher; + char *ivstring = NULL; + + count = pem_nobjs; + if (count > 0) + size = ((count / PEM_ITEM_CHUNK) + 1) * PEM_ITEM_CHUNK; + else + size = 0; + + /* + * only create token objects + */ + isToken = pem_GetBoolAttribute(CKA_TOKEN, pTemplate, + ulAttributeCount, pError); + if (CKR_OK != *pError) { + return (NSSCKMDObject *) NULL; + } + if (!isToken) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + return (NSSCKMDObject *) NULL; + } + + /* What slot are we adding the object to? */ + fwSlot = nssCKFWSession_GetFWSlot(fwSession); + if ((NSSCKFWSlot *) NULL == fwSlot) { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + *pError = CKR_GENERAL_ERROR; + return (NSSCKMDObject *) NULL; + + } + slotID = nssCKFWSlot_GetSlotID(fwSlot); + + token = (pemToken *) mdToken->etc; + + /* + * only create keys and certs. + */ + objClass = pem_GetULongAttribute(CKA_CLASS, pTemplate, + ulAttributeCount, pError); + if (CKR_OK != *pError) { + return (NSSCKMDObject *) NULL; + } + + cacert = pem_GetBoolAttribute(CKA_TRUST, pTemplate, + ulAttributeCount, pError); + + filename = pem_GetStringAttribute(CKA_LABEL, pTemplate, + ulAttributeCount, pError); + if (CKR_OK != *pError) { + return (NSSCKMDObject *) NULL; + } + +#ifdef notdef + if (objClass == CKO_PUBLIC_KEY) { + return CKR_OK; /* fake public key creation, happens as a side effect of + * private key creation */ + } +#endif + if (objClass == CKO_CERTIFICATE) { + int i; + + nobjs = ReadDERFromFile(&derlist, filename, PR_TRUE, &cipher, &ivstring, PR_TRUE /* certs only */); + if (nobjs < 1) + return (NSSCKMDObject *) NULL; + + objid = -1; + /* Brute force: find the id of the key, if any, in this slot */ + for (i = 0; i < pem_nobjs; i++) { + if ((slotID == gobj[i]->slotID) + && (gobj[i]->type == pemBareKey)) { + objid = atoi(gobj[i]->id.data); + } + } + + if (objid == -1) { + /* We're just adding a cert, we'll assume the key is next */ + objid = pem_nobjs + 1; + } + + if (cacert) { + /* Add the certificate. There may be more than one */ + int c; + for (c = 0; c < nobjs; c++) { + char nickname[1024]; + objid = pem_nobjs + 1; + + snprintf(nickname, 1024, "%s - %d", filename, c); + + io = (pemInternalObject *) CreateObject(CKO_CERTIFICATE, + pemCert, derlist[c], + NULL, nickname, 0, + slotID); + if (io == NULL) + goto loser; + PUT_Object(io, *pError); + pem_nobjs++; + + /* Add the trust object */ + io = CreateObject(CKO_NETSCAPE_TRUST, pemTrust, derlist[c], + NULL, nickname, 0, slotID); + if (io == NULL) + goto loser; + + PUT_Object(io, *pError); + pem_nobjs++; + } + } else { + io = (pemInternalObject *) CreateObject(CKO_CERTIFICATE, + pemCert, derlist[0], + NULL, filename, objid, + slotID); + if (io == NULL) + goto loser; + PUT_Object(io, *pError); + pem_nobjs++; + } + } else if (objClass == CKO_PRIVATE_KEY) { + /* Brute force: find the id of the certificate, if any, in this slot */ + int i; + SECItem certDER; + CK_SESSION_HANDLE hSession; + + nobjs = ReadDERFromFile(&derlist, filename, PR_TRUE, &cipher, &ivstring, PR_FALSE /* keys only */); + if (nobjs < 1) + return (NSSCKMDObject *) NULL; + + certDER.len = 0; /* in case there is no equivalent cert */ + + objid = -1; + for (i = 0; i < pem_nobjs; i++) { + if ((slotID == gobj[i]->slotID) && (gobj[i]->type == pemCert)) { + objid = atoi(gobj[i]->id.data); + certDER.data = + (void *) nss_ZAlloc(NULL, gobj[i]->derCert->len); + certDER.len = gobj[i]->derCert->len; + nsslibc_memcpy(certDER.data, gobj[i]->derCert->data, + gobj[i]->derCert->len); + } + } + + /* We're just adding a key, we'll assume the cert is next */ + if (objid == -1) + objid = pem_nobjs + 1; + + io = (pemInternalObject *) CreateObject(CKO_PRIVATE_KEY, + pemBareKey, &certDER, + derlist[0], filename, + objid, slotID); + if (io == NULL) + goto loser; + io->u.key.ivstring = ivstring; + io->u.key.cipher = cipher; + PUT_Object(io, *pError); + pem_nobjs++; + nss_ZFreeIf(certDER.data); + + /* If the key was encrypted then free the session to make it appear that + * the token was removed so we can force a login. + */ + if (cipher) { + PRIntervalTime onesec = PR_SecondsToInterval(1); + token_needsLogin[slotID - 1] = PR_TRUE; + + /* We have to sleep so that NSS will notice that the token was + * removed. + */ + PR_Sleep(onesec); + hSession = + nssCKFWInstance_FindSessionHandle(fwInstance, fwSession); + nssCKFWInstance_DestroySessionHandle(fwInstance, hSession); + } else { + *pError = CKR_KEY_UNEXTRACTABLE; + } + } else { + *pError = CKR_ATTRIBUTE_VALUE_INVALID; + } + + loser: + + for (i = 0; i < nobjs; i++) { + free(derlist[i]->data); + free(derlist[i]); + } + nss_ZFreeIf(filename); + nss_ZFreeIf(derlist); + if ((pemInternalObject *) NULL == io) { + return (NSSCKMDObject *) NULL; + } + return pem_CreateMDObject(NULL, io, pError); +} |