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

randombit / botan / 12661312886

07 Jan 2025 11:55PM UTC coverage: 91.251% (-0.02%) from 91.267%
12661312886

push

github

web-flow
Merge pull request #4518 from randombit/jack/ec-point-cleanups

Move EC_Point and related code to deprecated submodule

93407 of 102363 relevant lines covered (91.25%)

11518305.49 hits per line

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

96.88
/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
      Session& session() const { return *m_session; }
6✔
103

104
      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
      }
2✔
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
      }
2✔
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
      }
2✔
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);
2✔
446
   result.test_int_eq("ObjectId value", *reinterpret_cast<uint64_t*>(storedAttributes.at(4).pValue), 10);
2✔
447
   result.test_int_eq("Id type", storedAttributes.at(5).type, AttributeType::Id);
2✔
448
   result.test_int_eq("Id value", *reinterpret_cast<uint64_t*>(storedAttributes.at(5).pValue), 21);
2✔
449
   result.test_int_eq("PixelX type", storedAttributes.at(6).type, AttributeType::PixelX);
2✔
450
   result.test_int_eq("PixelX value", *reinterpret_cast<uint64_t*>(storedAttributes.at(6).pValue), 30);
2✔
451
   result.test_int_eq("PixelY type", storedAttributes.at(7).type, AttributeType::PixelY);
2✔
452
   result.test_int_eq("PixelY value", *reinterpret_cast<uint64_t*>(storedAttributes.at(7).pValue), 40);
2✔
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
}
8✔
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
}
1✔
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());
2✔
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());
2✔
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
}
2✔
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
}
2✔
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
}
2✔
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
      }
2✔
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
   auto rng = Test::new_rng(__func__);
1✔
614

615
   // create private key
616
   RSA_PrivateKey priv_key(*rng, 2048);
1✔
617
   result.confirm("Key self test OK", priv_key.check_key(*rng, true));
2✔
618

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

628
   props.set_token(true);
1✔
629
   props.set_private(true);
1✔
630
   props.set_decrypt(true);
1✔
631
   props.set_sign(true);
1✔
632

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

637
   pk.destroy();
1✔
638
   return result;
1✔
639
}
2✔
640

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

644
   TestSession test_session(true);
1✔
645

646
   auto rng = Test::new_rng(__func__);
1✔
647

648
   // create private key
649
   RSA_PrivateKey priv_key(*rng, 2048);
1✔
650

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

660
   props.set_token(true);
1✔
661
   props.set_private(true);
1✔
662
   props.set_decrypt(true);
1✔
663
   props.set_sign(true);
1✔
664
   props.set_extractable(true);
1✔
665
   props.set_sensitive(false);
1✔
666

667
   PKCS11_RSA_PrivateKey pk(test_session.session(), props);
1✔
668
   result.confirm("Check PK11 key", pk.check_key(*rng, true));
2✔
669

670
   RSA_PrivateKey exported = pk.export_key();
1✔
671
   result.test_success("RSA private key export was successful");
1✔
672
   result.confirm("Check exported key", exported.check_key(*rng, true));
2✔
673

674
   pk.destroy();
1✔
675
   return result;
1✔
676
}
2✔
677

678
Test::Result test_rsa_pubkey_import() {
1✔
679
   Test::Result result("PKCS11 import RSA public key");
1✔
680

681
   TestSession test_session(true);
1✔
682

683
   auto rng = Test::new_rng(__func__);
1✔
684

685
   // create public key from private key
686
   RSA_PrivateKey priv_key(*rng, 2048);
1✔
687

688
   // import to card
689
   RSA_PublicKeyImportProperties props(priv_key.get_n(), priv_key.get_e());
1✔
690
   props.set_token(true);
1✔
691
   props.set_encrypt(true);
1✔
692
   props.set_private(false);
1✔
693

694
   PKCS11_RSA_PublicKey pk(test_session.session(), props);
1✔
695
   result.test_success("RSA public key import was successful");
1✔
696
   result.confirm("Check PK11 key", pk.check_key(*rng, true));
2✔
697

698
   pk.destroy();
1✔
699

700
   return result;
2✔
701
}
2✔
702

703
Test::Result test_rsa_generate_private_key() {
1✔
704
   Test::Result result("PKCS11 generate RSA private key");
1✔
705
   TestSession test_session(true);
1✔
706

707
   RSA_PrivateKeyGenerationProperties props;
1✔
708
   props.set_token(true);
1✔
709
   props.set_private(true);
1✔
710
   props.set_sign(true);
1✔
711
   props.set_decrypt(true);
1✔
712

713
   PKCS11_RSA_PrivateKey pk(test_session.session(), 2048, props);
1✔
714
   result.test_success("RSA private key generation was successful");
1✔
715

716
   pk.destroy();
1✔
717

718
   return result;
1✔
719
}
1✔
720

721
PKCS11_RSA_KeyPair generate_rsa_keypair(const TestSession& test_session) {
3✔
722
   RSA_PublicKeyGenerationProperties pub_props(2048UL);
3✔
723
   pub_props.set_pub_exponent();
3✔
724
   pub_props.set_label("BOTAN_TEST_RSA_PUB_KEY");
3✔
725
   pub_props.set_token(true);
3✔
726
   pub_props.set_encrypt(true);
3✔
727
   pub_props.set_verify(true);
3✔
728
   pub_props.set_private(false);
3✔
729

730
   RSA_PrivateKeyGenerationProperties priv_props;
3✔
731
   priv_props.set_label("BOTAN_TEST_RSA_PRIV_KEY");
3✔
732
   priv_props.set_token(true);
3✔
733
   priv_props.set_private(true);
3✔
734
   priv_props.set_sign(true);
3✔
735
   priv_props.set_decrypt(true);
3✔
736

737
   return PKCS11::generate_rsa_keypair(test_session.session(), pub_props, priv_props);
3✔
738
}
3✔
739

740
Test::Result test_rsa_generate_key_pair() {
1✔
741
   Test::Result result("PKCS11 generate RSA key pair");
1✔
742
   TestSession test_session(true);
1✔
743

744
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
745
   result.test_success("RSA key pair generation was successful");
1✔
746

747
   keypair.first.destroy();
1✔
748
   keypair.second.destroy();
1✔
749

750
   return result;
1✔
751
}
1✔
752

753
Test::Result test_rsa_encrypt_decrypt() {
1✔
754
   Test::Result result("PKCS11 RSA encrypt decrypt");
1✔
755
   TestSession test_session(true);
1✔
756

757
   // generate key pair
758
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
759

760
   auto rng = Test::new_rng(__func__);
1✔
761

762
   auto encrypt_and_decrypt =
1✔
763
      [&](const std::vector<uint8_t>& plaintext, const std::string& padding, const bool blinding) {
5✔
764
         std::vector<uint8_t> encrypted;
5✔
765

766
         try {
5✔
767
            Botan::PK_Encryptor_EME encryptor(keypair.first, *rng, padding);
5✔
768
            encrypted = encryptor.encrypt(plaintext, *rng);
5✔
769
         } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
5✔
770
            result.test_failure("PKCS11 RSA encrypt " + padding, e.what());
×
771
         }
×
772

773
         Botan::secure_vector<uint8_t> decrypted;
5✔
774

775
         try {
5✔
776
            keypair.second.set_use_software_padding(blinding);
5✔
777
            Botan::PK_Decryptor_EME decryptor(keypair.second, *rng, padding);
5✔
778
            decrypted = decryptor.decrypt(encrypted);
5✔
779
         } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
5✔
780
            std::ostringstream err;
×
781
            err << "PKCS11 RSA decrypt " << padding;
×
782
            if(blinding) {
×
783
               err << " with userspace blinding";
×
784
            }
785

786
            result.test_failure(err.str(), e.what());
×
787
         }
×
788

789
         result.test_eq("RSA PKCS11 encrypt and decrypt: " + padding, decrypted, plaintext);
10✔
790
      };
10✔
791

792
   std::vector<uint8_t> plaintext(256);
1✔
793
   std::iota(std::begin(plaintext), std::end(plaintext), static_cast<uint8_t>(0));
1✔
794
   encrypt_and_decrypt(plaintext, "Raw", false);
1✔
795

796
   plaintext = {0x00, 0x01, 0x02, 0x03, 0x04, 0x00};
1✔
797
   encrypt_and_decrypt(plaintext, "EME-PKCS1-v1_5", false);
1✔
798
   encrypt_and_decrypt(plaintext, "EME-PKCS1-v1_5", true);
1✔
799

800
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", false);
1✔
801
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", true);
1✔
802

803
   keypair.first.destroy();
1✔
804
   keypair.second.destroy();
1✔
805

806
   return result;
2✔
807
}
2✔
808

809
Test::Result test_rsa_sign_verify() {
1✔
810
   Test::Result result("PKCS11 RSA sign and verify");
1✔
811
   TestSession test_session(true);
1✔
812

813
   // generate key pair
814
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
815

816
   auto rng = Test::new_rng(__func__);
1✔
817

818
   std::vector<uint8_t> plaintext(256);
1✔
819
   std::iota(std::begin(plaintext), std::end(plaintext), static_cast<uint8_t>(0));
1✔
820

821
   auto sign_and_verify = [&](const std::string& emsa, bool multipart) {
6✔
822
      Botan::PK_Signer signer(keypair.second, *rng, emsa, Botan::Signature_Format::Standard);
5✔
823
      std::vector<uint8_t> signature;
5✔
824
      if(multipart) {
5✔
825
         signer.update(plaintext.data(), plaintext.size() / 2);
2✔
826
         signature = signer.sign_message(plaintext.data() + plaintext.size() / 2, plaintext.size() / 2, *rng);
4✔
827
      } else {
828
         signature = signer.sign_message(plaintext, *rng);
6✔
829
      }
830

831
      Botan::PK_Verifier verifier(keypair.first, emsa, Botan::Signature_Format::Standard);
5✔
832
      bool rsa_ok = false;
5✔
833
      if(multipart) {
5✔
834
         verifier.update(plaintext.data(), plaintext.size() / 2);
2✔
835
         rsa_ok = verifier.verify_message(
2✔
836
            plaintext.data() + plaintext.size() / 2, plaintext.size() / 2, signature.data(), signature.size());
2✔
837
      } else {
838
         rsa_ok = verifier.verify_message(plaintext, signature);
3✔
839
      }
840

841
      result.test_eq("RSA PKCS11 sign and verify: " + emsa, rsa_ok, true);
5✔
842
   };
10✔
843

844
   // single-part sign
845
   sign_and_verify("Raw", false);
1✔
846
   sign_and_verify("EMSA3(SHA-256)", false);
1✔
847
   sign_and_verify("EMSA4(SHA-256)", false);
1✔
848

849
   // multi-part sign
850
   sign_and_verify("EMSA3(SHA-256)", true);
1✔
851
   sign_and_verify("EMSA4(SHA-256)", true);
1✔
852

853
   keypair.first.destroy();
1✔
854
   keypair.second.destroy();
1✔
855

856
   return result;
2✔
857
}
2✔
858

859
class PKCS11_RSA_Tests final : public Test {
×
860
   public:
861
      std::vector<Test::Result> run() override {
1✔
862
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
863
            {STRING_AND_FUNCTION(test_rsa_privkey_import)},
864
            {STRING_AND_FUNCTION(test_rsa_pubkey_import)},
865
            {STRING_AND_FUNCTION(test_rsa_privkey_export)},
866
            {STRING_AND_FUNCTION(test_rsa_generate_private_key)},
867
            {STRING_AND_FUNCTION(test_rsa_generate_key_pair)},
868
            {STRING_AND_FUNCTION(test_rsa_encrypt_decrypt)},
869
            {STRING_AND_FUNCTION(test_rsa_sign_verify)}};
8✔
870

871
         return run_pkcs11_tests("PKCS11 RSA", fns);
2✔
872
      }
2✔
873
};
874

875
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rsa", PKCS11_RSA_Tests);
876
   #endif
877

878
/***************************** PKCS11 ECDSA *****************************/
879

880
   #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
881
std::vector<uint8_t> encode_ec_point_in_octet_str(const Botan::EC_PublicKey& pk) {
4✔
882
   std::vector<uint8_t> enc;
4✔
883
   DER_Encoder(enc).encode(pk._public_ec_point().serialize_uncompressed(), ASN1_Type::OctetString);
12✔
884
   return enc;
4✔
885
}
×
886
   #endif
887

888
   #if defined(BOTAN_HAS_ECDSA)
889

890
Test::Result test_ecdsa_privkey_import() {
1✔
891
   Test::Result result("PKCS11 import ECDSA private key");
1✔
892

893
   TestSession test_session(true);
1✔
894

895
   auto rng = Test::new_rng(__func__);
1✔
896

897
   // create ecdsa private key
898
   ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
899
   result.confirm("Key self test OK", priv_key.check_key(*rng, true));
2✔
900

901
   // import to card
902
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
903
   props.set_token(true);
1✔
904
   props.set_private(true);
1✔
905
   props.set_sign(true);
1✔
906

907
   // label
908
   std::string label = "Botan test ecdsa key";
1✔
909
   props.set_label(label);
1✔
910

911
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
1✔
912
   result.test_success("ECDSA private key import was successful");
1✔
913
   pk.set_public_point(priv_key._public_ec_point());
1✔
914
   result.confirm("P11 key self test OK", pk.check_key(*rng, false));
2✔
915

916
   pk.destroy();
1✔
917
   return result;
1✔
918
}
2✔
919

920
Test::Result test_ecdsa_privkey_export() {
1✔
921
   Test::Result result("PKCS11 export ECDSA private key");
1✔
922

923
   TestSession test_session(true);
1✔
924

925
   auto rng = Test::new_rng(__func__);
1✔
926

927
   // create private key
928
   ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
929

930
   result.confirm("Check ECDSA key", priv_key.check_key(*rng, true));
2✔
931
   // import to card
932
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
933
   props.set_token(true);
1✔
934
   props.set_private(true);
1✔
935
   props.set_sign(true);
1✔
936
   props.set_extractable(true);
1✔
937

938
   // label
939
   std::string label = "Botan test ecdsa key";
1✔
940
   props.set_label(label);
1✔
941

942
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
1✔
943
   pk.set_public_point(priv_key._public_ec_point());
1✔
944
   result.confirm("Check PK11 key", pk.check_key(*rng, false));
2✔
945

946
   ECDSA_PrivateKey exported = pk.export_key();
1✔
947
   result.test_success("ECDSA private key export was successful");
1✔
948
   result.confirm("Check exported key valid", exported.check_key(*rng, true));
2✔
949
   result.test_eq("Check exported key contents", exported.private_key_bits(), priv_key.private_key_bits());
3✔
950

951
   pk.destroy();
1✔
952
   return result;
1✔
953
}
2✔
954

955
Test::Result test_ecdsa_pubkey_import() {
1✔
956
   Test::Result result("PKCS11 import ECDSA public key");
1✔
957

958
   TestSession test_session(true);
1✔
959

960
   auto rng = Test::new_rng(__func__);
1✔
961

962
   // create ecdsa private key
963
   ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
964

965
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
966

967
   // import to card
968
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
969
   props.set_token(true);
1✔
970
   props.set_verify(true);
1✔
971
   props.set_private(false);
1✔
972

973
   // label
974
   std::string label = "Botan test ecdsa pub key";
1✔
975
   props.set_label(label);
1✔
976

977
   PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
978
   result.test_success("ECDSA public key import was successful");
1✔
979

980
   pk.destroy();
1✔
981
   return result;
1✔
982
}
3✔
983

984
Test::Result test_ecdsa_pubkey_export() {
1✔
985
   Test::Result result("PKCS11 export ECDSA public key");
1✔
986

987
   TestSession test_session(true);
1✔
988

989
   auto rng = Test::new_rng(__func__);
1✔
990

991
   // create public key from private key
992
   ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
993

994
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
995

996
   // import to card
997
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
998
   props.set_token(true);
1✔
999
   props.set_verify(true);
1✔
1000
   props.set_private(false);
1✔
1001

1002
   // label
1003
   std::string label = "Botan test ecdsa pub key";
1✔
1004
   props.set_label(label);
1✔
1005

1006
   PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
1007

1008
   ECDSA_PublicKey exported = pk.export_key();
1✔
1009
   result.test_success("ECDSA public key export was successful");
1✔
1010

1011
   pk.destroy();
1✔
1012

1013
   return result;
2✔
1014
}
3✔
1015

1016
Test::Result test_ecdsa_generate_private_key() {
1✔
1017
   Test::Result result("PKCS11 generate ECDSA private key");
1✔
1018
   TestSession test_session(true);
1✔
1019

1020
   EC_PrivateKeyGenerationProperties props;
1✔
1021
   props.set_token(true);
1✔
1022
   props.set_private(true);
1✔
1023
   props.set_sign(true);
1✔
1024

1025
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), EC_Group::from_name("secp256r1").DER_encode(), props);
2✔
1026
   result.test_success("ECDSA private key generation was successful");
1✔
1027

1028
   pk.destroy();
1✔
1029

1030
   return result;
1✔
1031
}
1✔
1032

1033
PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(const TestSession& test_session,
6✔
1034
                                            const std::string& curve,
1035
                                            EC_Group_Encoding enc) {
1036
   EC_PublicKeyGenerationProperties pub_props(EC_Group::from_name(curve).DER_encode(enc));
12✔
1037
   pub_props.set_label("BOTAN_TEST_ECDSA_PUB_KEY");
6✔
1038
   pub_props.set_token(true);
6✔
1039
   pub_props.set_verify(true);
6✔
1040
   pub_props.set_private(false);
6✔
1041
   pub_props.set_modifiable(true);
6✔
1042

1043
   EC_PrivateKeyGenerationProperties priv_props;
6✔
1044
   priv_props.set_label("BOTAN_TEST_ECDSA_PRIV_KEY");
6✔
1045
   priv_props.set_token(true);
6✔
1046
   priv_props.set_private(true);
6✔
1047
   priv_props.set_sensitive(true);
6✔
1048
   priv_props.set_extractable(false);
6✔
1049
   priv_props.set_sign(true);
6✔
1050
   priv_props.set_modifiable(true);
6✔
1051

1052
   return PKCS11::generate_ecdsa_keypair(test_session.session(), pub_props, priv_props);
12✔
1053
}
6✔
1054

1055
Test::Result test_ecdsa_generate_keypair() {
1✔
1056
   Test::Result result("PKCS11 generate ECDSA key pair");
1✔
1057
   TestSession test_session(true);
1✔
1058
   std::vector<std::string> curves;
1✔
1059

1060
   curves.push_back("secp256r1");
2✔
1061
   curves.push_back("brainpool512r1");
2✔
1062

1063
   for(auto& curve : curves) {
3✔
1064
      PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session, curve, EC_Group_Encoding::NamedCurve);
2✔
1065

1066
      keypair.first.destroy();
2✔
1067
      keypair.second.destroy();
2✔
1068
   }
2✔
1069
   result.test_success("ECDSA key pair generation was successful");
1✔
1070

1071
   return result;
1✔
1072
}
1✔
1073

1074
Test::Result test_ecdsa_sign_verify_core(EC_Group_Encoding enc, const std::string& test_name) {
2✔
1075
   Test::Result result(test_name);
2✔
1076
   TestSession test_session(true);
2✔
1077
   std::vector<std::string> curves;
2✔
1078

1079
   curves.push_back("secp256r1");
4✔
1080
   curves.push_back("brainpool512r1");
4✔
1081

1082
   Slot& slot = test_session.slot();
2✔
1083
   SlotInfo info = slot.get_slot_info();
2✔
1084
   std::string manufacturer(reinterpret_cast<char*>(info.manufacturerID));
2✔
1085

1086
   auto rng = Test::new_rng(__func__);
2✔
1087

1088
   for(auto& curve : curves) {
6✔
1089
      // generate key pair
1090
      PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session, curve, enc);
4✔
1091

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

1094
      auto sign_and_verify = [&](const std::string& emsa, const Botan::Signature_Format format, bool check_soft) {
8✔
1095
         Botan::PK_Signer signer(keypair.second, *rng, emsa, format);
4✔
1096
         auto signature = signer.sign_message(plaintext, *rng);
4✔
1097

1098
         Botan::PK_Verifier token_verifier(keypair.first, emsa, format);
4✔
1099
         bool ecdsa_ok = token_verifier.verify_message(plaintext, signature);
4✔
1100

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

1103
         // test against software implementation if available
1104
         if(check_soft) {
4✔
1105
            Botan::PK_Verifier soft_verifier(keypair.first, emsa, format);
4✔
1106
            bool soft_ecdsa_ok = soft_verifier.verify_message(plaintext, signature);
4✔
1107

1108
            result.test_eq("ECDSA PKCS11 verify (in software): " + emsa, soft_ecdsa_ok, true);
4✔
1109
         }
4✔
1110
      };
8✔
1111

1112
      // SoftHSMv2 until now only supports "Raw"
1113
      if(manufacturer.find("SoftHSM project") == std::string::npos) {
4✔
1114
         sign_and_verify("SHA-256", Botan::Signature_Format::Standard, true);
×
1115
         sign_and_verify("SHA-256", Botan::Signature_Format::DerSequence, true);
×
1116
      }
1117

1118
      #if defined(BOTAN_HAS_EMSA_RAW)
1119
      sign_and_verify("Raw", Botan::Signature_Format::Standard, true);
4✔
1120
      #else
1121
      sign_and_verify("Raw", Botan::Signature_Format::Standard, false);
1122
      #endif
1123

1124
      keypair.first.destroy();
4✔
1125
      keypair.second.destroy();
4✔
1126
   }
8✔
1127

1128
   return result;
4✔
1129
}
2✔
1130

1131
Test::Result test_ecdsa_sign_verify() {
1✔
1132
   // pass the curve OID to the PKCS#11 library
1133
   return test_ecdsa_sign_verify_core(EC_Group_Encoding::NamedCurve, "PKCS11 ECDSA sign and verify");
2✔
1134
}
1135

1136
Test::Result test_ecdsa_curve_import() {
1✔
1137
   // pass the curve parameters to the PKCS#11 library and perform sign/verify to test them
1138
   return test_ecdsa_sign_verify_core(EC_Group_Encoding::Explicit, "PKCS11 ECDSA sign and verify with imported curve");
2✔
1139
}
1140

1141
class PKCS11_ECDSA_Tests final : public Test {
×
1142
   public:
1143
      std::vector<Test::Result> run() override {
1✔
1144
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1145
            {STRING_AND_FUNCTION(test_ecdsa_privkey_import)},
1146
            {STRING_AND_FUNCTION(test_ecdsa_privkey_export)},
1147
            {STRING_AND_FUNCTION(test_ecdsa_pubkey_import)},
1148
            {STRING_AND_FUNCTION(test_ecdsa_pubkey_export)},
1149
            {STRING_AND_FUNCTION(test_ecdsa_generate_private_key)},
1150
            {STRING_AND_FUNCTION(test_ecdsa_generate_keypair)},
1151
            {STRING_AND_FUNCTION(test_ecdsa_sign_verify)},
1152
            {STRING_AND_FUNCTION(test_ecdsa_curve_import)}};
9✔
1153

1154
         return run_pkcs11_tests("PKCS11 ECDSA", fns);
2✔
1155
      }
2✔
1156
};
1157

1158
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdsa", PKCS11_ECDSA_Tests);
1159

1160
   #endif
1161

1162
   #if defined(BOTAN_HAS_ECDH)
1163

1164
/***************************** PKCS11 ECDH *****************************/
1165

1166
Test::Result test_ecdh_privkey_import() {
1✔
1167
   Test::Result result("PKCS11 import ECDH private key");
1✔
1168

1169
   TestSession test_session(true);
1✔
1170

1171
   auto rng = Test::new_rng(__func__);
1✔
1172

1173
   // create ecdh private key
1174
   ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1175

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

1182
   // label
1183
   std::string label = "Botan test ecdh key";
1✔
1184
   props.set_label(label);
1✔
1185

1186
   PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1187
   result.test_success("ECDH private key import was successful");
1✔
1188

1189
   pk.destroy();
1✔
1190
   return result;
1✔
1191
}
2✔
1192

1193
Test::Result test_ecdh_privkey_export() {
1✔
1194
   Test::Result result("PKCS11 export ECDH private key");
1✔
1195

1196
   TestSession test_session(true);
1✔
1197

1198
   auto rng = Test::new_rng(__func__);
1✔
1199

1200
   // create private key
1201
   ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1202

1203
   // import to card
1204
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
1205
   props.set_token(true);
1✔
1206
   props.set_private(true);
1✔
1207
   props.set_derive(true);
1✔
1208
   props.set_extractable(true);
1✔
1209

1210
   // label
1211
   std::string label = "Botan test ecdh key";
1✔
1212
   props.set_label(label);
1✔
1213

1214
   PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1215

1216
   ECDH_PrivateKey exported = pk.export_key();
1✔
1217
   result.test_success("ECDH private key export was successful");
1✔
1218

1219
   pk.destroy();
1✔
1220
   return result;
1✔
1221
}
2✔
1222

1223
Test::Result test_ecdh_pubkey_import() {
1✔
1224
   Test::Result result("PKCS11 import ECDH public key");
1✔
1225

1226
   TestSession test_session(true);
1✔
1227

1228
   auto rng = Test::new_rng(__func__);
1✔
1229

1230
   // create ECDH private key
1231
   ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1232

1233
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
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_private(false);
1✔
1239
   props.set_derive(true);
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
   result.test_success("ECDH public key import was successful");
1✔
1247

1248
   pk.destroy();
1✔
1249
   return result;
2✔
1250
}
3✔
1251

1252
Test::Result test_ecdh_pubkey_export() {
1✔
1253
   Test::Result result("PKCS11 export ECDH public key");
1✔
1254

1255
   TestSession test_session(true);
1✔
1256

1257
   auto rng = Test::new_rng(__func__);
1✔
1258

1259
   // create public key from private key
1260
   ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1261

1262
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
1263

1264
   // import to card
1265
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
1266
   props.set_token(true);
1✔
1267
   props.set_derive(true);
1✔
1268
   props.set_private(false);
1✔
1269

1270
   // label
1271
   std::string label = "Botan test ECDH pub key";
1✔
1272
   props.set_label(label);
1✔
1273

1274
   PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1275

1276
   ECDH_PublicKey exported = pk.export_key();
1✔
1277
   result.test_success("ECDH public key export was successful");
1✔
1278

1279
   pk.destroy();
1✔
1280

1281
   return result;
2✔
1282
}
3✔
1283

1284
Test::Result test_ecdh_generate_private_key() {
1✔
1285
   Test::Result result("PKCS11 generate ECDH private key");
1✔
1286
   TestSession test_session(true);
1✔
1287

1288
   EC_PrivateKeyGenerationProperties props;
1✔
1289
   props.set_token(true);
1✔
1290
   props.set_private(true);
1✔
1291
   props.set_derive(true);
1✔
1292

1293
   PKCS11_ECDH_PrivateKey pk(test_session.session(), EC_Group::from_name("secp256r1").DER_encode(), props);
2✔
1294
   result.test_success("ECDH private key generation was successful");
1✔
1295

1296
   pk.destroy();
1✔
1297

1298
   return result;
1✔
1299
}
1✔
1300

1301
PKCS11_ECDH_KeyPair generate_ecdh_keypair(const TestSession& test_session, const std::string& label) {
3✔
1302
   EC_PublicKeyGenerationProperties pub_props(EC_Group::from_name("secp256r1").DER_encode());
6✔
1303
   pub_props.set_label(label + "_PUB_KEY");
3✔
1304
   pub_props.set_token(true);
3✔
1305
   pub_props.set_derive(true);
3✔
1306
   pub_props.set_private(false);
3✔
1307
   pub_props.set_modifiable(true);
3✔
1308

1309
   EC_PrivateKeyGenerationProperties priv_props;
3✔
1310
   priv_props.set_label(label + "_PRIV_KEY");
3✔
1311
   priv_props.set_token(true);
3✔
1312
   priv_props.set_private(true);
3✔
1313
   priv_props.set_sensitive(true);
3✔
1314
   priv_props.set_extractable(false);
3✔
1315
   priv_props.set_derive(true);
3✔
1316
   priv_props.set_modifiable(true);
3✔
1317

1318
   return PKCS11::generate_ecdh_keypair(test_session.session(), pub_props, priv_props);
6✔
1319
}
3✔
1320

1321
Test::Result test_ecdh_generate_keypair() {
1✔
1322
   Test::Result result("PKCS11 generate ECDH key pair");
1✔
1323
   TestSession test_session(true);
1✔
1324

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

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

1331
   return result;
2✔
1332
}
1✔
1333

1334
Test::Result test_ecdh_derive() {
1✔
1335
   Test::Result result("PKCS11 ECDH derive");
1✔
1336
   TestSession test_session(true);
1✔
1337

1338
   PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
1✔
1339
   PKCS11_ECDH_KeyPair keypair2 = generate_ecdh_keypair(test_session, "Botan test ECDH key2");
1✔
1340

1341
   auto rng = Test::new_rng(__func__);
1✔
1342

1343
   // SoftHSMv2 only supports CKD_NULL KDF at the moment
1344
   Botan::PK_Key_Agreement ka(keypair.second, *rng, "Raw");
1✔
1345
   Botan::PK_Key_Agreement kb(keypair2.second, *rng, "Raw");
1✔
1346

1347
   Botan::SymmetricKey alice_key = ka.derive_key(32, keypair2.first.raw_public_key_bits());
1✔
1348
   Botan::SymmetricKey bob_key = kb.derive_key(32, keypair.first.raw_public_key_bits());
1✔
1349

1350
   bool eq = alice_key == bob_key;
1✔
1351
   result.test_eq("same secret key derived", eq, true);
1✔
1352

1353
   keypair.first.destroy();
1✔
1354
   keypair.second.destroy();
1✔
1355
   keypair2.first.destroy();
1✔
1356
   keypair2.second.destroy();
1✔
1357

1358
   return result;
2✔
1359
}
5✔
1360

1361
class PKCS11_ECDH_Tests final : public Test {
×
1362
   public:
1363
      std::vector<Test::Result> run() override {
1✔
1364
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1365
            {STRING_AND_FUNCTION(test_ecdh_privkey_import)},
1366
            {STRING_AND_FUNCTION(test_ecdh_privkey_export)},
1367
            {STRING_AND_FUNCTION(test_ecdh_pubkey_import)},
1368
            {STRING_AND_FUNCTION(test_ecdh_pubkey_export)},
1369
            {STRING_AND_FUNCTION(test_ecdh_generate_private_key)},
1370
            {STRING_AND_FUNCTION(test_ecdh_generate_keypair)},
1371
            {STRING_AND_FUNCTION(test_ecdh_derive)}};
8✔
1372

1373
         return run_pkcs11_tests("PKCS11 ECDH", fns);
2✔
1374
      }
2✔
1375
};
1376

1377
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdh", PKCS11_ECDH_Tests);
1378

1379
   #endif
1380

1381
/***************************** PKCS11 RNG *****************************/
1382

1383
Test::Result test_rng_generate_random() {
1✔
1384
   Test::Result result("PKCS11 RNG generate random");
1✔
1385
   TestSession test_session(true);
1✔
1386

1387
   PKCS11_RNG p11_rng(test_session.session());
1✔
1388
   result.confirm("RNG already seeded", p11_rng.is_seeded());
2✔
1389

1390
   std::vector<uint8_t> random(20);
1✔
1391
   p11_rng.randomize(random.data(), random.size());
1✔
1392
   result.test_ne("random data generated", random, std::vector<uint8_t>(20));
2✔
1393

1394
   return result;
2✔
1395
}
1✔
1396

1397
Test::Result test_rng_add_entropy() {
1✔
1398
   Test::Result result("PKCS11 RNG add entropy random");
1✔
1399
   TestSession test_session(true);
1✔
1400

1401
   PKCS11_RNG p11_rng(test_session.session());
1✔
1402

1403
   result.confirm("RNG already seeded", p11_rng.is_seeded());
2✔
1404
   p11_rng.clear();
1✔
1405
   result.confirm("RNG ignores call to clear", p11_rng.is_seeded());
2✔
1406

1407
   result.test_eq("RNG ignores calls to reseed",
1✔
1408
                  p11_rng.reseed(Botan::Entropy_Sources::global_sources(), 256, std::chrono::milliseconds(300)),
1✔
1409
                  0);
1410

1411
   auto rng = Test::new_rng(__func__);
1✔
1412
   auto random = rng->random_vec(20);
1✔
1413
   p11_rng.add_entropy(random.data(), random.size());
1✔
1414
   result.test_success("entropy added");
1✔
1415

1416
   return result;
2✔
1417
}
2✔
1418

1419
   #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
1420

1421
Test::Result test_pkcs11_hmac_drbg() {
1✔
1422
   Test::Result result("PKCS11 HMAC_DRBG using PKCS11_RNG");
1✔
1423
   TestSession test_session(true);
1✔
1424

1425
   PKCS11_RNG p11_rng(test_session.session());
1✔
1426
   HMAC_DRBG drbg(MessageAuthenticationCode::create("HMAC(SHA-512)"), p11_rng);
1✔
1427
   // result.test_success("HMAC_DRBG(HMAC(SHA512)) instantiated with PKCS11_RNG");
1428

1429
   result.test_eq("HMAC_DRBG is not seeded yet.", drbg.is_seeded(), false);
1✔
1430
   secure_vector<uint8_t> rnd = drbg.random_vec(64);
1✔
1431
   result.test_eq("HMAC_DRBG is seeded now", drbg.is_seeded(), true);
1✔
1432

1433
   std::string personalization_string = "Botan PKCS#11 Tests";
1✔
1434
   std::vector<uint8_t> personalization_data(personalization_string.begin(), personalization_string.end());
1✔
1435
   drbg.add_entropy(personalization_data.data(), personalization_data.size());
1✔
1436

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

1440
   return result;
2✔
1441
}
3✔
1442
   #endif
1443

1444
class PKCS11_RNG_Tests final : public Test {
×
1445
   public:
1446
      std::vector<Test::Result> run() override {
1✔
1447
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1448
   #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
1449
            {STRING_AND_FUNCTION(test_pkcs11_hmac_drbg)},
1450
   #endif
1451
            {STRING_AND_FUNCTION(test_rng_generate_random)},
1452
            {STRING_AND_FUNCTION(test_rng_add_entropy)}
1453
         };
4✔
1454

1455
         return run_pkcs11_tests("PKCS11 RNG", fns);
2✔
1456
      }
2✔
1457
};
1458

1459
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rng", PKCS11_RNG_Tests);
1460

1461
/***************************** PKCS11 token management *****************************/
1462

1463
Test::Result test_set_pin() {
1✔
1464
   Test::Result result("PKCS11 set pin");
1✔
1465

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

1470
   PKCS11::set_pin(slot, SO_PIN(), TEST_PIN());
3✔
1471
   result.test_success("PIN set with SO_PIN to TEST_PIN");
1✔
1472

1473
   PKCS11::set_pin(slot, SO_PIN(), PIN());
3✔
1474
   result.test_success("PIN changed back with SO_PIN");
1✔
1475

1476
   return result;
2✔
1477
}
1✔
1478

1479
Test::Result test_initialize() {
1✔
1480
   Test::Result result("PKCS11 initialize token");
1✔
1481

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

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

1489
   return result;
2✔
1490
}
1✔
1491

1492
Test::Result test_change_pin() {
1✔
1493
   Test::Result result("PKCS11 change pin");
1✔
1494

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

1499
   PKCS11::change_pin(slot, PIN(), TEST_PIN());
3✔
1500
   result.test_success("PIN changed with PIN to TEST_PIN");
1✔
1501

1502
   PKCS11::change_pin(slot, TEST_PIN(), PIN());
3✔
1503
   result.test_success("PIN changed back with TEST_PIN to PIN");
1✔
1504

1505
   return result;
2✔
1506
}
1✔
1507

1508
Test::Result test_change_so_pin() {
1✔
1509
   Test::Result result("PKCS11 change so_pin");
1✔
1510

1511
   Module module(Test::pkcs11_lib());
1✔
1512
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
1513
   Slot slot(module, slot_vec.at(0));
1✔
1514

1515
   PKCS11::change_so_pin(slot, SO_PIN(), TEST_SO_PIN());
3✔
1516
   result.test_success("SO_PIN changed with SO_PIN to TEST_SO_PIN");
1✔
1517

1518
   PKCS11::change_so_pin(slot, TEST_SO_PIN(), SO_PIN());
3✔
1519
   result.test_success("SO_PIN changed back with TEST_SO_PIN to SO_PIN");
1✔
1520

1521
   return result;
2✔
1522
}
1✔
1523

1524
class PKCS11_Token_Management_Tests final : public Test {
×
1525
   public:
1526
      std::vector<Test::Result> run() override {
1✔
1527
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1528
            {STRING_AND_FUNCTION(test_set_pin)},
1529
            {STRING_AND_FUNCTION(test_initialize)},
1530
            {STRING_AND_FUNCTION(test_change_pin)},
1531
            {STRING_AND_FUNCTION(test_change_so_pin)}};
5✔
1532

1533
         return run_pkcs11_tests("PKCS11 token management", fns);
2✔
1534
      }
2✔
1535
};
1536

1537
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-manage", PKCS11_Token_Management_Tests);
1538

1539
/***************************** PKCS11 token management *****************************/
1540

1541
   #if defined(BOTAN_HAS_X509_CERTIFICATES)
1542

1543
Test::Result test_x509_import() {
1✔
1544
   Test::Result result("PKCS11 X509 cert import");
1✔
1545

1546
      #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1547
   TestSession test_session(true);
1✔
1548

1549
   X509_Certificate root(Test::data_file("x509/nist/test01/end.crt"));
2✔
1550
   X509_CertificateProperties props(root);
1✔
1551
   props.set_label("Botan PKCS#11 test certificate");
1✔
1552
   props.set_private(false);
1✔
1553
   props.set_token(true);
1✔
1554

1555
   PKCS11_X509_Certificate pkcs11_cert(test_session.session(), props);
1✔
1556
   result.test_success("X509 certificate imported");
1✔
1557

1558
   PKCS11_X509_Certificate pkcs11_cert2(test_session.session(), pkcs11_cert.handle());
1✔
1559
   result.test_eq("X509 certificate by handle", pkcs11_cert == pkcs11_cert2, true);
1✔
1560

1561
   pkcs11_cert.destroy();
1✔
1562
      #endif
1563

1564
   return result;
2✔
1565
}
1✔
1566

1567
class PKCS11_X509_Tests final : public Test {
×
1568
   public:
1569
      std::vector<Test::Result> run() override {
1✔
1570
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1571
            {STRING_AND_FUNCTION(test_x509_import)}};
2✔
1572

1573
         return run_pkcs11_tests("PKCS11 X509", fns);
2✔
1574
      }
2✔
1575
};
1576

1577
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-x509", PKCS11_X509_Tests);
1578

1579
   #endif
1580

1581
}  // namespace
1582

1583
#endif
1584

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

© 2026 Coveralls, Inc