int aws_pkcs11_lib_find_slot_with_token()

in source/pkcs11.c [619:753]


int aws_pkcs11_lib_find_slot_with_token(
    struct aws_pkcs11_lib *pkcs11_lib,
    const uint64_t *match_slot_id,
    const struct aws_string *match_token_label,
    CK_SLOT_ID *out_slot_id) {

    CK_SLOT_ID *slot_id_array = NULL; /* array of IDs */
    CK_SLOT_ID *candidate = NULL;     /* points to ID in slot_id_array */
    CK_TOKEN_INFO info;
    AWS_ZERO_STRUCT(info);
    bool success = false;

    /* query number of slots with tokens */
    CK_ULONG num_slots = 0;
    CK_RV rv = pkcs11_lib->function_list->C_GetSlotList(CK_TRUE /*tokenPresent*/, NULL /*pSlotList*/, &num_slots);
    if (rv != CKR_OK) {
        s_raise_ck_error(pkcs11_lib, "C_GetSlotList", rv);
        goto clean_up;
    }

    if (num_slots == 0) {
        AWS_LOGF_ERROR(AWS_LS_IO_PKCS11, "id=%p: No PKCS#11 tokens present in any slot", (void *)pkcs11_lib);
        aws_raise_error(AWS_ERROR_PKCS11_TOKEN_NOT_FOUND);
        goto clean_up;
    }

    AWS_LOGF_TRACE(
        AWS_LS_IO_PKCS11, "id=%p: Found %lu slots with tokens. Picking one...", (void *)pkcs11_lib, num_slots);

    /* allocate space for slot IDs */
    slot_id_array = aws_mem_calloc(pkcs11_lib->allocator, num_slots, sizeof(CK_SLOT_ID));

    /* query all slot IDs */
    rv = pkcs11_lib->function_list->C_GetSlotList(CK_TRUE /*tokenPresent*/, slot_id_array, &num_slots);
    if (rv != CKR_OK) {
        s_raise_ck_error(pkcs11_lib, "C_GetSlotList", rv);
        goto clean_up;
    }

    for (size_t i = 0; i < num_slots; ++i) {
        CK_SLOT_ID slot_id_i = slot_id_array[i];

        /* if specific slot_id requested, and this isn't it, then skip */
        if ((match_slot_id != NULL) && (*match_slot_id != slot_id_i)) {
            AWS_LOGF_TRACE(
                AWS_LS_IO_PKCS11,
                "id=%p: Ignoring PKCS#11 token because slot %lu doesn't match %" PRIu64,
                (void *)pkcs11_lib,
                slot_id_i,
                *match_slot_id);
            continue;
        }

        /* query token info */
        CK_TOKEN_INFO token_info_i;
        AWS_ZERO_STRUCT(token_info_i);
        rv = pkcs11_lib->function_list->C_GetTokenInfo(slot_id_i, &token_info_i);
        if (rv != CKR_OK) {
            s_raise_ck_error(pkcs11_lib, "C_GetTokenInfo", rv);
            goto clean_up;
        }

        /* if specific token label requested, and this isn't it, then skip */
        if (match_token_label != NULL) {
            struct aws_byte_cursor label_i = s_trim_padding(token_info_i.label, sizeof(token_info_i.label));
            if (aws_string_eq_byte_cursor(match_token_label, &label_i) == false) {
                AWS_LOGF_TRACE(
                    AWS_LS_IO_PKCS11,
                    "id=%p: Ignoring PKCS#11 token in slot %lu because label '" PRInSTR "' doesn't match '%s'",
                    (void *)pkcs11_lib,
                    slot_id_i,
                    AWS_BYTE_CURSOR_PRI(label_i),
                    aws_string_c_str(match_token_label));
                continue;
            }
        }

        /* this slot is a candidate! */

        /* be sure there's only one candidate */
        if (candidate != NULL) {
            AWS_LOGF_ERROR(
                AWS_LS_IO_PKCS11,
                "id=%p: Failed to choose PKCS#11 token, multiple tokens match search criteria",
                (void *)pkcs11_lib);
            aws_raise_error(AWS_ERROR_PKCS11_TOKEN_NOT_FOUND);
            goto clean_up;
        }

        /* the new candidate! */
        candidate = &slot_id_array[i];
        memcpy(&info, &token_info_i, sizeof(CK_TOKEN_INFO));
    }

    if (candidate == NULL) {
        AWS_LOGF_ERROR(
            AWS_LS_IO_PKCS11, "id=%p: Failed to find PKCS#11 token which matches search criteria", (void *)pkcs11_lib);
        aws_raise_error(AWS_ERROR_PKCS11_TOKEN_NOT_FOUND);
        goto clean_up;
    }

    /* success! */
    AWS_LOGF_DEBUG(
        AWS_LS_IO_PKCS11,
        "id=%p: Selected PKCS#11 token. slot:%lu label:'" PRInSTR "' manufacturerID:'" PRInSTR "' model:'" PRInSTR
        "' serialNumber:'" PRInSTR "' flags:0x%08lX sessionCount:%lu/%lu rwSessionCount:%lu/%lu"
        " freePublicMemory:%lu/%lu freePrivateMemory:%lu/%lu"
        " hardwareVersion:%" PRIu8 ".%" PRIu8 " firmwareVersion:%" PRIu8 ".%" PRIu8,
        (void *)pkcs11_lib,
        *candidate,
        AWS_BYTE_CURSOR_PRI(s_trim_padding(info.label, sizeof(info.label))),
        AWS_BYTE_CURSOR_PRI(s_trim_padding(info.manufacturerID, sizeof(info.manufacturerID))),
        AWS_BYTE_CURSOR_PRI(s_trim_padding(info.model, sizeof(info.model))),
        AWS_BYTE_CURSOR_PRI(s_trim_padding(info.serialNumber, sizeof(info.serialNumber))),
        info.flags,
        info.ulSessionCount,
        info.ulMaxSessionCount,
        info.ulRwSessionCount,
        info.ulMaxRwSessionCount,
        info.ulFreePublicMemory,
        info.ulTotalPublicMemory,
        info.ulFreePrivateMemory,
        info.ulTotalPrivateMemory,
        info.hardwareVersion.major,
        info.hardwareVersion.minor,
        info.firmwareVersion.major,
        info.firmwareVersion.minor);

    *out_slot_id = *candidate;
    success = true;

clean_up:
    aws_mem_release(pkcs11_lib->allocator, slot_id_array);
    return success ? AWS_OP_SUCCESS : AWS_OP_ERR;
}