int aws_pkcs11_lib_find_private_key()

in source/pkcs11.c [833:971]


int aws_pkcs11_lib_find_private_key(
    struct aws_pkcs11_lib *pkcs11_lib,
    CK_SESSION_HANDLE session_handle,
    const struct aws_string *match_label,
    CK_OBJECT_HANDLE *out_key_handle,
    CK_KEY_TYPE *out_key_type) {

    /* gets set true after everything succeeds */
    bool success = false;

    /* gets set true after search initialized.
     * indicates that C_FindObjectsFinal() must be run before function ends */
    bool must_finalize_search = false;

    /* set up search attributes */
    CK_OBJECT_CLASS key_class = CKO_PRIVATE_KEY;
    CK_ULONG num_attributes = 1;
    CK_ATTRIBUTE attributes[2] = {
        {
            .type = CKA_CLASS,
            .pValue = &key_class,
            .ulValueLen = sizeof(key_class),
        },
    };

    if (match_label != NULL) {
        if (match_label->len > ULONG_MAX) {
            AWS_LOGF_ERROR(
                AWS_LS_IO_PKCS11,
                "id=%p session=%lu: private key label is too long",
                (void *)pkcs11_lib,
                session_handle);
            aws_raise_error(AWS_ERROR_PKCS11_KEY_NOT_FOUND);
            goto clean_up;
        }

        CK_ATTRIBUTE *attr = &attributes[num_attributes++];
        attr->type = CKA_LABEL;
        attr->pValue = (void *)match_label->bytes;
        attr->ulValueLen = (CK_ULONG)match_label->len;
    }

    /* initialize search */
    CK_RV rv = pkcs11_lib->function_list->C_FindObjectsInit(session_handle, attributes, num_attributes);
    if (rv != CKR_OK) {
        s_raise_ck_session_error(pkcs11_lib, "C_FindObjectsInit", session_handle, rv);
        goto clean_up;
    }

    must_finalize_search = true;

    /* get search results.
     * note that we're asking for 2 objects max, so we can fail if we find more than one */
    CK_OBJECT_HANDLE found_objects[2] = {0};
    CK_ULONG num_found = 0;
    rv = pkcs11_lib->function_list->C_FindObjects(session_handle, found_objects, 2 /*max*/, &num_found);
    if (rv != CKR_OK) {
        s_raise_ck_session_error(pkcs11_lib, "C_FindObjects", session_handle, rv);
        goto clean_up;
    }

    if ((num_found == 0) || (found_objects[0] == CK_INVALID_HANDLE)) {
        AWS_LOGF_ERROR(
            AWS_LS_IO_PKCS11,
            "id=%p session=%lu: Failed to find private key on PKCS#11 token which matches search criteria",
            (void *)pkcs11_lib,
            session_handle);
        aws_raise_error(AWS_ERROR_PKCS11_KEY_NOT_FOUND);
        goto clean_up;
    }
    if (num_found > 1) {
        AWS_LOGF_ERROR(
            AWS_LS_IO_PKCS11,
            "id=%p session=%lu: Failed to choose private key, multiple objects on PKCS#11 token match search criteria",
            (void *)pkcs11_lib,
            session_handle);
        aws_raise_error(AWS_ERROR_PKCS11_KEY_NOT_FOUND);
        goto clean_up;
    }

    /* key found */
    CK_OBJECT_HANDLE key_handle = found_objects[0];

    /* query key-type */
    CK_KEY_TYPE key_type = 0;
    CK_ATTRIBUTE key_attributes[] = {
        {
            .type = CKA_KEY_TYPE,
            .pValue = &key_type,
            .ulValueLen = sizeof(key_type),
        },
    };

    rv = pkcs11_lib->function_list->C_GetAttributeValue(
        session_handle, key_handle, key_attributes, AWS_ARRAY_SIZE(key_attributes));
    if (rv != CKR_OK) {
        s_raise_ck_session_error(pkcs11_lib, "C_GetAttributeValue", session_handle, rv);
        goto clean_up;
    }

    switch (key_type) {
        case CKK_RSA:
            break;
        default:
            AWS_LOGF_ERROR(
                AWS_LS_IO_PKCS11,
                "id=%p session=%lu: PKCS#11 private key type %s (0x%08lX) is currently unsupported",
                (void *)pkcs11_lib,
                session_handle,
                s_ckk_str(key_type),
                key_type);
            aws_raise_error(AWS_ERROR_PKCS11_KEY_TYPE_UNSUPPORTED);
            goto clean_up;
    }

    /* Success! */
    AWS_LOGF_TRACE(
        AWS_LS_IO_PKCS11,
        "id=%p session=%lu: Found private key. type=%s",
        (void *)pkcs11_lib,
        session_handle,
        s_ckk_str(key_type));
    *out_key_handle = key_handle;
    *out_key_type = key_type;
    success = true;

clean_up:

    if (must_finalize_search) {
        rv = pkcs11_lib->function_list->C_FindObjectsFinal(session_handle);
        /* don't bother reporting error if we were already failing */
        if ((rv != CKR_OK) && (success == true)) {
            s_raise_ck_session_error(pkcs11_lib, "C_FindObjectsFinal", session_handle, rv);
            success = false;
        }
    }

    return success ? AWS_OP_SUCCESS : AWS_OP_ERR;
}