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

randombit / botan / 12805544433

16 Jan 2025 09:08AM UTC coverage: 90.876% (-0.4%) from 91.245%
12805544433

Pull #4540

github

web-flow
Merge cc1ceff51 into 9b798efbb
Pull Request #4540: PKCS #11 Version 3.2 Support

93425 of 102805 relevant lines covered (90.88%)

11409241.89 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_ENTROPY_SOURCE)
30
   #include <botan/entropy_src.h>
31
#endif
32

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

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

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

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

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

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

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

65
namespace Botan_Tests {
66

67
#if defined(BOTAN_HAS_PKCS11)
68

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

73
   for(size_t i = 0; i != fns.size(); ++i) {
86✔
74
      try {
75✔
75
         results.push_back(fns[i].second());
150✔
76
      } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
×
77
         results.push_back(Test::Result::Failure(name + " test " + fns[i].first, e.what()));
×
78

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

87
   return results;
11✔
88
}
×
89

90
namespace {
91

92
using namespace Botan;
93
using namespace PKCS11;
94

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

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

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

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

116
/***************************** Module *****************************/
117

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

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

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

126
   return result;
1✔
127
}
1✔
128

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

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

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

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

140
   return result;
1✔
141
}
1✔
142

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

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

150
   return result;
1✔
151
}
1✔
152

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

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

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

161
   return result;
1✔
162
}
1✔
163

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

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

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

179
/***************************** Slot *****************************/
180

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

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

188
   return result;
2✔
189
}
1✔
190

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

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

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

201
   return result;
2✔
202
}
1✔
203

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

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

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

215
   return result;
2✔
216
}
2✔
217

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

221
   SlotId invalid_id = 0;
2✔
222

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

228
   return invalid_id;
2✔
229
}
2✔
230

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

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

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

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

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

242
   return result;
1✔
243
}
1✔
244

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

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

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

256
   return result;
2✔
257
}
2✔
258

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

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

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

269
   return result;
2✔
270
}
2✔
271

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

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

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

282
   return result;
2✔
283
}
1✔
284

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

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

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

303
/***************************** Session *****************************/
304

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

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

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

331
   return result;
2✔
332
}
1✔
333

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

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

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

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

344
   return result;
1✔
345
}
1✔
346

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

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

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

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

360
   return result;
1✔
361
}
2✔
362

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

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

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

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

378
   return result;
1✔
379
}
2✔
380

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

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

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

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

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

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

405
   return result;
1✔
406
}
2✔
407

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

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

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

424
/***************************** Object *****************************/
425

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

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

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

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

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

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

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

458
   return result;
2✔
459
}
1✔
460

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

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

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

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

479
   return data_obj_props;
4✔
480
}
8✔
481

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

486
   TestSession test_session(true);
1✔
487

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

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

496
   return result;
2✔
497
}
1✔
498

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

502
   TestSession test_session(true);
1✔
503

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

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

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

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

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

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

531
   TestSession test_session(true);
1✔
532

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

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

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

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

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

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

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

564
   TestSession test_session(true);
1✔
565

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

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

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

580
   data_obj.destroy();
1✔
581

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

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

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

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

608
/***************************** PKCS11 RSA *****************************/
609

610
   #if defined(BOTAN_HAS_RSA)
611

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

615
   TestSession test_session(true);
1✔
616

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

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

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

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

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

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

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

648
   TestSession test_session(true);
1✔
649

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

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

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

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

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

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

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

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

685
   TestSession test_session(true);
1✔
686

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

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

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

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

702
   pk.destroy();
1✔
703

704
   return result;
2✔
705
}
2✔
706

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

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

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

720
   pk.destroy();
1✔
721

722
   return result;
1✔
723
}
1✔
724

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

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

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

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

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

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

754
   return result;
1✔
755
}
1✔
756

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

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

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

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

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

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

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

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

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

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

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

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

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

810
   return result;
2✔
811
}
2✔
812

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

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

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

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

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

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

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

848
   // single-part sign
849
   sign_and_verify("Raw", false);
1✔
850
   sign_and_verify("EMSA3(SHA-256)", false);
1✔
851
   sign_and_verify("EMSA4(SHA-256)", false);
1✔
852

853
   // multi-part sign
854
   sign_and_verify("EMSA3(SHA-256)", true);
1✔
855
   sign_and_verify("EMSA4(SHA-256)", true);
1✔
856

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

860
   return result;
2✔
861
}
2✔
862

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

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

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

882
/***************************** PKCS11 ECDSA *****************************/
883

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

892
   #if defined(BOTAN_HAS_ECDSA)
893

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

897
   TestSession test_session(true);
1✔
898

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

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

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

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

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

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

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

927
   TestSession test_session(true);
1✔
928

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

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

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

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

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

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

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

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

962
   TestSession test_session(true);
1✔
963

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

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

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

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

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

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

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

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

991
   TestSession test_session(true);
1✔
992

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

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

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

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

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

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

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

1015
   pk.destroy();
1✔
1016

1017
   return result;
2✔
1018
}
3✔
1019

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

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

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

1032
   pk.destroy();
1✔
1033

1034
   return result;
1✔
1035
}
1✔
1036

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

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

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

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

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

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

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

1075
   return result;
1✔
1076
}
1✔
1077

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1132
   return result;
4✔
1133
}
2✔
1134

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

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

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

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

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

1164
   #endif
1165

1166
   #if defined(BOTAN_HAS_ECDH)
1167

1168
/***************************** PKCS11 ECDH *****************************/
1169

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

1173
   TestSession test_session(true);
1✔
1174

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

1177
   // create ecdh private key
1178
   ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1179

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

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

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

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

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

1200
   TestSession test_session(true);
1✔
1201

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

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

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

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

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

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

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

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

1230
   TestSession test_session(true);
1✔
1231

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

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

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

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

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

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

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

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

1259
   TestSession test_session(true);
1✔
1260

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

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

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

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

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

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

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

1283
   pk.destroy();
1✔
1284

1285
   return result;
2✔
1286
}
3✔
1287

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

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

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

1300
   pk.destroy();
1✔
1301

1302
   return result;
1✔
1303
}
1✔
1304

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

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

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

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

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

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

1335
   return result;
2✔
1336
}
1✔
1337

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

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

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

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

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

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

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

1362
   return result;
2✔
1363
}
5✔
1364

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

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

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

1383
   #endif
1384

1385
/***************************** PKCS11 RNG *****************************/
1386

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

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

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

1398
   return result;
2✔
1399
}
1✔
1400

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

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

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

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

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

1422
   return result;
2✔
1423
}
2✔
1424

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

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

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

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

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

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

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

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

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

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

1467
/***************************** PKCS11 token management *****************************/
1468

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

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

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

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

1482
   return result;
2✔
1483
}
1✔
1484

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

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

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

1495
   return result;
2✔
1496
}
1✔
1497

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

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

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

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

1511
   return result;
2✔
1512
}
1✔
1513

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

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

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

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

1527
   return result;
2✔
1528
}
1✔
1529

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

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

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

1545
/***************************** PKCS11 token management *****************************/
1546

1547
   #if defined(BOTAN_HAS_X509_CERTIFICATES)
1548

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

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

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

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

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

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

1570
   return result;
2✔
1571
}
1✔
1572

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

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

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

1585
   #endif
1586

1587
}  // namespace
1588

1589
#endif
1590

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

© 2025 Coveralls, Inc