void InfoTests::testGetTokenInfo() { CK_RV rv; CK_TOKEN_INFO tokenInfo; // Just make sure that we finalize any previous failed tests C_Finalize(NULL_PTR); rv = C_GetTokenInfo(SLOT_NO_INIT_TOKEN, &tokenInfo); CPPUNIT_ASSERT(rv == CKR_CRYPTOKI_NOT_INITIALIZED); rv = C_Initialize(NULL_PTR); CPPUNIT_ASSERT(rv == CKR_OK); rv = C_GetTokenInfo(SLOT_NO_INIT_TOKEN, NULL_PTR); CPPUNIT_ASSERT(rv == CKR_ARGUMENTS_BAD); rv = C_GetTokenInfo(SLOT_INVALID, &tokenInfo); CPPUNIT_ASSERT(rv == CKR_SLOT_ID_INVALID); rv = C_GetTokenInfo(SLOT_NO_INIT_TOKEN, &tokenInfo); CPPUNIT_ASSERT(rv == CKR_OK); CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == 0); rv = C_GetTokenInfo(SLOT_INIT_TOKEN, &tokenInfo); CPPUNIT_ASSERT(rv == CKR_OK); CPPUNIT_ASSERT((tokenInfo.flags & CKF_TOKEN_INITIALIZED) == CKF_TOKEN_INITIALIZED); C_Finalize(NULL_PTR); }
static int pkcs11_check_token(PKCS11_CTX * ctx, PKCS11_SLOT * slot) { PKCS11_SLOT_private *priv = PRIVSLOT(slot); PKCS11_TOKEN_private *tpriv; CK_TOKEN_INFO info; int rv; if (slot->token) { pkcs11_destroy_token(slot->token); } else { slot->token = OPENSSL_malloc(sizeof(PKCS11_TOKEN)); if (slot->token == NULL) return -1; memset(slot->token, 0, sizeof(PKCS11_TOKEN)); } rv = CRYPTOKI_call(ctx, C_GetTokenInfo(priv->id, &info)); if (rv == CKR_TOKEN_NOT_PRESENT || rv == CKR_TOKEN_NOT_RECOGNIZED) { OPENSSL_free(slot->token); slot->token = NULL; return 0; } CRYPTOKI_checkerr(PKCS11_F_PKCS11_CHECK_TOKEN, rv); /* We have a token */ tpriv = OPENSSL_malloc(sizeof(PKCS11_TOKEN_private)); if (tpriv == NULL) return -1; memset(tpriv, 0, sizeof(PKCS11_TOKEN_private)); tpriv->parent = slot; tpriv->prv.keys = NULL; tpriv->prv.num = -1; tpriv->pub.keys = NULL; tpriv->pub.num = -1; tpriv->ncerts = -1; slot->token->label = PKCS11_DUP(info.label); slot->token->manufacturer = PKCS11_DUP(info.manufacturerID); slot->token->model = PKCS11_DUP(info.model); slot->token->serialnr = PKCS11_DUP(info.serialNumber); slot->token->initialized = (info.flags & CKF_TOKEN_INITIALIZED) ? 1 : 0; slot->token->loginRequired = (info.flags & CKF_LOGIN_REQUIRED) ? 1 : 0; slot->token->secureLogin = (info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ? 1 : 0; slot->token->userPinSet = (info.flags & CKF_USER_PIN_INITIALIZED) ? 1 : 0; slot->token->readOnly = (info.flags & CKF_WRITE_PROTECTED) ? 1 : 0; slot->token->hasRng = (info.flags & CKF_RNG) ? 1 : 0; slot->token->userPinCountLow = (info.flags & CKF_USER_PIN_COUNT_LOW) ? 1 : 0; slot->token->userPinFinalTry = (info.flags & CKF_USER_PIN_FINAL_TRY) ? 1 : 0; slot->token->userPinLocked = (info.flags & CKF_USER_PIN_LOCKED) ? 1 : 0; slot->token->userPinToBeChanged = (info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? 1 : 0; slot->token->soPinCountLow = (info.flags & CKF_SO_PIN_COUNT_LOW) ? 1 : 0; slot->token->soPinFinalTry = (info.flags & CKF_SO_PIN_FINAL_TRY) ? 1 : 0; slot->token->soPinLocked = (info.flags & CKF_SO_PIN_LOCKED) ? 1 : 0; slot->token->soPinToBeChanged = (info.flags & CKF_SO_PIN_TO_BE_CHANGED) ? 1 : 0; slot->token->_private = tpriv; return 0; }
void CPKCSDemoDlg::OnBtnKeypairgen() { StartOP(); CK_TOKEN_INFO tokenInfo = {0}; CK_RV rv = C_GetTokenInfo(m_pSlotList[0], &tokenInfo); if (CKR_OK != rv) { ShowMsg(NEWLINE"Can not get token information!"NEWLINE); return; } DlgUserPIN* dlgUserPIN = new DlgUserPIN; dlgUserPIN->DoModal(); delete dlgUserPIN; if("" == g_strUserPIN) { ShowMsg(NEWLINE"You should enter User PIN before generating RSA Key pair!"NEWLINE); return; } CK_ULONG ulPIN = g_strUserPIN.GetLength(); CK_BYTE_PTR pPIN = (CK_BYTE_PTR)g_strUserPIN.GetBuffer(ulPIN); ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); rv = C_Login(m_hSession, CKU_USER, pPIN, ulPIN); if(CKR_OK != rv) { ShowErr(NEWLINE"Can't use your User PIN login to token ,ErrorCode: 0x%08X."NEWLINE, rv); return; } else ShowMsg(NEWLINE"Logging in to token Successfully!"NEWLINE); ::SetCursor(::LoadCursor(NULL, IDC_WAIT)); rv = C_GenerateKeyPair( m_hSession, &keyGenMechanism, pubTemplate, countof(pubTemplate), priTemplate, countof(priTemplate), &m_hPubKey, &m_hPriKey); if(CKR_OK != rv) { ShowErr(NEWLINE"Can't generate RSA key pair, ErrorCode: 0x%08X."NEWLINE, rv); return; } else { m_btnKeyPairGen.EnableWindow(FALSE); m_btnSign.EnableWindow(TRUE); m_btnEncrypt.EnableWindow(TRUE); ShowMsg(NEWLINE"Generate Key Pair Successfully!"NEWLINE); ShowMsg(NEWLINE"Now you can Sign, Verify, Encrypt and Decrypt by using the Key Pair!"NEWLINE); m_bKeyGen = TRUE; } }
static int initFunction( DEVICE_INFO *deviceInfo, const char *name, const int nameLength ) { CK_SESSION_HANDLE hSession; CK_SLOT_ID slotList[ MAX_PKCS11_SLOTS + 8 ]; CK_ULONG slotCount = MAX_PKCS11_SLOTS; CK_SLOT_INFO slotInfo; CK_TOKEN_INFO tokenInfo; CK_RV status; PKCS11_INFO *pkcs11Info = deviceInfo->devicePKCS11; const PKCS11_MECHANISM_INFO *mechanismInfoPtr; char *labelPtr; int tokenSlot = DEFAULT_SLOT, i, labelLength, mechanismInfoSize; int cryptStatus, cryptStatus2; assert( isWritePtr( deviceInfo, sizeof( DEVICE_INFO ) ) ); assert( isReadPtr( name, nameLength ) ); /* Get information on all available slots */ memset( slotList, 0, sizeof( slotList ) ); status = C_GetSlotList( TRUE, slotList, &slotCount ); if( status != CKR_OK ) return( pkcs11MapError( status, CRYPT_ERROR_OPEN ) ); if( slotCount <= 0 ) { /* There are token slots present but no tokens in the slots */ return( CRYPT_ERROR_OPEN ); } /* Check whether a token name (used to select the slot) has been specified */ for( i = 1; i < nameLength - 1; i++ ) { if( name[ i ] == ':' && name[ i + 1 ] == ':' ) break; } if( i < nameLength - 1 ) { const char *tokenName = name + i + 2; /* Skip '::' */ const int tokenNameLength = nameLength - ( i + 2 ); if( tokenNameLength <= 0 ) return( CRYPT_ARGERROR_STR1 ); /* Some tokens don't implement named slots, so we also allow them to be specified using slot counts */ if( tokenNameLength == 1 && isDigit( *tokenName ) ) { tokenSlot = *tokenName - '0'; if( tokenSlot < 0 || tokenSlot > 9 ) return( CRYPT_ARGERROR_STR1 ); if( tokenSlot > slotCount - 1 ) /* Slots numbered from zero */ return( CRYPT_ERROR_NOTFOUND ); status = C_GetTokenInfo( slotList[ tokenSlot ], &tokenInfo ); if( status != CKR_OK ) return( CRYPT_ERROR_NOTFOUND ); } else { /* Check each (named) slot for a token matching the given name */ for( tokenSlot = 0; tokenSlot < slotCount && \ tokenSlot < FAILSAFE_ITERATIONS_MED; tokenSlot++ ) { status = C_GetTokenInfo( slotList[ tokenSlot ], &tokenInfo ); if( status == CKR_OK && \ !strCompare( tokenName, tokenInfo.label, tokenNameLength ) ) break; } ENSURES( tokenSlot < FAILSAFE_ITERATIONS_MED ); if( tokenSlot >= slotCount ) return( CRYPT_ERROR_NOTFOUND ); } } pkcs11Info->slotID = slotList[ tokenSlot ]; /* Get information on device-specific capabilities */ status = C_GetSlotInfo( pkcs11Info->slotID, &slotInfo ); if( status != CKR_OK ) { shutdownFunction( deviceInfo ); return( pkcs11MapError( status, CRYPT_ERROR_OPEN ) ); } if( slotInfo.flags & CKF_REMOVABLE_DEVICE ) { /* The device is removable */ deviceInfo->flags |= DEVICE_REMOVABLE; } status = C_GetTokenInfo( pkcs11Info->slotID, &tokenInfo ); if( status != CKR_OK ) { shutdownFunction( deviceInfo ); return( pkcs11MapError( status, CRYPT_ERROR_OPEN ) ); } if( tokenInfo.flags & CKF_RNG ) { /* The device has an onboard RNG that we can use */ deviceInfo->getRandomFunction = getRandomFunction; } #if 0 /* The Spyrus driver for pre-Lynks-II cards returns the local system time (with a GMT/localtime offset), ignoring the fact that the token has an onboard clock, so having the CKF_CLOCK_ON_TOKEN not set is accurate, although having it ignore the presence of the clock isn't very valid */ if( !( tokenInfo.flags & CKF_CLOCK_ON_TOKEN ) && \ ( !strCompare( tokenInfo.label, "Lynks Token", 11 ) || \ !strCompare( tokenInfo.model, "Rosetta", 7 ) ) ) { /* Fix buggy Spyrus PKCS #11 drivers which claim that the token doesn't have a RTC even though it does (the Rosetta (smart card) form of the token is even worse, it returns garbage in the label and manufacturer fields, but the model field is OK). There is a chance that there's a genuine problem with the clock (there are batches of tokens with bad clocks) but the time check that follows below will catch those */ tokenInfo.flags |= CKF_CLOCK_ON_TOKEN; } #endif /* 0 */ if( tokenInfo.flags & CKF_CLOCK_ON_TOKEN ) { const time_t theTime = getTokenTime( &tokenInfo ); const time_t currentTime = getTime(); /* The token claims to have an onboard clock that we can use. Since this could be arbitrarily inaccurate we compare it with the system time and only rely on it if it's within +/- 1 day of the system time. There is a second check that we should make to catch drivers that claim to read the time from the token but actually use the local computer's time, but this isn't easy to do. The most obvious way is to set the system time to a bogus value and check whether this matches the returned time, but this is somewhat drastic and requires superuser privs on most systems. An alternative is to check whether the claimed token time exactly matches the system time, but this will produce false positives if (for example) the token has been recently synchronised to the system time. For now all we can do is throw an exception if it appears that the token time is faked */ if( theTime > MIN_TIME_VALUE && \ theTime >= currentTime - 86400 && \ theTime <= currentTime + 86400 ) deviceInfo->flags |= DEVICE_TIME; /* If this check is triggered then the token time may be faked since it's identical to the host system time, see the comment above for details. We make an exception for soft-tokens (if we can detect them), which will (by definition) have the same time as the system time */ if( !( pkcs11InfoTbl[ pkcs11Info->deviceNo ].name[ 0 ] && \ !strCompare( pkcs11InfoTbl[ pkcs11Info->deviceNo ].name, "Software", 8 ) ) && \ theTime == currentTime ) { DEBUG_DIAG(( "PKCS #11 token time is the same as the host " "system time, token time may be faked by the " "driver." )); assert( DEBUG_WARN ); } } if( tokenInfo.flags & CKF_WRITE_PROTECTED ) { /* The device can't have data on it changed */ deviceInfo->flags |= DEVICE_READONLY; } if( ( tokenInfo.flags & CKF_LOGIN_REQUIRED ) || \ !( tokenInfo.flags & CKF_USER_PIN_INITIALIZED ) ) { /* The user needs to log in before using various device functions. We check for the absence of CKF_USER_PIN_INITIALIZED as well as the more obvious CKF_LOGIN_REQUIRED because if we've got an uninitialised device there's no PIN set so some devices will report that there's no login required (or at least none is possible). We need to introduce some sort of pipeline stall if this is the case because otherwise the user could successfully perform some functions that don't require a login (where the exact details of what's allowed without a login are device- specific) before running into mysterious failures when they get to functions that do require a login. To avoid this, we make an uninitialised device look like a login-required device, so the user gets an invalid-PIN error if they try and proceed */ deviceInfo->flags |= DEVICE_NEEDSLOGIN; } if( ( pkcs11Info->minPinSize = ( int ) tokenInfo.ulMinPinLen ) < 4 ) { /* Some devices report silly PIN sizes */ DEBUG_DIAG(( "Driver reports suspicious minimum PIN size %lu, " "using 4", tokenInfo.ulMinPinLen )); pkcs11Info->minPinSize = 4; } if( ( pkcs11Info->maxPinSize = ( int ) tokenInfo.ulMaxPinLen ) < 4 ) { /* Some devices report silly PIN sizes (setting this to ULONG_MAX or 4GB, which becomes -1 as an int, counts as silly). Since we can't differentiate between 0xFFFFFFFF = bogus value and 0xFFFFFFFF = ULONG_MAX we play it safe and set the limit to 8 bytes, which most devices should be able to handle */ DEBUG_DIAG(( "Driver reports suspicious maximum PIN size %lu, " "using 8", tokenInfo.ulMinPinLen )); pkcs11Info->maxPinSize = 8; } labelPtr = ( char * ) tokenInfo.label; for( labelLength = 32; labelLength > 0 && \ ( labelPtr[ labelLength - 1 ] == ' ' || \ !labelPtr[ labelLength - 1 ] ); labelLength-- ); /* Strip trailing blanks/nulls */ while( labelLength > 0 && *labelPtr == ' ' ) { /* Strip leading blanks */ labelPtr++; labelLength--; } if( labelLength > 0 ) { memcpy( pkcs11Info->label, labelPtr, labelLength ); pkcs11Info->labelLen = labelLength; sanitiseString( pkcs11Info->label, CRYPT_MAX_TEXTSIZE, labelLength ); } else { /* There's no label for the token, use the device label instead */ if( pkcs11InfoTbl[ pkcs11Info->deviceNo ].name[ 0 ] ) { labelLength = \ min( strlen( pkcs11InfoTbl[ pkcs11Info->deviceNo ].name ), CRYPT_MAX_TEXTSIZE ); memcpy( pkcs11Info->label, pkcs11InfoTbl[ pkcs11Info->deviceNo ].name, labelLength ); } } pkcs11Info->hActiveSignObject = CK_OBJECT_NONE; deviceInfo->label = pkcs11Info->label; deviceInfo->labelLen = pkcs11Info->labelLen; /* Open a session with the device. This gets a bit awkward because we can't tell whether a R/W session is OK without opening a session, but we can't open a session unless we know whether a R/W session is OK, so we first try for a RW session and if that fails we go for a read- only session */ status = C_OpenSession( pkcs11Info->slotID, CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession ); if( status == CKR_TOKEN_WRITE_PROTECTED ) { status = C_OpenSession( pkcs11Info->slotID, CKF_SERIAL_SESSION, NULL_PTR, NULL_PTR, &hSession ); } if( status != CKR_OK ) { cryptStatus = pkcs11MapError( status, CRYPT_ERROR_OPEN ); if( cryptStatus == CRYPT_ERROR_OPEN && \ !( tokenInfo.flags & CKF_USER_PIN_INITIALIZED ) ) { /* We couldn't do much with the error code, it could be that the token hasn't been initialised yet but unfortunately PKCS #11 doesn't define an error code for this condition. In addition many tokens will allow a session to be opened and then fail with a "PIN not set" error at a later point (which allows for more accurate error reporting), however a small number won't allow a session to be opened and return some odd-looking error because there's nothing useful available. The best way to report this in a meaningful manner to the caller is to check whether the user PIN has been initialised, if it hasn't then it's likely that the token as a whole hasn't been initialised so we return a not initialised error */ cryptStatus = CRYPT_ERROR_NOTINITED; } return( cryptStatus ); } ENSURES( hSession != CK_OBJECT_NONE ); pkcs11Info->hSession = hSession; deviceInfo->flags |= DEVICE_ACTIVE; /* Set up the capability information for this device. Since there can be devices that have one set of capabilities but not the other (e.g. a smart card that only performs RSA ops), we allow one of the two sets of mechanism information setups to fail, but not both */ mechanismInfoPtr = getMechanismInfoPKC( &mechanismInfoSize ); cryptStatus = getCapabilities( deviceInfo, mechanismInfoPtr, mechanismInfoSize ); mechanismInfoPtr = getMechanismInfoConv( &mechanismInfoSize ); cryptStatus2 = getCapabilities( deviceInfo, mechanismInfoPtr, mechanismInfoSize ); if( cryptStatusError( cryptStatus ) && cryptStatusError( cryptStatus2 ) ) { shutdownFunction( deviceInfo ); return( ( cryptStatus == CRYPT_ERROR ) ? \ CRYPT_ERROR_OPEN : ( int ) cryptStatus ); } return( CRYPT_OK ); }
static int get_pkcs11_key_value(libzfs_handle_t *hdl, zfs_cmd_t *zc, zfs_crypto_zckey_t cmd, pkcs11_uri_t *p11uri, char **keydata, size_t *keydatalen) { KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN; KMF_KEY_CLASS keyclass = KMF_SYMMETRIC; KMF_ENCODE_FORMAT format = KMF_FORMAT_RAWKEY; KMF_ATTRIBUTE attr[10]; KMF_KEY_HANDLE keys; KMF_CREDENTIAL cred; KMF_RAW_SYM_KEY rkey; KMF_HANDLE_T kmfh; KMF_RETURN err; boolean_t true_val = B_TRUE; CK_SLOT_ID slot; CK_TOKEN_INFO info; size_t n = 0; uint32_t numkeys = 0; /* Ask for all of the named keys */ char *token = NULL; if (kmf_initialize(&kmfh, NULL, NULL) != KMF_OK) { errno = EINVAL; return (-1); } kmf_set_attr_at_index(attr, n++, KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype)); if (p11uri->token) { token = strdup((const char *)p11uri->token); } else { /* If the token wasn't set we assume the metaslot */ token = strdup(METASLOT_TOKEN_LABEL); } kmf_set_attr_at_index(attr, n++, KMF_TOKEN_LABEL_ATTR, token, strlen(token)); kmf_set_attr_at_index(attr, n++, KMF_READONLY_ATTR, &true_val, sizeof (true_val)); kmf_set_attr_at_index(attr, n++, KMF_TOKEN_BOOL_ATTR, &true_val, sizeof (true_val)); err = kmf_configure_keystore(kmfh, n, attr); if (err != KMF_OK) goto out; if ((err = kmf_pk11_token_lookup(kmfh, token, &slot)) != KMF_OK || (err = C_GetTokenInfo(slot, &info)) != CKR_OK) goto out; /* Always prompt for PIN since the key is likey CKA_SENSITIVE */ if (prompt_pkcs11_pin(hdl, zc, cmd, p11uri, &cred.cred, &cred.credlen) != 0) goto out; kmf_set_attr_at_index(attr, n++, KMF_CREDENTIAL_ATTR, &cred, sizeof (KMF_CREDENTIAL)); kmf_set_attr_at_index(attr, n++, KMF_KEYLABEL_ATTR, p11uri->object, strlen((const char *)p11uri->object)); kmf_set_attr_at_index(attr, n++, KMF_KEYCLASS_ATTR, &keyclass, sizeof (keyclass)); kmf_set_attr_at_index(attr, n++, KMF_ENCODE_FORMAT_ATTR, &format, sizeof (format)); kmf_set_attr_at_index(attr, n++, KMF_COUNT_ATTR, &numkeys, sizeof (numkeys)); err = kmf_find_key(kmfh, n, attr); if (err != KMF_OK || numkeys != 1) goto out; kmf_set_attr_at_index(attr, n++, KMF_KEY_HANDLE_ATTR, &keys, sizeof (KMF_KEY_HANDLE)); err = kmf_find_key(kmfh, n, attr); err = kmf_get_sym_key_value(kmfh, &keys, &rkey); if (err != KMF_OK) goto out; if (rkey.keydata.len == *keydatalen) { *keydata = zfs_alloc(hdl, rkey.keydata.len); bcopy(rkey.keydata.val, *keydata, rkey.keydata.len); } *keydatalen = rkey.keydata.len; kmf_free_bigint(&rkey.keydata); out: if (token != NULL) free(token); (void) kmf_finalize(kmfh); if (numkeys == 1 && err == KMF_OK) { return (0); } else if (err == KMF_ERR_AUTH_FAILED) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "PKCS#11 token login failed.")); } else if (numkeys == 0) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "PKCS#11 token object not found.")); } else if (numkeys > 1) { zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "keysource points to multiple PKCS#11" " objects")); } ASSERT(errno != 0); return (-1); }
CK_SLOT_ID Cryptoki_FindSlot(LPCSTR szProvider, CK_MECHANISM_TYPE_PTR mechs, INT32 mechCnt) { CK_SLOT_ID slotList[10]; CK_ULONG slotCnt = ARRAYSIZE(slotList); UINT32 lenSP; CK_SLOT_ID slotID = CK_SLOT_ID_INVALID; UINT32 i; lenSP = szProvider == NULL ? 0 : hal_strlen_s(szProvider); if(CKR_OK == C_GetSlotList(TRUE, slotList, &slotCnt)) { for(i=0; i<slotCnt; i++) { CK_TOKEN_INFO info; if(mechCnt == 0) { slotID = slotList[i]; break; } else if(CKR_OK == C_GetTokenInfo(slotList[i], &info)) { INT32 len2 = hal_strlen_s((const char*)info.label); if((lenSP == 0) || ((lenSP == len2) && (hal_strncmp_s(szProvider, (const char*)info.label, lenSP) == 0))) { if(mechCnt > 0) { CK_MECHANISM_TYPE tokenMechs[100]; CK_ULONG cnt = 100; if(CKR_OK == C_GetMechanismList(slotList[i], tokenMechs, &cnt)) { bool slotIsOK = false; CK_ULONG t, s; for(s = 0; (INT32)s < mechCnt; s++) { slotIsOK = false; for(t = 0; t < cnt; t++) { if(mechs[s] == tokenMechs[t]) { slotIsOK = true; break; } } if(!slotIsOK) break; } if(slotIsOK) { slotID = slotList[i]; break; } } } else { slotID = slotList[i]; break; } } } } } return slotID; }
/* * Lists all slots with tokens in them. */ int pk_tokens(int argc, char *argv[]) { CK_SLOT_ID_PTR slots = NULL; CK_ULONG slot_count = 0; CK_TOKEN_INFO token_info; const char *fmt = NULL; CK_RV rv = CKR_OK; int i; cryptodebug("inside pk_tokens"); /* Get rid of subcommand word "tokens". */ argc--; argv++; /* No additional args allowed. */ if (argc != 0) return (PK_ERR_USAGE); /* Done parsing command line options. */ /* Get the list of slots with tokens in them. */ if ((rv = get_token_slots(&slots, &slot_count)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get token slot list (%s)."), pkcs11_strerror(rv)); return (PK_ERR_PK11); } /* Make sure we have something to display. */ if (slot_count == 0) { cryptoerror(LOG_STDERR, gettext("No slots with tokens found.")); return (0); } /* Display the list. */ fmt = "%-30.30s %-15.15s %-15.15s %-10.10s\n"; /* No I18N/L10N. */ (void) fprintf(stdout, fmt, gettext("Token Label"), gettext("Manuf ID"), gettext("Serial No"), gettext("PIN State")); for (i = 0; i < slot_count; i++) { cryptodebug("calling C_GetTokenInfo"); if ((rv = C_GetTokenInfo(slots[i], &token_info)) != CKR_OK) { cryptoerror(LOG_STDERR, gettext("Unable to get slot %d token info (%s)."), i, pkcs11_strerror(rv)); cryptodebug("token info error, slot %d (%s)", i, pkcs11_strerror(rv)); continue; } (void) fprintf(stdout, fmt, token_info.label, token_info.manufacturerID, token_info.serialNumber, (token_info.flags & CKF_USER_PIN_TO_BE_CHANGED) ? gettext("default") : gettext("user set")); } /* Clean up. */ free(slots); quick_finish(NULL); return (0); }