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

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 hits per line

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

97.05
/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
#endif
24

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

29
#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO)
30
   #include <botan/pubkey.h>
31
#endif
32

33
#if defined(BOTAN_HAS_ECC_GROUP)
34
   #include <botan/ec_group.h>
35
#endif
36

37
#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_PKCS11)
38
   #include <botan/p11_rsa.h>
39
   #include <botan/rsa.h>
40
#endif
41

42
#if defined(BOTAN_HAS_ECDSA) && defined(BOTAN_HAS_PKCS11)
43
   #include <botan/ecdsa.h>
44
   #include <botan/p11_ecdsa.h>
45
#endif
46

47
#if defined(BOTAN_HAS_ECDH) && defined(BOTAN_HAS_PKCS11)
48
   #include <botan/ecdh.h>
49
   #include <botan/p11_ecdh.h>
50
#endif
51

52
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_HAS_PKCS11)
53
   #include <botan/p11_x509.h>
54
   #include <botan/pkix_types.h>
55
#endif
56

57
#if defined(BOTAN_HAS_HMAC_DRBG)
58
   #include <botan/hmac_drbg.h>
59
#endif
60

61
namespace Botan_Tests {
62

63
#if defined(BOTAN_HAS_PKCS11)
64

65
std::vector<Test::Result> run_pkcs11_tests(const std::string& name,
11✔
66
                                           std::vector<std::pair<std::string, std::function<Test::Result()>>>& fns) {
67
   std::vector<Test::Result> results;
11✔
68

69
   for(size_t i = 0; i != fns.size(); ++i) {
85✔
70
      try {
74✔
71
         results.push_back(fns[i].second());
148✔
72
      } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
×
73
         results.push_back(Test::Result::Failure(name + " test " + fns[i].first, e.what()));
×
74

75
         if(e.get_return_value() == Botan::PKCS11::ReturnValue::PinIncorrect) {
×
76
            break;  // Do not continue to not potentially lock the token
77
         }
78
      } catch(std::exception& e) { results.push_back(Test::Result::Failure(name + " test " + fns[i].first, e.what())); }
×
79
   }
80

81
   return results;
11✔
82
}
×
83

84
namespace {
85

86
using namespace Botan;
87
using namespace PKCS11;
88

89
class TestSession {
90
   public:
91
      explicit TestSession(bool login) : m_module(new Module(Test::pkcs11_lib())) {
30✔
92
         std::vector<SlotId> slot_vec = Slot::get_available_slots(*m_module, true);
30✔
93
         m_slot = std::make_unique<Slot>(*m_module, slot_vec.at(0));
30✔
94
         m_session = std::make_unique<Session>(*m_slot, false);
30✔
95
         if(login) {
30✔
96
            m_session->login(UserType::User, PIN());
60✔
97
         }
98
      }
30✔
99

100
      inline Session& session() const { return *m_session; }
6✔
101

102
      inline Slot& slot() const { return *m_slot; }
2✔
103

104
   private:
105
      std::unique_ptr<Module> m_module = nullptr;
106
      std::unique_ptr<Slot> m_slot = nullptr;
107
      std::unique_ptr<Session> m_session = nullptr;
108
};
109

110
/***************************** Module *****************************/
111

112
Test::Result test_module_ctor() {
1✔
113
   Test::Result result("Module ctor");
1✔
114

115
   result.test_throws("Module ctor fails for non existent path", []() { Module failing_module("/a/b/c"); });
3✔
116

117
   Module module(Test::pkcs11_lib());
1✔
118
   result.test_success("Module ctor did not throw and completed successfully");
1✔
119

120
   return result;
1✔
121
}
1✔
122

123
Test::Result test_module_reload() {
1✔
124
   Test::Result result("Module reload");
1✔
125

126
   Module module(Test::pkcs11_lib());
1✔
127

128
   module.reload();
1✔
129
   result.test_success("Module reload did not throw and completed successfully");
1✔
130

131
   module.get_info();
1✔
132
   result.test_success("Module get_info() still works after reload");
1✔
133

134
   return result;
1✔
135
}
1✔
136

137
Test::Result test_multiple_modules() {
1✔
138
   Test::Result result("Module copy");
1✔
139
   Module first_module(Test::pkcs11_lib());
1✔
140

141
   result.test_throws("Module ctor fails if module is already initialized",
2✔
142
                      []() { Module second_module(Test::pkcs11_lib()); });
1✔
143

144
   return result;
1✔
145
}
1✔
146

147
Test::Result test_module_get_info() {
1✔
148
   Test::Result result("Module info");
1✔
149

150
   Module module(Test::pkcs11_lib());
1✔
151

152
   Info info = module.get_info();
1✔
153
   result.test_ne("Cryptoki version != 0", info.cryptokiVersion.major, 0);
1✔
154

155
   return result;
1✔
156
}
1✔
157

158
class Module_Tests final : public Test {
×
159
   public:
160
      std::vector<Test::Result> run() override {
1✔
161
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
162
            {STRING_AND_FUNCTION(test_module_ctor)},
163
            {STRING_AND_FUNCTION(test_multiple_modules)},
164
            {STRING_AND_FUNCTION(test_module_get_info)},
165
            {STRING_AND_FUNCTION(test_module_reload)}};
5✔
166

167
         return run_pkcs11_tests("Module", fns);
2✔
168
      }
1✔
169
};
170

171
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-module", Module_Tests);
172

173
/***************************** Slot *****************************/
174

175
Test::Result test_slot_get_available_slots() {
1✔
176
   Test::Result result("Slot get_available_slots");
1✔
177

178
   Module module(Test::pkcs11_lib());
1✔
179
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
180
   result.test_gte("Available Slots with attached token >= 1", slot_vec.size(), 1);
1✔
181

182
   return result;
2✔
183
}
1✔
184

185
Test::Result test_slot_ctor() {
1✔
186
   Test::Result result("Slot ctor");
1✔
187

188
   Module module(Test::pkcs11_lib());
1✔
189
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
190

191
   Slot slot(module, slot_vec.at(0));
1✔
192
   result.test_success("Slot ctor completed successfully");
1✔
193
   result.test_is_eq(slot.slot_id(), slot_vec.at(0));
1✔
194

195
   return result;
2✔
196
}
1✔
197

198
Test::Result test_get_slot_info() {
1✔
199
   Test::Result result("Slot get_slot_info");
1✔
200

201
   Module module(Test::pkcs11_lib());
1✔
202
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
203
   Slot slot(module, slot_vec.at(0));
1✔
204

205
   SlotInfo info = slot.get_slot_info();
1✔
206
   std::string description = reinterpret_cast<char*>(info.slotDescription);
1✔
207
   result.confirm("Slot description is not empty", !description.empty());
2✔
208

209
   return result;
2✔
210
}
2✔
211

212
SlotId get_invalid_slot_id(Module& module) {
2✔
213
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, false);
2✔
214

215
   SlotId invalid_id = 0;
2✔
216

217
   // find invalid slot id
218
   while(std::find(slot_vec.begin(), slot_vec.end(), invalid_id) != slot_vec.end()) {
2✔
219
      invalid_id++;
×
220
   }
221

222
   return invalid_id;
2✔
223
}
2✔
224

225
Test::Result test_slot_invalid_id() {
1✔
226
   Test::Result result("Slot get_slot_info with invalid slot id");
1✔
227

228
   Module module(Test::pkcs11_lib());
1✔
229

230
   SlotId invalid_id = get_invalid_slot_id(module);
1✔
231

232
   Slot slot(module, invalid_id);
1✔
233

234
   result.test_throws("get_slot_info fails for non existent slot id", [&slot]() { slot.get_slot_info(); });
3✔
235

236
   return result;
1✔
237
}
1✔
238

239
Test::Result test_get_token_info() {
1✔
240
   Test::Result result("Slot get_token_info");
1✔
241

242
   Module module(Test::pkcs11_lib());
1✔
243
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
244
   Slot slot(module, slot_vec.at(0));
1✔
245

246
   TokenInfo info = slot.get_token_info();
1✔
247
   std::string label = reinterpret_cast<char*>(info.label);
1✔
248
   result.confirm("Token label is not empty", !label.empty());
2✔
249

250
   return result;
2✔
251
}
2✔
252

253
Test::Result test_get_mechanism_list() {
1✔
254
   Test::Result result("Slot get_mechanism_list");
1✔
255

256
   Module module(Test::pkcs11_lib());
1✔
257
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
258
   Slot slot(module, slot_vec.at(0));
1✔
259

260
   std::vector<MechanismType> mechanisms = slot.get_mechanism_list();
1✔
261
   result.confirm("The Slot supports at least one mechanism", !mechanisms.empty());
2✔
262

263
   return result;
2✔
264
}
2✔
265

266
Test::Result test_get_mechanisms_info() {
1✔
267
   Test::Result result("Slot get_mechanism_info");
1✔
268

269
   Module module(Test::pkcs11_lib());
1✔
270
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
271
   Slot slot(module, slot_vec.at(0));
1✔
272

273
   slot.get_mechanism_info(MechanismType::RsaPkcsKeyPairGen);
1✔
274
   result.test_success("get_mechanism_info() completed successfully.");
1✔
275

276
   return result;
2✔
277
}
1✔
278

279
class Slot_Tests final : public Test {
×
280
   public:
281
      std::vector<Test::Result> run() override {
1✔
282
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
283
            {STRING_AND_FUNCTION(test_slot_get_available_slots)},
284
            {STRING_AND_FUNCTION(test_slot_ctor)},
285
            {STRING_AND_FUNCTION(test_get_slot_info)},
286
            {STRING_AND_FUNCTION(test_slot_invalid_id)},
287
            {STRING_AND_FUNCTION(test_get_token_info)},
288
            {STRING_AND_FUNCTION(test_get_mechanism_list)},
289
            {STRING_AND_FUNCTION(test_get_mechanisms_info)}};
8✔
290

291
         return run_pkcs11_tests("Slot", fns);
2✔
292
      }
1✔
293
};
294

295
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-slot", Slot_Tests);
296

297
/***************************** Session *****************************/
298

299
Test::Result test_session_ctor() {
1✔
300
   Test::Result result("Session ctor");
1✔
301

302
   Module module(Test::pkcs11_lib());
1✔
303
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
304
   Slot slot(module, slot_vec.at(0));
1✔
305

306
   {
1✔
307
      Session read_only_session(slot, true);
1✔
308
      result.test_success("read only session opened successfully");
1✔
309
   }
1✔
310
   {
1✔
311
      Session read_write_session(slot, false);
1✔
312
      result.test_success("read write session opened successfully");
1✔
313
   }
1✔
314
   {
1✔
315
      Flags flags = PKCS11::flags(Flag::SerialSession | Flag::RwSession);
1✔
316
      Session read_write_session2(slot, flags, nullptr, nullptr);
1✔
317
      result.test_success("read write session with flags param opened successfully");
1✔
318
   }
1✔
319
   {
1✔
320
      Session read_only_session(slot, true);
1✔
321
      Session read_write_session(slot, false);
1✔
322
      result.test_success("Opened multiple sessions successfully");
1✔
323
   }
1✔
324

325
   return result;
2✔
326
}
1✔
327

328
Test::Result test_session_ctor_invalid_slot() {
1✔
329
   Test::Result result("Session ctor with invalid slot id");
1✔
330

331
   Module module(Test::pkcs11_lib());
1✔
332

333
   SlotId invalid_id = get_invalid_slot_id(module);
1✔
334
   Slot slot(module, invalid_id);
1✔
335

336
   result.test_throws("Session ctor with invalid slot id fails", [&slot]() { Session session(slot, true); });
3✔
337

338
   return result;
1✔
339
}
1✔
340

341
Test::Result test_session_release() {
1✔
342
   Test::Result result("Session release/take ownership");
1✔
343

344
   Module module(Test::pkcs11_lib());
1✔
345
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
346
   Slot slot(module, slot_vec.at(0));
1✔
347

348
   Session session(slot, false);
1✔
349
   SessionHandle handle = session.release();
1✔
350

351
   Session session2(slot, handle);
1✔
352
   result.test_success("releasing ownership and taking ownership works as expected.");
1✔
353

354
   return result;
1✔
355
}
2✔
356

357
Test::Result test_session_login_logout() {
1✔
358
   Test::Result result("Session login/logout");
1✔
359

360
   Module module(Test::pkcs11_lib());
1✔
361
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
362
   Slot slot(module, slot_vec.at(0));
1✔
363

364
   Session session(slot, false);
1✔
365
   session.login(UserType::User, PIN());
1✔
366
   session.logoff();
1✔
367
   result.test_success("user login/logout succeeded");
1✔
368

369
   session.login(UserType::SO, SO_PIN());
1✔
370
   result.test_success("SO login succeeded");
1✔
371

372
   return result;
1✔
373
}
2✔
374

375
Test::Result test_session_info() {
1✔
376
   Test::Result result("Session session info");
1✔
377

378
   Module module(Test::pkcs11_lib());
1✔
379
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
380
   Slot slot(module, slot_vec.at(0));
1✔
381

382
   Session session(slot, false);
1✔
383
   SessionInfo info = session.get_info();
1✔
384
   result.test_is_eq("slot id is correct", info.slotID, slot_vec.at(0));
1✔
385
   result.test_is_eq(
1✔
386
      "state is a read write public session", info.state, static_cast<CK_STATE>(SessionState::RwPublicSession));
1✔
387

388
   session.login(UserType::User, PIN());
1✔
389
   info = session.get_info();
1✔
390
   result.test_is_eq(
1✔
391
      "state is a read write user session", info.state, static_cast<CK_STATE>(SessionState::RwUserFunctions));
1✔
392

393
   session.logoff();
1✔
394
   result.test_success("user login/logout succeeded");
1✔
395

396
   session.login(UserType::SO, SO_PIN());
1✔
397
   result.test_success("SO login succeeded");
1✔
398

399
   return result;
1✔
400
}
2✔
401

402
class Session_Tests final : public Test {
×
403
   public:
404
      std::vector<Test::Result> run() override {
1✔
405
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
406
            {STRING_AND_FUNCTION(test_session_ctor)},
407
            {STRING_AND_FUNCTION(test_session_ctor_invalid_slot)},
408
            {STRING_AND_FUNCTION(test_session_release)},
409
            {STRING_AND_FUNCTION(test_session_login_logout)},
410
            {STRING_AND_FUNCTION(test_session_info)}};
6✔
411

412
         return run_pkcs11_tests("Session", fns);
2✔
413
      }
1✔
414
};
415

416
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-session", Session_Tests);
417

418
/***************************** Object *****************************/
419

420
Test::Result test_attribute_container() {
1✔
421
   Test::Result result("AttributeContainer");
1✔
422

423
   AttributeContainer attributes;
1✔
424
   attributes.add_class(ObjectClass::PrivateKey);
1✔
425

426
   std::string label("test");
1✔
427
   attributes.add_string(AttributeType::Label, label);
1✔
428

429
   std::vector<uint8_t> bin(4);
1✔
430
   attributes.add_binary(AttributeType::Value, bin);
1✔
431

432
   attributes.add_bool(AttributeType::Sensitive, true);
1✔
433
   attributes.add_numeric(AttributeType::ObjectId, 10);
1✔
434
   attributes.add_numeric(AttributeType::Id, 20);
1✔
435
   attributes.add_numeric(AttributeType::PixelX, 30);
1✔
436
   // Test that overwriting the existing Id attribute works. The numeric attributes above should not be affected by this.
437
   attributes.add_numeric(AttributeType::Id, 21);
1✔
438
   attributes.add_numeric(AttributeType::PixelY, 40);
1✔
439

440
   result.test_eq("8 elements in attribute container", attributes.count(), 8);
1✔
441

442
   const std::vector<Botan::PKCS11::Attribute>& storedAttributes = attributes.attributes();
1✔
443
   result.test_int_eq("ObjectId type", storedAttributes.at(4).type, AttributeType::ObjectId);
1✔
444
   result.test_int_eq("ObjectId value", *reinterpret_cast<uint64_t*>(storedAttributes.at(4).pValue), 10);
1✔
445
   result.test_int_eq("Id type", storedAttributes.at(5).type, AttributeType::Id);
1✔
446
   result.test_int_eq("Id value", *reinterpret_cast<uint64_t*>(storedAttributes.at(5).pValue), 21);
1✔
447
   result.test_int_eq("PixelX type", storedAttributes.at(6).type, AttributeType::PixelX);
1✔
448
   result.test_int_eq("PixelX value", *reinterpret_cast<uint64_t*>(storedAttributes.at(6).pValue), 30);
1✔
449
   result.test_int_eq("PixelY type", storedAttributes.at(7).type, AttributeType::PixelY);
1✔
450
   result.test_int_eq("PixelY value", *reinterpret_cast<uint64_t*>(storedAttributes.at(7).pValue), 40);
1✔
451

452
   return result;
2✔
453
}
1✔
454

455
DataObjectProperties make_test_object(const std::string& label) {
4✔
456
   std::string value_string("test data");
4✔
457
   secure_vector<uint8_t> value(value_string.begin(), value_string.end());
4✔
458

459
   std::size_t id = 1337;
4✔
460
   std::string application = "Botan test application";
4✔
461

462
   std::vector<uint8_t> encoded_id;
4✔
463
   DER_Encoder(encoded_id).encode(id);
4✔
464

465
   DataObjectProperties data_obj_props;
4✔
466
   data_obj_props.set_application(application);
4✔
467
   data_obj_props.set_label(label);
4✔
468
   data_obj_props.set_value(value);
4✔
469
   data_obj_props.set_token(true);
4✔
470
   data_obj_props.set_modifiable(true);
4✔
471
   data_obj_props.set_object_id(encoded_id);
4✔
472

473
   return data_obj_props;
4✔
474
}
12✔
475

476
   #if defined(BOTAN_HAS_ASN1)
477
Test::Result test_create_destroy_data_object() {
1✔
478
   Test::Result result("Object create/delete data object");
1✔
479

480
   TestSession test_session(true);
1✔
481

482
   const std::string label = "Botan test data object";
1✔
483
   auto data_obj_props = make_test_object(label);
1✔
484
   Object data_obj(test_session.session(), data_obj_props);
1✔
485
   result.test_success("Data object creation was successful");
1✔
486

487
   data_obj.destroy();
1✔
488
   result.test_success("Data object deletion  was successful");
1✔
489

490
   return result;
2✔
491
}
2✔
492

493
Test::Result test_get_set_attribute_values() {
1✔
494
   Test::Result result("Object get/set attributes");
1✔
495

496
   TestSession test_session(true);
1✔
497

498
   // create object
499
   const std::string label = "Botan test data object";
1✔
500
   auto data_obj_props = make_test_object(label);
1✔
501
   Object data_obj(test_session.session(), data_obj_props);
1✔
502

503
   // get attribute
504
   secure_vector<uint8_t> retrieved_label = data_obj.get_attribute_value(AttributeType::Label);
1✔
505
   std::string retrieved_label_string(retrieved_label.begin(), retrieved_label.end());
1✔
506
   result.test_eq("label was set correctly", retrieved_label_string, label);
1✔
507

508
   // set attribute
509
   std::string new_label = "Botan test modified data object label";
1✔
510
   secure_vector<uint8_t> new_label_secvec(new_label.begin(), new_label.end());
1✔
511
   data_obj.set_attribute_value(AttributeType::Label, new_label_secvec);
1✔
512

513
   // get and check attribute
514
   retrieved_label = data_obj.get_attribute_value(AttributeType::Label);
2✔
515
   retrieved_label_string = std::string(retrieved_label.begin(), retrieved_label.end());
1✔
516
   result.test_eq("label was modified correctly", retrieved_label_string, new_label);
1✔
517

518
   data_obj.destroy();
1✔
519
   return result;
2✔
520
}
5✔
521

522
Test::Result test_object_finder() {
1✔
523
   Test::Result result("ObjectFinder");
1✔
524

525
   TestSession test_session(true);
1✔
526

527
   // create object
528
   const std::string label = "Botan test data object";
1✔
529
   auto data_obj_props = make_test_object(label);
1✔
530
   Object data_obj(test_session.session(), data_obj_props);
1✔
531

532
   // search created object
533
   AttributeContainer search_template;
1✔
534
   search_template.add_string(AttributeType::Label, label);
1✔
535
   ObjectFinder finder(test_session.session(), search_template.attributes());
1✔
536

537
   auto search_result = finder.find();
1✔
538
   result.test_eq("one object found", search_result.size(), 1);
1✔
539
   finder.finish();
1✔
540

541
   Object obj_found(test_session.session(), search_result.at(0));
1✔
542
   result.test_eq("found the object just created (same application)",
2✔
543
                  obj_found.get_attribute_value(AttributeType::Application),
2✔
544
                  data_obj.get_attribute_value(AttributeType::Application));
1✔
545

546
   auto search_result2 = Object::search<Object>(test_session.session(), search_template.attributes());
1✔
547
   result.test_eq("found the object just created (same label)",
3✔
548
                  obj_found.get_attribute_value(AttributeType::Label),
2✔
549
                  search_result2.at(0).get_attribute_value(AttributeType::Label));
1✔
550

551
   data_obj.destroy();
1✔
552
   return result;
1✔
553
}
3✔
554

555
Test::Result test_object_copy() {
1✔
556
   Test::Result result("Object copy");
1✔
557

558
   TestSession test_session(true);
1✔
559

560
   // create object
561
   const std::string label = "Botan test data object";
1✔
562
   auto data_obj_props = make_test_object(label);
1✔
563
   Object data_obj(test_session.session(), data_obj_props);
1✔
564

565
   // copy created object
566
   AttributeContainer copy_attributes;
1✔
567
   copy_attributes.add_string(AttributeType::Label, "Botan test copied object");
1✔
568
   ObjectHandle copied_obj_handle = data_obj.copy(copy_attributes);
1✔
569

570
   ObjectFinder searcher(test_session.session(), copy_attributes.attributes());
1✔
571
   auto search_result = searcher.find();
1✔
572
   result.test_eq("one object found", search_result.size(), 1);
1✔
573

574
   data_obj.destroy();
1✔
575

576
   Object copied_obj(test_session.session(), copied_obj_handle);
1✔
577
   copied_obj.destroy();
1✔
578
   return result;
2✔
579
}
3✔
580
   #endif
581

582
class Object_Tests final : public Test {
×
583
   public:
584
      std::vector<Test::Result> run() override {
1✔
585
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
586
            {STRING_AND_FUNCTION(test_attribute_container)}
587
   #if defined(BOTAN_HAS_ASN1)
588
            ,
589
            {STRING_AND_FUNCTION(test_create_destroy_data_object)},
590
            {STRING_AND_FUNCTION(test_get_set_attribute_values)},
591
            {STRING_AND_FUNCTION(test_object_finder)},
592
            {STRING_AND_FUNCTION(test_object_copy)}
593
   #endif
594
         };
6✔
595

596
         return run_pkcs11_tests("Object", fns);
2✔
597
      }
1✔
598
};
599

600
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-object", Object_Tests);
601

602
/***************************** PKCS11 RSA *****************************/
603

604
   #if defined(BOTAN_HAS_RSA)
605

606
Test::Result test_rsa_privkey_import() {
1✔
607
   Test::Result result("PKCS11 import RSA private key");
1✔
608

609
   TestSession test_session(true);
1✔
610

611
   // create private key
612
   RSA_PrivateKey priv_key(Test::rng(), 2048);
1✔
613
   result.confirm("Key self test OK", priv_key.check_key(Test::rng(), true));
2✔
614

615
   // import to card
616
   RSA_PrivateKeyImportProperties props(priv_key.get_n(), priv_key.get_d());
1✔
617
   props.set_pub_exponent(priv_key.get_e());
1✔
618
   props.set_prime_1(priv_key.get_p());
1✔
619
   props.set_prime_2(priv_key.get_q());
1✔
620
   props.set_coefficient(priv_key.get_c());
1✔
621
   props.set_exponent_1(priv_key.get_d1());
1✔
622
   props.set_exponent_2(priv_key.get_d2());
1✔
623

624
   props.set_token(true);
1✔
625
   props.set_private(true);
1✔
626
   props.set_decrypt(true);
1✔
627
   props.set_sign(true);
1✔
628

629
   PKCS11_RSA_PrivateKey pk(test_session.session(), props);
1✔
630
   result.test_success("RSA private key import was successful");
1✔
631
   result.confirm("PK self test OK", pk.check_key(Test::rng(), true));
2✔
632

633
   pk.destroy();
1✔
634
   return result;
1✔
635
}
1✔
636

637
Test::Result test_rsa_privkey_export() {
1✔
638
   Test::Result result("PKCS11 export RSA private key");
1✔
639

640
   TestSession test_session(true);
1✔
641

642
   // create private key
643
   RSA_PrivateKey priv_key(Test::rng(), 2048);
1✔
644

645
   // import to card
646
   RSA_PrivateKeyImportProperties props(priv_key.get_n(), priv_key.get_d());
1✔
647
   props.set_pub_exponent(priv_key.get_e());
1✔
648
   props.set_prime_1(priv_key.get_p());
1✔
649
   props.set_prime_2(priv_key.get_q());
1✔
650
   props.set_coefficient(priv_key.get_c());
1✔
651
   props.set_exponent_1(priv_key.get_d1());
1✔
652
   props.set_exponent_2(priv_key.get_d2());
1✔
653

654
   props.set_token(true);
1✔
655
   props.set_private(true);
1✔
656
   props.set_decrypt(true);
1✔
657
   props.set_sign(true);
1✔
658
   props.set_extractable(true);
1✔
659
   props.set_sensitive(false);
1✔
660

661
   PKCS11_RSA_PrivateKey pk(test_session.session(), props);
1✔
662
   result.confirm("Check PK11 key", pk.check_key(Test::rng(), true));
2✔
663

664
   RSA_PrivateKey exported = pk.export_key();
1✔
665
   result.test_success("RSA private key export was successful");
1✔
666
   result.confirm("Check exported key", exported.check_key(Test::rng(), true));
2✔
667

668
   pk.destroy();
1✔
669
   return result;
1✔
670
}
1✔
671

672
Test::Result test_rsa_pubkey_import() {
1✔
673
   Test::Result result("PKCS11 import RSA public key");
1✔
674

675
   TestSession test_session(true);
1✔
676

677
   // create public key from private key
678
   RSA_PrivateKey priv_key(Test::rng(), 2048);
1✔
679

680
   // import to card
681
   RSA_PublicKeyImportProperties props(priv_key.get_n(), priv_key.get_e());
1✔
682
   props.set_token(true);
1✔
683
   props.set_encrypt(true);
1✔
684
   props.set_private(false);
1✔
685

686
   PKCS11_RSA_PublicKey pk(test_session.session(), props);
1✔
687
   result.test_success("RSA public key import was successful");
1✔
688
   result.confirm("Check PK11 key", pk.check_key(Test::rng(), true));
2✔
689

690
   pk.destroy();
1✔
691

692
   return result;
2✔
693
}
1✔
694

695
Test::Result test_rsa_generate_private_key() {
1✔
696
   Test::Result result("PKCS11 generate RSA private key");
1✔
697
   TestSession test_session(true);
1✔
698

699
   RSA_PrivateKeyGenerationProperties props;
1✔
700
   props.set_token(true);
1✔
701
   props.set_private(true);
1✔
702
   props.set_sign(true);
1✔
703
   props.set_decrypt(true);
1✔
704

705
   PKCS11_RSA_PrivateKey pk(test_session.session(), 2048, props);
1✔
706
   result.test_success("RSA private key generation was successful");
1✔
707

708
   pk.destroy();
1✔
709

710
   return result;
1✔
711
}
1✔
712

713
PKCS11_RSA_KeyPair generate_rsa_keypair(const TestSession& test_session) {
3✔
714
   RSA_PublicKeyGenerationProperties pub_props(2048UL);
3✔
715
   pub_props.set_pub_exponent();
3✔
716
   pub_props.set_label("BOTAN_TEST_RSA_PUB_KEY");
3✔
717
   pub_props.set_token(true);
3✔
718
   pub_props.set_encrypt(true);
3✔
719
   pub_props.set_verify(true);
3✔
720
   pub_props.set_private(false);
3✔
721

722
   RSA_PrivateKeyGenerationProperties priv_props;
3✔
723
   priv_props.set_label("BOTAN_TEST_RSA_PRIV_KEY");
3✔
724
   priv_props.set_token(true);
3✔
725
   priv_props.set_private(true);
3✔
726
   priv_props.set_sign(true);
3✔
727
   priv_props.set_decrypt(true);
3✔
728

729
   return PKCS11::generate_rsa_keypair(test_session.session(), pub_props, priv_props);
3✔
730
}
3✔
731

732
Test::Result test_rsa_generate_key_pair() {
1✔
733
   Test::Result result("PKCS11 generate RSA key pair");
1✔
734
   TestSession test_session(true);
1✔
735

736
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
737
   result.test_success("RSA key pair generation was successful");
1✔
738

739
   keypair.first.destroy();
1✔
740
   keypair.second.destroy();
1✔
741

742
   return result;
1✔
743
}
1✔
744

745
Test::Result test_rsa_encrypt_decrypt() {
1✔
746
   Test::Result result("PKCS11 RSA encrypt decrypt");
1✔
747
   TestSession test_session(true);
1✔
748

749
   // generate key pair
750
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
751

752
   auto encrypt_and_decrypt =
1✔
753
      [&keypair, &result](const std::vector<uint8_t>& plaintext, const std::string& padding, const bool blinding) {
25✔
754
         std::vector<uint8_t> encrypted;
5✔
755

756
         try {
5✔
757
            Botan::PK_Encryptor_EME encryptor(keypair.first, Test::rng(), padding);
5✔
758
            encrypted = encryptor.encrypt(plaintext, Test::rng());
5✔
759
         } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
5✔
760
            result.test_failure("PKCS11 RSA encrypt " + padding, e.what());
×
761
         }
×
762

763
         Botan::secure_vector<uint8_t> decrypted;
5✔
764

765
         try {
5✔
766
            keypair.second.set_use_software_padding(blinding);
5✔
767
            Botan::PK_Decryptor_EME decryptor(keypair.second, Test::rng(), padding);
5✔
768
            decrypted = decryptor.decrypt(encrypted);
5✔
769
         } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
5✔
770
            std::ostringstream err;
×
771
            err << "PKCS11 RSA decrypt " << padding;
×
772
            if(blinding)
×
773
               err << " with userspace blinding";
×
774

775
            result.test_failure(err.str(), e.what());
×
776
         }
×
777

778
         result.test_eq("RSA PKCS11 encrypt and decrypt: " + padding, decrypted, plaintext);
10✔
779
      };
10✔
780

781
   std::vector<uint8_t> plaintext(256);
1✔
782
   std::iota(std::begin(plaintext), std::end(plaintext), static_cast<uint8_t>(0));
1✔
783
   encrypt_and_decrypt(plaintext, "Raw", false);
1✔
784

785
   plaintext = {0x00, 0x01, 0x02, 0x03, 0x04, 0x00};
1✔
786
   encrypt_and_decrypt(plaintext, "EME-PKCS1-v1_5", false);
1✔
787
   encrypt_and_decrypt(plaintext, "EME-PKCS1-v1_5", true);
1✔
788

789
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", false);
1✔
790
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", true);
1✔
791

792
   keypair.first.destroy();
1✔
793
   keypair.second.destroy();
1✔
794

795
   return result;
2✔
796
}
1✔
797

798
Test::Result test_rsa_sign_verify() {
1✔
799
   Test::Result result("PKCS11 RSA sign and verify");
1✔
800
   TestSession test_session(true);
1✔
801

802
   // generate key pair
803
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
804

805
   std::vector<uint8_t> plaintext(256);
1✔
806
   std::iota(std::begin(plaintext), std::end(plaintext), static_cast<uint8_t>(0));
1✔
807

808
   auto sign_and_verify = [&keypair, &plaintext, &result](const std::string& emsa, bool multipart) {
13✔
809
      Botan::PK_Signer signer(keypair.second, Test::rng(), emsa, Botan::Signature_Format::Standard);
5✔
810
      std::vector<uint8_t> signature;
5✔
811
      if(multipart) {
5✔
812
         signer.update(plaintext.data(), plaintext.size() / 2);
2✔
813
         signature = signer.sign_message(plaintext.data() + plaintext.size() / 2, plaintext.size() / 2, Test::rng());
4✔
814
      } else {
815
         signature = signer.sign_message(plaintext, Test::rng());
6✔
816
      }
817

818
      Botan::PK_Verifier verifier(keypair.first, emsa, Botan::Signature_Format::Standard);
5✔
819
      bool rsa_ok = false;
5✔
820
      if(multipart) {
5✔
821
         verifier.update(plaintext.data(), plaintext.size() / 2);
2✔
822
         rsa_ok = verifier.verify_message(
2✔
823
            plaintext.data() + plaintext.size() / 2, plaintext.size() / 2, signature.data(), signature.size());
2✔
824
      } else {
825
         rsa_ok = verifier.verify_message(plaintext, signature);
3✔
826
      }
827

828
      result.test_eq("RSA PKCS11 sign and verify: " + emsa, rsa_ok, true);
5✔
829
   };
10✔
830

831
   // single-part sign
832
   sign_and_verify("Raw", false);
1✔
833
   sign_and_verify("EMSA3(SHA-256)", false);
1✔
834
   sign_and_verify("EMSA4(SHA-256)", false);
1✔
835

836
   // multi-part sign
837
   sign_and_verify("EMSA3(SHA-256)", true);
1✔
838
   sign_and_verify("EMSA4(SHA-256)", true);
1✔
839

840
   keypair.first.destroy();
1✔
841
   keypair.second.destroy();
1✔
842

843
   return result;
2✔
844
}
1✔
845

846
class PKCS11_RSA_Tests final : public Test {
×
847
   public:
848
      std::vector<Test::Result> run() override {
1✔
849
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
850
            {STRING_AND_FUNCTION(test_rsa_privkey_import)},
851
            {STRING_AND_FUNCTION(test_rsa_pubkey_import)},
852
            {STRING_AND_FUNCTION(test_rsa_privkey_export)},
853
            {STRING_AND_FUNCTION(test_rsa_generate_private_key)},
854
            {STRING_AND_FUNCTION(test_rsa_generate_key_pair)},
855
            {STRING_AND_FUNCTION(test_rsa_encrypt_decrypt)},
856
            {STRING_AND_FUNCTION(test_rsa_sign_verify)}};
8✔
857

858
         return run_pkcs11_tests("PKCS11 RSA", fns);
2✔
859
      }
1✔
860
};
861

862
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rsa", PKCS11_RSA_Tests);
863
   #endif
864

865
/***************************** PKCS11 ECDSA *****************************/
866

867
   #if defined(BOTAN_HAS_ECC_GROUP) && (defined(BOTAN_HAS_ECDSA) || defined(BOTAN_HAS_ECDH))
868
std::vector<uint8_t> encode_ec_point_in_octet_str(const Botan::EC_Point& point) {
4✔
869
   std::vector<uint8_t> enc;
4✔
870
   DER_Encoder(enc).encode(point.encode(EC_Point_Format::Uncompressed), ASN1_Type::OctetString);
12✔
871
   return enc;
4✔
872
}
×
873
   #endif
874

875
   #if defined(BOTAN_HAS_ECDSA)
876

877
Test::Result test_ecdsa_privkey_import() {
1✔
878
   Test::Result result("PKCS11 import ECDSA private key");
1✔
879

880
   TestSession test_session(true);
1✔
881

882
   // create ecdsa private key
883
   ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
884
   result.confirm("Key self test OK", priv_key.check_key(Test::rng(), true));
2✔
885

886
   // import to card
887
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
888
   props.set_token(true);
1✔
889
   props.set_private(true);
1✔
890
   props.set_sign(true);
1✔
891

892
   // label
893
   std::string label = "Botan test ecdsa key";
1✔
894
   props.set_label(label);
1✔
895

896
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
1✔
897
   result.test_success("ECDSA private key import was successful");
1✔
898
   pk.set_public_point(priv_key.public_point());
1✔
899
   result.confirm("P11 key self test OK", pk.check_key(Test::rng(), false));
2✔
900

901
   pk.destroy();
1✔
902
   return result;
1✔
903
}
2✔
904

905
Test::Result test_ecdsa_privkey_export() {
1✔
906
   Test::Result result("PKCS11 export ECDSA private key");
1✔
907

908
   TestSession test_session(true);
1✔
909

910
   // create private key
911
   ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
912

913
   result.confirm("Check ECDSA key", priv_key.check_key(Test::rng(), true));
2✔
914
   // import to card
915
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
916
   props.set_token(true);
1✔
917
   props.set_private(true);
1✔
918
   props.set_sign(true);
1✔
919
   props.set_extractable(true);
1✔
920

921
   // label
922
   std::string label = "Botan test ecdsa key";
1✔
923
   props.set_label(label);
1✔
924

925
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
1✔
926
   pk.set_public_point(priv_key.public_point());
1✔
927
   result.confirm("Check PK11 key", pk.check_key(Test::rng(), false));
2✔
928

929
   ECDSA_PrivateKey exported = pk.export_key();
1✔
930
   result.test_success("ECDSA private key export was successful");
1✔
931
   result.confirm("Check exported key valid", exported.check_key(Test::rng(), true));
2✔
932
   result.test_eq("Check exported key contents", exported.private_key_bits(), priv_key.private_key_bits());
3✔
933

934
   pk.destroy();
1✔
935
   return result;
1✔
936
}
2✔
937

938
Test::Result test_ecdsa_pubkey_import() {
1✔
939
   Test::Result result("PKCS11 import ECDSA public key");
1✔
940

941
   TestSession test_session(true);
1✔
942

943
   // create ecdsa private key
944
   ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
945

946
   const auto enc_point = encode_ec_point_in_octet_str(priv_key.public_point());
1✔
947

948
   // import to card
949
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
950
   props.set_token(true);
1✔
951
   props.set_verify(true);
1✔
952
   props.set_private(false);
1✔
953

954
   // label
955
   std::string label = "Botan test ecdsa pub key";
1✔
956
   props.set_label(label);
1✔
957

958
   PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
959
   result.test_success("ECDSA public key import was successful");
1✔
960

961
   pk.destroy();
1✔
962
   return result;
1✔
963
}
3✔
964

965
Test::Result test_ecdsa_pubkey_export() {
1✔
966
   Test::Result result("PKCS11 export ECDSA public key");
1✔
967

968
   TestSession test_session(true);
1✔
969

970
   // create public key from private key
971
   ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
972

973
   const auto enc_point = encode_ec_point_in_octet_str(priv_key.public_point());
1✔
974

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

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

985
   PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
986

987
   ECDSA_PublicKey exported = pk.export_key();
1✔
988
   result.test_success("ECDSA public key export was successful");
1✔
989

990
   pk.destroy();
1✔
991

992
   return result;
2✔
993
}
3✔
994

995
Test::Result test_ecdsa_generate_private_key() {
1✔
996
   Test::Result result("PKCS11 generate ECDSA private key");
1✔
997
   TestSession test_session(true);
1✔
998

999
   EC_PrivateKeyGenerationProperties props;
1✔
1000
   props.set_token(true);
1✔
1001
   props.set_private(true);
1✔
1002
   props.set_sign(true);
1✔
1003

1004
   PKCS11_ECDSA_PrivateKey pk(
1✔
1005
      test_session.session(), EC_Group("secp256r1").DER_encode(EC_Group_Encoding::NamedCurve), props);
2✔
1006
   result.test_success("ECDSA private key generation was successful");
1✔
1007

1008
   pk.destroy();
1✔
1009

1010
   return result;
1✔
1011
}
1✔
1012

1013
PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(const TestSession& test_session,
6✔
1014
                                            const std::string& curve,
1015
                                            EC_Group_Encoding ec_dompar_enc) {
1016
   EC_PublicKeyGenerationProperties pub_props(EC_Group(curve).DER_encode(ec_dompar_enc));
12✔
1017
   pub_props.set_label("BOTAN_TEST_ECDSA_PUB_KEY");
6✔
1018
   pub_props.set_token(true);
6✔
1019
   pub_props.set_verify(true);
6✔
1020
   pub_props.set_private(false);
6✔
1021
   pub_props.set_modifiable(true);
6✔
1022

1023
   EC_PrivateKeyGenerationProperties priv_props;
6✔
1024
   priv_props.set_label("BOTAN_TEST_ECDSA_PRIV_KEY");
6✔
1025
   priv_props.set_token(true);
6✔
1026
   priv_props.set_private(true);
6✔
1027
   priv_props.set_sensitive(true);
6✔
1028
   priv_props.set_extractable(false);
6✔
1029
   priv_props.set_sign(true);
6✔
1030
   priv_props.set_modifiable(true);
6✔
1031

1032
   return PKCS11::generate_ecdsa_keypair(test_session.session(), pub_props, priv_props);
12✔
1033
}
6✔
1034

1035
Test::Result test_ecdsa_generate_keypair() {
1✔
1036
   Test::Result result("PKCS11 generate ECDSA key pair");
1✔
1037
   TestSession test_session(true);
1✔
1038
   std::vector<std::string> curves;
1✔
1039

1040
   curves.push_back("secp256r1");
2✔
1041
   curves.push_back("brainpool512r1");
2✔
1042

1043
   for(auto& curve : curves) {
3✔
1044
      PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session, curve, EC_Group_Encoding::NamedCurve);
2✔
1045

1046
      keypair.first.destroy();
2✔
1047
      keypair.second.destroy();
2✔
1048
   }
2✔
1049
   result.test_success("ECDSA key pair generation was successful");
1✔
1050

1051
   return result;
1✔
1052
}
1✔
1053

1054
Test::Result test_ecdsa_sign_verify_core(EC_Group_Encoding ec_dompar_enc, const std::string& test_name) {
2✔
1055
   Test::Result result(test_name);
2✔
1056
   TestSession test_session(true);
2✔
1057
   std::vector<std::string> curves;
2✔
1058

1059
   curves.push_back("secp256r1");
4✔
1060
   curves.push_back("brainpool512r1");
4✔
1061

1062
   Slot& slot = test_session.slot();
2✔
1063
   SlotInfo info = slot.get_slot_info();
2✔
1064
   std::string manufacturer(reinterpret_cast<char*>(info.manufacturerID));
2✔
1065

1066
   for(auto& curve : curves) {
6✔
1067
      // generate key pair
1068
      PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session, curve, ec_dompar_enc);
4✔
1069

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

1072
      auto sign_and_verify = [&keypair, &plaintext, &result](
8✔
1073
                                const std::string& emsa, const Botan::Signature_Format format, bool check_soft) {
12✔
1074
         Botan::PK_Signer signer(keypair.second, Test::rng(), emsa, format);
4✔
1075
         auto signature = signer.sign_message(plaintext, Test::rng());
4✔
1076

1077
         Botan::PK_Verifier token_verifier(keypair.first, emsa, format);
4✔
1078
         bool ecdsa_ok = token_verifier.verify_message(plaintext, signature);
4✔
1079

1080
         result.test_eq("ECDSA PKCS11 sign and verify: " + emsa, ecdsa_ok, true);
4✔
1081

1082
         // test against software implementation if available
1083
         if(check_soft) {
4✔
1084
            Botan::PK_Verifier soft_verifier(keypair.first, emsa, format);
4✔
1085
            bool soft_ecdsa_ok = soft_verifier.verify_message(plaintext, signature);
4✔
1086

1087
            result.test_eq("ECDSA PKCS11 verify (in software): " + emsa, soft_ecdsa_ok, true);
4✔
1088
         }
4✔
1089
      };
8✔
1090

1091
      // SoftHSMv2 until now only supports "Raw"
1092
      if(manufacturer.find("SoftHSM project") == std::string::npos) {
4✔
1093
         sign_and_verify("SHA-256", Botan::Signature_Format::Standard, true);
×
1094
         sign_and_verify("SHA-256", Botan::Signature_Format::DerSequence, true);
×
1095
      }
1096

1097
      #if defined(BOTAN_HAS_EMSA_RAW)
1098
      sign_and_verify("Raw", Botan::Signature_Format::Standard, true);
4✔
1099
      #else
1100
      sign_and_verify("Raw", Botan::Signature_Format::Standard, false);
1101
      #endif
1102

1103
      keypair.first.destroy();
4✔
1104
      keypair.second.destroy();
4✔
1105
   }
8✔
1106

1107
   return result;
4✔
1108
}
2✔
1109

1110
Test::Result test_ecdsa_sign_verify() {
1✔
1111
   // pass the curve OID to the PKCS#11 library
1112
   return test_ecdsa_sign_verify_core(EC_Group_Encoding::NamedCurve, "PKCS11 ECDSA sign and verify");
2✔
1113
}
1114

1115
Test::Result test_ecdsa_curve_import() {
1✔
1116
   // pass the curve parameters to the PKCS#11 library and perform sign/verify to test them
1117
   return test_ecdsa_sign_verify_core(EC_Group_Encoding::Explicit, "PKCS11 ECDSA sign and verify with imported curve");
2✔
1118
}
1119

1120
class PKCS11_ECDSA_Tests final : public Test {
×
1121
   public:
1122
      std::vector<Test::Result> run() override {
1✔
1123
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1124
            {STRING_AND_FUNCTION(test_ecdsa_privkey_import)},
1125
            {STRING_AND_FUNCTION(test_ecdsa_privkey_export)},
1126
            {STRING_AND_FUNCTION(test_ecdsa_pubkey_import)},
1127
            {STRING_AND_FUNCTION(test_ecdsa_pubkey_export)},
1128
            {STRING_AND_FUNCTION(test_ecdsa_generate_private_key)},
1129
            {STRING_AND_FUNCTION(test_ecdsa_generate_keypair)},
1130
            {STRING_AND_FUNCTION(test_ecdsa_sign_verify)},
1131
            {STRING_AND_FUNCTION(test_ecdsa_curve_import)}};
9✔
1132

1133
         return run_pkcs11_tests("PKCS11 ECDSA", fns);
2✔
1134
      }
1✔
1135
};
1136

1137
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdsa", PKCS11_ECDSA_Tests);
1138

1139
   #endif
1140

1141
   #if defined(BOTAN_HAS_ECDH)
1142

1143
/***************************** PKCS11 ECDH *****************************/
1144

1145
Test::Result test_ecdh_privkey_import() {
1✔
1146
   Test::Result result("PKCS11 import ECDH private key");
1✔
1147

1148
   TestSession test_session(true);
1✔
1149

1150
   // create ecdh private key
1151
   ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
1152

1153
   // import to card
1154
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
1155
   props.set_token(true);
1✔
1156
   props.set_private(true);
1✔
1157
   props.set_derive(true);
1✔
1158

1159
   // label
1160
   std::string label = "Botan test ecdh key";
1✔
1161
   props.set_label(label);
1✔
1162

1163
   PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1164
   result.test_success("ECDH private key import was successful");
1✔
1165

1166
   pk.destroy();
1✔
1167
   return result;
1✔
1168
}
2✔
1169

1170
Test::Result test_ecdh_privkey_export() {
1✔
1171
   Test::Result result("PKCS11 export ECDH private key");
1✔
1172

1173
   TestSession test_session(true);
1✔
1174

1175
   // create private key
1176
   ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
1177

1178
   // import to card
1179
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
1180
   props.set_token(true);
1✔
1181
   props.set_private(true);
1✔
1182
   props.set_derive(true);
1✔
1183
   props.set_extractable(true);
1✔
1184

1185
   // label
1186
   std::string label = "Botan test ecdh key";
1✔
1187
   props.set_label(label);
1✔
1188

1189
   PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1190

1191
   ECDH_PrivateKey exported = pk.export_key();
1✔
1192
   result.test_success("ECDH private key export was successful");
1✔
1193

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

1198
Test::Result test_ecdh_pubkey_import() {
1✔
1199
   Test::Result result("PKCS11 import ECDH public key");
1✔
1200

1201
   TestSession test_session(true);
1✔
1202

1203
   // create ECDH private key
1204
   ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
1205

1206
   const auto enc_point = encode_ec_point_in_octet_str(priv_key.public_point());
1✔
1207

1208
   // import to card
1209
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
1210
   props.set_token(true);
1✔
1211
   props.set_private(false);
1✔
1212
   props.set_derive(true);
1✔
1213

1214
   // label
1215
   std::string label = "Botan test ECDH pub key";
1✔
1216
   props.set_label(label);
1✔
1217

1218
   PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1219
   result.test_success("ECDH public key import was successful");
1✔
1220

1221
   pk.destroy();
1✔
1222
   return result;
2✔
1223
}
3✔
1224

1225
Test::Result test_ecdh_pubkey_export() {
1✔
1226
   Test::Result result("PKCS11 export ECDH public key");
1✔
1227

1228
   TestSession test_session(true);
1✔
1229

1230
   // create public key from private key
1231
   ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
1232

1233
   const auto enc_point = encode_ec_point_in_octet_str(priv_key.public_point());
1✔
1234

1235
   // import to card
1236
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
1237
   props.set_token(true);
1✔
1238
   props.set_derive(true);
1✔
1239
   props.set_private(false);
1✔
1240

1241
   // label
1242
   std::string label = "Botan test ECDH pub key";
1✔
1243
   props.set_label(label);
1✔
1244

1245
   PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1246

1247
   ECDH_PublicKey exported = pk.export_key();
1✔
1248
   result.test_success("ECDH public key export was successful");
1✔
1249

1250
   pk.destroy();
1✔
1251

1252
   return result;
2✔
1253
}
3✔
1254

1255
Test::Result test_ecdh_generate_private_key() {
1✔
1256
   Test::Result result("PKCS11 generate ECDH private key");
1✔
1257
   TestSession test_session(true);
1✔
1258

1259
   EC_PrivateKeyGenerationProperties props;
1✔
1260
   props.set_token(true);
1✔
1261
   props.set_private(true);
1✔
1262
   props.set_derive(true);
1✔
1263

1264
   PKCS11_ECDH_PrivateKey pk(
1✔
1265
      test_session.session(), EC_Group("secp256r1").DER_encode(EC_Group_Encoding::NamedCurve), props);
2✔
1266
   result.test_success("ECDH private key generation was successful");
1✔
1267

1268
   pk.destroy();
1✔
1269

1270
   return result;
1✔
1271
}
1✔
1272

1273
PKCS11_ECDH_KeyPair generate_ecdh_keypair(const TestSession& test_session, const std::string& label) {
3✔
1274
   EC_PublicKeyGenerationProperties pub_props(EC_Group("secp256r1").DER_encode(EC_Group_Encoding::NamedCurve));
6✔
1275
   pub_props.set_label(label + "_PUB_KEY");
3✔
1276
   pub_props.set_token(true);
3✔
1277
   pub_props.set_derive(true);
3✔
1278
   pub_props.set_private(false);
3✔
1279
   pub_props.set_modifiable(true);
3✔
1280

1281
   EC_PrivateKeyGenerationProperties priv_props;
3✔
1282
   priv_props.set_label(label + "_PRIV_KEY");
3✔
1283
   priv_props.set_token(true);
3✔
1284
   priv_props.set_private(true);
3✔
1285
   priv_props.set_sensitive(true);
3✔
1286
   priv_props.set_extractable(false);
3✔
1287
   priv_props.set_derive(true);
3✔
1288
   priv_props.set_modifiable(true);
3✔
1289

1290
   return PKCS11::generate_ecdh_keypair(test_session.session(), pub_props, priv_props);
6✔
1291
}
3✔
1292

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

1297
   PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
1✔
1298
   result.test_success("ECDH key pair generation was successful");
1✔
1299

1300
   keypair.first.destroy();
1✔
1301
   keypair.second.destroy();
1✔
1302

1303
   return result;
2✔
1304
}
1✔
1305

1306
Test::Result test_ecdh_derive() {
1✔
1307
   Test::Result result("PKCS11 ECDH derive");
1✔
1308
   TestSession test_session(true);
1✔
1309

1310
   PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
1✔
1311
   PKCS11_ECDH_KeyPair keypair2 = generate_ecdh_keypair(test_session, "Botan test ECDH key2");
1✔
1312

1313
   // SoftHSMv2 only supports CKD_NULL KDF at the moment
1314
   Botan::PK_Key_Agreement ka(keypair.second, Test::rng(), "Raw");
1✔
1315
   Botan::PK_Key_Agreement kb(keypair2.second, Test::rng(), "Raw");
1✔
1316

1317
   Botan::SymmetricKey alice_key =
1✔
1318
      ka.derive_key(32, keypair2.first.public_point().encode(EC_Point_Format::Uncompressed));
1✔
1319
   Botan::SymmetricKey bob_key = kb.derive_key(32, keypair.first.public_point().encode(EC_Point_Format::Uncompressed));
1✔
1320

1321
   bool eq = alice_key == bob_key;
1✔
1322
   result.test_eq("same secret key derived", eq, true);
1✔
1323

1324
   keypair.first.destroy();
1✔
1325
   keypair.second.destroy();
1✔
1326
   keypair2.first.destroy();
1✔
1327
   keypair2.second.destroy();
1✔
1328

1329
   return result;
2✔
1330
}
4✔
1331

1332
class PKCS11_ECDH_Tests final : public Test {
×
1333
   public:
1334
      std::vector<Test::Result> run() override {
1✔
1335
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1336
            {STRING_AND_FUNCTION(test_ecdh_privkey_import)},
1337
            {STRING_AND_FUNCTION(test_ecdh_privkey_export)},
1338
            {STRING_AND_FUNCTION(test_ecdh_pubkey_import)},
1339
            {STRING_AND_FUNCTION(test_ecdh_pubkey_export)},
1340
            {STRING_AND_FUNCTION(test_ecdh_generate_private_key)},
1341
            {STRING_AND_FUNCTION(test_ecdh_generate_keypair)},
1342
            {STRING_AND_FUNCTION(test_ecdh_derive)}};
8✔
1343

1344
         return run_pkcs11_tests("PKCS11 ECDH", fns);
2✔
1345
      }
1✔
1346
};
1347

1348
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdh", PKCS11_ECDH_Tests);
1349

1350
   #endif
1351

1352
/***************************** PKCS11 RNG *****************************/
1353

1354
Test::Result test_rng_generate_random() {
1✔
1355
   Test::Result result("PKCS11 RNG generate random");
1✔
1356
   TestSession test_session(true);
1✔
1357

1358
   PKCS11_RNG rng(test_session.session());
1✔
1359
   result.confirm("RNG already seeded", rng.is_seeded());
2✔
1360

1361
   std::vector<uint8_t> random(20);
1✔
1362
   rng.randomize(random.data(), random.size());
1✔
1363
   result.test_ne("random data generated", random, std::vector<uint8_t>(20));
3✔
1364

1365
   return result;
2✔
1366
}
1✔
1367

1368
Test::Result test_rng_add_entropy() {
1✔
1369
   Test::Result result("PKCS11 RNG add entropy random");
1✔
1370
   TestSession test_session(true);
1✔
1371

1372
   PKCS11_RNG rng(test_session.session());
1✔
1373

1374
   result.confirm("RNG already seeded", rng.is_seeded());
2✔
1375
   rng.clear();
1✔
1376
   result.confirm("RNG ignores call to clear", rng.is_seeded());
2✔
1377

1378
   result.test_eq("RNG ignores calls to reseed",
1✔
1379
                  rng.reseed(Botan::Entropy_Sources::global_sources(), 256, std::chrono::milliseconds(300)),
1✔
1380
                  0);
1381

1382
   auto random = Test::rng().random_vec(20);
1✔
1383
   rng.add_entropy(random.data(), random.size());
1✔
1384
   result.test_success("entropy added");
1✔
1385

1386
   return result;
2✔
1387
}
1✔
1388

1389
   #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
1390

1391
Test::Result test_pkcs11_hmac_drbg() {
1✔
1392
   Test::Result result("PKCS11 HMAC_DRBG using PKCS11_RNG");
1✔
1393
   TestSession test_session(true);
1✔
1394

1395
   PKCS11_RNG p11_rng(test_session.session());
1✔
1396
   HMAC_DRBG drbg(MessageAuthenticationCode::create("HMAC(SHA-512)"), p11_rng);
1✔
1397
   // result.test_success("HMAC_DRBG(HMAC(SHA512)) instantiated with PKCS11_RNG");
1398

1399
   result.test_eq("HMAC_DRBG is not seeded yet.", drbg.is_seeded(), false);
1✔
1400
   secure_vector<uint8_t> rnd = drbg.random_vec(64);
1✔
1401
   result.test_eq("HMAC_DRBG is seeded now", drbg.is_seeded(), true);
1✔
1402

1403
   std::string personalization_string = "Botan PKCS#11 Tests";
1✔
1404
   std::vector<uint8_t> personalization_data(personalization_string.begin(), personalization_string.end());
1✔
1405
   drbg.add_entropy(personalization_data.data(), personalization_data.size());
1✔
1406

1407
   auto rnd_vec = drbg.random_vec(256);
1✔
1408
   result.test_ne("HMAC_DRBG generated a random vector", rnd_vec, std::vector<uint8_t>(256));
3✔
1409

1410
   return result;
2✔
1411
}
4✔
1412
   #endif
1413

1414
class PKCS11_RNG_Tests final : public Test {
×
1415
   public:
1416
      std::vector<Test::Result> run() override {
1✔
1417
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1418
   #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
1419
            {STRING_AND_FUNCTION(test_pkcs11_hmac_drbg)},
1420
   #endif
1421
            {STRING_AND_FUNCTION(test_rng_generate_random)},
1422
            {STRING_AND_FUNCTION(test_rng_add_entropy)}
1423
         };
4✔
1424

1425
         return run_pkcs11_tests("PKCS11 RNG", fns);
2✔
1426
      }
1✔
1427
};
1428

1429
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rng", PKCS11_RNG_Tests);
1430

1431
/***************************** PKCS11 token management *****************************/
1432

1433
Test::Result test_set_pin() {
1✔
1434
   Test::Result result("PKCS11 set pin");
1✔
1435

1436
   Module module(Test::pkcs11_lib());
1✔
1437
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
1438
   Slot slot(module, slot_vec.at(0));
1✔
1439

1440
   PKCS11::set_pin(slot, SO_PIN(), TEST_PIN());
3✔
1441
   result.test_success("PIN set with SO_PIN to TEST_PIN");
1✔
1442

1443
   PKCS11::set_pin(slot, SO_PIN(), PIN());
3✔
1444
   result.test_success("PIN changed back with SO_PIN");
1✔
1445

1446
   return result;
2✔
1447
}
1✔
1448

1449
Test::Result test_initialize() {
1✔
1450
   Test::Result result("PKCS11 initialize token");
1✔
1451

1452
   Module module(Test::pkcs11_lib());
1✔
1453
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
1454
   Slot slot(module, slot_vec.at(0));
1✔
1455

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

1459
   return result;
2✔
1460
}
1✔
1461

1462
Test::Result test_change_pin() {
1✔
1463
   Test::Result result("PKCS11 change pin");
1✔
1464

1465
   Module module(Test::pkcs11_lib());
1✔
1466
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
1467
   Slot slot(module, slot_vec.at(0));
1✔
1468

1469
   PKCS11::change_pin(slot, PIN(), TEST_PIN());
3✔
1470
   result.test_success("PIN changed with PIN to TEST_PIN");
1✔
1471

1472
   PKCS11::change_pin(slot, TEST_PIN(), PIN());
3✔
1473
   result.test_success("PIN changed back with TEST_PIN to PIN");
1✔
1474

1475
   return result;
2✔
1476
}
1✔
1477

1478
Test::Result test_change_so_pin() {
1✔
1479
   Test::Result result("PKCS11 change so_pin");
1✔
1480

1481
   Module module(Test::pkcs11_lib());
1✔
1482
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
1483
   Slot slot(module, slot_vec.at(0));
1✔
1484

1485
   PKCS11::change_so_pin(slot, SO_PIN(), TEST_SO_PIN());
3✔
1486
   result.test_success("SO_PIN changed with SO_PIN to TEST_SO_PIN");
1✔
1487

1488
   PKCS11::change_so_pin(slot, TEST_SO_PIN(), SO_PIN());
3✔
1489
   result.test_success("SO_PIN changed back with TEST_SO_PIN to SO_PIN");
1✔
1490

1491
   return result;
2✔
1492
}
1✔
1493

1494
class PKCS11_Token_Management_Tests final : public Test {
×
1495
   public:
1496
      std::vector<Test::Result> run() override {
1✔
1497
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1498
            {STRING_AND_FUNCTION(test_set_pin)},
1499
            {STRING_AND_FUNCTION(test_initialize)},
1500
            {STRING_AND_FUNCTION(test_change_pin)},
1501
            {STRING_AND_FUNCTION(test_change_so_pin)}};
5✔
1502

1503
         return run_pkcs11_tests("PKCS11 token management", fns);
2✔
1504
      }
1✔
1505
};
1506

1507
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-manage", PKCS11_Token_Management_Tests);
1508

1509
/***************************** PKCS11 token management *****************************/
1510

1511
   #if defined(BOTAN_HAS_X509_CERTIFICATES)
1512

1513
Test::Result test_x509_import() {
1✔
1514
   Test::Result result("PKCS11 X509 cert import");
1✔
1515

1516
      #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1517
   TestSession test_session(true);
1✔
1518

1519
   X509_Certificate root(Test::data_file("x509/nist/test01/end.crt"));
2✔
1520
   X509_CertificateProperties props(root);
1✔
1521
   props.set_label("Botan PKCS#11 test certificate");
1✔
1522
   props.set_private(false);
1✔
1523
   props.set_token(true);
1✔
1524

1525
   PKCS11_X509_Certificate pkcs11_cert(test_session.session(), props);
1✔
1526
   result.test_success("X509 certificate imported");
1✔
1527

1528
   PKCS11_X509_Certificate pkcs11_cert2(test_session.session(), pkcs11_cert.handle());
1✔
1529
   result.test_eq("X509 certificate by handle", pkcs11_cert == pkcs11_cert2, true);
1✔
1530

1531
   pkcs11_cert.destroy();
1✔
1532
      #endif
1533

1534
   return result;
2✔
1535
}
1✔
1536

1537
class PKCS11_X509_Tests final : public Test {
×
1538
   public:
1539
      std::vector<Test::Result> run() override {
1✔
1540
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1541
            {STRING_AND_FUNCTION(test_x509_import)}};
2✔
1542

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

1547
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-x509", PKCS11_X509_Tests);
1548

1549
   #endif
1550

1551
}
1552

1553
#endif
1554

1555
}
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

© 2025 Coveralls, Inc