Open
Bug 2075845
Opened 7 days ago
Updated 3 days ago
C_VerifyInit returns CKR_MECHANISM_INVALID for CKM_AES_CMAC, although the mechanism advertises CKF_VERIFY and C_SignInit accepts it
Categories
(NSS :: Libraries, defect, P3)
NSS
Libraries
Tracking
(Not tracked)
UNCONFIRMED
People
(Reporter: eric.knauel, Unassigned)
Details
Attachments
(2 files)
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36
Steps to reproduce
softoken advertises sign and verify for both AES-CMAC mechanisms. Output of p11slotinfo (from https://github.com/Mastercard/pkcs11-tools), NSS 3.130, excerpt:
PKCS#11 Library
---------------
Name : /opt/homebrew/Cellar/nss/3.130/lib/libsoftokn3.dylib
Lib version : 3.130
API version : 2.40
Description : NSS Internal Crypto Services
Manufacturer: Mozilla Foundation
Slot[1]
-------------
Slot Number : 2
Description : NSS User Private Key and Certificate Services
Manufacturer: Mozilla Foundation
Slot Flags : [ CKF_TOKEN_PRESENT ]
Token
-------------
Label : NSS Certificate DB
Manufacturer: Mozilla Foundation
Token Flags : [ CKF_RNG CKF_LOGIN_REQUIRED CKF_USER_PIN_INITIALIZED CKF_DUAL_CRYPTO_OPERATIONS CKF_TOKEN_INITIALIZED ]
Mechanisms:
-----------
[...]
CKM_AES_CMAC --- --- --- sig --- vfy --- --- --- --- --- --- --- --- SW (0000108a)
CKM_AES_CMAC_GENERAL --- --- --- sig --- vfy --- --- --- --- --- --- --- --- SW (0000108b)
[...]
Steps to reproduce: build and run the attached cmac_verify.c against softoken, with a fresh database created by certutil -N:
cc -I <dir containing the OASIS pkcs11.h> -o cmac_verify cmac_verify.c -ldl
NSS_LIB_PARAMS=configDir=<db dir> ./cmac_verify <path to libsoftokn3> <user PIN>
The program:
- generates a 128-bit AES session key with CKA_SIGN and CKA_VERIFY;
- reads the mechanism info for CKM_AES_CMAC;
- computes a MAC with C_SignInit/C_Sign;
- tries to verify it with C_VerifyInit/C_Verify, using the same key and mechanism and no parameter.
Program to reproduce:
/*
* Minimal reproducer: C_VerifyInit rejects CKM_AES_CMAC, which C_SignInit accepts.
*
* Generates an AES key with CKA_SIGN and CKA_VERIFY, reads the mechanism info
* for CKM_AES_CMAC, computes a MAC with C_SignInit/C_Sign and checks it with
* C_VerifyInit/C_Verify -- same key, same mechanism, no parameter.
*
* Expected: C_GetMechanismInfo reports CKF_VERIFY for CKM_AES_CMAC, so
* C_VerifyInit accepts it and C_Verify returns CKR_OK for the MAC just made.
* PKCS#11 3.1 (6.14, Table 116 "Mechanisms vs. Functions") lists both AES-CMAC
* mechanisms for sign and verify.
*
* Against NSS softoken 3.120 (Ubuntu 26.04's libnss3 2:3.120-1ubuntu2.1) the
* mechanism info does advertise CKF_SIGN | CKF_VERIFY, and signing works, but
* C_VerifyInit fails with CKR_MECHANISM_INVALID.
*
* In NSS's source (lib/softoken/pkcs11c.c) the mechanism switch in
* NSC_SignInit has cases for CKM_AES_CMAC and CKM_AES_CMAC_GENERAL; the one in
* NSC_VerifyInit has neither and falls through to its default,
* CKR_MECHANISM_INVALID. CKM_AES_CMAC_GENERAL is therefore affected too; this
* program only exercises CKM_AES_CMAC.
*
* cc -I c_src -o /tmp/cmac_verify test/support/cmac_verify.c -ldl
* /tmp/cmac_verify <module.so> <user-pin> [token-label]
*
* NSS softoken finds its database through NSS_LIB_PARAMS and exposes two slots,
* so the token is selected by label (default "NSS Certificate DB").
* test/support/nss-spy-log.sh builds this against p11ex's test image and
* writes cmac_verify-pkcs11-spy.log; see that script for how to run it.
*
* Exits non-zero if verification cannot be initialised or fails.
*/
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CK_PTR *
#define CK_DECLARE_FUNCTION(returnType, name) returnType name
#define CK_DECLARE_FUNCTION_POINTER(returnType, name) returnType(CK_PTR name)
#define CK_CALLBACK_FUNCTION(returnType, name) returnType(CK_PTR name)
#ifndef NULL_PTR
#define NULL_PTR NULL
#endif
#include "pkcs11.h"
static CK_FUNCTION_LIST_PTR p11;
#define CHECK(rv, what) \
do { \
if ((rv) != CKR_OK) { \
fprintf(stderr, "%s failed: 0x%lx\n", (what), (unsigned long)(rv)); \
return 1; \
} \
} while (0)
/* Token labels are blank-padded to 32 bytes. */
static int find_slot(const char *label, CK_SLOT_ID *slot) {
CK_SLOT_ID slots[32];
CK_ULONG count = 32;
size_t n = strlen(label);
if (p11->C_GetSlotList(CK_TRUE, slots, &count) != CKR_OK) {
return 0;
}
for (CK_ULONG i = 0; i < count; i++) {
CK_TOKEN_INFO info;
int match = 1;
if (p11->C_GetTokenInfo(slots[i], &info) != CKR_OK || n > sizeof(info.label) ||
memcmp(info.label, label, n) != 0) {
continue;
}
for (size_t j = n; j < sizeof(info.label); j++) {
if (info.label[j] != ' ') {
match = 0;
}
}
if (match) {
*slot = slots[i];
return 1;
}
}
return 0;
}
int main(int argc, char **argv) {
void *handle;
CK_C_GetFunctionList get_list;
CK_SLOT_ID slot;
const char *label;
CK_SESSION_HANDLE session;
CK_OBJECT_HANDLE key;
CK_MECHANISM_INFO info;
CK_RV rv;
CK_MECHANISM mech = {CKM_AES_CMAC, NULL, 0};
CK_BYTE msg[] = "p11ex AES-CMAC verify reproducer";
CK_ULONG msg_len = (CK_ULONG)(sizeof(msg) - 1);
CK_BYTE mac[64];
CK_ULONG mac_len = sizeof(mac);
if (argc < 3) {
fprintf(stderr, "usage: %s <module.so> <user-pin> [token-label]\n", argv[0]);
return 2;
}
label = argc > 3 ? argv[3] : "NSS Certificate DB";
handle = dlopen(argv[1], RTLD_NOW);
if (!handle) {
fprintf(stderr, "dlopen: %s\n", dlerror());
return 1;
}
get_list = (CK_C_GetFunctionList)dlsym(handle, "C_GetFunctionList");
if (!get_list) {
fprintf(stderr, "no C_GetFunctionList\n");
return 1;
}
rv = get_list(&p11);
CHECK(rv, "C_GetFunctionList");
rv = p11->C_Initialize(NULL);
CHECK(rv, "C_Initialize");
if (!find_slot(label, &slot)) {
fprintf(stderr, "no token labelled \"%s\"\n", label);
return 1;
}
rv = p11->C_OpenSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL,
&session);
CHECK(rv, "C_OpenSession");
rv = p11->C_Login(session, CKU_USER, (CK_UTF8CHAR_PTR)argv[2],
(CK_ULONG)strlen(argv[2]));
CHECK(rv, "C_Login");
{
CK_MECHANISM keygen = {CKM_AES_KEY_GEN, NULL, 0};
CK_BBOOL yes = CK_TRUE, no = CK_FALSE;
CK_ULONG value_len = 16;
CK_ATTRIBUTE tmpl[] = {{CKA_TOKEN, &no, sizeof(no)},
{CKA_VALUE_LEN, &value_len, sizeof(value_len)},
{CKA_SIGN, &yes, sizeof(yes)},
{CKA_VERIFY, &yes, sizeof(yes)}};
rv = p11->C_GenerateKey(session, &keygen, tmpl, 4, &key);
CHECK(rv, "C_GenerateKey");
}
printf("module: %s\n", argv[1]);
printf("token: %s\n\n", label);
rv = p11->C_GetMechanismInfo(slot, CKM_AES_CMAC, &info);
CHECK(rv, "C_GetMechanismInfo");
printf("CKM_AES_CMAC mechanism info: flags 0x%lx (CKF_SIGN %s, CKF_VERIFY %s)\n\n",
(unsigned long)info.flags, (info.flags & CKF_SIGN) ? "set" : "not set",
(info.flags & CKF_VERIFY) ? "set" : "not set");
rv = p11->C_SignInit(session, &mech, key);
printf("C_SignInit(CKM_AES_CMAC) -> rv 0x%lx\n", (unsigned long)rv);
CHECK(rv, "C_SignInit");
rv = p11->C_Sign(session, msg, msg_len, mac, &mac_len);
printf("C_Sign -> rv 0x%lx, %lu byte MAC\n", (unsigned long)rv,
(unsigned long)mac_len);
CHECK(rv, "C_Sign");
rv = p11->C_VerifyInit(session, &mech, key);
printf("C_VerifyInit(CKM_AES_CMAC) -> rv 0x%lx%s\n", (unsigned long)rv,
rv == CKR_MECHANISM_INVALID ? " CKR_MECHANISM_INVALID" : "");
if (rv == CKR_OK) {
rv = p11->C_Verify(session, msg, msg_len, mac, mac_len);
printf("C_Verify -> rv 0x%lx\n", (unsigned long)rv);
}
p11->C_DestroyObject(session, key);
p11->C_Logout(session);
p11->C_CloseSession(session);
p11->C_Finalize(NULL);
if (rv != CKR_OK) {
printf("\nFAIL: a MAC made with CKM_AES_CMAC cannot be verified with it\n");
return 1;
}
printf("\nok: the MAC verifies\n");
return 0;
}
Actual results
CKM_AES_CMAC mechanism info: flags 0x2800 (CKF_SIGN set, CKF_VERIFY set)
C_SignInit(CKM_AES_CMAC) -> rv 0x0
C_Sign -> rv 0x0, 16 byte MAC
C_VerifyInit(CKM_AES_CMAC) -> rv 0x70 CKR_MECHANISM_INVALID
The attached pkcs11-spy log (NSS 3.120) shows the same sequence.
Expected results
C_VerifyInit succeeds and C_Verify returns CKR_OK for the MAC just produced:
- The token's own mechanism info says CKF_VERIFY is supported (see above).
- PKCS#11 3.1, section 6.14, Table 116 lists both CKM_AES_CMAC and CKM_AES_CMAC_GENERAL for Sign & Verify.
| Reporter | ||
Comment 1•7 days ago
|
||
Updated•3 days ago
|
Severity: -- → S3
Priority: -- → P3
You need to log in
before you can comment on or make changes to this bug.
Description
•