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

randombit / botan / 5134090420

31 May 2023 03:12PM UTC coverage: 91.721% (-0.3%) from 91.995%
5134090420

push

github

randombit
Merge GH #3565 Disable noisy/pointless pylint warnings

76048 of 82912 relevant lines covered (91.72%)

11755290.1 hits per line

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

96.83
/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) {
×
79
         results.push_back(Test::Result::Failure(name + " test " + fns[i].first, e.what()));
×
80
      }
×
81
   }
82

83
   return results;
11✔
84
}
×
85

86
namespace {
87

88
using namespace Botan;
89
using namespace PKCS11;
90

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

102
      inline Session& session() const { return *m_session; }
6✔
103

104
      inline Slot& slot() const { return *m_slot; }
2✔
105

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

112
/***************************** Module *****************************/
113

114
Test::Result test_module_ctor() {
1✔
115
   Test::Result result("Module ctor");
1✔
116

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

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

122
   return result;
1✔
123
}
1✔
124

125
Test::Result test_module_reload() {
1✔
126
   Test::Result result("Module reload");
1✔
127

128
   Module module(Test::pkcs11_lib());
1✔
129

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

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

136
   return result;
1✔
137
}
1✔
138

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

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

146
   return result;
1✔
147
}
1✔
148

149
Test::Result test_module_get_info() {
1✔
150
   Test::Result result("Module info");
1✔
151

152
   Module module(Test::pkcs11_lib());
1✔
153

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

157
   return result;
1✔
158
}
1✔
159

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

169
         return run_pkcs11_tests("Module", fns);
2✔
170
      }
1✔
171
};
172

173
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-module", Module_Tests);
174

175
/***************************** Slot *****************************/
176

177
Test::Result test_slot_get_available_slots() {
1✔
178
   Test::Result result("Slot get_available_slots");
1✔
179

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

184
   return result;
2✔
185
}
1✔
186

187
Test::Result test_slot_ctor() {
1✔
188
   Test::Result result("Slot ctor");
1✔
189

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

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

197
   return result;
2✔
198
}
1✔
199

200
Test::Result test_get_slot_info() {
1✔
201
   Test::Result result("Slot get_slot_info");
1✔
202

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

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

211
   return result;
2✔
212
}
2✔
213

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

217
   SlotId invalid_id = 0;
2✔
218

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

224
   return invalid_id;
2✔
225
}
2✔
226

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

230
   Module module(Test::pkcs11_lib());
1✔
231

232
   SlotId invalid_id = get_invalid_slot_id(module);
1✔
233

234
   Slot slot(module, invalid_id);
1✔
235

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

238
   return result;
1✔
239
}
1✔
240

241
Test::Result test_get_token_info() {
1✔
242
   Test::Result result("Slot get_token_info");
1✔
243

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

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

252
   return result;
2✔
253
}
2✔
254

255
Test::Result test_get_mechanism_list() {
1✔
256
   Test::Result result("Slot get_mechanism_list");
1✔
257

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

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

265
   return result;
2✔
266
}
2✔
267

268
Test::Result test_get_mechanisms_info() {
1✔
269
   Test::Result result("Slot get_mechanism_info");
1✔
270

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

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

278
   return result;
2✔
279
}
1✔
280

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

293
         return run_pkcs11_tests("Slot", fns);
2✔
294
      }
1✔
295
};
296

297
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-slot", Slot_Tests);
298

299
/***************************** Session *****************************/
300

301
Test::Result test_session_ctor() {
1✔
302
   Test::Result result("Session ctor");
1✔
303

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

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

327
   return result;
2✔
328
}
1✔
329

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

333
   Module module(Test::pkcs11_lib());
1✔
334

335
   SlotId invalid_id = get_invalid_slot_id(module);
1✔
336
   Slot slot(module, invalid_id);
1✔
337

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

340
   return result;
1✔
341
}
1✔
342

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

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

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

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

356
   return result;
1✔
357
}
2✔
358

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

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

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

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

374
   return result;
1✔
375
}
2✔
376

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

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

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

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

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

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

401
   return result;
1✔
402
}
2✔
403

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

414
         return run_pkcs11_tests("Session", fns);
2✔
415
      }
1✔
416
};
417

418
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-session", Session_Tests);
419

420
/***************************** Object *****************************/
421

422
Test::Result test_attribute_container() {
1✔
423
   Test::Result result("AttributeContainer");
1✔
424

425
   AttributeContainer attributes;
1✔
426
   attributes.add_class(ObjectClass::PrivateKey);
1✔
427

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

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

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

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

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

454
   return result;
2✔
455
}
1✔
456

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

461
   std::size_t id = 1337;
4✔
462
   std::string application = "Botan test application";
4✔
463

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

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

475
   return data_obj_props;
4✔
476
}
12✔
477

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

482
   TestSession test_session(true);
1✔
483

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

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

492
   return result;
2✔
493
}
2✔
494

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

498
   TestSession test_session(true);
1✔
499

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

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

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

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

520
   data_obj.destroy();
1✔
521
   return result;
2✔
522
}
5✔
523

524
Test::Result test_object_finder() {
1✔
525
   Test::Result result("ObjectFinder");
1✔
526

527
   TestSession test_session(true);
1✔
528

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

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

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

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

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

553
   data_obj.destroy();
1✔
554
   return result;
1✔
555
}
3✔
556

557
Test::Result test_object_copy() {
1✔
558
   Test::Result result("Object copy");
1✔
559

560
   TestSession test_session(true);
1✔
561

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

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

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

576
   data_obj.destroy();
1✔
577

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

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

598
         return run_pkcs11_tests("Object", fns);
2✔
599
      }
1✔
600
};
601

602
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-object", Object_Tests);
603

604
/***************************** PKCS11 RSA *****************************/
605

606
   #if defined(BOTAN_HAS_RSA)
607

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

611
   TestSession test_session(true);
1✔
612

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

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

626
   props.set_token(true);
1✔
627
   props.set_private(true);
1✔
628
   props.set_decrypt(true);
1✔
629
   props.set_sign(true);
1✔
630

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

635
   pk.destroy();
1✔
636
   return result;
1✔
637
}
1✔
638

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

642
   TestSession test_session(true);
1✔
643

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

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

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

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

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

670
   pk.destroy();
1✔
671
   return result;
1✔
672
}
1✔
673

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

677
   TestSession test_session(true);
1✔
678

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

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

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

692
   pk.destroy();
1✔
693

694
   return result;
2✔
695
}
1✔
696

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

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

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

710
   pk.destroy();
1✔
711

712
   return result;
1✔
713
}
1✔
714

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

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

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

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

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

741
   keypair.first.destroy();
1✔
742
   keypair.second.destroy();
1✔
743

744
   return result;
1✔
745
}
1✔
746

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

751
   // generate key pair
752
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
753

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

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

765
         Botan::secure_vector<uint8_t> decrypted;
5✔
766

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

778
            result.test_failure(err.str(), e.what());
×
779
         }
×
780

781
         result.test_eq("RSA PKCS11 encrypt and decrypt: " + padding, decrypted, plaintext);
10✔
782
      };
10✔
783

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

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

792
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", false);
1✔
793
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", true);
1✔
794

795
   keypair.first.destroy();
1✔
796
   keypair.second.destroy();
1✔
797

798
   return result;
2✔
799
}
1✔
800

801
Test::Result test_rsa_sign_verify() {
1✔
802
   Test::Result result("PKCS11 RSA sign and verify");
1✔
803
   TestSession test_session(true);
1✔
804

805
   // generate key pair
806
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
807

808
   std::vector<uint8_t> plaintext(256);
1✔
809
   std::iota(std::begin(plaintext), std::end(plaintext), static_cast<uint8_t>(0));
1✔
810

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

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

831
      result.test_eq("RSA PKCS11 sign and verify: " + emsa, rsa_ok, true);
5✔
832
   };
10✔
833

834
   // single-part sign
835
   sign_and_verify("Raw", false);
1✔
836
   sign_and_verify("EMSA3(SHA-256)", false);
1✔
837
   sign_and_verify("EMSA4(SHA-256)", false);
1✔
838

839
   // multi-part sign
840
   sign_and_verify("EMSA3(SHA-256)", true);
1✔
841
   sign_and_verify("EMSA4(SHA-256)", true);
1✔
842

843
   keypair.first.destroy();
1✔
844
   keypair.second.destroy();
1✔
845

846
   return result;
2✔
847
}
1✔
848

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

861
         return run_pkcs11_tests("PKCS11 RSA", fns);
2✔
862
      }
1✔
863
};
864

865
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rsa", PKCS11_RSA_Tests);
866
   #endif
867

868
/***************************** PKCS11 ECDSA *****************************/
869

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

878
   #if defined(BOTAN_HAS_ECDSA)
879

880
Test::Result test_ecdsa_privkey_import() {
1✔
881
   Test::Result result("PKCS11 import ECDSA private key");
1✔
882

883
   TestSession test_session(true);
1✔
884

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

889
   // import to card
890
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
891
   props.set_token(true);
1✔
892
   props.set_private(true);
1✔
893
   props.set_sign(true);
1✔
894

895
   // label
896
   std::string label = "Botan test ecdsa key";
1✔
897
   props.set_label(label);
1✔
898

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

904
   pk.destroy();
1✔
905
   return result;
1✔
906
}
2✔
907

908
Test::Result test_ecdsa_privkey_export() {
1✔
909
   Test::Result result("PKCS11 export ECDSA private key");
1✔
910

911
   TestSession test_session(true);
1✔
912

913
   // create private key
914
   ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
915

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

924
   // label
925
   std::string label = "Botan test ecdsa key";
1✔
926
   props.set_label(label);
1✔
927

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

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

937
   pk.destroy();
1✔
938
   return result;
1✔
939
}
2✔
940

941
Test::Result test_ecdsa_pubkey_import() {
1✔
942
   Test::Result result("PKCS11 import ECDSA public key");
1✔
943

944
   TestSession test_session(true);
1✔
945

946
   // create ecdsa private key
947
   ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
948

949
   const auto enc_point = encode_ec_point_in_octet_str(priv_key.public_point());
1✔
950

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

957
   // label
958
   std::string label = "Botan test ecdsa pub key";
1✔
959
   props.set_label(label);
1✔
960

961
   PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
962
   result.test_success("ECDSA public key import was successful");
1✔
963

964
   pk.destroy();
1✔
965
   return result;
1✔
966
}
3✔
967

968
Test::Result test_ecdsa_pubkey_export() {
1✔
969
   Test::Result result("PKCS11 export ECDSA public key");
1✔
970

971
   TestSession test_session(true);
1✔
972

973
   // create public key from private key
974
   ECDSA_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
975

976
   const auto enc_point = encode_ec_point_in_octet_str(priv_key.public_point());
1✔
977

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

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

988
   PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
989

990
   ECDSA_PublicKey exported = pk.export_key();
1✔
991
   result.test_success("ECDSA public key export was successful");
1✔
992

993
   pk.destroy();
1✔
994

995
   return result;
2✔
996
}
3✔
997

998
Test::Result test_ecdsa_generate_private_key() {
1✔
999
   Test::Result result("PKCS11 generate ECDSA private key");
1✔
1000
   TestSession test_session(true);
1✔
1001

1002
   EC_PrivateKeyGenerationProperties props;
1✔
1003
   props.set_token(true);
1✔
1004
   props.set_private(true);
1✔
1005
   props.set_sign(true);
1✔
1006

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

1011
   pk.destroy();
1✔
1012

1013
   return result;
1✔
1014
}
1✔
1015

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

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

1035
   return PKCS11::generate_ecdsa_keypair(test_session.session(), pub_props, priv_props);
12✔
1036
}
6✔
1037

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

1043
   curves.push_back("secp256r1");
2✔
1044
   curves.push_back("brainpool512r1");
2✔
1045

1046
   for(auto& curve : curves) {
3✔
1047
      PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session, curve, EC_Group_Encoding::NamedCurve);
2✔
1048

1049
      keypair.first.destroy();
2✔
1050
      keypair.second.destroy();
2✔
1051
   }
2✔
1052
   result.test_success("ECDSA key pair generation was successful");
1✔
1053

1054
   return result;
1✔
1055
}
1✔
1056

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

1062
   curves.push_back("secp256r1");
4✔
1063
   curves.push_back("brainpool512r1");
4✔
1064

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

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

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

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

1080
         Botan::PK_Verifier token_verifier(keypair.first, emsa, format);
4✔
1081
         bool ecdsa_ok = token_verifier.verify_message(plaintext, signature);
4✔
1082

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

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

1090
            result.test_eq("ECDSA PKCS11 verify (in software): " + emsa, soft_ecdsa_ok, true);
4✔
1091
         }
4✔
1092
      };
8✔
1093

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

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

1106
      keypair.first.destroy();
4✔
1107
      keypair.second.destroy();
4✔
1108
   }
8✔
1109

1110
   return result;
4✔
1111
}
2✔
1112

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

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

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

1136
         return run_pkcs11_tests("PKCS11 ECDSA", fns);
2✔
1137
      }
1✔
1138
};
1139

1140
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdsa", PKCS11_ECDSA_Tests);
1141

1142
   #endif
1143

1144
   #if defined(BOTAN_HAS_ECDH)
1145

1146
/***************************** PKCS11 ECDH *****************************/
1147

1148
Test::Result test_ecdh_privkey_import() {
1✔
1149
   Test::Result result("PKCS11 import ECDH private key");
1✔
1150

1151
   TestSession test_session(true);
1✔
1152

1153
   // create ecdh private key
1154
   ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
1155

1156
   // import to card
1157
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
1158
   props.set_token(true);
1✔
1159
   props.set_private(true);
1✔
1160
   props.set_derive(true);
1✔
1161

1162
   // label
1163
   std::string label = "Botan test ecdh key";
1✔
1164
   props.set_label(label);
1✔
1165

1166
   PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1167
   result.test_success("ECDH private key import was successful");
1✔
1168

1169
   pk.destroy();
1✔
1170
   return result;
1✔
1171
}
2✔
1172

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

1176
   TestSession test_session(true);
1✔
1177

1178
   // create private key
1179
   ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
1180

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

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

1192
   PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1193

1194
   ECDH_PrivateKey exported = pk.export_key();
1✔
1195
   result.test_success("ECDH private key export was successful");
1✔
1196

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

1201
Test::Result test_ecdh_pubkey_import() {
1✔
1202
   Test::Result result("PKCS11 import ECDH public key");
1✔
1203

1204
   TestSession test_session(true);
1✔
1205

1206
   // create ECDH private key
1207
   ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
1208

1209
   const auto enc_point = encode_ec_point_in_octet_str(priv_key.public_point());
1✔
1210

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

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

1221
   PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1222
   result.test_success("ECDH public key import was successful");
1✔
1223

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

1228
Test::Result test_ecdh_pubkey_export() {
1✔
1229
   Test::Result result("PKCS11 export ECDH public key");
1✔
1230

1231
   TestSession test_session(true);
1✔
1232

1233
   // create public key from private key
1234
   ECDH_PrivateKey priv_key(Test::rng(), EC_Group("secp256r1"));
2✔
1235

1236
   const auto enc_point = encode_ec_point_in_octet_str(priv_key.public_point());
1✔
1237

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

1244
   // label
1245
   std::string label = "Botan test ECDH pub key";
1✔
1246
   props.set_label(label);
1✔
1247

1248
   PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1249

1250
   ECDH_PublicKey exported = pk.export_key();
1✔
1251
   result.test_success("ECDH public key export was successful");
1✔
1252

1253
   pk.destroy();
1✔
1254

1255
   return result;
2✔
1256
}
3✔
1257

1258
Test::Result test_ecdh_generate_private_key() {
1✔
1259
   Test::Result result("PKCS11 generate ECDH private key");
1✔
1260
   TestSession test_session(true);
1✔
1261

1262
   EC_PrivateKeyGenerationProperties props;
1✔
1263
   props.set_token(true);
1✔
1264
   props.set_private(true);
1✔
1265
   props.set_derive(true);
1✔
1266

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

1271
   pk.destroy();
1✔
1272

1273
   return result;
1✔
1274
}
1✔
1275

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

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

1293
   return PKCS11::generate_ecdh_keypair(test_session.session(), pub_props, priv_props);
6✔
1294
}
3✔
1295

1296
Test::Result test_ecdh_generate_keypair() {
1✔
1297
   Test::Result result("PKCS11 generate ECDH key pair");
1✔
1298
   TestSession test_session(true);
1✔
1299

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

1303
   keypair.first.destroy();
1✔
1304
   keypair.second.destroy();
1✔
1305

1306
   return result;
2✔
1307
}
1✔
1308

1309
Test::Result test_ecdh_derive() {
1✔
1310
   Test::Result result("PKCS11 ECDH derive");
1✔
1311
   TestSession test_session(true);
1✔
1312

1313
   PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
1✔
1314
   PKCS11_ECDH_KeyPair keypair2 = generate_ecdh_keypair(test_session, "Botan test ECDH key2");
1✔
1315

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

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

1324
   bool eq = alice_key == bob_key;
1✔
1325
   result.test_eq("same secret key derived", eq, true);
1✔
1326

1327
   keypair.first.destroy();
1✔
1328
   keypair.second.destroy();
1✔
1329
   keypair2.first.destroy();
1✔
1330
   keypair2.second.destroy();
1✔
1331

1332
   return result;
2✔
1333
}
4✔
1334

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

1347
         return run_pkcs11_tests("PKCS11 ECDH", fns);
2✔
1348
      }
1✔
1349
};
1350

1351
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdh", PKCS11_ECDH_Tests);
1352

1353
   #endif
1354

1355
/***************************** PKCS11 RNG *****************************/
1356

1357
Test::Result test_rng_generate_random() {
1✔
1358
   Test::Result result("PKCS11 RNG generate random");
1✔
1359
   TestSession test_session(true);
1✔
1360

1361
   PKCS11_RNG rng(test_session.session());
1✔
1362
   result.confirm("RNG already seeded", rng.is_seeded());
2✔
1363

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

1368
   return result;
2✔
1369
}
1✔
1370

1371
Test::Result test_rng_add_entropy() {
1✔
1372
   Test::Result result("PKCS11 RNG add entropy random");
1✔
1373
   TestSession test_session(true);
1✔
1374

1375
   PKCS11_RNG rng(test_session.session());
1✔
1376

1377
   result.confirm("RNG already seeded", rng.is_seeded());
2✔
1378
   rng.clear();
1✔
1379
   result.confirm("RNG ignores call to clear", rng.is_seeded());
2✔
1380

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

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

1389
   return result;
2✔
1390
}
1✔
1391

1392
   #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
1393

1394
Test::Result test_pkcs11_hmac_drbg() {
1✔
1395
   Test::Result result("PKCS11 HMAC_DRBG using PKCS11_RNG");
1✔
1396
   TestSession test_session(true);
1✔
1397

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

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

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

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

1413
   return result;
2✔
1414
}
4✔
1415
   #endif
1416

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

1428
         return run_pkcs11_tests("PKCS11 RNG", fns);
2✔
1429
      }
1✔
1430
};
1431

1432
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rng", PKCS11_RNG_Tests);
1433

1434
/***************************** PKCS11 token management *****************************/
1435

1436
Test::Result test_set_pin() {
1✔
1437
   Test::Result result("PKCS11 set pin");
1✔
1438

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

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

1446
   PKCS11::set_pin(slot, SO_PIN(), PIN());
3✔
1447
   result.test_success("PIN changed back with SO_PIN");
1✔
1448

1449
   return result;
2✔
1450
}
1✔
1451

1452
Test::Result test_initialize() {
1✔
1453
   Test::Result result("PKCS11 initialize token");
1✔
1454

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

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

1462
   return result;
2✔
1463
}
1✔
1464

1465
Test::Result test_change_pin() {
1✔
1466
   Test::Result result("PKCS11 change pin");
1✔
1467

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

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

1475
   PKCS11::change_pin(slot, TEST_PIN(), PIN());
3✔
1476
   result.test_success("PIN changed back with TEST_PIN to PIN");
1✔
1477

1478
   return result;
2✔
1479
}
1✔
1480

1481
Test::Result test_change_so_pin() {
1✔
1482
   Test::Result result("PKCS11 change so_pin");
1✔
1483

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

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

1491
   PKCS11::change_so_pin(slot, TEST_SO_PIN(), SO_PIN());
3✔
1492
   result.test_success("SO_PIN changed back with TEST_SO_PIN to SO_PIN");
1✔
1493

1494
   return result;
2✔
1495
}
1✔
1496

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

1506
         return run_pkcs11_tests("PKCS11 token management", fns);
2✔
1507
      }
1✔
1508
};
1509

1510
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-manage", PKCS11_Token_Management_Tests);
1511

1512
/***************************** PKCS11 token management *****************************/
1513

1514
   #if defined(BOTAN_HAS_X509_CERTIFICATES)
1515

1516
Test::Result test_x509_import() {
1✔
1517
   Test::Result result("PKCS11 X509 cert import");
1✔
1518

1519
      #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1520
   TestSession test_session(true);
1✔
1521

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

1528
   PKCS11_X509_Certificate pkcs11_cert(test_session.session(), props);
1✔
1529
   result.test_success("X509 certificate imported");
1✔
1530

1531
   PKCS11_X509_Certificate pkcs11_cert2(test_session.session(), pkcs11_cert.handle());
1✔
1532
   result.test_eq("X509 certificate by handle", pkcs11_cert == pkcs11_cert2, true);
1✔
1533

1534
   pkcs11_cert.destroy();
1✔
1535
      #endif
1536

1537
   return result;
2✔
1538
}
1✔
1539

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

1546
         return run_pkcs11_tests("PKCS11 X509", fns);
2✔
1547
      }
1✔
1548
};
1549

1550
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-x509", PKCS11_X509_Tests);
1551

1552
   #endif
1553

1554
}  // namespace
1555

1556
#endif
1557

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

© 2025 Coveralls, Inc