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

randombit / botan / 16247597625

13 Jul 2025 09:19AM UTC coverage: 90.574% (-0.001%) from 90.575%
16247597625

push

github

web-flow
Merge pull request #4974 from randombit/jack/fix-clang-tidy-modernize-loop-convert

Enable and fix clang-tidy warning modernize-loop-convert

99094 of 109407 relevant lines covered (90.57%)

12407263.12 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
   #include <botan/internal/fmt.h>
24
#endif
25

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

30
#if defined(BOTAN_HAS_ENTROPY_SOURCE)
31
   #include <botan/entropy_src.h>
32
#endif
33

34
#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO)
35
   #include <botan/pubkey.h>
36
#endif
37

38
#if defined(BOTAN_HAS_ECC_GROUP)
39
   #include <botan/ec_group.h>
40
#endif
41

42
#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_PKCS11)
43
   #include <botan/p11_rsa.h>
44
   #include <botan/rsa.h>
45
#endif
46

47
#if defined(BOTAN_HAS_ECDSA) && defined(BOTAN_HAS_PKCS11)
48
   #include <botan/ecdsa.h>
49
   #include <botan/p11_ecdsa.h>
50
#endif
51

52
#if defined(BOTAN_HAS_ECDH) && defined(BOTAN_HAS_PKCS11)
53
   #include <botan/ecdh.h>
54
   #include <botan/p11_ecdh.h>
55
#endif
56

57
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_HAS_PKCS11)
58
   #include <botan/p11_x509.h>
59
   #include <botan/pkix_types.h>
60
#endif
61

62
#if defined(BOTAN_HAS_HMAC_DRBG)
63
   #include <botan/hmac_drbg.h>
64
#endif
65

66
namespace Botan_Tests {
67

68
#if defined(BOTAN_HAS_PKCS11)
69

70
std::vector<Test::Result> run_pkcs11_tests(const std::string& name,
11✔
71
                                           std::vector<std::pair<std::string, std::function<Test::Result()>>>& fns) {
72
   std::vector<Test::Result> results;
11✔
73

74
   for(const auto& [fn_name, fn] : fns) {
85✔
75
      try {
74✔
76
         results.push_back(fn());
148✔
77
      } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
×
78
         results.push_back(Test::Result::Failure(Botan::fmt("{} test {}", name, fn_name), e.what()));
×
79

80
         if(e.get_return_value() == Botan::PKCS11::ReturnValue::PinIncorrect) {
×
81
            break;  // Do not continue to not potentially lock the token
82
         }
83
      } catch(std::exception& e) {
×
84
         results.push_back(Test::Result::Failure(Botan::fmt("{} test {}", name, fn_name), e.what()));
×
85
      }
×
86
   }
87

88
   return results;
11✔
89
}
×
90

91
namespace {
92

93
using namespace Botan;
94
using namespace PKCS11;
95

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

107
      Session& session() const { return *m_session; }
6✔
108

109
      Slot& slot() const { return *m_slot; }
2✔
110

111
   private:
112
      std::unique_ptr<Module> m_module = nullptr;
113
      std::unique_ptr<Slot> m_slot = nullptr;
114
      std::unique_ptr<Session> m_session = nullptr;
115
};
116

117
/***************************** Module *****************************/
118

119
Test::Result test_module_ctor() {
1✔
120
   Test::Result result("Module ctor");
1✔
121

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

124
   Module module(Test::pkcs11_lib());
1✔
125
   result.test_success("Module ctor did not throw and completed successfully");
1✔
126

127
   return result;
1✔
128
}
1✔
129

130
Test::Result test_module_reload() {
1✔
131
   Test::Result result("Module reload");
1✔
132

133
   Module module(Test::pkcs11_lib());
1✔
134

135
   module.reload();
1✔
136
   result.test_success("Module reload did not throw and completed successfully");
1✔
137

138
   module.get_info();
1✔
139
   result.test_success("Module get_info() still works after reload");
1✔
140

141
   return result;
1✔
142
}
1✔
143

144
Test::Result test_multiple_modules() {
1✔
145
   Test::Result result("Module copy");
1✔
146
   Module first_module(Test::pkcs11_lib());
1✔
147

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

151
   return result;
1✔
152
}
1✔
153

154
Test::Result test_module_get_info() {
1✔
155
   Test::Result result("Module info");
1✔
156

157
   Module module(Test::pkcs11_lib());
1✔
158

159
   Info info = module.get_info();
1✔
160
   result.test_ne("Cryptoki version != 0", info.cryptokiVersion.major, 0);
1✔
161

162
   return result;
1✔
163
}
1✔
164

165
class Module_Tests final : public Test {
×
166
   public:
167
      std::vector<Test::Result> run() override {
1✔
168
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
169
            {STRING_AND_FUNCTION(test_module_ctor)},
170
            {STRING_AND_FUNCTION(test_multiple_modules)},
171
            {STRING_AND_FUNCTION(test_module_get_info)},
172
            {STRING_AND_FUNCTION(test_module_reload)}};
5✔
173

174
         return run_pkcs11_tests("Module", fns);
2✔
175
      }
2✔
176
};
177

178
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-module", Module_Tests);
179

180
/***************************** Slot *****************************/
181

182
Test::Result test_slot_get_available_slots() {
1✔
183
   Test::Result result("Slot get_available_slots");
1✔
184

185
   Module module(Test::pkcs11_lib());
1✔
186
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
187
   result.test_gte("Available Slots with attached token >= 1", slot_vec.size(), 1);
1✔
188

189
   return result;
2✔
190
}
1✔
191

192
Test::Result test_slot_ctor() {
1✔
193
   Test::Result result("Slot ctor");
1✔
194

195
   Module module(Test::pkcs11_lib());
1✔
196
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
197

198
   Slot slot(module, slot_vec.at(0));
1✔
199
   result.test_success("Slot ctor completed successfully");
1✔
200
   result.test_is_eq(slot.slot_id(), slot_vec.at(0));
1✔
201

202
   return result;
2✔
203
}
1✔
204

205
Test::Result test_get_slot_info() {
1✔
206
   Test::Result result("Slot get_slot_info");
1✔
207

208
   Module module(Test::pkcs11_lib());
1✔
209
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
210
   Slot slot(module, slot_vec.at(0));
1✔
211

212
   SlotInfo info = slot.get_slot_info();
1✔
213
   std::string description = reinterpret_cast<char*>(info.slotDescription);
1✔
214
   result.confirm("Slot description is not empty", !description.empty());
2✔
215

216
   return result;
2✔
217
}
2✔
218

219
SlotId get_invalid_slot_id(Module& module) {
2✔
220
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, false);
2✔
221

222
   SlotId invalid_id = 0;
2✔
223

224
   // find invalid slot id
225
   while(std::find(slot_vec.begin(), slot_vec.end(), invalid_id) != slot_vec.end()) {
2✔
226
      invalid_id++;
×
227
   }
228

229
   return invalid_id;
2✔
230
}
2✔
231

232
Test::Result test_slot_invalid_id() {
1✔
233
   Test::Result result("Slot get_slot_info with invalid slot id");
1✔
234

235
   Module module(Test::pkcs11_lib());
1✔
236

237
   SlotId invalid_id = get_invalid_slot_id(module);
1✔
238

239
   Slot slot(module, invalid_id);
1✔
240

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

243
   return result;
1✔
244
}
1✔
245

246
Test::Result test_get_token_info() {
1✔
247
   Test::Result result("Slot get_token_info");
1✔
248

249
   Module module(Test::pkcs11_lib());
1✔
250
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
251
   Slot slot(module, slot_vec.at(0));
1✔
252

253
   TokenInfo info = slot.get_token_info();
1✔
254
   std::string label = reinterpret_cast<char*>(info.label);
1✔
255
   result.confirm("Token label is not empty", !label.empty());
2✔
256

257
   return result;
2✔
258
}
2✔
259

260
Test::Result test_get_mechanism_list() {
1✔
261
   Test::Result result("Slot get_mechanism_list");
1✔
262

263
   Module module(Test::pkcs11_lib());
1✔
264
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
265
   Slot slot(module, slot_vec.at(0));
1✔
266

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

270
   return result;
2✔
271
}
2✔
272

273
Test::Result test_get_mechanisms_info() {
1✔
274
   Test::Result result("Slot get_mechanism_info");
1✔
275

276
   Module module(Test::pkcs11_lib());
1✔
277
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
278
   Slot slot(module, slot_vec.at(0));
1✔
279

280
   slot.get_mechanism_info(MechanismType::RsaPkcsKeyPairGen);
1✔
281
   result.test_success("get_mechanism_info() completed successfully.");
1✔
282

283
   return result;
2✔
284
}
1✔
285

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

298
         return run_pkcs11_tests("Slot", fns);
2✔
299
      }
2✔
300
};
301

302
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-slot", Slot_Tests);
303

304
/***************************** Session *****************************/
305

306
Test::Result test_session_ctor() {
1✔
307
   Test::Result result("Session ctor");
1✔
308

309
   Module module(Test::pkcs11_lib());
1✔
310
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
311
   Slot slot(module, slot_vec.at(0));
1✔
312

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

332
   return result;
2✔
333
}
1✔
334

335
Test::Result test_session_ctor_invalid_slot() {
1✔
336
   Test::Result result("Session ctor with invalid slot id");
1✔
337

338
   Module module(Test::pkcs11_lib());
1✔
339

340
   SlotId invalid_id = get_invalid_slot_id(module);
1✔
341
   Slot slot(module, invalid_id);
1✔
342

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

345
   return result;
1✔
346
}
1✔
347

348
Test::Result test_session_release() {
1✔
349
   Test::Result result("Session release/take ownership");
1✔
350

351
   Module module(Test::pkcs11_lib());
1✔
352
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
353
   Slot slot(module, slot_vec.at(0));
1✔
354

355
   Session session(slot, false);
1✔
356
   SessionHandle handle = session.release();
1✔
357

358
   Session session2(slot, handle);
1✔
359
   result.test_success("releasing ownership and taking ownership works as expected.");
1✔
360

361
   return result;
1✔
362
}
2✔
363

364
Test::Result test_session_login_logout() {
1✔
365
   Test::Result result("Session login/logout");
1✔
366

367
   Module module(Test::pkcs11_lib());
1✔
368
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
369
   Slot slot(module, slot_vec.at(0));
1✔
370

371
   Session session(slot, false);
1✔
372
   session.login(UserType::User, PIN());
1✔
373
   session.logoff();
1✔
374
   result.test_success("user login/logout succeeded");
1✔
375

376
   session.login(UserType::SO, SO_PIN());
1✔
377
   result.test_success("SO login succeeded");
1✔
378

379
   return result;
1✔
380
}
2✔
381

382
Test::Result test_session_info() {
1✔
383
   Test::Result result("Session session info");
1✔
384

385
   Module module(Test::pkcs11_lib());
1✔
386
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
387
   Slot slot(module, slot_vec.at(0));
1✔
388

389
   Session session(slot, false);
1✔
390
   SessionInfo info = session.get_info();
1✔
391
   result.test_is_eq("slot id is correct", info.slotID, slot_vec.at(0));
1✔
392
   result.test_is_eq(
1✔
393
      "state is a read write public session", info.state, static_cast<CK_STATE>(SessionState::RwPublicSession));
1✔
394

395
   session.login(UserType::User, PIN());
1✔
396
   info = session.get_info();
1✔
397
   result.test_is_eq(
1✔
398
      "state is a read write user session", info.state, static_cast<CK_STATE>(SessionState::RwUserFunctions));
1✔
399

400
   session.logoff();
1✔
401
   result.test_success("user login/logout succeeded");
1✔
402

403
   session.login(UserType::SO, SO_PIN());
1✔
404
   result.test_success("SO login succeeded");
1✔
405

406
   return result;
1✔
407
}
2✔
408

409
class Session_Tests final : public Test {
×
410
   public:
411
      std::vector<Test::Result> run() override {
1✔
412
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
413
            {STRING_AND_FUNCTION(test_session_ctor)},
414
            {STRING_AND_FUNCTION(test_session_ctor_invalid_slot)},
415
            {STRING_AND_FUNCTION(test_session_release)},
416
            {STRING_AND_FUNCTION(test_session_login_logout)},
417
            {STRING_AND_FUNCTION(test_session_info)}};
6✔
418

419
         return run_pkcs11_tests("Session", fns);
2✔
420
      }
2✔
421
};
422

423
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-session", Session_Tests);
424

425
/***************************** Object *****************************/
426

427
Test::Result test_attribute_container() {
1✔
428
   Test::Result result("AttributeContainer");
1✔
429

430
   AttributeContainer attributes;
1✔
431
   attributes.add_class(ObjectClass::PrivateKey);
1✔
432

433
   std::string label("test");
1✔
434
   attributes.add_string(AttributeType::Label, label);
1✔
435

436
   std::vector<uint8_t> bin(4);
1✔
437
   attributes.add_binary(AttributeType::Value, bin);
1✔
438

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

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

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

459
   return result;
2✔
460
}
1✔
461

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

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

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

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

480
   return data_obj_props;
4✔
481
}
8✔
482

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

487
   TestSession test_session(true);
1✔
488

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

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

497
   return result;
2✔
498
}
1✔
499

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

503
   TestSession test_session(true);
1✔
504

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

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

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

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

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

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

532
   TestSession test_session(true);
1✔
533

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

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

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

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

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

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

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

565
   TestSession test_session(true);
1✔
566

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

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

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

581
   data_obj.destroy();
1✔
582

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

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

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

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

609
/***************************** PKCS11 RSA *****************************/
610

611
   #if defined(BOTAN_HAS_RSA)
612

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

616
   TestSession test_session(true);
1✔
617

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

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

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

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

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

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

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

649
   TestSession test_session(true);
1✔
650

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

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

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

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

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

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

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

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

686
   TestSession test_session(true);
1✔
687

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

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

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

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

703
   pk.destroy();
1✔
704

705
   return result;
2✔
706
}
2✔
707

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

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

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

721
   pk.destroy();
1✔
722

723
   return result;
1✔
724
}
1✔
725

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

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

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

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

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

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

755
   return result;
1✔
756
}
1✔
757

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

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

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

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

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

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

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

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

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

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

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

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

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

811
   return result;
2✔
812
}
2✔
813

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

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

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

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

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

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

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

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

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

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

861
   return result;
2✔
862
}
2✔
863

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

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

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

883
/***************************** PKCS11 ECDSA *****************************/
884

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

893
   #if defined(BOTAN_HAS_ECDSA)
894

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

898
   TestSession test_session(true);
1✔
899

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

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

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

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

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

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

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

928
   TestSession test_session(true);
1✔
929

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

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

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

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

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

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

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

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

963
   TestSession test_session(true);
1✔
964

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

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

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

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

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

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

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

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

992
   TestSession test_session(true);
1✔
993

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

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

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

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

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

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

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

1016
   pk.destroy();
1✔
1017

1018
   return result;
2✔
1019
}
3✔
1020

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

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

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

1033
   pk.destroy();
1✔
1034

1035
   return result;
1✔
1036
}
1✔
1037

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

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

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

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

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

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

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

1076
   return result;
1✔
1077
}
1✔
1078

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1133
   return result;
4✔
1134
}
2✔
1135

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

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

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

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

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

1165
   #endif
1166

1167
   #if defined(BOTAN_HAS_ECDH)
1168

1169
/***************************** PKCS11 ECDH *****************************/
1170

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

1174
   TestSession test_session(true);
1✔
1175

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

1178
   // create ecdh private key
1179
   ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
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

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

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

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

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

1201
   TestSession test_session(true);
1✔
1202

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

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

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

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

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

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

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

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

1231
   TestSession test_session(true);
1✔
1232

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

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

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

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

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

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

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

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

1260
   TestSession test_session(true);
1✔
1261

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

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

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

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

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

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

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

1284
   pk.destroy();
1✔
1285

1286
   return result;
2✔
1287
}
3✔
1288

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

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

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

1301
   pk.destroy();
1✔
1302

1303
   return result;
1✔
1304
}
1✔
1305

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

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

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

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

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

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

1336
   return result;
2✔
1337
}
1✔
1338

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

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

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

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

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

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

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

1363
   return result;
2✔
1364
}
5✔
1365

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

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

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

1384
   #endif
1385

1386
/***************************** PKCS11 RNG *****************************/
1387

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

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

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

1399
   return result;
2✔
1400
}
1✔
1401

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

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

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

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

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

1423
   return result;
2✔
1424
}
2✔
1425

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1483
   return result;
2✔
1484
}
1✔
1485

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

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

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

1496
   return result;
2✔
1497
}
1✔
1498

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

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

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

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

1512
   return result;
2✔
1513
}
1✔
1514

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

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

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

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

1528
   return result;
2✔
1529
}
1✔
1530

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

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

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

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

1548
   #if defined(BOTAN_HAS_X509_CERTIFICATES)
1549

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

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

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

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

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

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

1571
   return result;
2✔
1572
}
1✔
1573

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

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

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

1586
   #endif
1587

1588
}  // namespace
1589

1590
#endif
1591

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

© 2026 Coveralls, Inc