diff options
author | Daiki Ueno <dueno@redhat.com> | 2019-11-06 11:33:14 +0100 |
---|---|---|
committer | Daiki Ueno <dueno@redhat.com> | 2019-11-06 11:33:14 +0100 |
commit | 0e52897da7438eae158b1e4b6637116302cb0bf2 (patch) | |
tree | abcdc0f20cc7109477a7519787f53cde40f09ddd | |
parent | 34813d0525df1d7976e57c25cdaccb1865ef3668 (diff) | |
download | nss-hg-0e52897da7438eae158b1e4b6637116302cb0bf2.tar.gz |
Bug 1577803, pk11wrap: set friendly flag if token implements CKP_PUBLIC_CERTIFICATES_TOKEN, r=rrelyea
Summary: This makes NSS look for CKO_PROFILE object at token initialization time to check if it implements the [[ https://docs.oasis-open.org/pkcs11/pkcs11-profiles/v3.0/pkcs11-profiles-v3.0.pdf | Public Certificates Token profile ]] as defined in PKCS #11 v3.0. If it is found, the token is automatically marked as friendly so no authentication attempts will be made when accessing certificates.
Reviewers: rrelyea
Reviewed By: rrelyea
Subscribers: reviewbot
Bug #: 1577803
Differential Revision: https://phabricator.services.mozilla.com/D45669
-rw-r--r-- | gtests/pk11_gtest/pk11_module_unittest.cc | 17 | ||||
-rw-r--r-- | gtests/pkcs11testmodule/pkcs11testmodule.cpp | 97 | ||||
-rw-r--r-- | lib/pk11wrap/debug_module.c | 31 | ||||
-rw-r--r-- | lib/pk11wrap/pk11obj.c | 26 | ||||
-rw-r--r-- | lib/pk11wrap/pk11slot.c | 81 | ||||
-rw-r--r-- | lib/pk11wrap/secmodti.h | 2 | ||||
-rw-r--r-- | lib/util/pkcs11t.h | 15 |
7 files changed, 252 insertions, 17 deletions
diff --git a/gtests/pk11_gtest/pk11_module_unittest.cc b/gtests/pk11_gtest/pk11_module_unittest.cc index 508e1387a..1cc1df06e 100644 --- a/gtests/pk11_gtest/pk11_module_unittest.cc +++ b/gtests/pk11_gtest/pk11_module_unittest.cc @@ -51,7 +51,9 @@ TEST_F(Pkcs11ModuleTest, ListSlots) { // These tokens are always present. const std::vector<std::string> kSlotsWithToken = { "NSS Internal Cryptographic Services", - "NSS User Private Key and Certificate Services", "Test PKCS11 Slot 二"}; + "NSS User Private Key and Certificate Services", + "Test PKCS11 Public Certs Slot", + "Test PKCS11 Slot 二"}; std::vector<std::string> foundSlots; do { @@ -66,4 +68,17 @@ TEST_F(Pkcs11ModuleTest, ListSlots) { foundSlots.begin())); } +TEST_F(Pkcs11ModuleTest, PublicCertificatesToken) { + const std::string kRegularToken = "Test PKCS11 Tokeñ 2 Label"; + const std::string kPublicCertificatesToken = "Test PKCS11 Public Certs Token"; + + ScopedPK11SlotInfo slot1(PK11_FindSlotByName(kRegularToken.c_str())); + EXPECT_NE(nullptr, slot1); + EXPECT_FALSE(PK11_IsFriendly(slot1.get())); + + ScopedPK11SlotInfo slot2(PK11_FindSlotByName(kPublicCertificatesToken.c_str())); + EXPECT_NE(nullptr, slot2); + EXPECT_TRUE(PK11_IsFriendly(slot2.get())); +} + } // namespace nss_test diff --git a/gtests/pkcs11testmodule/pkcs11testmodule.cpp b/gtests/pkcs11testmodule/pkcs11testmodule.cpp index ea5a0201f..dbb574442 100644 --- a/gtests/pkcs11testmodule/pkcs11testmodule.cpp +++ b/gtests/pkcs11testmodule/pkcs11testmodule.cpp @@ -76,17 +76,25 @@ CK_RV Test_C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR) { return CKR_OK; } static int tokenPresent = 0; +// The token in slot 4 has 2 objects. Both of them are profile object +// and identified by object ID 1 or 2. +static bool readingProfile = false; +static const CK_PROFILE_ID profiles[] = {CKP_PUBLIC_CERTIFICATES_TOKEN, + CKP_BASELINE_PROVIDER}; +static int profileIndex = 0; + CK_RV Test_C_GetSlotList(CK_BBOOL limitToTokensPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) { if (!pulCount) { return CKR_ARGUMENTS_BAD; } - CK_SLOT_ID slots[3]; + CK_SLOT_ID slots[4]; CK_ULONG slotCount = 0; - // We always return slot 2. + // We always return slot 2 and 4. slots[slotCount++] = 2; + slots[slotCount++] = 4; // Slot 1 is a removable slot where a token is present if // tokenPresent = CK_TRUE. @@ -103,7 +111,7 @@ CK_RV Test_C_GetSlotList(CK_BBOOL limitToTokensPresent, if (*pulCount < slotCount) { return CKR_BUFFER_TOO_SMALL; } - memcpy(pSlotList, slots, sizeof(CK_ULONG) * slotCount); + memcpy(pSlotList, slots, sizeof(CK_SLOT_ID) * slotCount); } *pulCount = slotCount; @@ -113,6 +121,7 @@ CK_RV Test_C_GetSlotList(CK_BBOOL limitToTokensPresent, static const char TestSlotDescription[] = "Test PKCS11 Slot"; static const char TestSlot2Description[] = "Test PKCS11 Slot 二"; static const char TestSlot3Description[] = "Empty PKCS11 Slot"; +static const char TestSlot4Description[] = "Test PKCS11 Public Certs Slot"; CK_RV Test_C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { if (!pInfo) { @@ -133,6 +142,10 @@ CK_RV Test_C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { CopyString(pInfo->slotDescription, TestSlot3Description); pInfo->flags = CKF_REMOVABLE_DEVICE; break; + case 4: + CopyString(pInfo->slotDescription, TestSlot4Description); + pInfo->flags = CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE; + break; default: return CKR_ARGUMENTS_BAD; } @@ -148,6 +161,7 @@ CK_RV Test_C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { // as UTF-8. static const char TestTokenLabel[] = "Test PKCS11 Tokeñ Label"; static const char TestToken2Label[] = "Test PKCS11 Tokeñ 2 Label"; +static const char TestToken4Label[] = "Test PKCS11 Public Certs Token"; static const char TestTokenModel[] = "Test Model"; CK_RV Test_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { @@ -162,6 +176,9 @@ CK_RV Test_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { case 2: CopyString(pInfo->label, TestToken2Label); break; + case 4: + CopyString(pInfo->label, TestToken4Label); + break; default: return CKR_ARGUMENTS_BAD; } @@ -223,6 +240,9 @@ CK_RV Test_C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS, CK_VOID_PTR, CK_NOTIFY, case 2: *phSession = 2; break; + case 4: + *phSession = 4; + break; default: return CKR_ARGUMENTS_BAD; } @@ -247,6 +267,9 @@ CK_RV Test_C_GetSessionInfo(CK_SESSION_HANDLE hSession, case 2: pInfo->slotID = 2; break; + case 4: + pInfo->slotID = 4; + break; default: return CKR_ARGUMENTS_BAD; } @@ -289,8 +312,27 @@ CK_RV Test_C_GetObjectSize(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ULONG_PTR) { return CKR_FUNCTION_NOT_SUPPORTED; } -CK_RV Test_C_GetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, - CK_ATTRIBUTE_PTR, CK_ULONG) { +CK_RV Test_C_GetAttributeValue(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE hObject, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { + if (hSession == 4) { + assert(hObject >= 1 && + hObject - 1 < sizeof(profiles) / sizeof(profiles[0])); + for (CK_ULONG count = 0; count < ulCount; count++) { + if (pTemplate[count].type == CKA_PROFILE_ID) { + if (pTemplate[count].pValue) { + assert(pTemplate[count].ulValueLen == sizeof(CK_ULONG)); + CK_ULONG value = profiles[hObject - 1]; + memcpy(pTemplate[count].pValue, &value, sizeof(value)); + } else { + pTemplate[count].ulValueLen = sizeof(CK_ULONG); + } + } else { + pTemplate[count].ulValueLen = (CK_ULONG)-1; + } + } + return CKR_OK; + } return CKR_FUNCTION_NOT_SUPPORTED; } @@ -299,17 +341,54 @@ CK_RV Test_C_SetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, return CKR_FUNCTION_NOT_SUPPORTED; } -CK_RV Test_C_FindObjectsInit(CK_SESSION_HANDLE, CK_ATTRIBUTE_PTR, CK_ULONG) { +CK_RV Test_C_FindObjectsInit(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { + // Slot 4 + if (hSession == 4) { + for (CK_ULONG count = 0; count < ulCount; count++) { + CK_ATTRIBUTE attribute = pTemplate[count]; + if (attribute.type == CKA_CLASS) { + assert(attribute.ulValueLen == sizeof(CK_ULONG)); + + CK_ULONG value; + memcpy(&value, attribute.pValue, attribute.ulValueLen); + if (value == CKO_PROFILE) { + readingProfile = true; + profileIndex = 0; + break; + } + } + } + } return CKR_OK; } -CK_RV Test_C_FindObjects(CK_SESSION_HANDLE, CK_OBJECT_HANDLE_PTR, CK_ULONG, +CK_RV Test_C_FindObjects(CK_SESSION_HANDLE hSession, + CK_OBJECT_HANDLE_PTR phObject, + CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { - *pulObjectCount = 0; + if (readingProfile) { + assert(hSession == 4); + CK_ULONG count = ulMaxObjectCount; + size_t remaining = sizeof(profiles) / sizeof(profiles[0]) - profileIndex; + if (count > remaining) { + count = remaining; + } + for (CK_ULONG i = 0; i < count; i++) { + phObject[i] = i + 1; + } + profileIndex += count; + *pulObjectCount = count; + } else { + *pulObjectCount = 0; + } return CKR_OK; } -CK_RV Test_C_FindObjectsFinal(CK_SESSION_HANDLE) { return CKR_OK; } +CK_RV Test_C_FindObjectsFinal(CK_SESSION_HANDLE hSession) { + readingProfile = false; + return CKR_OK; +} CK_RV Test_C_EncryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE) { diff --git a/lib/pk11wrap/debug_module.c b/lib/pk11wrap/debug_module.c index 59b89c37a..6dddb24b4 100644 --- a/lib/pk11wrap/debug_module.c +++ b/lib/pk11wrap/debug_module.c @@ -134,6 +134,7 @@ get_attr_type_str(CK_ATTRIBUTE_TYPE atype, char *str, int len) CASE(CKA_RESET_ON_INIT); CASE(CKA_HAS_RESET); CASE(CKA_VENDOR_DEFINED); + CASE(CKA_PROFILE_ID); CASE(CKA_NSS_URL); CASE(CKA_NSS_EMAIL); CASE(CKA_NSS_SMIME_INFO); @@ -189,6 +190,7 @@ get_obj_class(CK_OBJECT_CLASS objClass, char *str, int len) CASE(CKO_SECRET_KEY); CASE(CKO_HW_FEATURE); CASE(CKO_DOMAIN_PARAMETERS); + CASE(CKO_PROFILE); CASE(CKO_NSS_CRL); CASE(CKO_NSS_SMIME); CASE(CKO_NSS_TRUST); @@ -203,6 +205,27 @@ get_obj_class(CK_OBJECT_CLASS objClass, char *str, int len) } static void +get_profile_val(CK_PROFILE_ID profile, char *str, int len) +{ + + const char *a = NULL; + + switch (profile) { + CASE(CKP_INVALID_ID); + CASE(CKP_BASELINE_PROVIDER); + CASE(CKP_EXTENDED_PROVIDER); + CASE(CKP_AUTHENTICATION_TOKEN); + CASE(CKP_PUBLIC_CERTIFICATES_TOKEN); + default: + break; + } + if (a) + PR_snprintf(str, len, "%s", a); + else + PR_snprintf(str, len, "0x%p", profile); +} + +static void get_trust_val(CK_TRUST trust, char *str, int len) { const char *a = NULL; @@ -688,6 +711,14 @@ print_attr_value(CK_ATTRIBUTE_PTR attr) atype, valstr, attr->ulValueLen)); break; } + case CKA_PROFILE_ID: + if (attr->ulValueLen > 0 && attr->pValue) { + CK_PROFILE_ID profile = *((CK_PROFILE_ID *)attr->pValue); + get_profile_val(profile, valstr, sizeof valstr); + PR_LOG(modlog, 4, (fmt_s_s_d, + atype, valstr, attr->ulValueLen)); + break; + } case CKA_ISSUER: case CKA_SUBJECT: if (attr->ulValueLen > 0 && attr->pValue) { diff --git a/lib/pk11wrap/pk11obj.c b/lib/pk11wrap/pk11obj.c index 16ff15a80..bc9e93454 100644 --- a/lib/pk11wrap/pk11obj.c +++ b/lib/pk11wrap/pk11obj.c @@ -1830,15 +1830,24 @@ pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, { CK_OBJECT_HANDLE *objID = NULL; CK_ULONG returned_count = 0; + PRBool owner = PR_TRUE; + CK_SESSION_HANDLE session; + PRBool haslock = PR_FALSE; CK_RV crv = CKR_SESSION_HANDLE_INVALID; - PK11_EnterSlotMonitor(slot); - if (slot->session != CK_INVALID_SESSION) { - crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, + session = pk11_GetNewSession(slot, &owner); + haslock = (!owner || !(slot->isThreadSafe)); + if (haslock) { + PK11_EnterSlotMonitor(slot); + } + if (session != CK_INVALID_SESSION) { + crv = PK11_GETTAB(slot)->C_FindObjectsInit(session, findTemplate, templCount); } if (crv != CKR_OK) { - PK11_ExitSlotMonitor(slot); + if (haslock) + PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot, session, owner); PORT_SetError(PK11_MapError(crv)); *object_count = -1; return NULL; @@ -1863,7 +1872,7 @@ pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, PORT_Free(oldObjID); break; } - crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, + crv = PK11_GETTAB(slot)->C_FindObjects(session, &objID[*object_count], PK11_SEARCH_CHUNKSIZE, &returned_count); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); @@ -1874,8 +1883,11 @@ pk11_FindObjectsByTemplate(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, *object_count += returned_count; } while (returned_count == PK11_SEARCH_CHUNKSIZE); - PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); - PK11_ExitSlotMonitor(slot); + PK11_GETTAB(slot)->C_FindObjectsFinal(session); + if (haslock) { + PK11_ExitSlotMonitor(slot); + } + pk11_CloseSession(slot, session, owner); if (objID && (*object_count == 0)) { PORT_Free(objID); diff --git a/lib/pk11wrap/pk11slot.c b/lib/pk11wrap/pk11slot.c index 12aeddc8a..072294056 100644 --- a/lib/pk11wrap/pk11slot.c +++ b/lib/pk11wrap/pk11slot.c @@ -419,6 +419,8 @@ PK11_NewSlotInfo(SECMODModule *mod) slot->hasRootCerts = PR_FALSE; slot->hasRootTrust = PR_FALSE; slot->nssToken = NULL; + slot->profileList = NULL; + slot->profileCount = 0; return slot; } @@ -446,6 +448,9 @@ PK11_DestroySlot(PK11SlotInfo *slot) if (slot->mechanismList) { PORT_Free(slot->mechanismList); } + if (slot->profileList) { + PORT_Free(slot->profileList); + } if (slot->isThreadSafe && slot->sessionLock) { PZ_DestroyLock(slot->sessionLock); } @@ -1170,6 +1175,76 @@ PK11_ReadMechanismList(PK11SlotInfo *slot) return SECSuccess; } +static SECStatus +pk11_ReadProfileList(PK11SlotInfo *slot) +{ + CK_ATTRIBUTE findTemp[2]; + CK_ATTRIBUTE *attrs; + CK_BBOOL cktrue = CK_TRUE; + CK_OBJECT_CLASS oclass = CKO_PROFILE; + int tsize; + int objCount; + CK_OBJECT_HANDLE *handles = NULL; + int i; + + attrs = findTemp; + PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); + attrs++; + PK11_SETATTRS(attrs, CKA_CLASS, &oclass, sizeof(oclass)); + attrs++; + tsize = attrs - findTemp; + PORT_Assert(tsize <= sizeof(findTemp) / sizeof(CK_ATTRIBUTE)); + + if (slot->profileList) { + PORT_Free(slot->profileList); + slot->profileList = NULL; + } + slot->profileCount = 0; + + objCount = 0; + handles = pk11_FindObjectsByTemplate(slot, findTemp, tsize, &objCount); + if (handles == NULL) { + if (objCount < 0) { + return SECFailure; /* error code is set */ + } + PORT_Assert(objCount == 0); + return SECSuccess; + } + + slot->profileList = (CK_PROFILE_ID *) + PORT_Alloc(objCount * sizeof(CK_PROFILE_ID)); + if (slot->profileList == NULL) { + PORT_Free(handles); + return SECFailure; /* error code is set */ + } + + for (i = 0; i < objCount; i++) { + CK_ULONG value; + + value = PK11_ReadULongAttribute(slot, handles[i], CKA_PROFILE_ID); + if (value == CK_UNAVAILABLE_INFORMATION) { + continue; + } + slot->profileList[slot->profileCount++] = value; + } + + PORT_Free(handles); + return SECSuccess; +} + +static PRBool +pk11_HasProfile(PK11SlotInfo *slot, CK_PROFILE_ID id) +{ + int i; + + for (i = 0; i < slot->profileCount; i++) { + if (slot->profileList[i] == id) { + return PR_TRUE; + } + } + return PR_FALSE; +} + /* * initialize a new token * unlike initialize slot, this can be called multiple times in the lifetime @@ -1291,6 +1366,11 @@ PK11_InitToken(PK11SlotInfo *slot, PRBool loadCerts) if (status != PR_SUCCESS) return SECFailure; + rv = pk11_ReadProfileList(slot); + if (rv != SECSuccess) { + return SECFailure; + } + if (!(slot->isInternal) && (slot->hasRandom)) { /* if this slot has a random number generater, use it to add entropy * to the internal slot. */ @@ -1695,6 +1775,7 @@ PK11_IsFriendly(PK11SlotInfo *slot) { /* internal slot always has public readable certs */ return (PRBool)(slot->isInternal || + pk11_HasProfile(slot, CKP_PUBLIC_CERTIFICATES_TOKEN) || ((slot->defaultFlags & SECMOD_FRIENDLY_FLAG) == SECMOD_FRIENDLY_FLAG)); } diff --git a/lib/pk11wrap/secmodti.h b/lib/pk11wrap/secmodti.h index 260e6387d..4af20100d 100644 --- a/lib/pk11wrap/secmodti.h +++ b/lib/pk11wrap/secmodti.h @@ -111,6 +111,8 @@ struct PK11SlotInfoStr { CK_TOKEN_INFO tokenInfo; /* fast mechanism lookup */ char mechanismBits[256]; + CK_PROFILE_ID *profileList; + int profileCount; }; /* Symetric Key structure. Reference Counted */ diff --git a/lib/util/pkcs11t.h b/lib/util/pkcs11t.h index 6ee6609a9..d57da409a 100644 --- a/lib/util/pkcs11t.h +++ b/lib/util/pkcs11t.h @@ -313,6 +313,7 @@ typedef CK_ULONG CK_OBJECT_CLASS; /* CKO_HW_FEATURE is new for v2.10 */ /* CKO_DOMAIN_PARAMETERS is new for v2.11 */ /* CKO_MECHANISM is new for v2.20 */ +/* CKO_PROFILE is new for v3.00 */ #define CKO_DATA 0x00000000 #define CKO_CERTIFICATE 0x00000001 #define CKO_PUBLIC_KEY 0x00000002 @@ -321,10 +322,23 @@ typedef CK_ULONG CK_OBJECT_CLASS; #define CKO_HW_FEATURE 0x00000005 #define CKO_DOMAIN_PARAMETERS 0x00000006 #define CKO_MECHANISM 0x00000007 +#define CKO_PROFILE 0x00000009 #define CKO_VENDOR_DEFINED 0x80000000 typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR; +/* CK_PROFILE_ID is new for v3.00. CK_PROFILE_ID is a value that + * identifies the profile that the token supports. */ +typedef CK_ULONG CK_PROFILE_ID; + +/* Profile ID's */ +#define CKP_INVALID_ID 0x00000000UL +#define CKP_BASELINE_PROVIDER 0x00000001UL +#define CKP_EXTENDED_PROVIDER 0x00000002UL +#define CKP_AUTHENTICATION_TOKEN 0x00000003UL +#define CKP_PUBLIC_CERTIFICATES_TOKEN 0x00000004UL +#define CKP_VENDOR_DEFINED 0x80000000UL + /* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a * value that identifies the hardware feature type of an object * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */ @@ -536,6 +550,7 @@ typedef CK_ULONG CK_ATTRIBUTE_TYPE; #define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502 #define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503 #define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x00000600) +#define CKA_PROFILE_ID 0x00000601UL #define CKA_VENDOR_DEFINED 0x80000000 |