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 "pkcs11.h" michael@0: michael@0: #ifndef DEVM_H michael@0: #include "devm.h" michael@0: #endif /* DEVM_H */ michael@0: michael@0: #ifndef CKHELPER_H michael@0: #include "ckhelper.h" michael@0: #endif /* CKHELPER_H */ michael@0: michael@0: extern const NSSError NSS_ERROR_DEVICE_ERROR; michael@0: michael@0: static const CK_BBOOL s_true = CK_TRUE; michael@0: NSS_IMPLEMENT_DATA const NSSItem michael@0: g_ck_true = { (CK_VOID_PTR)&s_true, sizeof(s_true) }; michael@0: michael@0: static const CK_BBOOL s_false = CK_FALSE; michael@0: NSS_IMPLEMENT_DATA const NSSItem michael@0: g_ck_false = { (CK_VOID_PTR)&s_false, sizeof(s_false) }; michael@0: michael@0: static const CK_OBJECT_CLASS s_class_cert = CKO_CERTIFICATE; michael@0: NSS_IMPLEMENT_DATA const NSSItem michael@0: g_ck_class_cert = { (CK_VOID_PTR)&s_class_cert, sizeof(s_class_cert) }; michael@0: michael@0: static const CK_OBJECT_CLASS s_class_pubkey = CKO_PUBLIC_KEY; michael@0: NSS_IMPLEMENT_DATA const NSSItem michael@0: g_ck_class_pubkey = { (CK_VOID_PTR)&s_class_pubkey, sizeof(s_class_pubkey) }; michael@0: michael@0: static const CK_OBJECT_CLASS s_class_privkey = CKO_PRIVATE_KEY; michael@0: NSS_IMPLEMENT_DATA const NSSItem michael@0: g_ck_class_privkey = { (CK_VOID_PTR)&s_class_privkey, sizeof(s_class_privkey) }; michael@0: michael@0: static PRBool michael@0: is_string_attribute ( michael@0: CK_ATTRIBUTE_TYPE aType michael@0: ) michael@0: { michael@0: PRBool isString; michael@0: switch (aType) { michael@0: case CKA_LABEL: michael@0: case CKA_NSS_EMAIL: michael@0: isString = PR_TRUE; michael@0: break; michael@0: default: michael@0: isString = PR_FALSE; michael@0: break; michael@0: } michael@0: return isString; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssCKObject_GetAttributes ( michael@0: CK_OBJECT_HANDLE object, michael@0: CK_ATTRIBUTE_PTR obj_template, michael@0: CK_ULONG count, michael@0: NSSArena *arenaOpt, michael@0: nssSession *session, michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: nssArenaMark *mark = NULL; michael@0: CK_SESSION_HANDLE hSession; michael@0: CK_ULONG i = 0; michael@0: CK_RV ckrv; michael@0: PRStatus nssrv; michael@0: PRBool alloced = PR_FALSE; michael@0: void *epv = nssSlot_GetCryptokiEPV(slot); michael@0: hSession = session->handle; michael@0: if (arenaOpt) { michael@0: mark = nssArena_Mark(arenaOpt); michael@0: if (!mark) { michael@0: goto loser; michael@0: } michael@0: } michael@0: nssSession_EnterMonitor(session); michael@0: /* XXX kinda hacky, if the storage size is already in the first template michael@0: * item, then skip the alloc portion michael@0: */ michael@0: if (obj_template[0].ulValueLen == 0) { michael@0: /* Get the storage size needed for each attribute */ michael@0: ckrv = CKAPI(epv)->C_GetAttributeValue(hSession, michael@0: object, obj_template, count); michael@0: if (ckrv != CKR_OK && michael@0: ckrv != CKR_ATTRIBUTE_TYPE_INVALID && michael@0: ckrv != CKR_ATTRIBUTE_SENSITIVE) michael@0: { michael@0: nssSession_ExitMonitor(session); michael@0: nss_SetError(NSS_ERROR_DEVICE_ERROR); michael@0: goto loser; michael@0: } michael@0: /* Allocate memory for each attribute. */ michael@0: for (i=0; iC_GetAttributeValue(hSession, michael@0: object, obj_template, count); michael@0: nssSession_ExitMonitor(session); michael@0: if (ckrv != CKR_OK && michael@0: ckrv != CKR_ATTRIBUTE_TYPE_INVALID && michael@0: ckrv != CKR_ATTRIBUTE_SENSITIVE) michael@0: { michael@0: nss_SetError(NSS_ERROR_DEVICE_ERROR); michael@0: goto loser; michael@0: } michael@0: if (alloced && arenaOpt) { michael@0: nssrv = nssArena_Unmark(arenaOpt, mark); michael@0: if (nssrv != PR_SUCCESS) { michael@0: goto loser; michael@0: } michael@0: } michael@0: michael@0: if (count > 1 && ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) || michael@0: (ckrv == CKR_ATTRIBUTE_SENSITIVE))) { michael@0: /* old tokens would keep the length of '0' and not deal with any michael@0: * of the attributes we passed. For those tokens read them one at michael@0: * a time */ michael@0: for (i=0; i < count; i++) { michael@0: if ((obj_template[i].ulValueLen == 0) michael@0: || (obj_template[i].ulValueLen == -1)) { michael@0: obj_template[i].ulValueLen=0; michael@0: (void) nssCKObject_GetAttributes(object,&obj_template[i], 1, michael@0: arenaOpt, session, slot); michael@0: } michael@0: } michael@0: } michael@0: return PR_SUCCESS; michael@0: loser: michael@0: if (alloced) { michael@0: if (arenaOpt) { michael@0: /* release all arena memory allocated before the failure. */ michael@0: (void)nssArena_Release(arenaOpt, mark); michael@0: } else { michael@0: CK_ULONG j; michael@0: /* free each heap object that was allocated before the failure. */ michael@0: for (j=0; jdata = (void *)attr.pValue; michael@0: rvItem->size = (PRUint32)attr.ulValueLen; michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRBool michael@0: nssCKObject_IsAttributeTrue ( michael@0: CK_OBJECT_HANDLE object, michael@0: CK_ATTRIBUTE_TYPE attribute, michael@0: nssSession *session, michael@0: NSSSlot *slot, michael@0: PRStatus *rvStatus michael@0: ) michael@0: { michael@0: CK_BBOOL bool; michael@0: CK_ATTRIBUTE_PTR attr; michael@0: CK_ATTRIBUTE atemplate = { 0, NULL, 0 }; michael@0: CK_RV ckrv; michael@0: void *epv = nssSlot_GetCryptokiEPV(slot); michael@0: attr = &atemplate; michael@0: NSS_CK_SET_ATTRIBUTE_VAR(attr, attribute, bool); michael@0: nssSession_EnterMonitor(session); michael@0: ckrv = CKAPI(epv)->C_GetAttributeValue(session->handle, object, michael@0: &atemplate, 1); michael@0: nssSession_ExitMonitor(session); michael@0: if (ckrv != CKR_OK) { michael@0: *rvStatus = PR_FAILURE; michael@0: return PR_FALSE; michael@0: } michael@0: *rvStatus = PR_SUCCESS; michael@0: return (PRBool)(bool == CK_TRUE); michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssCKObject_SetAttributes ( michael@0: CK_OBJECT_HANDLE object, michael@0: CK_ATTRIBUTE_PTR obj_template, michael@0: CK_ULONG count, michael@0: nssSession *session, michael@0: NSSSlot *slot michael@0: ) michael@0: { michael@0: CK_RV ckrv; michael@0: void *epv = nssSlot_GetCryptokiEPV(slot); michael@0: nssSession_EnterMonitor(session); michael@0: ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle, object, michael@0: obj_template, count); michael@0: nssSession_ExitMonitor(session); michael@0: if (ckrv == CKR_OK) { michael@0: return PR_SUCCESS; michael@0: } else { michael@0: return PR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRBool michael@0: nssCKObject_IsTokenObjectTemplate ( michael@0: CK_ATTRIBUTE_PTR objectTemplate, michael@0: CK_ULONG otsize michael@0: ) michael@0: { michael@0: CK_ULONG ul; michael@0: for (ul=0; ulpValue) { michael@0: /* default to PKIX */ michael@0: return NSSCertificateType_PKIX; michael@0: } michael@0: ckCertType = *((CK_ULONG *)attrib->pValue); michael@0: switch (ckCertType) { michael@0: case CKC_X_509: michael@0: return NSSCertificateType_PKIX; michael@0: default: michael@0: break; michael@0: } michael@0: return NSSCertificateType_Unknown; michael@0: } michael@0: michael@0: /* incoming pointers must be valid */ michael@0: NSS_IMPLEMENT PRStatus michael@0: nssCryptokiCertificate_GetAttributes ( michael@0: nssCryptokiObject *certObject, michael@0: nssSession *sessionOpt, michael@0: NSSArena *arenaOpt, michael@0: NSSCertificateType *certTypeOpt, michael@0: NSSItem *idOpt, michael@0: NSSDER *encodingOpt, michael@0: NSSDER *issuerOpt, michael@0: NSSDER *serialOpt, michael@0: NSSDER *subjectOpt michael@0: ) michael@0: { michael@0: PRStatus status; michael@0: PRUint32 i; michael@0: nssSession *session; michael@0: NSSSlot *slot; michael@0: CK_ULONG template_size; michael@0: CK_ATTRIBUTE_PTR attr; michael@0: CK_ATTRIBUTE cert_template[6]; michael@0: /* Set up a template of all options chosen by caller */ michael@0: NSS_CK_TEMPLATE_START(cert_template, attr, template_size); michael@0: if (certTypeOpt) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_CERTIFICATE_TYPE); michael@0: } michael@0: if (idOpt) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_ID); michael@0: } michael@0: if (encodingOpt) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE); michael@0: } michael@0: if (issuerOpt) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_ISSUER); michael@0: } michael@0: if (serialOpt) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SERIAL_NUMBER); michael@0: } michael@0: if (subjectOpt) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SUBJECT); michael@0: } michael@0: NSS_CK_TEMPLATE_FINISH(cert_template, attr, template_size); michael@0: if (template_size == 0) { michael@0: /* caller didn't want anything */ michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: status = nssToken_GetCachedObjectAttributes(certObject->token, arenaOpt, michael@0: certObject, CKO_CERTIFICATE, michael@0: cert_template, template_size); michael@0: if (status != PR_SUCCESS) { michael@0: michael@0: session = sessionOpt ? michael@0: sessionOpt : michael@0: nssToken_GetDefaultSession(certObject->token); michael@0: if (!session) { michael@0: nss_SetError(NSS_ERROR_INVALID_ARGUMENT); michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: slot = nssToken_GetSlot(certObject->token); michael@0: status = nssCKObject_GetAttributes(certObject->handle, michael@0: cert_template, template_size, michael@0: arenaOpt, session, slot); michael@0: nssSlot_Destroy(slot); michael@0: if (status != PR_SUCCESS) { michael@0: return status; michael@0: } michael@0: } michael@0: michael@0: i=0; michael@0: if (certTypeOpt) { michael@0: *certTypeOpt = nss_cert_type_from_ck_attrib(&cert_template[i]); i++; michael@0: } michael@0: if (idOpt) { michael@0: NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], idOpt); i++; michael@0: } michael@0: if (encodingOpt) { michael@0: NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], encodingOpt); i++; michael@0: } michael@0: if (issuerOpt) { michael@0: NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], issuerOpt); i++; michael@0: } michael@0: if (serialOpt) { michael@0: NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], serialOpt); i++; michael@0: } michael@0: if (subjectOpt) { michael@0: NSS_CK_ATTRIBUTE_TO_ITEM(&cert_template[i], subjectOpt); i++; michael@0: } michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: static nssTrustLevel michael@0: get_nss_trust ( michael@0: CK_TRUST ckt michael@0: ) michael@0: { michael@0: nssTrustLevel t; michael@0: switch (ckt) { michael@0: case CKT_NSS_NOT_TRUSTED: t = nssTrustLevel_NotTrusted; break; michael@0: case CKT_NSS_TRUSTED_DELEGATOR: t = nssTrustLevel_TrustedDelegator; michael@0: break; michael@0: case CKT_NSS_VALID_DELEGATOR: t = nssTrustLevel_ValidDelegator; break; michael@0: case CKT_NSS_TRUSTED: t = nssTrustLevel_Trusted; break; michael@0: case CKT_NSS_MUST_VERIFY_TRUST: t = nssTrustLevel_MustVerify; break; michael@0: case CKT_NSS_TRUST_UNKNOWN: michael@0: default: michael@0: t = nssTrustLevel_Unknown; break; michael@0: } michael@0: return t; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssCryptokiTrust_GetAttributes ( michael@0: nssCryptokiObject *trustObject, michael@0: nssSession *sessionOpt, michael@0: NSSItem *sha1_hash, michael@0: nssTrustLevel *serverAuth, michael@0: nssTrustLevel *clientAuth, michael@0: nssTrustLevel *codeSigning, michael@0: nssTrustLevel *emailProtection, michael@0: PRBool *stepUpApproved michael@0: ) michael@0: { michael@0: PRStatus status; michael@0: NSSSlot *slot; michael@0: nssSession *session; michael@0: CK_BBOOL isToken = PR_FALSE; michael@0: CK_BBOOL stepUp = PR_FALSE; michael@0: CK_TRUST saTrust = CKT_NSS_TRUST_UNKNOWN; michael@0: CK_TRUST caTrust = CKT_NSS_TRUST_UNKNOWN; michael@0: CK_TRUST epTrust = CKT_NSS_TRUST_UNKNOWN; michael@0: CK_TRUST csTrust = CKT_NSS_TRUST_UNKNOWN; michael@0: CK_ATTRIBUTE_PTR attr; michael@0: CK_ATTRIBUTE trust_template[7]; michael@0: CK_ATTRIBUTE_PTR sha1_hash_attr; michael@0: CK_ULONG trust_size; michael@0: michael@0: /* Use the trust object to find the trust settings */ michael@0: NSS_CK_TEMPLATE_START(trust_template, attr, trust_size); michael@0: NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TOKEN, isToken); michael@0: NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH, saTrust); michael@0: NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH, caTrust); michael@0: NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, epTrust); michael@0: NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING, csTrust); michael@0: NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_STEP_UP_APPROVED, stepUp); michael@0: sha1_hash_attr = attr; michael@0: NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, sha1_hash); michael@0: NSS_CK_TEMPLATE_FINISH(trust_template, attr, trust_size); michael@0: michael@0: status = nssToken_GetCachedObjectAttributes(trustObject->token, NULL, michael@0: trustObject, michael@0: CKO_NSS_TRUST, michael@0: trust_template, trust_size); michael@0: if (status != PR_SUCCESS) { michael@0: session = sessionOpt ? michael@0: sessionOpt : michael@0: nssToken_GetDefaultSession(trustObject->token); michael@0: if (!session) { michael@0: nss_SetError(NSS_ERROR_INVALID_ARGUMENT); michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: slot = nssToken_GetSlot(trustObject->token); michael@0: status = nssCKObject_GetAttributes(trustObject->handle, michael@0: trust_template, trust_size, michael@0: NULL, session, slot); michael@0: nssSlot_Destroy(slot); michael@0: if (status != PR_SUCCESS) { michael@0: return status; michael@0: } michael@0: } michael@0: michael@0: if (sha1_hash_attr->ulValueLen == -1) { michael@0: /* The trust object does not have the CKA_CERT_SHA1_HASH attribute. */ michael@0: sha1_hash_attr->ulValueLen = 0; michael@0: } michael@0: sha1_hash->size = sha1_hash_attr->ulValueLen; michael@0: *serverAuth = get_nss_trust(saTrust); michael@0: *clientAuth = get_nss_trust(caTrust); michael@0: *emailProtection = get_nss_trust(epTrust); michael@0: *codeSigning = get_nss_trust(csTrust); michael@0: *stepUpApproved = stepUp; michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssCryptokiCRL_GetAttributes ( michael@0: nssCryptokiObject *crlObject, michael@0: nssSession *sessionOpt, michael@0: NSSArena *arenaOpt, michael@0: NSSItem *encodingOpt, michael@0: NSSItem *subjectOpt, michael@0: CK_ULONG* crl_class, michael@0: NSSUTF8 **urlOpt, michael@0: PRBool *isKRLOpt michael@0: ) michael@0: { michael@0: PRStatus status; michael@0: NSSSlot *slot; michael@0: nssSession *session; michael@0: CK_ATTRIBUTE_PTR attr; michael@0: CK_ATTRIBUTE crl_template[7]; michael@0: CK_ULONG crl_size; michael@0: PRUint32 i; michael@0: michael@0: NSS_CK_TEMPLATE_START(crl_template, attr, crl_size); michael@0: if (crl_class) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_CLASS); michael@0: } michael@0: if (encodingOpt) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE); michael@0: } michael@0: if (urlOpt) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NSS_URL); michael@0: } michael@0: if (isKRLOpt) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_NSS_KRL); michael@0: } michael@0: if (subjectOpt) { michael@0: NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_SUBJECT); michael@0: } michael@0: NSS_CK_TEMPLATE_FINISH(crl_template, attr, crl_size); michael@0: michael@0: status = nssToken_GetCachedObjectAttributes(crlObject->token, NULL, michael@0: crlObject, michael@0: CKO_NSS_CRL, michael@0: crl_template, crl_size); michael@0: if (status != PR_SUCCESS) { michael@0: session = sessionOpt ? michael@0: sessionOpt : michael@0: nssToken_GetDefaultSession(crlObject->token); michael@0: if (session == NULL) { michael@0: nss_SetError(NSS_ERROR_INVALID_ARGUMENT); michael@0: return PR_FAILURE; michael@0: } michael@0: michael@0: slot = nssToken_GetSlot(crlObject->token); michael@0: status = nssCKObject_GetAttributes(crlObject->handle, michael@0: crl_template, crl_size, michael@0: arenaOpt, session, slot); michael@0: nssSlot_Destroy(slot); michael@0: if (status != PR_SUCCESS) { michael@0: return status; michael@0: } michael@0: } michael@0: michael@0: i=0; michael@0: if (crl_class) { michael@0: NSS_CK_ATTRIBUTE_TO_ULONG(&crl_template[i], *crl_class); i++; michael@0: } michael@0: if (encodingOpt) { michael@0: NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], encodingOpt); i++; michael@0: } michael@0: if (urlOpt) { michael@0: NSS_CK_ATTRIBUTE_TO_UTF8(&crl_template[i], *urlOpt); i++; michael@0: } michael@0: if (isKRLOpt) { michael@0: NSS_CK_ATTRIBUTE_TO_BOOL(&crl_template[i], *isKRLOpt); i++; michael@0: } michael@0: if (subjectOpt) { michael@0: NSS_CK_ATTRIBUTE_TO_ITEM(&crl_template[i], subjectOpt); i++; michael@0: } michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssCryptokiPrivateKey_SetCertificate ( michael@0: nssCryptokiObject *keyObject, michael@0: nssSession *sessionOpt, michael@0: const NSSUTF8 *nickname, michael@0: NSSItem *id, michael@0: NSSDER *subject michael@0: ) michael@0: { michael@0: CK_RV ckrv; michael@0: CK_ATTRIBUTE_PTR attr; michael@0: CK_ATTRIBUTE key_template[3]; michael@0: CK_ULONG key_size; michael@0: void *epv = nssToken_GetCryptokiEPV(keyObject->token); michael@0: nssSession *session; michael@0: NSSToken *token = keyObject->token; michael@0: nssSession *defaultSession = nssToken_GetDefaultSession(token); michael@0: PRBool createdSession = PR_FALSE; michael@0: michael@0: NSS_CK_TEMPLATE_START(key_template, attr, key_size); michael@0: NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname); michael@0: NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id); michael@0: NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject); michael@0: NSS_CK_TEMPLATE_FINISH(key_template, attr, key_size); michael@0: michael@0: if (sessionOpt) { michael@0: if (!nssSession_IsReadWrite(sessionOpt)) { michael@0: return PR_FAILURE; michael@0: } michael@0: session = sessionOpt; michael@0: } else if (defaultSession && nssSession_IsReadWrite(defaultSession)) { michael@0: session = defaultSession; michael@0: } else { michael@0: NSSSlot *slot = nssToken_GetSlot(token); michael@0: session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE); michael@0: nssSlot_Destroy(slot); michael@0: if (!session) { michael@0: return PR_FAILURE; michael@0: } michael@0: createdSession = PR_TRUE; michael@0: } michael@0: michael@0: ckrv = CKAPI(epv)->C_SetAttributeValue(session->handle, michael@0: keyObject->handle, michael@0: key_template, michael@0: key_size); michael@0: michael@0: if (createdSession) { michael@0: nssSession_Destroy(session); michael@0: } michael@0: michael@0: return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE; michael@0: } michael@0: