summaryrefslogtreecommitdiffstats
path: root/pobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'pobject.c')
-rw-r--r--pobject.c1175
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);
+}