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

randombit / botan / 22020273955

14 Feb 2026 04:02PM UTC coverage: 90.059% (-0.005%) from 90.064%
22020273955

push

github

web-flow
Merge pull request #5328 from randombit/jack/test-predicates

Change Test::Result integer and bool predicates to be specifically named

102238 of 113523 relevant lines covered (90.06%)

11567860.88 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_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());
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.confirm("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.confirm("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_is_eq("slot id is correct", info.slotID, slot_vec.at(0));
1✔
393
   result.test_is_eq(
2✔
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(
2✔
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_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_is_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_is_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_is_eq("PixelX type", storedAttributes.at(6).type, static_cast<CK_ATTRIBUTE_TYPE>(AttributeType::PixelX));
1✔
457
   result.test_u64_eq("PixelX value", *reinterpret_cast<uint64_t*>(storedAttributes.at(6).pValue), 30);
1✔
458
   result.test_is_eq("PixelY type", storedAttributes.at(7).type, static_cast<CK_ATTRIBUTE_TYPE>(AttributeType::PixelY));
1✔
459
   result.test_u64_eq("PixelY value", *reinterpret_cast<uint64_t*>(storedAttributes.at(7).pValue), 40);
1✔
460

461
   return result;
2✔
462
}
1✔
463

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

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

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

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

482
   return data_obj_props;
4✔
483
}
8✔
484

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

489
   const TestSession test_session(true);
1✔
490

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

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

499
   return result;
3✔
500
}
1✔
501

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

505
   const TestSession test_session(true);
1✔
506

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

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

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

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

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

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

534
   const TestSession test_session(true);
1✔
535

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

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

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

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

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

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

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

567
   const TestSession test_session(true);
1✔
568

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

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

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

583
   data_obj.destroy();
1✔
584

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

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

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

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

611
/***************************** PKCS11 RSA *****************************/
612

613
   #if defined(BOTAN_HAS_RSA)
614

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

618
   const TestSession test_session(true);
1✔
619

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

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

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

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

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

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

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

651
   const TestSession test_session(true);
1✔
652

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

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

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

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

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

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

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

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

688
   const TestSession test_session(true);
1✔
689

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

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

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

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

705
   pk.destroy();
1✔
706

707
   return result;
2✔
708
}
2✔
709

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

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

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

723
   pk.destroy();
1✔
724

725
   return result;
1✔
726
}
1✔
727

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

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

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

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

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

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

757
   return result;
1✔
758
}
1✔
759

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

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

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

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

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

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

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

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

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

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

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

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

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

813
   return result;
2✔
814
}
2✔
815

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

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

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

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

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

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

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

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

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

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

863
   return result;
2✔
864
}
2✔
865

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

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

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

885
/***************************** PKCS11 ECDSA *****************************/
886

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

895
   #if defined(BOTAN_HAS_ECDSA)
896

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

900
   const TestSession test_session(true);
1✔
901

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

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

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

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

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

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

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

930
   const TestSession test_session(true);
1✔
931

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

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

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

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

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

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

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

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

965
   const TestSession test_session(true);
1✔
966

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

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

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

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

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

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

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

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

994
   const TestSession test_session(true);
1✔
995

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

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

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

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

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

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

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

1018
   pk.destroy();
1✔
1019

1020
   return result;
2✔
1021
}
3✔
1022

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

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

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

1035
   pk.destroy();
1✔
1036

1037
   return result;
1✔
1038
}
1✔
1039

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

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

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

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

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

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

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

1078
   return result;
1✔
1079
}
1✔
1080

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1135
   return result;
4✔
1136
}
2✔
1137

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

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

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

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

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

1167
   #endif
1168

1169
   #if defined(BOTAN_HAS_ECDH)
1170

1171
/***************************** PKCS11 ECDH *****************************/
1172

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

1176
   const TestSession test_session(true);
1✔
1177

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

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

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

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

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

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

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

1203
   const TestSession test_session(true);
1✔
1204

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

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

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

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

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

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

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

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

1233
   const TestSession test_session(true);
1✔
1234

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

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

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

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

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

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

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

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

1262
   const TestSession test_session(true);
1✔
1263

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

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

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

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

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

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

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

1286
   pk.destroy();
1✔
1287

1288
   return result;
2✔
1289
}
3✔
1290

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

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

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

1303
   pk.destroy();
1✔
1304

1305
   return result;
1✔
1306
}
1✔
1307

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

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

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

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

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

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

1338
   return result;
2✔
1339
}
1✔
1340

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

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

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

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

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

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

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

1365
   return result;
2✔
1366
}
5✔
1367

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

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

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

1386
   #endif
1387

1388
/***************************** PKCS11 RNG *****************************/
1389

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

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

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

1401
   return result;
2✔
1402
}
1✔
1403

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

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

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

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

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

1424
   return result;
2✔
1425
}
2✔
1426

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

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

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

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

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

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

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

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

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

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

1469
/***************************** PKCS11 token management *****************************/
1470

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

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

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

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

1484
   return result;
2✔
1485
}
1✔
1486

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

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

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

1497
   return result;
2✔
1498
}
1✔
1499

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

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

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

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

1513
   return result;
2✔
1514
}
1✔
1515

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

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

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

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

1529
   return result;
2✔
1530
}
1✔
1531

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

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

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

1547
/***************************** PKCS11 token management *****************************/
1548

1549
   #if defined(BOTAN_HAS_X509_CERTIFICATES)
1550

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

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

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

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

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

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

1572
   return result;
2✔
1573
}
1✔
1574

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

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

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

1587
   #endif
1588

1589
}  // namespace
1590

1591
#endif
1592

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