Botan 3.11.0
Crypto and TLS for C&
p11_interface.cpp
Go to the documentation of this file.
1/*
2* PKCS #11 Interface Wrapper Implementation
3* (C) 2025 Jack Lloyd
4* 2025 Fabian Albert - Rohde & Schwarz Cybersecurity GmbH
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8#include <botan/assert.h>
9#include <botan/p11.h>
10
11#include <algorithm>
12#include <array>
13#include <iterator>
14#include <string_view>
15#include <vector>
16
17namespace Botan::PKCS11 {
18
19namespace {
20
21constexpr std::array<Utf8Char, 8> PKCS11_INTERFACE_NAME_ARR = {"PKCS 11"}; // including \0
22const std::span<const Utf8Char> PKCS11_INTERFACE_NAME(PKCS11_INTERFACE_NAME_ARR.data(),
23 PKCS11_INTERFACE_NAME_ARR.size() - 1);
24
25std::strong_ordering operator<=>(const Version& left, const Version& right) {
26 // Compare both versions by concatenating their bytes: major || minor
27 auto version_value = [](const Version& v) -> uint16_t {
28 return static_cast<uint16_t>(v.major) << 8 | static_cast<uint16_t>(v.minor);
29 };
30 return version_value(left) <=> version_value(right);
31}
32
33bool operator==(const Version& left, const Version& right) {
34 return left.major == right.major && left.minor == right.minor;
35}
36
37Version version_of(const Interface& interface) {
38 // PKCS #11 CK_INTERFACE documentation:
39 // pFunctionList - the interface function list which must always begin with
40 // a CK_VERSION structure as the first field
41 return *reinterpret_cast<Version*>(interface.pFunctionList);
42}
43
44std::span<const Utf8Char> name_of(const Interface& interface) {
45 // We cannot use std::basic_string_view<Utf8Char> since some compilers do not
46 // seem to support string views with unsigned characters.
47 const std::string_view s(reinterpret_cast<char*>(interface.pInterfaceName));
48 return std::span<const Utf8Char>(reinterpret_cast<const Utf8Char*>(s.data()), s.size());
49}
50
51} // namespace
52
57
59 return version_of(m_interface);
60}
61
62std::span<const Utf8Char> InterfaceWrapper::name() const {
63 return name_of(m_interface);
64}
65
67 Ulong count = 0;
68 auto rv = LowLevel::C_GetInterfaceList(library, nullptr, &count, nullptr);
69 if(!rv) {
70 // Method could not be executed. Probably due to a cryptoki library with PKCS #11 < 3.0.
71 // Try the legacy C_GetFunctionList method (for PKCS#11 version 2.40).
72 FunctionList* func_list = nullptr; // NOLINT(*-const-correctness) bug in clang-tidy
73 rv = LowLevel::C_GetFunctionList(library, &func_list, nullptr);
74 if(!rv) {
75 throw Invalid_Argument("Failed to load function list for PKCS#11 library.");
76 }
77
80 .pFunctionList = func_list,
81 .flags = 0,
82 }};
83 }
84 std::vector<Interface> interface_list(count);
85 rv = LowLevel::C_GetInterfaceList(library, interface_list.data(), &count, nullptr);
86 if(!rv) {
87 // The interface list count could be computed but the interface list cannot be received. This should not happen.
88 throw Invalid_Argument("Unexpected error while loading PKCS#11 interface list.");
89 }
90
91 // We only load interfaces named "PKCS 11" (which are the pure ones defined in the spec) with
92 // version >= 2.40.
93 auto is_valid_interface = [](const Interface& i) {
94 // This is also done by the example in PKCS #11 (version >= 3.0) spec.
95 // Note that version above the currently supported maximal version should
96 // be compatible too.
97 const Version version = version_of(i);
98 return version >= Version{2, 40};
99 };
100 std::vector<Interface> valid_interfaces;
101 std::copy_if(interface_list.begin(), interface_list.end(), std::back_inserter(valid_interfaces), is_valid_interface);
102
103 if(valid_interfaces.empty()) {
104 throw Invalid_Argument("No supported PKCS #11 interfaces found.");
105 }
106
107 // We prioritize valid interfaces the following way:
108 // Higher versions are preferred over lower ones. If multiple interfaces of
109 // the highest version exist, fork safe interfaces are preferred.
110 auto priority_comparator = [](const Interface& left, const Interface& right) {
111 const Version left_version = version_of(left);
112 const Version right_version = version_of(right);
113
114 if(left_version == right_version) {
115 return (left.flags & static_cast<CK_FLAGS>(Flag::InterfaceForkSafe)) <
116 (right.flags & static_cast<CK_FLAGS>(Flag::InterfaceForkSafe));
117 }
118 return left_version < right_version;
119 };
120 auto best_interface = std::max_element(valid_interfaces.begin(), valid_interfaces.end(), priority_comparator);
121 return InterfaceWrapper(*best_interface);
122}
123
125 if(!std::ranges::equal(name(), PKCS11_INTERFACE_NAME)) {
126 throw Botan::Invalid_State("Vendor defined PKCS #11 interfaces are not supported.");
127 }
128 return *reinterpret_cast<FunctionList*>(raw_interface().pFunctionList);
129}
130
132 if(!std::ranges::equal(name(), PKCS11_INTERFACE_NAME)) {
133 throw Botan::Invalid_State("Vendor defined PKCS #11 interfaces are not supported.");
134 }
135 if(version() < Version{3, 0}) {
136 throw Botan::Invalid_State("Loaded interface does not support PKCS #11 v3.0 features");
137 }
138 return *reinterpret_cast<FunctionList30*>(raw_interface().pFunctionList);
139}
140
142 if(!std::ranges::equal(name(), PKCS11_INTERFACE_NAME)) {
143 throw Botan::Invalid_State("Vendor defined PKCS #11 interfaces are not supported.");
144 }
145 if(version() < Version{3, 2}) {
146 throw Botan::Invalid_State("Loaded interface does not support PKCS #11 v3.2 features");
147 }
148 return *reinterpret_cast<FunctionList32*>(raw_interface().pFunctionList);
149}
150
152 static std::array<Utf8Char, 8> STATIC_PKCS11_INTERFACE_NAME_ARR = {"PKCS 11"};
153 return STATIC_PKCS11_INTERFACE_NAME_ARR.data();
154}
155
156} // namespace Botan::PKCS11
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:114
const FunctionList32 & func_3_2() const
Access a function list that contains all methods since PKCS #11 v.3.2.
static Utf8Char * p11_interface_name_ptr()
std::span< const Utf8Char > name() const
Access the name of the interface.
InterfaceWrapper(Interface raw_interface)
Basic constructor using an interface.
const Interface & raw_interface() const
Access the underlying interface object.
Definition p11.h:1290
const FunctionList30 & func_3_0() const
Access a function list that contains all methods since PKCS #11 v.3.0.
const FunctionList & func_2_40() const
Access a function list that contains all methods since PKCS #11 v.2.40.
static InterfaceWrapper latest_p11_interface(Dynamically_Loaded_Library &library)
Version version() const
Access the version of the interface.
static bool C_GetFunctionList(const Dynamically_Loaded_Library &pkcs11_module, FunctionList **function_list_ptr_ptr, ReturnValue *return_value=ThrowException)
Definition p11.cpp:90
static bool C_GetInterfaceList(const Dynamically_Loaded_Library &pkcs11_module, Interface *interface_list_ptr, Ulong *count_ptr, ReturnValue *return_value=ThrowException)
Definition p11.cpp:100
CK_FUNCTION_LIST FunctionList
Definition p11.h:1187
CK_VERSION Version
Definition p11.h:1200
CK_INTERFACE Interface
Definition p11.h:1191
CK_FUNCTION_LIST_3_0 FunctionList30
Definition p11.h:1189
CK_UTF8CHAR Utf8Char
Definition p11.h:1208
CK_FUNCTION_LIST_3_2 FunctionList32
Definition p11.h:1190
CK_ULONG Ulong
Definition p11.h:1203
bool operator==(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
Definition alg_id.cpp:53
auto operator<=>(const Strong< T, Tags... > &lhs, const Strong< T, Tags... > &rhs)
CK_ULONG CK_FLAGS
Definition pkcs11.h:49
CK_FLAGS flags
Definition pkcs11.h:1308
void * pFunctionList
Definition pkcs11.h:1307