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

randombit / botan / 21753596263

06 Feb 2026 02:13PM UTC coverage: 90.063% (-0.01%) from 90.073%
21753596263

Pull #5289

github

web-flow
Merge 587099284 into 8ea0ca252
Pull Request #5289: Further misc header reductions, forward declarations, etc

102237 of 113517 relevant lines covered (90.06%)

11402137.11 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 "test_pkcs11.h"
11
#include "tests.h"
12

13
#include <memory>
14
#include <numeric>
15
#include <sstream>
16
#include <string>
17
#include <vector>
18

19
#if defined(BOTAN_HAS_PKCS11)
20
   #include <botan/p11.h>
21
   #include <botan/p11_object.h>
22
   #include <botan/p11_randomgenerator.h>
23
   #include <botan/internal/fmt.h>
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"); });
3✔
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");
1✔
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",
2✔
150
                      []() { Module const 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_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_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_is_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.confirm("Slot description is not empty", !description.empty());
2✔
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(); });
3✔
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.confirm("Token label is not empty", !label.empty());
2✔
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.confirm("The Slot supports at least one mechanism", !mechanisms.empty());
2✔
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); });
3✔
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_is_eq("slot id is correct", info.slotID, slot_vec.at(0));
1✔
393
   result.test_is_eq(
1✔
394
      "state is a read write public session", info.state, static_cast<CK_STATE>(SessionState::RwPublicSession));
1✔
395

396
   session.login(UserType::User, PIN());
1✔
397
   info = session.get_info();
1✔
398
   result.test_is_eq(
1✔
399
      "state is a read write user session", info.state, static_cast<CK_STATE>(SessionState::RwUserFunctions));
1✔
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_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_int_eq("ObjectId type", storedAttributes.at(4).type, AttributeType::ObjectId);
2✔
452
   result.test_int_eq("ObjectId value", *reinterpret_cast<uint64_t*>(storedAttributes.at(4).pValue), 10);
2✔
453
   result.test_int_eq("Id type", storedAttributes.at(5).type, AttributeType::Id);
2✔
454
   result.test_int_eq("Id value", *reinterpret_cast<uint64_t*>(storedAttributes.at(5).pValue), 21);
2✔
455
   result.test_int_eq("PixelX type", storedAttributes.at(6).type, AttributeType::PixelX);
2✔
456
   result.test_int_eq("PixelX value", *reinterpret_cast<uint64_t*>(storedAttributes.at(6).pValue), 30);
2✔
457
   result.test_int_eq("PixelY type", storedAttributes.at(7).type, AttributeType::PixelY);
2✔
458
   result.test_int_eq("PixelY value", *reinterpret_cast<uint64_t*>(storedAttributes.at(7).pValue), 40);
2✔
459

460
   return result;
2✔
461
}
1✔
462

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

467
   const std::size_t id = 1337;
4✔
468
   const std::string application = "Botan test application";
4✔
469

470
   std::vector<uint8_t> encoded_id;
4✔
471
   DER_Encoder(encoded_id).encode(id);
4✔
472

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

481
   return data_obj_props;
4✔
482
}
8✔
483

484
   #if defined(BOTAN_HAS_ASN1)
485
Test::Result test_create_destroy_data_object() {
1✔
486
   Test::Result result("Object create/delete data object");
1✔
487

488
   const TestSession test_session(true);
1✔
489

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

495
   data_obj.destroy();
1✔
496
   result.test_success("Data object deletion  was successful");
1✔
497

498
   return result;
2✔
499
}
1✔
500

501
Test::Result test_get_set_attribute_values() {
1✔
502
   Test::Result result("Object get/set attributes");
1✔
503

504
   const TestSession test_session(true);
1✔
505

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

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

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

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

526
   data_obj.destroy();
1✔
527
   return result;
2✔
528
}
2✔
529

530
Test::Result test_object_finder() {
1✔
531
   Test::Result result("ObjectFinder");
1✔
532

533
   const TestSession test_session(true);
1✔
534

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

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

545
   auto search_result = finder.find();
1✔
546
   result.test_eq("one object found", search_result.size(), 1);
1✔
547
   finder.finish();
1✔
548

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

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

559
   data_obj.destroy();
1✔
560
   return result;
1✔
561
}
2✔
562

563
Test::Result test_object_copy() {
1✔
564
   Test::Result result("Object copy");
1✔
565

566
   const TestSession test_session(true);
1✔
567

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

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

578
   const ObjectFinder searcher(test_session.session(), copy_attributes.attributes());
1✔
579
   auto search_result = searcher.find();
1✔
580
   result.test_eq("one object found", search_result.size(), 1);
1✔
581

582
   data_obj.destroy();
1✔
583

584
   const Object copied_obj(test_session.session(), copied_obj_handle);
1✔
585
   copied_obj.destroy();
1✔
586
   return result;
2✔
587
}
2✔
588
   #endif
589

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

604
         return run_pkcs11_tests("Object", fns);
2✔
605
      }
2✔
606
};
607

608
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-object", Object_Tests);
609

610
/***************************** PKCS11 RSA *****************************/
611

612
   #if defined(BOTAN_HAS_RSA)
613

614
Test::Result test_rsa_privkey_import() {
1✔
615
   Test::Result result("PKCS11 import RSA private key");
1✔
616

617
   const TestSession test_session(true);
1✔
618

619
   auto rng = Test::new_rng(__func__);
1✔
620

621
   // create private key
622
   const RSA_PrivateKey priv_key(*rng, 2048);
1✔
623
   result.confirm("Key self test OK", priv_key.check_key(*rng, true));
2✔
624

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

634
   props.set_token(true);
1✔
635
   props.set_private(true);
1✔
636
   props.set_decrypt(true);
1✔
637
   props.set_sign(true);
1✔
638

639
   const PKCS11_RSA_PrivateKey pk(test_session.session(), props);
1✔
640
   result.test_success("RSA private key import was successful");
1✔
641
   result.confirm("PK self test OK", pk.check_key(*rng, true));
2✔
642

643
   pk.destroy();
1✔
644
   return result;
1✔
645
}
2✔
646

647
Test::Result test_rsa_privkey_export() {
1✔
648
   Test::Result result("PKCS11 export RSA private key");
1✔
649

650
   const TestSession test_session(true);
1✔
651

652
   auto rng = Test::new_rng(__func__);
1✔
653

654
   // create private key
655
   const RSA_PrivateKey priv_key(*rng, 2048);
1✔
656

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

666
   props.set_token(true);
1✔
667
   props.set_private(true);
1✔
668
   props.set_decrypt(true);
1✔
669
   props.set_sign(true);
1✔
670
   props.set_extractable(true);
1✔
671
   props.set_sensitive(false);
1✔
672

673
   const PKCS11_RSA_PrivateKey pk(test_session.session(), props);
1✔
674
   result.confirm("Check PK11 key", pk.check_key(*rng, true));
2✔
675

676
   const RSA_PrivateKey exported = pk.export_key();
1✔
677
   result.test_success("RSA private key export was successful");
1✔
678
   result.confirm("Check exported key", exported.check_key(*rng, true));
2✔
679

680
   pk.destroy();
1✔
681
   return result;
1✔
682
}
2✔
683

684
Test::Result test_rsa_pubkey_import() {
1✔
685
   Test::Result result("PKCS11 import RSA public key");
1✔
686

687
   const TestSession test_session(true);
1✔
688

689
   auto rng = Test::new_rng(__func__);
1✔
690

691
   // create public key from private key
692
   const RSA_PrivateKey priv_key(*rng, 2048);
1✔
693

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

700
   const PKCS11_RSA_PublicKey pk(test_session.session(), props);
1✔
701
   result.test_success("RSA public key import was successful");
1✔
702
   result.confirm("Check PK11 key", pk.check_key(*rng, true));
2✔
703

704
   pk.destroy();
1✔
705

706
   return result;
2✔
707
}
2✔
708

709
Test::Result test_rsa_generate_private_key() {
1✔
710
   Test::Result result("PKCS11 generate RSA private key");
1✔
711
   const TestSession test_session(true);
1✔
712

713
   RSA_PrivateKeyGenerationProperties props;
1✔
714
   props.set_token(true);
1✔
715
   props.set_private(true);
1✔
716
   props.set_sign(true);
1✔
717
   props.set_decrypt(true);
1✔
718

719
   const PKCS11_RSA_PrivateKey pk(test_session.session(), 2048, props);
1✔
720
   result.test_success("RSA private key generation was successful");
1✔
721

722
   pk.destroy();
1✔
723

724
   return result;
1✔
725
}
1✔
726

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

736
   RSA_PrivateKeyGenerationProperties priv_props;
3✔
737
   priv_props.set_label("BOTAN_TEST_RSA_PRIV_KEY");
3✔
738
   priv_props.set_token(true);
3✔
739
   priv_props.set_private(true);
3✔
740
   priv_props.set_sign(true);
3✔
741
   priv_props.set_decrypt(true);
3✔
742

743
   return PKCS11::generate_rsa_keypair(test_session.session(), pub_props, priv_props);
3✔
744
}
3✔
745

746
Test::Result test_rsa_generate_key_pair() {
1✔
747
   Test::Result result("PKCS11 generate RSA key pair");
1✔
748
   const TestSession test_session(true);
1✔
749

750
   const PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
751
   result.test_success("RSA key pair generation was successful");
1✔
752

753
   keypair.first.destroy();
1✔
754
   keypair.second.destroy();
1✔
755

756
   return result;
1✔
757
}
1✔
758

759
Test::Result test_rsa_encrypt_decrypt() {
1✔
760
   Test::Result result("PKCS11 RSA encrypt decrypt");
1✔
761
   const TestSession test_session(true);
1✔
762

763
   // generate key pair
764
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
765

766
   auto rng = Test::new_rng(__func__);
1✔
767

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

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

779
         Botan::secure_vector<uint8_t> decrypted;
5✔
780

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

792
            result.test_failure(err.str(), e.what());
×
793
         }
×
794

795
         result.test_eq("RSA PKCS11 encrypt and decrypt: " + padding, decrypted, plaintext);
10✔
796
      };
10✔
797

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

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

806
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", false);
1✔
807
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", true);
1✔
808

809
   keypair.first.destroy();
1✔
810
   keypair.second.destroy();
1✔
811

812
   return result;
2✔
813
}
2✔
814

815
Test::Result test_rsa_sign_verify() {
1✔
816
   Test::Result result("PKCS11 RSA sign and verify");
1✔
817
   const TestSession test_session(true);
1✔
818

819
   // generate key pair
820
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
821

822
   auto rng = Test::new_rng(__func__);
1✔
823

824
   std::vector<uint8_t> plaintext(256);
1✔
825
   std::iota(std::begin(plaintext), std::end(plaintext), static_cast<uint8_t>(0));
1✔
826

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

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

847
      result.test_eq("RSA PKCS11 sign and verify: " + padding, rsa_ok, true);
5✔
848
   };
10✔
849

850
   // single-part sign
851
   sign_and_verify("Raw", false);
1✔
852
   sign_and_verify("PKCS1v15(SHA-256)", false);
1✔
853
   sign_and_verify("PSS(SHA-256)", false);
1✔
854

855
   // multi-part sign
856
   sign_and_verify("PKCS1v15(SHA-256)", true);
1✔
857
   sign_and_verify("PSS(SHA-256)", true);
1✔
858

859
   keypair.first.destroy();
1✔
860
   keypair.second.destroy();
1✔
861

862
   return result;
2✔
863
}
2✔
864

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

877
         return run_pkcs11_tests("PKCS11 RSA", fns);
2✔
878
      }
2✔
879
};
880

881
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rsa", PKCS11_RSA_Tests);
882
   #endif
883

884
/***************************** PKCS11 ECDSA *****************************/
885

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

894
   #if defined(BOTAN_HAS_ECDSA)
895

896
Test::Result test_ecdsa_privkey_import() {
1✔
897
   Test::Result result("PKCS11 import ECDSA private key");
1✔
898

899
   const TestSession test_session(true);
1✔
900

901
   auto rng = Test::new_rng(__func__);
1✔
902

903
   // create ecdsa private key
904
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
905
   result.confirm("Key self test OK", priv_key.check_key(*rng, true));
2✔
906

907
   // import to card
908
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
909
   props.set_token(true);
1✔
910
   props.set_private(true);
1✔
911
   props.set_sign(true);
1✔
912

913
   // label
914
   const std::string label = "Botan test ecdsa key";
1✔
915
   props.set_label(label);
1✔
916

917
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
1✔
918
   result.test_success("ECDSA private key import was successful");
1✔
919
   pk.set_public_point(priv_key._public_ec_point());
1✔
920
   result.confirm("P11 key self test OK", pk.check_key(*rng, false));
2✔
921

922
   pk.destroy();
1✔
923
   return result;
1✔
924
}
2✔
925

926
Test::Result test_ecdsa_privkey_export() {
1✔
927
   Test::Result result("PKCS11 export ECDSA private key");
1✔
928

929
   const TestSession test_session(true);
1✔
930

931
   auto rng = Test::new_rng(__func__);
1✔
932

933
   // create private key
934
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
935

936
   result.confirm("Check ECDSA key", priv_key.check_key(*rng, true));
2✔
937
   // import to card
938
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
939
   props.set_token(true);
1✔
940
   props.set_private(true);
1✔
941
   props.set_sign(true);
1✔
942
   props.set_extractable(true);
1✔
943

944
   // label
945
   const std::string label = "Botan test ecdsa key";
1✔
946
   props.set_label(label);
1✔
947

948
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
1✔
949
   pk.set_public_point(priv_key._public_ec_point());
1✔
950
   result.confirm("Check PK11 key", pk.check_key(*rng, false));
2✔
951

952
   const ECDSA_PrivateKey exported = pk.export_key();
1✔
953
   result.test_success("ECDSA private key export was successful");
1✔
954
   result.confirm("Check exported key valid", exported.check_key(*rng, true));
2✔
955
   result.test_eq("Check exported key contents", exported.private_key_bits(), priv_key.private_key_bits());
3✔
956

957
   pk.destroy();
1✔
958
   return result;
1✔
959
}
2✔
960

961
Test::Result test_ecdsa_pubkey_import() {
1✔
962
   Test::Result result("PKCS11 import ECDSA public key");
1✔
963

964
   const TestSession test_session(true);
1✔
965

966
   auto rng = Test::new_rng(__func__);
1✔
967

968
   // create ecdsa private key
969
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
970

971
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
972

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

979
   // label
980
   const std::string label = "Botan test ecdsa pub key";
1✔
981
   props.set_label(label);
1✔
982

983
   const PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
984
   result.test_success("ECDSA public key import was successful");
1✔
985

986
   pk.destroy();
1✔
987
   return result;
1✔
988
}
3✔
989

990
Test::Result test_ecdsa_pubkey_export() {
1✔
991
   Test::Result result("PKCS11 export ECDSA public key");
1✔
992

993
   const TestSession test_session(true);
1✔
994

995
   auto rng = Test::new_rng(__func__);
1✔
996

997
   // create public key from private key
998
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
999

1000
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
1001

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

1008
   // label
1009
   const std::string label = "Botan test ecdsa pub key";
1✔
1010
   props.set_label(label);
1✔
1011

1012
   const PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
1013

1014
   const ECDSA_PublicKey exported = pk.export_key();
1✔
1015
   result.test_success("ECDSA public key export was successful");
1✔
1016

1017
   pk.destroy();
1✔
1018

1019
   return result;
2✔
1020
}
3✔
1021

1022
Test::Result test_ecdsa_generate_private_key() {
1✔
1023
   Test::Result result("PKCS11 generate ECDSA private key");
1✔
1024
   const TestSession test_session(true);
1✔
1025

1026
   EC_PrivateKeyGenerationProperties props;
1✔
1027
   props.set_token(true);
1✔
1028
   props.set_private(true);
1✔
1029
   props.set_sign(true);
1✔
1030

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

1034
   pk.destroy();
1✔
1035

1036
   return result;
1✔
1037
}
1✔
1038

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

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

1058
   return PKCS11::generate_ecdsa_keypair(test_session.session(), pub_props, priv_props);
12✔
1059
}
6✔
1060

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

1066
   curves.push_back("secp256r1");
2✔
1067
   curves.push_back("brainpool512r1");
2✔
1068

1069
   for(const auto& curve : curves) {
3✔
1070
      const PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session, curve, EC_Group_Encoding::NamedCurve);
2✔
1071

1072
      keypair.first.destroy();
2✔
1073
      keypair.second.destroy();
2✔
1074
   }
2✔
1075
   result.test_success("ECDSA key pair generation was successful");
1✔
1076

1077
   return result;
1✔
1078
}
1✔
1079

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

1085
   curves.push_back("secp256r1");
4✔
1086
   curves.push_back("brainpool512r1");
4✔
1087

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

1092
   auto rng = Test::new_rng(__func__);
2✔
1093

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

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

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

1104
         Botan::PK_Verifier token_verifier(keypair.first, padding, format);
4✔
1105
         const bool ecdsa_ok = token_verifier.verify_message(plaintext, signature);
4✔
1106

1107
         result.test_eq("ECDSA PKCS11 sign and verify: " + padding, ecdsa_ok, true);
4✔
1108

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

1114
            result.test_eq("ECDSA PKCS11 verify (in software): " + padding, soft_ecdsa_ok, true);
4✔
1115
         }
4✔
1116
      };
8✔
1117

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

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

1130
      keypair.first.destroy();
4✔
1131
      keypair.second.destroy();
4✔
1132
   }
8✔
1133

1134
   return result;
4✔
1135
}
2✔
1136

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

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

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

1160
         return run_pkcs11_tests("PKCS11 ECDSA", fns);
2✔
1161
      }
2✔
1162
};
1163

1164
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdsa", PKCS11_ECDSA_Tests);
1165

1166
   #endif
1167

1168
   #if defined(BOTAN_HAS_ECDH)
1169

1170
/***************************** PKCS11 ECDH *****************************/
1171

1172
Test::Result test_ecdh_privkey_import() {
1✔
1173
   Test::Result result("PKCS11 import ECDH private key");
1✔
1174

1175
   const TestSession test_session(true);
1✔
1176

1177
   auto rng = Test::new_rng(__func__);
1✔
1178

1179
   // create ecdh private key
1180
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1181

1182
   // import to card
1183
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
1184
   props.set_token(true);
1✔
1185
   props.set_private(true);
1✔
1186
   props.set_derive(true);
1✔
1187

1188
   // label
1189
   const std::string label = "Botan test ecdh key";
1✔
1190
   props.set_label(label);
1✔
1191

1192
   const PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1193
   result.test_success("ECDH private key import was successful");
1✔
1194

1195
   pk.destroy();
1✔
1196
   return result;
1✔
1197
}
2✔
1198

1199
Test::Result test_ecdh_privkey_export() {
1✔
1200
   Test::Result result("PKCS11 export ECDH private key");
1✔
1201

1202
   const TestSession test_session(true);
1✔
1203

1204
   auto rng = Test::new_rng(__func__);
1✔
1205

1206
   // create private key
1207
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1208

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

1216
   // label
1217
   const std::string label = "Botan test ecdh key";
1✔
1218
   props.set_label(label);
1✔
1219

1220
   const PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1221

1222
   const ECDH_PrivateKey exported = pk.export_key();
1✔
1223
   result.test_success("ECDH private key export was successful");
1✔
1224

1225
   pk.destroy();
1✔
1226
   return result;
1✔
1227
}
2✔
1228

1229
Test::Result test_ecdh_pubkey_import() {
1✔
1230
   Test::Result result("PKCS11 import ECDH public key");
1✔
1231

1232
   const TestSession test_session(true);
1✔
1233

1234
   auto rng = Test::new_rng(__func__);
1✔
1235

1236
   // create ECDH private key
1237
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1238

1239
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
1240

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

1247
   // label
1248
   const std::string label = "Botan test ECDH pub key";
1✔
1249
   props.set_label(label);
1✔
1250

1251
   const PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1252
   result.test_success("ECDH public key import was successful");
1✔
1253

1254
   pk.destroy();
1✔
1255
   return result;
2✔
1256
}
3✔
1257

1258
Test::Result test_ecdh_pubkey_export() {
1✔
1259
   Test::Result result("PKCS11 export ECDH public key");
1✔
1260

1261
   const TestSession test_session(true);
1✔
1262

1263
   auto rng = Test::new_rng(__func__);
1✔
1264

1265
   // create public key from private key
1266
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1267

1268
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
1269

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

1276
   // label
1277
   const std::string label = "Botan test ECDH pub key";
1✔
1278
   props.set_label(label);
1✔
1279

1280
   const PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1281

1282
   const ECDH_PublicKey exported = pk.export_key();
1✔
1283
   result.test_success("ECDH public key export was successful");
1✔
1284

1285
   pk.destroy();
1✔
1286

1287
   return result;
2✔
1288
}
3✔
1289

1290
Test::Result test_ecdh_generate_private_key() {
1✔
1291
   Test::Result result("PKCS11 generate ECDH private key");
1✔
1292
   const TestSession test_session(true);
1✔
1293

1294
   EC_PrivateKeyGenerationProperties props;
1✔
1295
   props.set_token(true);
1✔
1296
   props.set_private(true);
1✔
1297
   props.set_derive(true);
1✔
1298

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

1302
   pk.destroy();
1✔
1303

1304
   return result;
1✔
1305
}
1✔
1306

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

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

1324
   return PKCS11::generate_ecdh_keypair(test_session.session(), pub_props, priv_props);
6✔
1325
}
3✔
1326

1327
Test::Result test_ecdh_generate_keypair() {
1✔
1328
   Test::Result result("PKCS11 generate ECDH key pair");
1✔
1329
   const TestSession test_session(true);
1✔
1330

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

1334
   keypair.first.destroy();
1✔
1335
   keypair.second.destroy();
1✔
1336

1337
   return result;
2✔
1338
}
1✔
1339

1340
Test::Result test_ecdh_derive() {
1✔
1341
   Test::Result result("PKCS11 ECDH derive");
1✔
1342
   const TestSession test_session(true);
1✔
1343

1344
   const PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
1✔
1345
   const PKCS11_ECDH_KeyPair keypair2 = generate_ecdh_keypair(test_session, "Botan test ECDH key2");
1✔
1346

1347
   auto rng = Test::new_rng(__func__);
1✔
1348

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

1353
   const Botan::SymmetricKey alice_key = ka.derive_key(32, keypair2.first.raw_public_key_bits());
1✔
1354
   const Botan::SymmetricKey bob_key = kb.derive_key(32, keypair.first.raw_public_key_bits());
1✔
1355

1356
   const bool eq = alice_key == bob_key;
1✔
1357
   result.test_eq("same secret key derived", eq, true);
1✔
1358

1359
   keypair.first.destroy();
1✔
1360
   keypair.second.destroy();
1✔
1361
   keypair2.first.destroy();
1✔
1362
   keypair2.second.destroy();
1✔
1363

1364
   return result;
2✔
1365
}
5✔
1366

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

1379
         return run_pkcs11_tests("PKCS11 ECDH", fns);
2✔
1380
      }
2✔
1381
};
1382

1383
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdh", PKCS11_ECDH_Tests);
1384

1385
   #endif
1386

1387
/***************************** PKCS11 RNG *****************************/
1388

1389
Test::Result test_rng_generate_random() {
1✔
1390
   Test::Result result("PKCS11 RNG generate random");
1✔
1391
   const TestSession test_session(true);
1✔
1392

1393
   PKCS11_RNG p11_rng(test_session.session());
1✔
1394
   result.confirm("RNG already seeded", p11_rng.is_seeded());
2✔
1395

1396
   std::vector<uint8_t> random(20);
1✔
1397
   p11_rng.randomize(random.data(), random.size());
1✔
1398
   result.test_ne("random data generated", random, std::vector<uint8_t>(20));
2✔
1399

1400
   return result;
2✔
1401
}
1✔
1402

1403
Test::Result test_rng_add_entropy() {
1✔
1404
   Test::Result result("PKCS11 RNG add entropy random");
1✔
1405
   const TestSession test_session(true);
1✔
1406

1407
   PKCS11_RNG p11_rng(test_session.session());
1✔
1408

1409
   result.confirm("RNG already seeded", p11_rng.is_seeded());
2✔
1410
   p11_rng.clear();
1✔
1411
   result.confirm("RNG ignores call to clear", p11_rng.is_seeded());
2✔
1412

1413
   #if defined(BOTAN_HAS_ENTROPY_SOURCE)
1414
   result.test_eq(
1✔
1415
      "RNG ignores calls to reseed", p11_rng.reseed_from_sources(Botan::Entropy_Sources::global_sources(), 256), 0);
1416
   #endif
1417

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

1423
   return result;
2✔
1424
}
2✔
1425

1426
   #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
1427

1428
Test::Result test_pkcs11_hmac_drbg() {
1✔
1429
   Test::Result result("PKCS11 HMAC_DRBG using PKCS11_RNG");
1✔
1430
   const TestSession test_session(true);
1✔
1431

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

1436
   result.test_eq("HMAC_DRBG is not seeded yet.", drbg.is_seeded(), false);
1✔
1437
   const secure_vector<uint8_t> rnd = drbg.random_vec(64);
1✔
1438
   result.test_eq("HMAC_DRBG is seeded now", drbg.is_seeded(), true);
1✔
1439

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

1444
   auto rnd_vec = drbg.random_vec(256);
1✔
1445
   result.test_ne("HMAC_DRBG generated a random vector", rnd_vec, std::vector<uint8_t>(256));
2✔
1446

1447
   return result;
2✔
1448
}
3✔
1449
   #endif
1450

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

1462
         return run_pkcs11_tests("PKCS11 RNG", fns);
2✔
1463
      }
2✔
1464
};
1465

1466
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rng", PKCS11_RNG_Tests);
1467

1468
/***************************** PKCS11 token management *****************************/
1469

1470
Test::Result test_set_pin() {
1✔
1471
   Test::Result result("PKCS11 set pin");
1✔
1472

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

1477
   PKCS11::set_pin(slot, SO_PIN(), TEST_PIN());
3✔
1478
   result.test_success("PIN set with SO_PIN to TEST_PIN");
1✔
1479

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

1483
   return result;
2✔
1484
}
1✔
1485

1486
Test::Result test_initialize() {
1✔
1487
   Test::Result result("PKCS11 initialize token");
1✔
1488

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

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

1496
   return result;
2✔
1497
}
1✔
1498

1499
Test::Result test_change_pin() {
1✔
1500
   Test::Result result("PKCS11 change pin");
1✔
1501

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

1506
   PKCS11::change_pin(slot, PIN(), TEST_PIN());
3✔
1507
   result.test_success("PIN changed with PIN to TEST_PIN");
1✔
1508

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

1512
   return result;
2✔
1513
}
1✔
1514

1515
Test::Result test_change_so_pin() {
1✔
1516
   Test::Result result("PKCS11 change so_pin");
1✔
1517

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

1522
   PKCS11::change_so_pin(slot, SO_PIN(), TEST_SO_PIN());
3✔
1523
   result.test_success("SO_PIN changed with SO_PIN to TEST_SO_PIN");
1✔
1524

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

1528
   return result;
2✔
1529
}
1✔
1530

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

1540
         return run_pkcs11_tests("PKCS11 token management", fns);
2✔
1541
      }
2✔
1542
};
1543

1544
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-manage", PKCS11_Token_Management_Tests);
1545

1546
/***************************** PKCS11 token management *****************************/
1547

1548
   #if defined(BOTAN_HAS_X509_CERTIFICATES)
1549

1550
Test::Result test_x509_import() {
1✔
1551
   Test::Result result("PKCS11 X509 cert import");
1✔
1552

1553
      #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1554
   const TestSession test_session(true);
1✔
1555

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

1562
   const PKCS11_X509_Certificate pkcs11_cert(test_session.session(), props);
1✔
1563
   result.test_success("X509 certificate imported");
1✔
1564

1565
   const PKCS11_X509_Certificate pkcs11_cert2(test_session.session(), pkcs11_cert.handle());
1✔
1566
   result.test_eq("X509 certificate by handle", pkcs11_cert == pkcs11_cert2, true);
1✔
1567

1568
   pkcs11_cert.destroy();
1✔
1569
      #endif
1570

1571
   return result;
2✔
1572
}
1✔
1573

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

1580
         return run_pkcs11_tests("PKCS11 X509", fns);
2✔
1581
      }
2✔
1582
};
1583

1584
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-x509", PKCS11_X509_Tests);
1585

1586
   #endif
1587

1588
}  // namespace
1589

1590
#endif
1591

1592
}  // 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