• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 22037645935

15 Feb 2026 02:49PM UTC coverage: 90.059% (-1.6%) from 91.706%
22037645935

push

github

web-flow
Merge pull request #5340 from randombit/jack/test-h-misc-cmp

Further cleanups of test predicates

102371 of 113671 relevant lines covered (90.06%)

11413670.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.95
/src/tests/test_pkcs11_high_level.cpp
1
/*
2
* (C) 2016 Daniel Neus
3
* (C) 2016 Philipp Weber
4
* (C) 2019 Michael Boric
5
* (C) 2020 René Korthaus
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9

10
#include "tests.h"
11

12
#if defined(BOTAN_HAS_PKCS11)
13
   #include "test_pkcs11.h"
14
   #include <botan/p11.h>
15
   #include <botan/p11_object.h>
16
   #include <botan/p11_randomgenerator.h>
17
   #include <botan/internal/fmt.h>
18
   #include <algorithm>
19
   #include <memory>
20
   #include <numeric>
21
   #include <sstream>
22
   #include <string>
23
   #include <vector>
24
#endif
25

26
#if defined(BOTAN_HAS_ASN1)
27
   #include <botan/der_enc.h>
28
#endif
29

30
#if defined(BOTAN_HAS_ENTROPY_SOURCE)
31
   #include <botan/entropy_src.h>
32
#endif
33

34
#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO)
35
   #include <botan/pubkey.h>
36
#endif
37

38
#if defined(BOTAN_HAS_ECC_GROUP)
39
   #include <botan/ec_group.h>
40
#endif
41

42
#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_PKCS11)
43
   #include <botan/p11_rsa.h>
44
   #include <botan/rsa.h>
45
#endif
46

47
#if defined(BOTAN_HAS_ECDSA) && defined(BOTAN_HAS_PKCS11)
48
   #include <botan/ecdsa.h>
49
   #include <botan/p11_ecdsa.h>
50
#endif
51

52
#if defined(BOTAN_HAS_ECDH) && defined(BOTAN_HAS_PKCS11)
53
   #include <botan/ecdh.h>
54
   #include <botan/p11_ecdh.h>
55
#endif
56

57
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_HAS_PKCS11)
58
   #include <botan/p11_x509.h>
59
   #include <botan/pkix_types.h>
60
#endif
61

62
#if defined(BOTAN_HAS_HMAC_DRBG)
63
   #include <botan/hmac_drbg.h>
64
   #include <botan/mac.h>
65
#endif
66

67
namespace Botan_Tests {
68

69
#if defined(BOTAN_HAS_PKCS11)
70

71
std::vector<Test::Result> run_pkcs11_tests(const std::string& name,
11✔
72
                                           std::vector<std::pair<std::string, std::function<Test::Result()>>>& fns) {
73
   std::vector<Test::Result> results;
11✔
74

75
   for(const auto& [fn_name, fn] : fns) {
86✔
76
      try {
75✔
77
         results.push_back(fn());
150✔
78
      } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
×
79
         results.push_back(Test::Result::Failure(Botan::fmt("{} test {}", name, fn_name), e.what()));
×
80

81
         if(e.get_return_value() == Botan::PKCS11::ReturnValue::PinIncorrect) {
×
82
            break;  // Do not continue to not potentially lock the token
83
         }
84
      } catch(std::exception& e) {
×
85
         results.push_back(Test::Result::Failure(Botan::fmt("{} test {}", name, fn_name), e.what()));
×
86
      }
×
87
   }
88

89
   return results;
11✔
90
}
×
91

92
namespace {
93

94
using namespace Botan;
95
using namespace PKCS11;
96

97
class TestSession {
98
   public:
99
      explicit TestSession(bool login) : m_module(new Module(Test::pkcs11_lib())) {
30✔
100
         std::vector<SlotId> slot_vec = Slot::get_available_slots(*m_module, true);
30✔
101
         m_slot = std::make_unique<Slot>(*m_module, slot_vec.at(0));
30✔
102
         m_session = std::make_unique<Session>(*m_slot, false);
30✔
103
         if(login) {
30✔
104
            m_session->login(UserType::User, PIN());
60✔
105
         }
106
      }
30✔
107

108
      Session& session() const { return *m_session; }
6✔
109

110
      Slot& slot() const { return *m_slot; }
2✔
111

112
   private:
113
      std::unique_ptr<Module> m_module = nullptr;
114
      std::unique_ptr<Slot> m_slot = nullptr;
115
      std::unique_ptr<Session> m_session = nullptr;
116
};
117

118
/***************************** Module *****************************/
119

120
Test::Result test_module_ctor() {
1✔
121
   Test::Result result("Module ctor");
1✔
122

123
   result.test_throws("Module ctor fails for non existent path", []() { Module("/a/b/c"); });
2✔
124

125
   const Module module(Test::pkcs11_lib());
1✔
126
   result.test_success("Module ctor did not throw and completed successfully");
1✔
127

128
   return result;
1✔
129
}
1✔
130

131
Test::Result test_module_reload() {
1✔
132
   Test::Result result("Module reload");
1✔
133

134
   Module module(Test::pkcs11_lib());
1✔
135

136
   module.reload();
1✔
137
   result.test_success("Module reload did not throw and completed successfully");
1✔
138

139
   module.get_info();
1✔
140
   result.test_success("Module get_info() still works after reload");
2✔
141

142
   return result;
1✔
143
}
1✔
144

145
Test::Result test_multiple_modules() {
1✔
146
   Test::Result result("Module copy");
1✔
147
   const Module first_module(Test::pkcs11_lib());
1✔
148

149
   result.test_throws("Module ctor fails if module is already initialized",
1✔
150
                      []() { const Module second_module(Test::pkcs11_lib()); });
1✔
151

152
   return result;
1✔
153
}
1✔
154

155
Test::Result test_module_get_info() {
1✔
156
   Test::Result result("Module info");
1✔
157

158
   const Module module(Test::pkcs11_lib());
1✔
159

160
   const Info info = module.get_info();
1✔
161
   result.test_sz_ne("Cryptoki version != 0", info.cryptokiVersion.major, 0);
1✔
162

163
   return result;
1✔
164
}
1✔
165

166
class Module_Tests final : public Test {
1✔
167
   public:
168
      std::vector<Test::Result> run() override {
1✔
169
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
170
            {STRING_AND_FUNCTION(test_module_ctor)},
171
            {STRING_AND_FUNCTION(test_multiple_modules)},
172
            {STRING_AND_FUNCTION(test_module_get_info)},
173
            {STRING_AND_FUNCTION(test_module_reload)}};
5✔
174

175
         return run_pkcs11_tests("Module", fns);
2✔
176
      }
2✔
177
};
178

179
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-module", Module_Tests);
180

181
/***************************** Slot *****************************/
182

183
Test::Result test_slot_get_available_slots() {
1✔
184
   Test::Result result("Slot get_available_slots");
1✔
185

186
   Module module(Test::pkcs11_lib());
1✔
187
   const std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
188
   result.test_sz_gte("Available Slots with attached token >= 1", slot_vec.size(), 1);
1✔
189

190
   return result;
2✔
191
}
1✔
192

193
Test::Result test_slot_ctor() {
1✔
194
   Test::Result result("Slot ctor");
1✔
195

196
   Module module(Test::pkcs11_lib());
1✔
197
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
198

199
   const Slot slot(module, slot_vec.at(0));
1✔
200
   result.test_success("Slot ctor completed successfully");
1✔
201
   result.test_u64_eq(slot.slot_id(), slot_vec.at(0));
1✔
202

203
   return result;
2✔
204
}
1✔
205

206
Test::Result test_get_slot_info() {
1✔
207
   Test::Result result("Slot get_slot_info");
1✔
208

209
   Module module(Test::pkcs11_lib());
1✔
210
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
211
   const Slot slot(module, slot_vec.at(0));
1✔
212

213
   SlotInfo info = slot.get_slot_info();
1✔
214
   const std::string description = reinterpret_cast<char*>(info.slotDescription);
1✔
215
   result.test_is_true("Slot description is not empty", !description.empty());
1✔
216

217
   return result;
2✔
218
}
2✔
219

220
SlotId get_invalid_slot_id(Module& module) {
2✔
221
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, false);
2✔
222

223
   SlotId invalid_id = 0;
2✔
224

225
   // find invalid slot id
226
   while(std::find(slot_vec.begin(), slot_vec.end(), invalid_id) != slot_vec.end()) {
2✔
227
      invalid_id++;
×
228
   }
229

230
   return invalid_id;
2✔
231
}
2✔
232

233
Test::Result test_slot_invalid_id() {
1✔
234
   Test::Result result("Slot get_slot_info with invalid slot id");
1✔
235

236
   Module module(Test::pkcs11_lib());
1✔
237

238
   const SlotId invalid_id = get_invalid_slot_id(module);
1✔
239

240
   Slot slot(module, invalid_id);
1✔
241

242
   result.test_throws("get_slot_info fails for non existent slot id", [&slot]() { slot.get_slot_info(); });
2✔
243

244
   return result;
1✔
245
}
1✔
246

247
Test::Result test_get_token_info() {
1✔
248
   Test::Result result("Slot get_token_info");
1✔
249

250
   Module module(Test::pkcs11_lib());
1✔
251
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
252
   const Slot slot(module, slot_vec.at(0));
1✔
253

254
   TokenInfo info = slot.get_token_info();
1✔
255
   const std::string label = reinterpret_cast<char*>(info.label);
1✔
256
   result.test_is_true("Token label is not empty", !label.empty());
1✔
257

258
   return result;
2✔
259
}
2✔
260

261
Test::Result test_get_mechanism_list() {
1✔
262
   Test::Result result("Slot get_mechanism_list");
1✔
263

264
   Module module(Test::pkcs11_lib());
1✔
265
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
266
   const Slot slot(module, slot_vec.at(0));
1✔
267

268
   const std::vector<MechanismType> mechanisms = slot.get_mechanism_list();
1✔
269
   result.test_is_true("The Slot supports at least one mechanism", !mechanisms.empty());
1✔
270

271
   return result;
2✔
272
}
2✔
273

274
Test::Result test_get_mechanisms_info() {
1✔
275
   Test::Result result("Slot get_mechanism_info");
1✔
276

277
   Module module(Test::pkcs11_lib());
1✔
278
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
279
   const Slot slot(module, slot_vec.at(0));
1✔
280

281
   slot.get_mechanism_info(MechanismType::RsaPkcsKeyPairGen);
1✔
282
   result.test_success("get_mechanism_info() completed successfully.");
1✔
283

284
   return result;
2✔
285
}
1✔
286

287
class Slot_Tests final : public Test {
1✔
288
   public:
289
      std::vector<Test::Result> run() override {
1✔
290
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
291
            {STRING_AND_FUNCTION(test_slot_get_available_slots)},
292
            {STRING_AND_FUNCTION(test_slot_ctor)},
293
            {STRING_AND_FUNCTION(test_get_slot_info)},
294
            {STRING_AND_FUNCTION(test_slot_invalid_id)},
295
            {STRING_AND_FUNCTION(test_get_token_info)},
296
            {STRING_AND_FUNCTION(test_get_mechanism_list)},
297
            {STRING_AND_FUNCTION(test_get_mechanisms_info)}};
8✔
298

299
         return run_pkcs11_tests("Slot", fns);
2✔
300
      }
2✔
301
};
302

303
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-slot", Slot_Tests);
304

305
/***************************** Session *****************************/
306

307
Test::Result test_session_ctor() {
1✔
308
   Test::Result result("Session ctor");
1✔
309

310
   Module module(Test::pkcs11_lib());
1✔
311
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
312
   Slot slot(module, slot_vec.at(0));
1✔
313

314
   {
1✔
315
      const Session read_only_session(slot, true);
1✔
316
      result.test_success("read only session opened successfully");
1✔
317
   }
1✔
318
   {
1✔
319
      const Session read_write_session(slot, false);
1✔
320
      result.test_success("read write session opened successfully");
1✔
321
   }
1✔
322
   {
1✔
323
      const Flags flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
1✔
324
      const Session read_write_session2(slot, flags, nullptr, nullptr);
1✔
325
      result.test_success("read write session with flags param opened successfully");
1✔
326
   }
1✔
327
   {
1✔
328
      const Session read_only_session(slot, true);
1✔
329
      const Session read_write_session(slot, false);
1✔
330
      result.test_success("Opened multiple sessions successfully");
1✔
331
   }
1✔
332

333
   return result;
2✔
334
}
1✔
335

336
Test::Result test_session_ctor_invalid_slot() {
1✔
337
   Test::Result result("Session ctor with invalid slot id");
1✔
338

339
   Module module(Test::pkcs11_lib());
1✔
340

341
   const SlotId invalid_id = get_invalid_slot_id(module);
1✔
342
   Slot slot(module, invalid_id);
1✔
343

344
   result.test_throws("Session ctor with invalid slot id fails", [&slot]() { Session(slot, true); });
2✔
345

346
   return result;
1✔
347
}
1✔
348

349
Test::Result test_session_release() {
1✔
350
   Test::Result result("Session release/take ownership");
1✔
351

352
   Module module(Test::pkcs11_lib());
1✔
353
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
354
   Slot slot(module, slot_vec.at(0));
1✔
355

356
   Session session(slot, false);
1✔
357
   const SessionHandle handle = session.release();
1✔
358

359
   const Session session2(slot, handle);
1✔
360
   result.test_success("releasing ownership and taking ownership works as expected.");
1✔
361

362
   return result;
1✔
363
}
2✔
364

365
Test::Result test_session_login_logout() {
1✔
366
   Test::Result result("Session login/logout");
1✔
367

368
   Module module(Test::pkcs11_lib());
1✔
369
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
370
   Slot slot(module, slot_vec.at(0));
1✔
371

372
   Session session(slot, false);
1✔
373
   session.login(UserType::User, PIN());
1✔
374
   session.logoff();
1✔
375
   result.test_success("user login/logout succeeded");
1✔
376

377
   session.login(UserType::SO, SO_PIN());
1✔
378
   result.test_success("SO login succeeded");
1✔
379

380
   return result;
1✔
381
}
2✔
382

383
Test::Result test_session_info() {
1✔
384
   Test::Result result("Session session info");
1✔
385

386
   Module module(Test::pkcs11_lib());
1✔
387
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
388
   Slot slot(module, slot_vec.at(0));
1✔
389

390
   Session session(slot, false);
1✔
391
   SessionInfo info = session.get_info();
1✔
392
   result.test_u64_eq("slot id is correct", info.slotID, slot_vec.at(0));
1✔
393
   result.test_u64_eq(
1✔
394
      "state is a read write public session", info.state, static_cast<CK_STATE>(SessionState::RwPublicSession));
395

396
   session.login(UserType::User, PIN());
1✔
397
   info = session.get_info();
1✔
398
   result.test_u64_eq(
1✔
399
      "state is a read write user session", info.state, static_cast<CK_STATE>(SessionState::RwUserFunctions));
400

401
   session.logoff();
1✔
402
   result.test_success("user login/logout succeeded");
1✔
403

404
   session.login(UserType::SO, SO_PIN());
1✔
405
   result.test_success("SO login succeeded");
1✔
406

407
   return result;
1✔
408
}
2✔
409

410
class Session_Tests final : public Test {
1✔
411
   public:
412
      std::vector<Test::Result> run() override {
1✔
413
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
414
            {STRING_AND_FUNCTION(test_session_ctor)},
415
            {STRING_AND_FUNCTION(test_session_ctor_invalid_slot)},
416
            {STRING_AND_FUNCTION(test_session_release)},
417
            {STRING_AND_FUNCTION(test_session_login_logout)},
418
            {STRING_AND_FUNCTION(test_session_info)}};
6✔
419

420
         return run_pkcs11_tests("Session", fns);
2✔
421
      }
2✔
422
};
423

424
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-session", Session_Tests);
425

426
/***************************** Object *****************************/
427

428
Test::Result test_attribute_container() {
1✔
429
   Test::Result result("AttributeContainer");
1✔
430

431
   AttributeContainer attributes;
1✔
432
   attributes.add_class(ObjectClass::PrivateKey);
1✔
433

434
   const std::string label("test");
1✔
435
   attributes.add_string(AttributeType::Label, label);
1✔
436

437
   const std::vector<uint8_t> bin(4);
1✔
438
   attributes.add_binary(AttributeType::Value, bin);
1✔
439

440
   attributes.add_bool(AttributeType::Sensitive, true);
1✔
441
   attributes.add_numeric(AttributeType::ObjectId, 10);
1✔
442
   attributes.add_numeric(AttributeType::Id, 20);
1✔
443
   attributes.add_numeric(AttributeType::PixelX, 30);
1✔
444
   // Test that overwriting the existing Id attribute works. The numeric attributes above should not be affected by this.
445
   attributes.add_numeric(AttributeType::Id, 21);
1✔
446
   attributes.add_numeric(AttributeType::PixelY, 40);
1✔
447

448
   result.test_sz_eq("8 elements in attribute container", attributes.count(), 8);
1✔
449

450
   const std::vector<Botan::PKCS11::Attribute>& storedAttributes = attributes.attributes();
1✔
451
   result.test_u64_eq(
1✔
452
      "ObjectId type", storedAttributes.at(4).type, static_cast<CK_ATTRIBUTE_TYPE>(AttributeType::ObjectId));
1✔
453
   result.test_u64_eq("ObjectId value", *reinterpret_cast<uint64_t*>(storedAttributes.at(4).pValue), 10);
1✔
454
   result.test_u64_eq("Id type", storedAttributes.at(5).type, static_cast<CK_ATTRIBUTE_TYPE>(AttributeType::Id));
1✔
455
   result.test_u64_eq("Id value", *reinterpret_cast<uint64_t*>(storedAttributes.at(5).pValue), 21);
1✔
456
   result.test_u64_eq(
1✔
457
      "PixelX type", storedAttributes.at(6).type, static_cast<CK_ATTRIBUTE_TYPE>(AttributeType::PixelX));
1✔
458
   result.test_u64_eq("PixelX value", *reinterpret_cast<uint64_t*>(storedAttributes.at(6).pValue), 30);
1✔
459
   result.test_u64_eq(
1✔
460
      "PixelY type", storedAttributes.at(7).type, static_cast<CK_ATTRIBUTE_TYPE>(AttributeType::PixelY));
1✔
461
   result.test_u64_eq("PixelY value", *reinterpret_cast<uint64_t*>(storedAttributes.at(7).pValue), 40);
1✔
462

463
   return result;
2✔
464
}
1✔
465

466
DataObjectProperties make_test_object(const std::string& label) {
4✔
467
   std::string value_string("test data");
4✔
468
   const secure_vector<uint8_t> value(value_string.begin(), value_string.end());
4✔
469

470
   const std::size_t id = 1337;
4✔
471
   const std::string application = "Botan test application";
4✔
472

473
   std::vector<uint8_t> encoded_id;
4✔
474
   DER_Encoder(encoded_id).encode(id);
4✔
475

476
   DataObjectProperties data_obj_props;
4✔
477
   data_obj_props.set_application(application);
4✔
478
   data_obj_props.set_label(label);
4✔
479
   data_obj_props.set_value(value);
4✔
480
   data_obj_props.set_token(true);
4✔
481
   data_obj_props.set_modifiable(true);
4✔
482
   data_obj_props.set_object_id(encoded_id);
4✔
483

484
   return data_obj_props;
4✔
485
}
8✔
486

487
   #if defined(BOTAN_HAS_ASN1)
488
Test::Result test_create_destroy_data_object() {
1✔
489
   Test::Result result("Object create/delete data object");
1✔
490

491
   const TestSession test_session(true);
1✔
492

493
   const std::string label = "Botan test data object";
1✔
494
   auto data_obj_props = make_test_object(label);
1✔
495
   const Object data_obj(test_session.session(), data_obj_props);
1✔
496
   result.test_success("Data object creation was successful");
1✔
497

498
   data_obj.destroy();
1✔
499
   result.test_success("Data object deletion  was successful");
1✔
500

501
   return result;
2✔
502
}
1✔
503

504
Test::Result test_get_set_attribute_values() {
1✔
505
   Test::Result result("Object get/set attributes");
1✔
506

507
   const TestSession test_session(true);
1✔
508

509
   // create object
510
   const std::string label = "Botan test data object";
1✔
511
   auto data_obj_props = make_test_object(label);
1✔
512
   const Object data_obj(test_session.session(), data_obj_props);
1✔
513

514
   // get attribute
515
   secure_vector<uint8_t> retrieved_label = data_obj.get_attribute_value(AttributeType::Label);
1✔
516
   std::string retrieved_label_string(retrieved_label.begin(), retrieved_label.end());
2✔
517
   result.test_str_eq("label was set correctly", retrieved_label_string, label);
1✔
518

519
   // set attribute
520
   std::string new_label = "Botan test modified data object label";
1✔
521
   const secure_vector<uint8_t> new_label_secvec(new_label.begin(), new_label.end());
1✔
522
   data_obj.set_attribute_value(AttributeType::Label, new_label_secvec);
1✔
523

524
   // get and check attribute
525
   retrieved_label = data_obj.get_attribute_value(AttributeType::Label);
2✔
526
   retrieved_label_string = std::string(retrieved_label.begin(), retrieved_label.end());
2✔
527
   result.test_str_eq("label was modified correctly", retrieved_label_string, new_label);
1✔
528

529
   data_obj.destroy();
1✔
530
   return result;
2✔
531
}
2✔
532

533
Test::Result test_object_finder() {
1✔
534
   Test::Result result("ObjectFinder");
1✔
535

536
   const TestSession test_session(true);
1✔
537

538
   // create object
539
   const std::string label = "Botan test data object";
1✔
540
   auto data_obj_props = make_test_object(label);
1✔
541
   const Object data_obj(test_session.session(), data_obj_props);
1✔
542

543
   // search created object
544
   AttributeContainer search_template;
1✔
545
   search_template.add_string(AttributeType::Label, label);
1✔
546
   ObjectFinder finder(test_session.session(), search_template.attributes());
1✔
547

548
   auto search_result = finder.find();
1✔
549
   result.test_sz_eq("one object found", search_result.size(), 1);
1✔
550
   finder.finish();
1✔
551

552
   const Object obj_found(test_session.session(), search_result.at(0));
1✔
553
   result.test_eq("found the object just created (same application)",
1✔
554
                  obj_found.get_attribute_value(AttributeType::Application),
2✔
555
                  data_obj.get_attribute_value(AttributeType::Application));
1✔
556

557
   auto search_result2 = Object::search<Object>(test_session.session(), search_template.attributes());
1✔
558
   result.test_eq("found the object just created (same label)",
2✔
559
                  obj_found.get_attribute_value(AttributeType::Label),
2✔
560
                  search_result2.at(0).get_attribute_value(AttributeType::Label));
1✔
561

562
   data_obj.destroy();
1✔
563
   return result;
1✔
564
}
2✔
565

566
Test::Result test_object_copy() {
1✔
567
   Test::Result result("Object copy");
1✔
568

569
   const TestSession test_session(true);
1✔
570

571
   // create object
572
   const std::string label = "Botan test data object";
1✔
573
   auto data_obj_props = make_test_object(label);
1✔
574
   const Object data_obj(test_session.session(), data_obj_props);
1✔
575

576
   // copy created object
577
   AttributeContainer copy_attributes;
1✔
578
   copy_attributes.add_string(AttributeType::Label, "Botan test copied object");
1✔
579
   const ObjectHandle copied_obj_handle = data_obj.copy(copy_attributes);
1✔
580

581
   const ObjectFinder searcher(test_session.session(), copy_attributes.attributes());
1✔
582
   auto search_result = searcher.find();
1✔
583
   result.test_sz_eq("one object found", search_result.size(), 1);
1✔
584

585
   data_obj.destroy();
1✔
586

587
   const Object copied_obj(test_session.session(), copied_obj_handle);
1✔
588
   copied_obj.destroy();
1✔
589
   return result;
2✔
590
}
2✔
591
   #endif
592

593
class Object_Tests final : public Test {
1✔
594
   public:
595
      std::vector<Test::Result> run() override {
1✔
596
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
597
            {STRING_AND_FUNCTION(test_attribute_container)}
598
   #if defined(BOTAN_HAS_ASN1)
599
            ,
600
            {STRING_AND_FUNCTION(test_create_destroy_data_object)},
601
            {STRING_AND_FUNCTION(test_get_set_attribute_values)},
602
            {STRING_AND_FUNCTION(test_object_finder)},
603
            {STRING_AND_FUNCTION(test_object_copy)}
604
   #endif
605
         };
6✔
606

607
         return run_pkcs11_tests("Object", fns);
2✔
608
      }
2✔
609
};
610

611
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-object", Object_Tests);
612

613
/***************************** PKCS11 RSA *****************************/
614

615
   #if defined(BOTAN_HAS_RSA)
616

617
Test::Result test_rsa_privkey_import() {
1✔
618
   Test::Result result("PKCS11 import RSA private key");
1✔
619

620
   const TestSession test_session(true);
1✔
621

622
   auto rng = Test::new_rng(__func__);
1✔
623

624
   // create private key
625
   const RSA_PrivateKey priv_key(*rng, 2048);
1✔
626
   result.test_is_true("Key self test OK", priv_key.check_key(*rng, true));
1✔
627

628
   // import to card
629
   RSA_PrivateKeyImportProperties props(priv_key.get_n(), priv_key.get_d());
1✔
630
   props.set_pub_exponent(priv_key.get_e());
1✔
631
   props.set_prime_1(priv_key.get_p());
1✔
632
   props.set_prime_2(priv_key.get_q());
1✔
633
   props.set_coefficient(priv_key.get_c());
1✔
634
   props.set_exponent_1(priv_key.get_d1());
1✔
635
   props.set_exponent_2(priv_key.get_d2());
1✔
636

637
   props.set_token(true);
1✔
638
   props.set_private(true);
1✔
639
   props.set_decrypt(true);
1✔
640
   props.set_sign(true);
1✔
641

642
   const PKCS11_RSA_PrivateKey pk(test_session.session(), props);
1✔
643
   result.test_success("RSA private key import was successful");
1✔
644
   result.test_is_true("PK self test OK", pk.check_key(*rng, true));
1✔
645

646
   pk.destroy();
1✔
647
   return result;
1✔
648
}
2✔
649

650
Test::Result test_rsa_privkey_export() {
1✔
651
   Test::Result result("PKCS11 export RSA private key");
1✔
652

653
   const TestSession test_session(true);
1✔
654

655
   auto rng = Test::new_rng(__func__);
1✔
656

657
   // create private key
658
   const RSA_PrivateKey priv_key(*rng, 2048);
1✔
659

660
   // import to card
661
   RSA_PrivateKeyImportProperties props(priv_key.get_n(), priv_key.get_d());
1✔
662
   props.set_pub_exponent(priv_key.get_e());
1✔
663
   props.set_prime_1(priv_key.get_p());
1✔
664
   props.set_prime_2(priv_key.get_q());
1✔
665
   props.set_coefficient(priv_key.get_c());
1✔
666
   props.set_exponent_1(priv_key.get_d1());
1✔
667
   props.set_exponent_2(priv_key.get_d2());
1✔
668

669
   props.set_token(true);
1✔
670
   props.set_private(true);
1✔
671
   props.set_decrypt(true);
1✔
672
   props.set_sign(true);
1✔
673
   props.set_extractable(true);
1✔
674
   props.set_sensitive(false);
1✔
675

676
   const PKCS11_RSA_PrivateKey pk(test_session.session(), props);
1✔
677
   result.test_is_true("Check PK11 key", pk.check_key(*rng, true));
1✔
678

679
   const RSA_PrivateKey exported = pk.export_key();
1✔
680
   result.test_success("RSA private key export was successful");
1✔
681
   result.test_is_true("Check exported key", exported.check_key(*rng, true));
1✔
682

683
   pk.destroy();
1✔
684
   return result;
1✔
685
}
2✔
686

687
Test::Result test_rsa_pubkey_import() {
1✔
688
   Test::Result result("PKCS11 import RSA public key");
1✔
689

690
   const TestSession test_session(true);
1✔
691

692
   auto rng = Test::new_rng(__func__);
1✔
693

694
   // create public key from private key
695
   const RSA_PrivateKey priv_key(*rng, 2048);
1✔
696

697
   // import to card
698
   RSA_PublicKeyImportProperties props(priv_key.get_n(), priv_key.get_e());
1✔
699
   props.set_token(true);
1✔
700
   props.set_encrypt(true);
1✔
701
   props.set_private(false);
1✔
702

703
   const PKCS11_RSA_PublicKey pk(test_session.session(), props);
1✔
704
   result.test_success("RSA public key import was successful");
1✔
705
   result.test_is_true("Check PK11 key", pk.check_key(*rng, true));
1✔
706

707
   pk.destroy();
1✔
708

709
   return result;
2✔
710
}
2✔
711

712
Test::Result test_rsa_generate_private_key() {
1✔
713
   Test::Result result("PKCS11 generate RSA private key");
1✔
714
   const TestSession test_session(true);
1✔
715

716
   RSA_PrivateKeyGenerationProperties props;
1✔
717
   props.set_token(true);
1✔
718
   props.set_private(true);
1✔
719
   props.set_sign(true);
1✔
720
   props.set_decrypt(true);
1✔
721

722
   const PKCS11_RSA_PrivateKey pk(test_session.session(), 2048, props);
1✔
723
   result.test_success("RSA private key generation was successful");
1✔
724

725
   pk.destroy();
1✔
726

727
   return result;
1✔
728
}
1✔
729

730
PKCS11_RSA_KeyPair generate_rsa_keypair(const TestSession& test_session) {
3✔
731
   RSA_PublicKeyGenerationProperties pub_props(2048UL);
3✔
732
   pub_props.set_pub_exponent();
3✔
733
   pub_props.set_label("BOTAN_TEST_RSA_PUB_KEY");
3✔
734
   pub_props.set_token(true);
3✔
735
   pub_props.set_encrypt(true);
3✔
736
   pub_props.set_verify(true);
3✔
737
   pub_props.set_private(false);
3✔
738

739
   RSA_PrivateKeyGenerationProperties priv_props;
3✔
740
   priv_props.set_label("BOTAN_TEST_RSA_PRIV_KEY");
3✔
741
   priv_props.set_token(true);
3✔
742
   priv_props.set_private(true);
3✔
743
   priv_props.set_sign(true);
3✔
744
   priv_props.set_decrypt(true);
3✔
745

746
   return PKCS11::generate_rsa_keypair(test_session.session(), pub_props, priv_props);
3✔
747
}
3✔
748

749
Test::Result test_rsa_generate_key_pair() {
1✔
750
   Test::Result result("PKCS11 generate RSA key pair");
1✔
751
   const TestSession test_session(true);
1✔
752

753
   const PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
754
   result.test_success("RSA key pair generation was successful");
1✔
755

756
   keypair.first.destroy();
1✔
757
   keypair.second.destroy();
1✔
758

759
   return result;
1✔
760
}
1✔
761

762
Test::Result test_rsa_encrypt_decrypt() {
1✔
763
   Test::Result result("PKCS11 RSA encrypt decrypt");
1✔
764
   const TestSession test_session(true);
1✔
765

766
   // generate key pair
767
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
768

769
   auto rng = Test::new_rng(__func__);
1✔
770

771
   auto encrypt_and_decrypt =
1✔
772
      [&](const std::vector<uint8_t>& plaintext, const std::string& padding, const bool blinding) {
5✔
773
         std::vector<uint8_t> encrypted;
5✔
774

775
         try {
5✔
776
            const Botan::PK_Encryptor_EME encryptor(keypair.first, *rng, padding);
5✔
777
            encrypted = encryptor.encrypt(plaintext, *rng);
5✔
778
         } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
5✔
779
            result.test_failure("PKCS11 RSA encrypt " + padding, e.what());
×
780
         }
×
781

782
         Botan::secure_vector<uint8_t> decrypted;
5✔
783

784
         try {
5✔
785
            keypair.second.set_use_software_padding(blinding);
5✔
786
            const Botan::PK_Decryptor_EME decryptor(keypair.second, *rng, padding);
5✔
787
            decrypted = decryptor.decrypt(encrypted);
5✔
788
         } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
5✔
789
            std::ostringstream err;
×
790
            err << "PKCS11 RSA decrypt " << padding;
×
791
            if(blinding) {
×
792
               err << " with userspace blinding";
×
793
            }
794

795
            result.test_failure(err.str(), e.what());
×
796
         }
×
797

798
         result.test_eq("RSA PKCS11 encrypt and decrypt: " + padding, decrypted, plaintext);
5✔
799
      };
10✔
800

801
   std::vector<uint8_t> plaintext(256);
1✔
802
   std::iota(std::begin(plaintext), std::end(plaintext), static_cast<uint8_t>(0));
1✔
803
   encrypt_and_decrypt(plaintext, "Raw", false);
1✔
804

805
   plaintext = {0x00, 0x01, 0x02, 0x03, 0x04, 0x00};
1✔
806
   encrypt_and_decrypt(plaintext, "EME-PKCS1-v1_5", false);
1✔
807
   encrypt_and_decrypt(plaintext, "EME-PKCS1-v1_5", true);
1✔
808

809
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", false);
1✔
810
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", true);
1✔
811

812
   keypair.first.destroy();
1✔
813
   keypair.second.destroy();
1✔
814

815
   return result;
2✔
816
}
2✔
817

818
Test::Result test_rsa_sign_verify() {
1✔
819
   Test::Result result("PKCS11 RSA sign and verify");
1✔
820
   const TestSession test_session(true);
1✔
821

822
   // generate key pair
823
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
824

825
   auto rng = Test::new_rng(__func__);
1✔
826

827
   std::vector<uint8_t> plaintext(256);
1✔
828
   std::iota(std::begin(plaintext), std::end(plaintext), static_cast<uint8_t>(0));
1✔
829

830
   auto sign_and_verify = [&](const std::string& padding, bool multipart) {
6✔
831
      Botan::PK_Signer signer(keypair.second, *rng, padding, Botan::Signature_Format::Standard);
5✔
832
      std::vector<uint8_t> signature;
5✔
833
      if(multipart) {
5✔
834
         signer.update(plaintext.data(), plaintext.size() / 2);
2✔
835
         signature = signer.sign_message(plaintext.data() + plaintext.size() / 2, plaintext.size() / 2, *rng);
4✔
836
      } else {
837
         signature = signer.sign_message(plaintext, *rng);
6✔
838
      }
839

840
      Botan::PK_Verifier verifier(keypair.first, padding, Botan::Signature_Format::Standard);
5✔
841
      bool rsa_ok = false;
5✔
842
      if(multipart) {
5✔
843
         verifier.update(plaintext.data(), plaintext.size() / 2);
2✔
844
         rsa_ok = verifier.verify_message(
2✔
845
            plaintext.data() + plaintext.size() / 2, plaintext.size() / 2, signature.data(), signature.size());
2✔
846
      } else {
847
         rsa_ok = verifier.verify_message(plaintext, signature);
3✔
848
      }
849

850
      result.test_is_true("RSA PKCS11 sign and verify: " + padding, rsa_ok);
5✔
851
   };
10✔
852

853
   // single-part sign
854
   sign_and_verify("Raw", false);
1✔
855
   sign_and_verify("PKCS1v15(SHA-256)", false);
1✔
856
   sign_and_verify("PSS(SHA-256)", false);
1✔
857

858
   // multi-part sign
859
   sign_and_verify("PKCS1v15(SHA-256)", true);
1✔
860
   sign_and_verify("PSS(SHA-256)", true);
1✔
861

862
   keypair.first.destroy();
1✔
863
   keypair.second.destroy();
1✔
864

865
   return result;
2✔
866
}
2✔
867

868
class PKCS11_RSA_Tests final : public Test {
1✔
869
   public:
870
      std::vector<Test::Result> run() override {
1✔
871
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
872
            {STRING_AND_FUNCTION(test_rsa_privkey_import)},
873
            {STRING_AND_FUNCTION(test_rsa_pubkey_import)},
874
            {STRING_AND_FUNCTION(test_rsa_privkey_export)},
875
            {STRING_AND_FUNCTION(test_rsa_generate_private_key)},
876
            {STRING_AND_FUNCTION(test_rsa_generate_key_pair)},
877
            {STRING_AND_FUNCTION(test_rsa_encrypt_decrypt)},
878
            {STRING_AND_FUNCTION(test_rsa_sign_verify)}};
8✔
879

880
         return run_pkcs11_tests("PKCS11 RSA", fns);
2✔
881
      }
2✔
882
};
883

884
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rsa", PKCS11_RSA_Tests);
885
   #endif
886

887
/***************************** PKCS11 ECDSA *****************************/
888

889
   #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
890
std::vector<uint8_t> encode_ec_point_in_octet_str(const Botan::EC_PublicKey& pk) {
4✔
891
   std::vector<uint8_t> enc;
4✔
892
   DER_Encoder(enc).encode(pk._public_ec_point().serialize_uncompressed(), ASN1_Type::OctetString);
12✔
893
   return enc;
4✔
894
}
×
895
   #endif
896

897
   #if defined(BOTAN_HAS_ECDSA)
898

899
Test::Result test_ecdsa_privkey_import() {
1✔
900
   Test::Result result("PKCS11 import ECDSA private key");
1✔
901

902
   const TestSession test_session(true);
1✔
903

904
   auto rng = Test::new_rng(__func__);
1✔
905

906
   // create ecdsa private key
907
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
908
   result.test_is_true("Key self test OK", priv_key.check_key(*rng, true));
1✔
909

910
   // import to card
911
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
912
   props.set_token(true);
1✔
913
   props.set_private(true);
1✔
914
   props.set_sign(true);
1✔
915

916
   // label
917
   const std::string label = "Botan test ecdsa key";
1✔
918
   props.set_label(label);
1✔
919

920
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
1✔
921
   result.test_success("ECDSA private key import was successful");
1✔
922
   pk.set_public_point(priv_key._public_ec_point());
1✔
923
   result.test_is_true("P11 key self test OK", pk.check_key(*rng, false));
1✔
924

925
   pk.destroy();
1✔
926
   return result;
1✔
927
}
2✔
928

929
Test::Result test_ecdsa_privkey_export() {
1✔
930
   Test::Result result("PKCS11 export ECDSA private key");
1✔
931

932
   const TestSession test_session(true);
1✔
933

934
   auto rng = Test::new_rng(__func__);
1✔
935

936
   // create private key
937
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
938

939
   result.test_is_true("Check ECDSA key", priv_key.check_key(*rng, true));
1✔
940
   // import to card
941
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
942
   props.set_token(true);
1✔
943
   props.set_private(true);
1✔
944
   props.set_sign(true);
1✔
945
   props.set_extractable(true);
1✔
946

947
   // label
948
   const std::string label = "Botan test ecdsa key";
1✔
949
   props.set_label(label);
1✔
950

951
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
1✔
952
   pk.set_public_point(priv_key._public_ec_point());
1✔
953
   result.test_is_true("Check PK11 key", pk.check_key(*rng, false));
1✔
954

955
   const ECDSA_PrivateKey exported = pk.export_key();
1✔
956
   result.test_success("ECDSA private key export was successful");
1✔
957
   result.test_is_true("Check exported key valid", exported.check_key(*rng, true));
1✔
958
   result.test_eq("Check exported key contents", exported.private_key_bits(), priv_key.private_key_bits());
2✔
959

960
   pk.destroy();
1✔
961
   return result;
1✔
962
}
2✔
963

964
Test::Result test_ecdsa_pubkey_import() {
1✔
965
   Test::Result result("PKCS11 import ECDSA public key");
1✔
966

967
   const TestSession test_session(true);
1✔
968

969
   auto rng = Test::new_rng(__func__);
1✔
970

971
   // create ecdsa private key
972
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
973

974
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
975

976
   // import to card
977
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
978
   props.set_token(true);
1✔
979
   props.set_verify(true);
1✔
980
   props.set_private(false);
1✔
981

982
   // label
983
   const std::string label = "Botan test ecdsa pub key";
1✔
984
   props.set_label(label);
1✔
985

986
   const PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
987
   result.test_success("ECDSA public key import was successful");
1✔
988

989
   pk.destroy();
1✔
990
   return result;
1✔
991
}
3✔
992

993
Test::Result test_ecdsa_pubkey_export() {
1✔
994
   Test::Result result("PKCS11 export ECDSA public key");
1✔
995

996
   const TestSession test_session(true);
1✔
997

998
   auto rng = Test::new_rng(__func__);
1✔
999

1000
   // create public key from private key
1001
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1002

1003
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
1004

1005
   // import to card
1006
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
1007
   props.set_token(true);
1✔
1008
   props.set_verify(true);
1✔
1009
   props.set_private(false);
1✔
1010

1011
   // label
1012
   const std::string label = "Botan test ecdsa pub key";
1✔
1013
   props.set_label(label);
1✔
1014

1015
   const PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
1016

1017
   const ECDSA_PublicKey exported = pk.export_key();
1✔
1018
   result.test_success("ECDSA public key export was successful");
1✔
1019

1020
   pk.destroy();
1✔
1021

1022
   return result;
2✔
1023
}
3✔
1024

1025
Test::Result test_ecdsa_generate_private_key() {
1✔
1026
   Test::Result result("PKCS11 generate ECDSA private key");
1✔
1027
   const TestSession test_session(true);
1✔
1028

1029
   EC_PrivateKeyGenerationProperties props;
1✔
1030
   props.set_token(true);
1✔
1031
   props.set_private(true);
1✔
1032
   props.set_sign(true);
1✔
1033

1034
   const PKCS11_ECDSA_PrivateKey pk(test_session.session(), EC_Group::from_name("secp256r1").DER_encode(), props);
2✔
1035
   result.test_success("ECDSA private key generation was successful");
1✔
1036

1037
   pk.destroy();
1✔
1038

1039
   return result;
1✔
1040
}
1✔
1041

1042
PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(const TestSession& test_session,
6✔
1043
                                            const std::string& curve,
1044
                                            EC_Group_Encoding enc) {
1045
   EC_PublicKeyGenerationProperties pub_props(EC_Group::from_name(curve).DER_encode(enc));
12✔
1046
   pub_props.set_label("BOTAN_TEST_ECDSA_PUB_KEY");
6✔
1047
   pub_props.set_token(true);
6✔
1048
   pub_props.set_verify(true);
6✔
1049
   pub_props.set_private(false);
6✔
1050
   pub_props.set_modifiable(true);
6✔
1051

1052
   EC_PrivateKeyGenerationProperties priv_props;
6✔
1053
   priv_props.set_label("BOTAN_TEST_ECDSA_PRIV_KEY");
6✔
1054
   priv_props.set_token(true);
6✔
1055
   priv_props.set_private(true);
6✔
1056
   priv_props.set_sensitive(true);
6✔
1057
   priv_props.set_extractable(false);
6✔
1058
   priv_props.set_sign(true);
6✔
1059
   priv_props.set_modifiable(true);
6✔
1060

1061
   return PKCS11::generate_ecdsa_keypair(test_session.session(), pub_props, priv_props);
12✔
1062
}
6✔
1063

1064
Test::Result test_ecdsa_generate_keypair() {
1✔
1065
   Test::Result result("PKCS11 generate ECDSA key pair");
1✔
1066
   const TestSession test_session(true);
1✔
1067
   std::vector<std::string> curves;
1✔
1068

1069
   curves.push_back("secp256r1");
2✔
1070
   curves.push_back("brainpool512r1");
2✔
1071

1072
   for(const auto& curve : curves) {
3✔
1073
      const PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session, curve, EC_Group_Encoding::NamedCurve);
2✔
1074

1075
      keypair.first.destroy();
2✔
1076
      keypair.second.destroy();
2✔
1077
   }
2✔
1078
   result.test_success("ECDSA key pair generation was successful");
1✔
1079

1080
   return result;
1✔
1081
}
1✔
1082

1083
Test::Result test_ecdsa_sign_verify_core(EC_Group_Encoding enc, const std::string& test_name) {
2✔
1084
   Test::Result result(test_name);
2✔
1085
   const TestSession test_session(true);
2✔
1086
   std::vector<std::string> curves;
2✔
1087

1088
   curves.push_back("secp256r1");
4✔
1089
   curves.push_back("brainpool512r1");
4✔
1090

1091
   const Slot& slot = test_session.slot();
2✔
1092
   SlotInfo info = slot.get_slot_info();
2✔
1093
   const std::string manufacturer(reinterpret_cast<char*>(info.manufacturerID));
2✔
1094

1095
   auto rng = Test::new_rng(__func__);
2✔
1096

1097
   for(const auto& curve : curves) {
6✔
1098
      // generate key pair
1099
      PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session, curve, enc);
4✔
1100

1101
      std::vector<uint8_t> plaintext(20, 0x01);
4✔
1102

1103
      auto sign_and_verify = [&](const std::string& padding, const Botan::Signature_Format format, bool check_soft) {
8✔
1104
         Botan::PK_Signer signer(keypair.second, *rng, padding, format);
4✔
1105
         auto signature = signer.sign_message(plaintext, *rng);
4✔
1106

1107
         Botan::PK_Verifier token_verifier(keypair.first, padding, format);
4✔
1108
         const bool ecdsa_ok = token_verifier.verify_message(plaintext, signature);
4✔
1109

1110
         result.test_is_true("ECDSA PKCS11 sign and verify: " + padding, ecdsa_ok);
4✔
1111

1112
         // test against software implementation if available
1113
         if(check_soft) {
4✔
1114
            Botan::PK_Verifier soft_verifier(keypair.first, padding, format);
4✔
1115
            const bool soft_ecdsa_ok = soft_verifier.verify_message(plaintext, signature);
4✔
1116

1117
            result.test_is_true("ECDSA PKCS11 verify (in software): " + padding, soft_ecdsa_ok);
4✔
1118
         }
4✔
1119
      };
8✔
1120

1121
      // SoftHSMv2 until now only supports "Raw"
1122
      if(manufacturer.find("SoftHSM project") == std::string::npos) {
4✔
1123
         sign_and_verify("SHA-256", Botan::Signature_Format::Standard, true);
×
1124
         sign_and_verify("SHA-256", Botan::Signature_Format::DerSequence, true);
×
1125
      }
1126

1127
      #if defined(BOTAN_HAS_EMSA_RAW)
1128
      sign_and_verify("Raw", Botan::Signature_Format::Standard, true);
4✔
1129
      #else
1130
      sign_and_verify("Raw", Botan::Signature_Format::Standard, false);
1131
      #endif
1132

1133
      keypair.first.destroy();
4✔
1134
      keypair.second.destroy();
4✔
1135
   }
8✔
1136

1137
   return result;
4✔
1138
}
2✔
1139

1140
Test::Result test_ecdsa_sign_verify() {
1✔
1141
   // pass the curve OID to the PKCS#11 library
1142
   return test_ecdsa_sign_verify_core(EC_Group_Encoding::NamedCurve, "PKCS11 ECDSA sign and verify");
2✔
1143
}
1144

1145
Test::Result test_ecdsa_curve_import() {
1✔
1146
   // pass the curve parameters to the PKCS#11 library and perform sign/verify to test them
1147
   return test_ecdsa_sign_verify_core(EC_Group_Encoding::Explicit, "PKCS11 ECDSA sign and verify with imported curve");
2✔
1148
}
1149

1150
class PKCS11_ECDSA_Tests final : public Test {
1✔
1151
   public:
1152
      std::vector<Test::Result> run() override {
1✔
1153
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1154
            {STRING_AND_FUNCTION(test_ecdsa_privkey_import)},
1155
            {STRING_AND_FUNCTION(test_ecdsa_privkey_export)},
1156
            {STRING_AND_FUNCTION(test_ecdsa_pubkey_import)},
1157
            {STRING_AND_FUNCTION(test_ecdsa_pubkey_export)},
1158
            {STRING_AND_FUNCTION(test_ecdsa_generate_private_key)},
1159
            {STRING_AND_FUNCTION(test_ecdsa_generate_keypair)},
1160
            {STRING_AND_FUNCTION(test_ecdsa_sign_verify)},
1161
            {STRING_AND_FUNCTION(test_ecdsa_curve_import)}};
9✔
1162

1163
         return run_pkcs11_tests("PKCS11 ECDSA", fns);
2✔
1164
      }
2✔
1165
};
1166

1167
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdsa", PKCS11_ECDSA_Tests);
1168

1169
   #endif
1170

1171
   #if defined(BOTAN_HAS_ECDH)
1172

1173
/***************************** PKCS11 ECDH *****************************/
1174

1175
Test::Result test_ecdh_privkey_import() {
1✔
1176
   Test::Result result("PKCS11 import ECDH private key");
1✔
1177

1178
   const TestSession test_session(true);
1✔
1179

1180
   auto rng = Test::new_rng(__func__);
1✔
1181

1182
   // create ecdh private key
1183
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1184

1185
   // import to card
1186
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
1187
   props.set_token(true);
1✔
1188
   props.set_private(true);
1✔
1189
   props.set_derive(true);
1✔
1190

1191
   // label
1192
   const std::string label = "Botan test ecdh key";
1✔
1193
   props.set_label(label);
1✔
1194

1195
   const PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1196
   result.test_success("ECDH private key import was successful");
1✔
1197

1198
   pk.destroy();
1✔
1199
   return result;
1✔
1200
}
2✔
1201

1202
Test::Result test_ecdh_privkey_export() {
1✔
1203
   Test::Result result("PKCS11 export ECDH private key");
1✔
1204

1205
   const TestSession test_session(true);
1✔
1206

1207
   auto rng = Test::new_rng(__func__);
1✔
1208

1209
   // create private key
1210
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1211

1212
   // import to card
1213
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
1214
   props.set_token(true);
1✔
1215
   props.set_private(true);
1✔
1216
   props.set_derive(true);
1✔
1217
   props.set_extractable(true);
1✔
1218

1219
   // label
1220
   const std::string label = "Botan test ecdh key";
1✔
1221
   props.set_label(label);
1✔
1222

1223
   const PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1224

1225
   const ECDH_PrivateKey exported = pk.export_key();
1✔
1226
   result.test_success("ECDH private key export was successful");
1✔
1227

1228
   pk.destroy();
1✔
1229
   return result;
1✔
1230
}
2✔
1231

1232
Test::Result test_ecdh_pubkey_import() {
1✔
1233
   Test::Result result("PKCS11 import ECDH public key");
1✔
1234

1235
   const TestSession test_session(true);
1✔
1236

1237
   auto rng = Test::new_rng(__func__);
1✔
1238

1239
   // create ECDH private key
1240
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1241

1242
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
1243

1244
   // import to card
1245
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
1246
   props.set_token(true);
1✔
1247
   props.set_private(false);
1✔
1248
   props.set_derive(true);
1✔
1249

1250
   // label
1251
   const std::string label = "Botan test ECDH pub key";
1✔
1252
   props.set_label(label);
1✔
1253

1254
   const PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1255
   result.test_success("ECDH public key import was successful");
1✔
1256

1257
   pk.destroy();
1✔
1258
   return result;
2✔
1259
}
3✔
1260

1261
Test::Result test_ecdh_pubkey_export() {
1✔
1262
   Test::Result result("PKCS11 export ECDH public key");
1✔
1263

1264
   const TestSession test_session(true);
1✔
1265

1266
   auto rng = Test::new_rng(__func__);
1✔
1267

1268
   // create public key from private key
1269
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1270

1271
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
1272

1273
   // import to card
1274
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
1275
   props.set_token(true);
1✔
1276
   props.set_derive(true);
1✔
1277
   props.set_private(false);
1✔
1278

1279
   // label
1280
   const std::string label = "Botan test ECDH pub key";
1✔
1281
   props.set_label(label);
1✔
1282

1283
   const PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1284

1285
   const ECDH_PublicKey exported = pk.export_key();
1✔
1286
   result.test_success("ECDH public key export was successful");
1✔
1287

1288
   pk.destroy();
1✔
1289

1290
   return result;
2✔
1291
}
3✔
1292

1293
Test::Result test_ecdh_generate_private_key() {
1✔
1294
   Test::Result result("PKCS11 generate ECDH private key");
1✔
1295
   const TestSession test_session(true);
1✔
1296

1297
   EC_PrivateKeyGenerationProperties props;
1✔
1298
   props.set_token(true);
1✔
1299
   props.set_private(true);
1✔
1300
   props.set_derive(true);
1✔
1301

1302
   const PKCS11_ECDH_PrivateKey pk(test_session.session(), EC_Group::from_name("secp256r1").DER_encode(), props);
2✔
1303
   result.test_success("ECDH private key generation was successful");
1✔
1304

1305
   pk.destroy();
1✔
1306

1307
   return result;
1✔
1308
}
1✔
1309

1310
PKCS11_ECDH_KeyPair generate_ecdh_keypair(const TestSession& test_session, const std::string& label) {
3✔
1311
   EC_PublicKeyGenerationProperties pub_props(EC_Group::from_name("secp256r1").DER_encode());
6✔
1312
   pub_props.set_label(label + "_PUB_KEY");
3✔
1313
   pub_props.set_token(true);
3✔
1314
   pub_props.set_derive(true);
3✔
1315
   pub_props.set_private(false);
3✔
1316
   pub_props.set_modifiable(true);
3✔
1317

1318
   EC_PrivateKeyGenerationProperties priv_props;
3✔
1319
   priv_props.set_label(label + "_PRIV_KEY");
3✔
1320
   priv_props.set_token(true);
3✔
1321
   priv_props.set_private(true);
3✔
1322
   priv_props.set_sensitive(true);
3✔
1323
   priv_props.set_extractable(false);
3✔
1324
   priv_props.set_derive(true);
3✔
1325
   priv_props.set_modifiable(true);
3✔
1326

1327
   return PKCS11::generate_ecdh_keypair(test_session.session(), pub_props, priv_props);
6✔
1328
}
3✔
1329

1330
Test::Result test_ecdh_generate_keypair() {
1✔
1331
   Test::Result result("PKCS11 generate ECDH key pair");
1✔
1332
   const TestSession test_session(true);
1✔
1333

1334
   const PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
1✔
1335
   result.test_success("ECDH key pair generation was successful");
1✔
1336

1337
   keypair.first.destroy();
1✔
1338
   keypair.second.destroy();
1✔
1339

1340
   return result;
2✔
1341
}
1✔
1342

1343
Test::Result test_ecdh_derive() {
1✔
1344
   Test::Result result("PKCS11 ECDH derive");
1✔
1345
   const TestSession test_session(true);
1✔
1346

1347
   const PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
1✔
1348
   const PKCS11_ECDH_KeyPair keypair2 = generate_ecdh_keypair(test_session, "Botan test ECDH key2");
1✔
1349

1350
   auto rng = Test::new_rng(__func__);
1✔
1351

1352
   // SoftHSMv2 only supports CKD_NULL KDF at the moment
1353
   const Botan::PK_Key_Agreement ka(keypair.second, *rng, "Raw");
1✔
1354
   const Botan::PK_Key_Agreement kb(keypair2.second, *rng, "Raw");
1✔
1355

1356
   const Botan::SymmetricKey alice_key = ka.derive_key(32, keypair2.first.raw_public_key_bits());
1✔
1357
   const Botan::SymmetricKey bob_key = kb.derive_key(32, keypair.first.raw_public_key_bits());
1✔
1358

1359
   const bool eq = alice_key == bob_key;
1✔
1360
   result.test_is_true("same secret key derived", eq);
1✔
1361

1362
   keypair.first.destroy();
1✔
1363
   keypair.second.destroy();
1✔
1364
   keypair2.first.destroy();
1✔
1365
   keypair2.second.destroy();
1✔
1366

1367
   return result;
2✔
1368
}
5✔
1369

1370
class PKCS11_ECDH_Tests final : public Test {
1✔
1371
   public:
1372
      std::vector<Test::Result> run() override {
1✔
1373
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1374
            {STRING_AND_FUNCTION(test_ecdh_privkey_import)},
1375
            {STRING_AND_FUNCTION(test_ecdh_privkey_export)},
1376
            {STRING_AND_FUNCTION(test_ecdh_pubkey_import)},
1377
            {STRING_AND_FUNCTION(test_ecdh_pubkey_export)},
1378
            {STRING_AND_FUNCTION(test_ecdh_generate_private_key)},
1379
            {STRING_AND_FUNCTION(test_ecdh_generate_keypair)},
1380
            {STRING_AND_FUNCTION(test_ecdh_derive)}};
8✔
1381

1382
         return run_pkcs11_tests("PKCS11 ECDH", fns);
2✔
1383
      }
2✔
1384
};
1385

1386
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdh", PKCS11_ECDH_Tests);
1387

1388
   #endif
1389

1390
/***************************** PKCS11 RNG *****************************/
1391

1392
Test::Result test_rng_generate_random() {
1✔
1393
   Test::Result result("PKCS11 RNG generate random");
1✔
1394
   const TestSession test_session(true);
1✔
1395

1396
   PKCS11_RNG p11_rng(test_session.session());
1✔
1397
   result.test_is_true("RNG already seeded", p11_rng.is_seeded());
1✔
1398

1399
   std::vector<uint8_t> random(20);
1✔
1400
   p11_rng.randomize(random.data(), random.size());
1✔
1401
   result.test_ne("random data generated", random, std::vector<uint8_t>(20));
1✔
1402

1403
   return result;
2✔
1404
}
1✔
1405

1406
Test::Result test_rng_add_entropy() {
1✔
1407
   Test::Result result("PKCS11 RNG add entropy random");
1✔
1408
   const TestSession test_session(true);
1✔
1409

1410
   PKCS11_RNG p11_rng(test_session.session());
1✔
1411

1412
   result.test_is_true("RNG already seeded", p11_rng.is_seeded());
1✔
1413
   p11_rng.clear();
1✔
1414
   result.test_is_true("RNG ignores call to clear", p11_rng.is_seeded());
1✔
1415

1416
   #if defined(BOTAN_HAS_ENTROPY_SOURCE)
1417
   result.test_sz_eq(
1✔
1418
      "RNG ignores calls to reseed", p11_rng.reseed_from_sources(Botan::Entropy_Sources::global_sources(), 256), 0);
1419
   #endif
1420

1421
   auto rng = Test::new_rng(__func__);
1✔
1422
   auto random = rng->random_vec(20);
1✔
1423
   p11_rng.add_entropy(random.data(), random.size());
1✔
1424
   result.test_success("entropy added");
1✔
1425

1426
   return result;
2✔
1427
}
2✔
1428

1429
   #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
1430

1431
Test::Result test_pkcs11_hmac_drbg() {
1✔
1432
   Test::Result result("PKCS11 HMAC_DRBG using PKCS11_RNG");
1✔
1433
   const TestSession test_session(true);
1✔
1434

1435
   PKCS11_RNG p11_rng(test_session.session());
1✔
1436
   HMAC_DRBG drbg(MessageAuthenticationCode::create("HMAC(SHA-512)"), p11_rng);
1✔
1437
   // result.test_success("HMAC_DRBG(HMAC(SHA512)) instantiated with PKCS11_RNG");
1438

1439
   result.test_is_false("HMAC_DRBG is not seeded yet.", drbg.is_seeded());
1✔
1440
   const secure_vector<uint8_t> rnd = drbg.random_vec(64);
1✔
1441
   result.test_is_true("HMAC_DRBG is seeded now", drbg.is_seeded());
1✔
1442

1443
   std::string personalization_string = "Botan PKCS#11 Tests";
1✔
1444
   std::vector<uint8_t> personalization_data(personalization_string.begin(), personalization_string.end());
1✔
1445
   drbg.add_entropy(personalization_data.data(), personalization_data.size());
1✔
1446

1447
   auto rnd_vec = drbg.random_vec(256);
1✔
1448
   result.test_ne("HMAC_DRBG generated a random vector", rnd_vec, std::vector<uint8_t>(256));
1✔
1449

1450
   return result;
2✔
1451
}
3✔
1452
   #endif
1453

1454
class PKCS11_RNG_Tests final : public Test {
1✔
1455
   public:
1456
      std::vector<Test::Result> run() override {
1✔
1457
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1458
   #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
1459
            {STRING_AND_FUNCTION(test_pkcs11_hmac_drbg)},
1460
   #endif
1461
            {STRING_AND_FUNCTION(test_rng_generate_random)},
1462
            {STRING_AND_FUNCTION(test_rng_add_entropy)}
1463
         };
4✔
1464

1465
         return run_pkcs11_tests("PKCS11 RNG", fns);
2✔
1466
      }
2✔
1467
};
1468

1469
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rng", PKCS11_RNG_Tests);
1470

1471
/***************************** PKCS11 token management *****************************/
1472

1473
Test::Result test_set_pin() {
1✔
1474
   Test::Result result("PKCS11 set pin");
1✔
1475

1476
   Module module(Test::pkcs11_lib());
1✔
1477
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
1478
   Slot slot(module, slot_vec.at(0));
1✔
1479

1480
   PKCS11::set_pin(slot, SO_PIN(), TEST_PIN());
3✔
1481
   result.test_success("PIN set with SO_PIN to TEST_PIN");
1✔
1482

1483
   PKCS11::set_pin(slot, SO_PIN(), PIN());
3✔
1484
   result.test_success("PIN changed back with SO_PIN");
1✔
1485

1486
   return result;
2✔
1487
}
1✔
1488

1489
Test::Result test_initialize() {
1✔
1490
   Test::Result result("PKCS11 initialize token");
1✔
1491

1492
   Module module(Test::pkcs11_lib());
1✔
1493
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
1494
   Slot slot(module, slot_vec.at(0));
1✔
1495

1496
   PKCS11::initialize_token(slot, "Botan PKCS#11 tests", SO_PIN(), PIN());
3✔
1497
   result.test_success("token initialized");
1✔
1498

1499
   return result;
2✔
1500
}
1✔
1501

1502
Test::Result test_change_pin() {
1✔
1503
   Test::Result result("PKCS11 change pin");
1✔
1504

1505
   Module module(Test::pkcs11_lib());
1✔
1506
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
1507
   Slot slot(module, slot_vec.at(0));
1✔
1508

1509
   PKCS11::change_pin(slot, PIN(), TEST_PIN());
3✔
1510
   result.test_success("PIN changed with PIN to TEST_PIN");
1✔
1511

1512
   PKCS11::change_pin(slot, TEST_PIN(), PIN());
3✔
1513
   result.test_success("PIN changed back with TEST_PIN to PIN");
1✔
1514

1515
   return result;
2✔
1516
}
1✔
1517

1518
Test::Result test_change_so_pin() {
1✔
1519
   Test::Result result("PKCS11 change so_pin");
1✔
1520

1521
   Module module(Test::pkcs11_lib());
1✔
1522
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
1523
   Slot slot(module, slot_vec.at(0));
1✔
1524

1525
   PKCS11::change_so_pin(slot, SO_PIN(), TEST_SO_PIN());
3✔
1526
   result.test_success("SO_PIN changed with SO_PIN to TEST_SO_PIN");
1✔
1527

1528
   PKCS11::change_so_pin(slot, TEST_SO_PIN(), SO_PIN());
3✔
1529
   result.test_success("SO_PIN changed back with TEST_SO_PIN to SO_PIN");
1✔
1530

1531
   return result;
2✔
1532
}
1✔
1533

1534
class PKCS11_Token_Management_Tests final : public Test {
1✔
1535
   public:
1536
      std::vector<Test::Result> run() override {
1✔
1537
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1538
            {STRING_AND_FUNCTION(test_set_pin)},
1539
            {STRING_AND_FUNCTION(test_initialize)},
1540
            {STRING_AND_FUNCTION(test_change_pin)},
1541
            {STRING_AND_FUNCTION(test_change_so_pin)}};
5✔
1542

1543
         return run_pkcs11_tests("PKCS11 token management", fns);
2✔
1544
      }
2✔
1545
};
1546

1547
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-manage", PKCS11_Token_Management_Tests);
1548

1549
/***************************** PKCS11 token management *****************************/
1550

1551
   #if defined(BOTAN_HAS_X509_CERTIFICATES)
1552

1553
Test::Result test_x509_import() {
1✔
1554
   Test::Result result("PKCS11 X509 cert import");
1✔
1555

1556
      #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1557
   const TestSession test_session(true);
1✔
1558

1559
   const X509_Certificate root(Test::data_file("x509/nist/test01/end.crt"));
2✔
1560
   X509_CertificateProperties props(root);
1✔
1561
   props.set_label("Botan PKCS#11 test certificate");
1✔
1562
   props.set_private(false);
1✔
1563
   props.set_token(true);
1✔
1564

1565
   const PKCS11_X509_Certificate pkcs11_cert(test_session.session(), props);
1✔
1566
   result.test_success("X509 certificate imported");
1✔
1567

1568
   const PKCS11_X509_Certificate pkcs11_cert2(test_session.session(), pkcs11_cert.handle());
1✔
1569
   result.test_is_true("X509 certificate by handle", pkcs11_cert == pkcs11_cert2);
1✔
1570

1571
   pkcs11_cert.destroy();
1✔
1572
      #endif
1573

1574
   return result;
2✔
1575
}
1✔
1576

1577
class PKCS11_X509_Tests final : public Test {
1✔
1578
   public:
1579
      std::vector<Test::Result> run() override {
1✔
1580
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1581
            {STRING_AND_FUNCTION(test_x509_import)}};
2✔
1582

1583
         return run_pkcs11_tests("PKCS11 X509", fns);
2✔
1584
      }
2✔
1585
};
1586

1587
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-x509", PKCS11_X509_Tests);
1588

1589
   #endif
1590

1591
}  // namespace
1592

1593
#endif
1594

1595
}  // namespace Botan_Tests
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc