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

randombit / botan / 28994301380

09 Jul 2026 12:46AM UTC coverage: 89.396% (+1.7%) from 87.739%
28994301380

push

github

web-flow
Merge pull request #5712 from randombit/jack/cdp-aia-extn

Improve CDP, AIA and IDP extension decoding and handling

113303 of 126743 relevant lines covered (89.4%)

10806632.55 hits per line

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

97.96
/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 "tests.h"
11

12
#if defined(BOTAN_HAS_PKCS11)
13
   #include "test_pkcs11.h"
14
   #include <botan/p11.h>
15
   #include <botan/p11_object.h>
16
   #include <botan/p11_randomgenerator.h>
17
   #include <botan/internal/fmt.h>
18
   #include <algorithm>
19
   #include <memory>
20
   #include <numeric>
21
   #include <sstream>
22
   #include <string>
23
   #include <vector>
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
   #include <botan/mac.h>
65
#endif
66

67
namespace Botan_Tests {
68

69
#if defined(BOTAN_HAS_PKCS11)
70

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

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

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

89
   return results;
11✔
90
}
×
91

92
namespace {
93

94
using namespace Botan;
95
using namespace PKCS11;
96

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

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

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

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

118
/***************************** Module *****************************/
119

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

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

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

128
   return result;
1✔
129
}
1✔
130

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

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

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

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

142
   return result;
1✔
143
}
1✔
144

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

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

152
   return result;
1✔
153
}
1✔
154

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

158
   const Module module(Test::pkcs11_lib());
1✔
159

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

163
   return result;
1✔
164
}
1✔
165

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

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

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

181
/***************************** Slot *****************************/
182

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

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

190
   return result;
2✔
191
}
1✔
192

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

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

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

203
   return result;
2✔
204
}
1✔
205

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

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

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

217
   return result;
2✔
218
}
2✔
219

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

223
   SlotId invalid_id = 0;
2✔
224

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

230
   return invalid_id;
2✔
231
}
2✔
232

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

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

238
   const SlotId invalid_id = get_invalid_slot_id(module);
1✔
239

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

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

244
   return result;
1✔
245
}
1✔
246

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

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

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

258
   return result;
2✔
259
}
2✔
260

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

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

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

271
   return result;
2✔
272
}
2✔
273

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

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

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

284
   return result;
2✔
285
}
1✔
286

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

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

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

305
/***************************** Session *****************************/
306

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

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

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

333
   return result;
2✔
334
}
1✔
335

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

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

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

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

346
   return result;
1✔
347
}
1✔
348

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

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

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

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

362
   return result;
1✔
363
}
2✔
364

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

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

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

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

380
   return result;
1✔
381
}
2✔
382

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

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

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

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

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

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

407
   return result;
1✔
408
}
2✔
409

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

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

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

426
/***************************** Object *****************************/
427

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

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

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

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

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

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

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

463
   return result;
2✔
464
}
1✔
465

466
DataObjectProperties make_test_object(const std::string& label) {
4✔
467
   std::string value_string("test data");
4✔
468
   const secure_vector<uint8_t> value(value_string.begin(), value_string.end());
4✔
469

470
   const std::size_t id = 1337;
4✔
471
   const std::string application = "Botan test application";
4✔
472

473
   std::vector<uint8_t> encoded_id;
4✔
474
   DER_Encoder(encoded_id).encode(id);
4✔
475

476
   DataObjectProperties data_obj_props;
4✔
477
   data_obj_props.set_application(application);
4✔
478
   data_obj_props.set_label(label);
4✔
479
   data_obj_props.set_value(value);
4✔
480
   data_obj_props.set_token(true);
4✔
481
   data_obj_props.set_modifiable(true);
4✔
482
   data_obj_props.set_object_id(encoded_id);
4✔
483

484
   return data_obj_props;
4✔
485
}
8✔
486

487
   #if defined(BOTAN_HAS_ASN1)
488
Test::Result test_create_destroy_data_object() {
1✔
489
   Test::Result result("Object create/delete data object");
1✔
490

491
   const TestSession test_session(true);
1✔
492

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

498
   data_obj.destroy();
1✔
499
   result.test_success("Data object deletion  was successful");
1✔
500

501
   return result;
2✔
502
}
1✔
503

504
Test::Result test_get_set_attribute_values() {
1✔
505
   Test::Result result("Object get/set attributes");
1✔
506

507
   const TestSession test_session(true);
1✔
508

509
   // create object
510
   const std::string label = "Botan test data object";
1✔
511
   auto data_obj_props = make_test_object(label);
1✔
512
   const Object data_obj(test_session.session(), data_obj_props);
1✔
513

514
   // get attribute
515
   secure_vector<uint8_t> retrieved_label = data_obj.get_attribute_value(AttributeType::Label);
1✔
516
   std::string retrieved_label_string(retrieved_label.begin(), retrieved_label.end());
2✔
517
   result.test_str_eq("label was set correctly", retrieved_label_string, label);
1✔
518

519
   // set attribute
520
   std::string new_label = "Botan test modified data object label";
1✔
521
   const secure_vector<uint8_t> new_label_secvec(new_label.begin(), new_label.end());
1✔
522
   data_obj.set_attribute_value(AttributeType::Label, new_label_secvec);
1✔
523

524
   // get and check attribute
525
   retrieved_label = data_obj.get_attribute_value(AttributeType::Label);
2✔
526
   retrieved_label_string = std::string(retrieved_label.begin(), retrieved_label.end());
2✔
527
   result.test_str_eq("label was modified correctly", retrieved_label_string, new_label);
1✔
528

529
   data_obj.destroy();
1✔
530
   return result;
2✔
531
}
2✔
532

533
Test::Result test_object_finder() {
1✔
534
   Test::Result result("ObjectFinder");
1✔
535

536
   const TestSession test_session(true);
1✔
537

538
   // create object
539
   const std::string label = "Botan test data object";
1✔
540
   auto data_obj_props = make_test_object(label);
1✔
541
   const Object data_obj(test_session.session(), data_obj_props);
1✔
542

543
   // search created object
544
   AttributeContainer search_template;
1✔
545
   search_template.add_string(AttributeType::Label, label);
1✔
546
   ObjectFinder finder(test_session.session(), search_template.attributes());
1✔
547

548
   auto search_result = finder.find();
1✔
549
   result.test_sz_eq("one object found", search_result.size(), 1);
1✔
550
   finder.finish();
1✔
551

552
   const Object obj_found(test_session.session(), search_result.at(0));
1✔
553
   result.test_bin_eq("found the object just created (same application)",
1✔
554
                      obj_found.get_attribute_value(AttributeType::Application),
2✔
555
                      data_obj.get_attribute_value(AttributeType::Application));
1✔
556

557
   auto search_result2 = Object::search<Object>(test_session.session(), search_template.attributes());
1✔
558
   result.test_bin_eq("found the object just created (same label)",
2✔
559
                      obj_found.get_attribute_value(AttributeType::Label),
2✔
560
                      search_result2.at(0).get_attribute_value(AttributeType::Label));
1✔
561

562
   data_obj.destroy();
1✔
563
   return result;
1✔
564
}
2✔
565

566
Test::Result test_object_copy() {
1✔
567
   Test::Result result("Object copy");
1✔
568

569
   const TestSession test_session(true);
1✔
570

571
   // create object
572
   const std::string label = "Botan test data object";
1✔
573
   auto data_obj_props = make_test_object(label);
1✔
574
   const Object data_obj(test_session.session(), data_obj_props);
1✔
575

576
   // copy created object
577
   AttributeContainer copy_attributes;
1✔
578
   copy_attributes.add_string(AttributeType::Label, "Botan test copied object");
1✔
579
   const ObjectHandle copied_obj_handle = data_obj.copy(copy_attributes);
1✔
580

581
   const ObjectFinder searcher(test_session.session(), copy_attributes.attributes());
1✔
582
   auto search_result = searcher.find();
1✔
583
   result.test_sz_eq("one object found", search_result.size(), 1);
1✔
584

585
   data_obj.destroy();
1✔
586

587
   const Object copied_obj(test_session.session(), copied_obj_handle);
1✔
588
   copied_obj.destroy();
1✔
589
   return result;
2✔
590
}
2✔
591
   #endif
592

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

607
         return run_pkcs11_tests("Object", fns);
2✔
608
      }
2✔
609
};
610

611
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-object", Object_Tests);
612

613
/***************************** PKCS11 RSA *****************************/
614

615
   #if defined(BOTAN_HAS_RSA)
616

617
Test::Result test_rsa_privkey_import() {
1✔
618
   Test::Result result("PKCS11 import RSA private key");
1✔
619

620
   const TestSession test_session(true);
1✔
621

622
   auto rng = Test::new_rng(__func__);
1✔
623

624
   // create private key
625
   const RSA_PrivateKey priv_key(*rng, 2048);
1✔
626
   result.test_is_true("Key self test OK", priv_key.check_key(*rng, true));
1✔
627

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

637
   props.set_token(true);
1✔
638
   props.set_private(true);
1✔
639
   props.set_decrypt(true);
1✔
640
   props.set_sign(true);
1✔
641

642
   const PKCS11_RSA_PrivateKey pk(test_session.session(), props);
1✔
643
   result.test_success("RSA private key import was successful");
1✔
644
   result.test_is_true("PK self test OK", pk.check_key(*rng, true));
1✔
645

646
   pk.destroy();
1✔
647
   return result;
1✔
648
}
2✔
649

650
Test::Result test_rsa_privkey_export() {
1✔
651
   Test::Result result("PKCS11 export RSA private key");
1✔
652

653
   const TestSession test_session(true);
1✔
654

655
   auto rng = Test::new_rng(__func__);
1✔
656

657
   // create private key
658
   const RSA_PrivateKey priv_key(*rng, 2048);
1✔
659

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

669
   props.set_token(true);
1✔
670
   props.set_private(true);
1✔
671
   props.set_decrypt(true);
1✔
672
   props.set_sign(true);
1✔
673
   props.set_extractable(true);
1✔
674
   props.set_sensitive(false);
1✔
675

676
   const PKCS11_RSA_PrivateKey pk(test_session.session(), props);
1✔
677
   result.test_is_true("Check PK11 key", pk.check_key(*rng, true));
1✔
678

679
   const RSA_PrivateKey exported = pk.export_key();
1✔
680
   result.test_success("RSA private key export was successful");
1✔
681
   result.test_is_true("Check exported key", exported.check_key(*rng, true));
1✔
682

683
   pk.destroy();
1✔
684
   return result;
1✔
685
}
2✔
686

687
Test::Result test_rsa_pubkey_import() {
1✔
688
   Test::Result result("PKCS11 import RSA public key");
1✔
689

690
   const TestSession test_session(true);
1✔
691

692
   auto rng = Test::new_rng(__func__);
1✔
693

694
   // create public key from private key
695
   const RSA_PrivateKey priv_key(*rng, 2048);
1✔
696

697
   // import to card
698
   RSA_PublicKeyImportProperties props(priv_key.get_n(), priv_key.get_e());
1✔
699
   props.set_token(true);
1✔
700
   props.set_encrypt(true);
1✔
701
   props.set_private(false);
1✔
702

703
   const PKCS11_RSA_PublicKey pk(test_session.session(), props);
1✔
704
   result.test_success("RSA public key import was successful");
1✔
705
   result.test_is_true("Check PK11 key", pk.check_key(*rng, true));
1✔
706

707
   pk.destroy();
1✔
708

709
   return result;
2✔
710
}
2✔
711

712
Test::Result test_rsa_generate_private_key() {
1✔
713
   Test::Result result("PKCS11 generate RSA private key");
1✔
714
   const TestSession test_session(true);
1✔
715

716
   RSA_PrivateKeyGenerationProperties props;
1✔
717
   props.set_token(true);
1✔
718
   props.set_private(true);
1✔
719
   props.set_sign(true);
1✔
720
   props.set_decrypt(true);
1✔
721

722
   const PKCS11_RSA_PrivateKey pk(test_session.session(), 2048, props);
1✔
723
   result.test_success("RSA private key generation was successful");
1✔
724

725
   pk.destroy();
1✔
726

727
   return result;
1✔
728
}
1✔
729

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

739
   RSA_PrivateKeyGenerationProperties priv_props;
3✔
740
   priv_props.set_label("BOTAN_TEST_RSA_PRIV_KEY");
3✔
741
   priv_props.set_token(true);
3✔
742
   priv_props.set_private(true);
3✔
743
   priv_props.set_sign(true);
3✔
744
   priv_props.set_decrypt(true);
3✔
745

746
   return PKCS11::generate_rsa_keypair(test_session.session(), pub_props, priv_props);
3✔
747
}
3✔
748

749
Test::Result test_rsa_generate_key_pair() {
1✔
750
   Test::Result result("PKCS11 generate RSA key pair");
1✔
751
   const TestSession test_session(true);
1✔
752

753
   const PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
754
   result.test_success("RSA key pair generation was successful");
1✔
755

756
   keypair.first.destroy();
1✔
757
   keypair.second.destroy();
1✔
758

759
   return result;
1✔
760
}
1✔
761

762
Test::Result test_rsa_encrypt_decrypt() {
1✔
763
   Test::Result result("PKCS11 RSA encrypt decrypt");
1✔
764
   const TestSession test_session(true);
1✔
765

766
   // generate key pair
767
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
768

769
   auto rng = Test::new_rng(__func__);
1✔
770

771
   auto encrypt_and_decrypt =
1✔
772
      [&](const std::vector<uint8_t>& plaintext, const std::string& padding, const bool blinding) {
5✔
773
         std::vector<uint8_t> encrypted;
5✔
774

775
         try {
5✔
776
            const Botan::PK_Encryptor_EME encryptor(keypair.first, *rng, padding);
5✔
777
            encrypted = encryptor.encrypt(plaintext, *rng);
5✔
778
            result.test_sz_lte(
5✔
779
               "ciphertext length estimate", encrypted.size(), encryptor.ciphertext_length(plaintext.size()));
780
         } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
5✔
781
            result.test_failure("PKCS11 RSA encrypt " + padding, e.what());
×
782
         }
×
783

784
         Botan::secure_vector<uint8_t> decrypted;
5✔
785

786
         try {
5✔
787
            keypair.second.set_use_software_padding(blinding);
5✔
788
            const Botan::PK_Decryptor_EME decryptor(keypair.second, *rng, padding);
5✔
789
            decrypted = decryptor.decrypt(encrypted);
5✔
790

791
            result.test_sz_lte(
5✔
792
               "plaintext length estimate", decrypted.size(), decryptor.plaintext_length(encrypted.size()));
793
            result.test_sz_lte(
5✔
794
               "ciphertext length estimate", encrypted.size(), decryptor.ciphertext_length(decrypted.size()));
795
         } catch(Botan::PKCS11::PKCS11_ReturnError& e) {
5✔
796
            std::ostringstream err;
×
797
            err << "PKCS11 RSA decrypt " << padding;
×
798
            if(blinding) {
×
799
               err << " with userspace blinding";
×
800
            }
801

802
            result.test_failure(err.str(), e.what());
×
803
         }
×
804

805
         result.test_bin_eq("RSA PKCS11 encrypt and decrypt: " + padding, decrypted, plaintext);
10✔
806
      };
10✔
807

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

812
   plaintext = {0x00, 0x01, 0x02, 0x03, 0x04, 0x00};
1✔
813
   encrypt_and_decrypt(plaintext, "EME-PKCS1-v1_5", false);
1✔
814
   encrypt_and_decrypt(plaintext, "EME-PKCS1-v1_5", true);
1✔
815

816
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", false);
1✔
817
   encrypt_and_decrypt(plaintext, "OAEP(SHA-1)", true);
1✔
818

819
   keypair.first.destroy();
1✔
820
   keypair.second.destroy();
1✔
821

822
   return result;
2✔
823
}
2✔
824

825
Test::Result test_rsa_sign_verify() {
1✔
826
   Test::Result result("PKCS11 RSA sign and verify");
1✔
827
   const TestSession test_session(true);
1✔
828

829
   // generate key pair
830
   PKCS11_RSA_KeyPair keypair = generate_rsa_keypair(test_session);
1✔
831

832
   auto rng = Test::new_rng(__func__);
1✔
833

834
   std::vector<uint8_t> plaintext(256);
1✔
835
   std::iota(std::begin(plaintext), std::end(plaintext), static_cast<uint8_t>(0));
1✔
836

837
   auto sign_and_verify = [&](const std::string& padding, bool multipart) {
6✔
838
      Botan::PK_Signer signer(keypair.second, *rng, padding, Botan::Signature_Format::Standard);
5✔
839
      std::vector<uint8_t> signature;
5✔
840
      if(multipart) {
5✔
841
         signer.update(plaintext.data(), plaintext.size() / 2);
2✔
842
         signature = signer.sign_message(plaintext.data() + plaintext.size() / 2, plaintext.size() / 2, *rng);
4✔
843
      } else {
844
         signature = signer.sign_message(plaintext, *rng);
6✔
845
      }
846

847
      Botan::PK_Verifier verifier(keypair.first, padding, Botan::Signature_Format::Standard);
5✔
848
      bool rsa_ok = false;
5✔
849
      if(multipart) {
5✔
850
         verifier.update(plaintext.data(), plaintext.size() / 2);
2✔
851
         rsa_ok = verifier.verify_message(
2✔
852
            plaintext.data() + plaintext.size() / 2, plaintext.size() / 2, signature.data(), signature.size());
2✔
853
      } else {
854
         rsa_ok = verifier.verify_message(plaintext, signature);
3✔
855
      }
856

857
      result.test_is_true("RSA PKCS11 sign and verify: " + padding, rsa_ok);
5✔
858
   };
10✔
859

860
   // single-part sign
861
   sign_and_verify("Raw", false);
1✔
862
   sign_and_verify("PKCS1v15(SHA-256)", false);
1✔
863
   sign_and_verify("PSS(SHA-256)", false);
1✔
864

865
   // multi-part sign
866
   sign_and_verify("PKCS1v15(SHA-256)", true);
1✔
867
   sign_and_verify("PSS(SHA-256)", true);
1✔
868

869
   keypair.first.destroy();
1✔
870
   keypair.second.destroy();
1✔
871

872
   return result;
2✔
873
}
2✔
874

875
class PKCS11_RSA_Tests final : public Test {
1✔
876
   public:
877
      std::vector<Test::Result> run() override {
1✔
878
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
879
            {STRING_AND_FUNCTION(test_rsa_privkey_import)},
880
            {STRING_AND_FUNCTION(test_rsa_pubkey_import)},
881
            {STRING_AND_FUNCTION(test_rsa_privkey_export)},
882
            {STRING_AND_FUNCTION(test_rsa_generate_private_key)},
883
            {STRING_AND_FUNCTION(test_rsa_generate_key_pair)},
884
            {STRING_AND_FUNCTION(test_rsa_encrypt_decrypt)},
885
            {STRING_AND_FUNCTION(test_rsa_sign_verify)}};
8✔
886

887
         return run_pkcs11_tests("PKCS11 RSA", fns);
2✔
888
      }
2✔
889
};
890

891
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rsa", PKCS11_RSA_Tests);
892
   #endif
893

894
/***************************** PKCS11 ECDSA *****************************/
895

896
   #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
897
std::vector<uint8_t> encode_ec_point_in_octet_str(const Botan::EC_PublicKey& pk) {
4✔
898
   std::vector<uint8_t> enc;
4✔
899
   DER_Encoder(enc).encode(pk._public_ec_point().serialize_uncompressed(), ASN1_Type::OctetString);
8✔
900
   return enc;
4✔
901
}
×
902
   #endif
903

904
   #if defined(BOTAN_HAS_ECDSA)
905

906
Test::Result test_ecdsa_privkey_import() {
1✔
907
   Test::Result result("PKCS11 import ECDSA private key");
1✔
908

909
   const TestSession test_session(true);
1✔
910

911
   auto rng = Test::new_rng(__func__);
1✔
912

913
   // create ecdsa private key
914
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
915
   result.test_is_true("Key self test OK", priv_key.check_key(*rng, true));
1✔
916

917
   // import to card
918
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
919
   props.set_token(true);
1✔
920
   props.set_private(true);
1✔
921
   props.set_sign(true);
1✔
922

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

927
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
1✔
928
   result.test_success("ECDSA private key import was successful");
1✔
929
   pk.set_public_point(priv_key._public_ec_point());
1✔
930
   result.test_is_true("P11 key self test OK", pk.check_key(*rng, false));
1✔
931

932
   pk.destroy();
1✔
933
   return result;
1✔
934
}
2✔
935

936
Test::Result test_ecdsa_privkey_export() {
1✔
937
   Test::Result result("PKCS11 export ECDSA private key");
1✔
938

939
   const TestSession test_session(true);
1✔
940

941
   auto rng = Test::new_rng(__func__);
1✔
942

943
   // create private key
944
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
945

946
   result.test_is_true("Check ECDSA key", priv_key.check_key(*rng, true));
1✔
947
   // import to card
948
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
949
   props.set_token(true);
1✔
950
   props.set_private(true);
1✔
951
   props.set_sign(true);
1✔
952
   props.set_extractable(true);
1✔
953

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

958
   PKCS11_ECDSA_PrivateKey pk(test_session.session(), props);
1✔
959
   pk.set_public_point(priv_key._public_ec_point());
1✔
960
   result.test_is_true("Check PK11 key", pk.check_key(*rng, false));
1✔
961

962
   const ECDSA_PrivateKey exported = pk.export_key();
1✔
963
   result.test_success("ECDSA private key export was successful");
1✔
964
   result.test_is_true("Check exported key valid", exported.check_key(*rng, true));
1✔
965
   result.test_bin_eq("Check exported key contents", exported.private_key_bits(), priv_key.private_key_bits());
2✔
966

967
   pk.destroy();
1✔
968
   return result;
1✔
969
}
2✔
970

971
Test::Result test_ecdsa_pubkey_import() {
1✔
972
   Test::Result result("PKCS11 import ECDSA public key");
1✔
973

974
   const TestSession test_session(true);
1✔
975

976
   auto rng = Test::new_rng(__func__);
1✔
977

978
   // create ecdsa private key
979
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
980

981
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
982

983
   // import to card
984
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
985
   props.set_token(true);
1✔
986
   props.set_verify(true);
1✔
987
   props.set_private(false);
1✔
988

989
   // label
990
   const std::string label = "Botan test ecdsa pub key";
1✔
991
   props.set_label(label);
1✔
992

993
   const PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
994
   result.test_success("ECDSA public key import was successful");
1✔
995

996
   pk.destroy();
1✔
997
   return result;
1✔
998
}
3✔
999

1000
Test::Result test_ecdsa_pubkey_export() {
1✔
1001
   Test::Result result("PKCS11 export ECDSA public key");
1✔
1002

1003
   const TestSession test_session(true);
1✔
1004

1005
   auto rng = Test::new_rng(__func__);
1✔
1006

1007
   // create public key from private key
1008
   const ECDSA_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1009

1010
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
1011

1012
   // import to card
1013
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
1014
   props.set_token(true);
1✔
1015
   props.set_verify(true);
1✔
1016
   props.set_private(false);
1✔
1017

1018
   // label
1019
   const std::string label = "Botan test ecdsa pub key";
1✔
1020
   props.set_label(label);
1✔
1021

1022
   const PKCS11_ECDSA_PublicKey pk(test_session.session(), props);
1✔
1023

1024
   const ECDSA_PublicKey exported = pk.export_key();
1✔
1025
   result.test_success("ECDSA public key export was successful");
1✔
1026

1027
   pk.destroy();
1✔
1028

1029
   return result;
2✔
1030
}
3✔
1031

1032
Test::Result test_ecdsa_generate_private_key() {
1✔
1033
   Test::Result result("PKCS11 generate ECDSA private key");
1✔
1034
   const TestSession test_session(true);
1✔
1035

1036
   EC_PrivateKeyGenerationProperties props;
1✔
1037
   props.set_token(true);
1✔
1038
   props.set_private(true);
1✔
1039
   props.set_sign(true);
1✔
1040

1041
   const PKCS11_ECDSA_PrivateKey pk(test_session.session(), EC_Group::from_name("secp256r1").DER_encode(), props);
2✔
1042
   result.test_success("ECDSA private key generation was successful");
1✔
1043

1044
   pk.destroy();
1✔
1045

1046
   return result;
1✔
1047
}
1✔
1048

1049
PKCS11_ECDSA_KeyPair generate_ecdsa_keypair(const TestSession& test_session,
6✔
1050
                                            const std::string& curve,
1051
                                            EC_Group_Encoding enc) {
1052
   EC_PublicKeyGenerationProperties pub_props(EC_Group::from_name(curve).DER_encode(enc));
12✔
1053
   pub_props.set_label("BOTAN_TEST_ECDSA_PUB_KEY");
6✔
1054
   pub_props.set_token(true);
6✔
1055
   pub_props.set_verify(true);
6✔
1056
   pub_props.set_private(false);
6✔
1057
   pub_props.set_modifiable(true);
6✔
1058

1059
   EC_PrivateKeyGenerationProperties priv_props;
6✔
1060
   priv_props.set_label("BOTAN_TEST_ECDSA_PRIV_KEY");
6✔
1061
   priv_props.set_token(true);
6✔
1062
   priv_props.set_private(true);
6✔
1063
   priv_props.set_sensitive(true);
6✔
1064
   priv_props.set_extractable(false);
6✔
1065
   priv_props.set_sign(true);
6✔
1066
   priv_props.set_modifiable(true);
6✔
1067

1068
   return PKCS11::generate_ecdsa_keypair(test_session.session(), pub_props, priv_props);
12✔
1069
}
6✔
1070

1071
Test::Result test_ecdsa_generate_keypair() {
1✔
1072
   Test::Result result("PKCS11 generate ECDSA key pair");
1✔
1073
   const TestSession test_session(true);
1✔
1074
   std::vector<std::string> curves;
1✔
1075

1076
   curves.push_back("secp256r1");
2✔
1077
   curves.push_back("brainpool512r1");
2✔
1078

1079
   for(const auto& curve : curves) {
3✔
1080
      const PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session, curve, EC_Group_Encoding::NamedCurve);
2✔
1081

1082
      keypair.first.destroy();
2✔
1083
      keypair.second.destroy();
2✔
1084
   }
2✔
1085
   result.test_success("ECDSA key pair generation was successful");
1✔
1086

1087
   return result;
1✔
1088
}
1✔
1089

1090
Test::Result test_ecdsa_sign_verify_core(EC_Group_Encoding enc, const std::string& test_name) {
2✔
1091
   Test::Result result(test_name);
2✔
1092
   const TestSession test_session(true);
2✔
1093
   std::vector<std::string> curves;
2✔
1094

1095
   curves.push_back("secp256r1");
4✔
1096
   curves.push_back("brainpool512r1");
4✔
1097

1098
   const Slot& slot = test_session.slot();
2✔
1099
   SlotInfo info = slot.get_slot_info();
2✔
1100
   const std::string manufacturer(reinterpret_cast<char*>(info.manufacturerID));
2✔
1101

1102
   auto rng = Test::new_rng(__func__);
2✔
1103

1104
   for(const auto& curve : curves) {
6✔
1105
      // generate key pair
1106
      PKCS11_ECDSA_KeyPair keypair = generate_ecdsa_keypair(test_session, curve, enc);
4✔
1107

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

1110
      auto sign_and_verify = [&](const std::string& padding, const Botan::Signature_Format format, bool check_soft) {
8✔
1111
         Botan::PK_Signer signer(keypair.second, *rng, padding, format);
4✔
1112
         auto signature = signer.sign_message(plaintext, *rng);
4✔
1113

1114
         Botan::PK_Verifier token_verifier(keypair.first, padding, format);
4✔
1115
         const bool ecdsa_ok = token_verifier.verify_message(plaintext, signature);
4✔
1116

1117
         result.test_is_true("ECDSA PKCS11 sign and verify: " + padding, ecdsa_ok);
4✔
1118

1119
         // test against software implementation if available
1120
         if(check_soft) {
4✔
1121
            Botan::PK_Verifier soft_verifier(keypair.first, padding, format);
4✔
1122
            const bool soft_ecdsa_ok = soft_verifier.verify_message(plaintext, signature);
4✔
1123

1124
            result.test_is_true("ECDSA PKCS11 verify (in software): " + padding, soft_ecdsa_ok);
4✔
1125
         }
4✔
1126
      };
8✔
1127

1128
      // SoftHSMv2 until now only supports "Raw"
1129
      if(manufacturer.find("SoftHSM project") == std::string::npos) {
4✔
1130
         sign_and_verify("SHA-256", Botan::Signature_Format::Standard, true);
×
1131
         sign_and_verify("SHA-256", Botan::Signature_Format::DerSequence, true);
×
1132
      }
1133

1134
      #if defined(BOTAN_HAS_EMSA_RAW)
1135
      sign_and_verify("Raw", Botan::Signature_Format::Standard, true);
4✔
1136
      #else
1137
      sign_and_verify("Raw", Botan::Signature_Format::Standard, false);
1138
      #endif
1139

1140
      keypair.first.destroy();
4✔
1141
      keypair.second.destroy();
4✔
1142
   }
8✔
1143

1144
   return result;
4✔
1145
}
2✔
1146

1147
Test::Result test_ecdsa_sign_verify() {
1✔
1148
   // pass the curve OID to the PKCS#11 library
1149
   return test_ecdsa_sign_verify_core(EC_Group_Encoding::NamedCurve, "PKCS11 ECDSA sign and verify");
2✔
1150
}
1151

1152
Test::Result test_ecdsa_curve_import() {
1✔
1153
   // pass the curve parameters to the PKCS#11 library and perform sign/verify to test them
1154
   return test_ecdsa_sign_verify_core(EC_Group_Encoding::Explicit, "PKCS11 ECDSA sign and verify with imported curve");
2✔
1155
}
1156

1157
class PKCS11_ECDSA_Tests final : public Test {
1✔
1158
   public:
1159
      std::vector<Test::Result> run() override {
1✔
1160
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1161
            {STRING_AND_FUNCTION(test_ecdsa_privkey_import)},
1162
            {STRING_AND_FUNCTION(test_ecdsa_privkey_export)},
1163
            {STRING_AND_FUNCTION(test_ecdsa_pubkey_import)},
1164
            {STRING_AND_FUNCTION(test_ecdsa_pubkey_export)},
1165
            {STRING_AND_FUNCTION(test_ecdsa_generate_private_key)},
1166
            {STRING_AND_FUNCTION(test_ecdsa_generate_keypair)},
1167
            {STRING_AND_FUNCTION(test_ecdsa_sign_verify)},
1168
            {STRING_AND_FUNCTION(test_ecdsa_curve_import)}};
9✔
1169

1170
         return run_pkcs11_tests("PKCS11 ECDSA", fns);
2✔
1171
      }
2✔
1172
};
1173

1174
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdsa", PKCS11_ECDSA_Tests);
1175

1176
   #endif
1177

1178
   #if defined(BOTAN_HAS_ECDH)
1179

1180
/***************************** PKCS11 ECDH *****************************/
1181

1182
Test::Result test_ecdh_privkey_import() {
1✔
1183
   Test::Result result("PKCS11 import ECDH private key");
1✔
1184

1185
   const TestSession test_session(true);
1✔
1186

1187
   auto rng = Test::new_rng(__func__);
1✔
1188

1189
   // create ecdh private key
1190
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1191

1192
   // import to card
1193
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
1194
   props.set_token(true);
1✔
1195
   props.set_private(true);
1✔
1196
   props.set_derive(true);
1✔
1197

1198
   // label
1199
   const std::string label = "Botan test ecdh key";
1✔
1200
   props.set_label(label);
1✔
1201

1202
   const PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1203
   result.test_success("ECDH private key import was successful");
1✔
1204

1205
   pk.destroy();
1✔
1206
   return result;
1✔
1207
}
2✔
1208

1209
Test::Result test_ecdh_privkey_export() {
1✔
1210
   Test::Result result("PKCS11 export ECDH private key");
1✔
1211

1212
   const TestSession test_session(true);
1✔
1213

1214
   auto rng = Test::new_rng(__func__);
1✔
1215

1216
   // create private key
1217
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1218

1219
   // import to card
1220
   EC_PrivateKeyImportProperties props(priv_key.DER_domain(), priv_key.private_value());
1✔
1221
   props.set_token(true);
1✔
1222
   props.set_private(true);
1✔
1223
   props.set_derive(true);
1✔
1224
   props.set_extractable(true);
1✔
1225

1226
   // label
1227
   const std::string label = "Botan test ecdh key";
1✔
1228
   props.set_label(label);
1✔
1229

1230
   const PKCS11_ECDH_PrivateKey pk(test_session.session(), props);
1✔
1231

1232
   const ECDH_PrivateKey exported = pk.export_key();
1✔
1233
   result.test_success("ECDH private key export was successful");
1✔
1234

1235
   pk.destroy();
1✔
1236
   return result;
1✔
1237
}
2✔
1238

1239
Test::Result test_ecdh_pubkey_import() {
1✔
1240
   Test::Result result("PKCS11 import ECDH public key");
1✔
1241

1242
   const TestSession test_session(true);
1✔
1243

1244
   auto rng = Test::new_rng(__func__);
1✔
1245

1246
   // create ECDH private key
1247
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1248

1249
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
1250

1251
   // import to card
1252
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
1253
   props.set_token(true);
1✔
1254
   props.set_private(false);
1✔
1255
   props.set_derive(true);
1✔
1256

1257
   // label
1258
   const std::string label = "Botan test ECDH pub key";
1✔
1259
   props.set_label(label);
1✔
1260

1261
   const PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1262
   result.test_success("ECDH public key import was successful");
1✔
1263

1264
   pk.destroy();
1✔
1265
   return result;
2✔
1266
}
3✔
1267

1268
Test::Result test_ecdh_pubkey_export() {
1✔
1269
   Test::Result result("PKCS11 export ECDH public key");
1✔
1270

1271
   const TestSession test_session(true);
1✔
1272

1273
   auto rng = Test::new_rng(__func__);
1✔
1274

1275
   // create public key from private key
1276
   const ECDH_PrivateKey priv_key(*rng, EC_Group::from_name("secp256r1"));
1✔
1277

1278
   const auto enc_point = encode_ec_point_in_octet_str(priv_key);
1✔
1279

1280
   // import to card
1281
   EC_PublicKeyImportProperties props(priv_key.DER_domain(), enc_point);
1✔
1282
   props.set_token(true);
1✔
1283
   props.set_derive(true);
1✔
1284
   props.set_private(false);
1✔
1285

1286
   // label
1287
   const std::string label = "Botan test ECDH pub key";
1✔
1288
   props.set_label(label);
1✔
1289

1290
   const PKCS11_ECDH_PublicKey pk(test_session.session(), props);
1✔
1291

1292
   const ECDH_PublicKey exported = pk.export_key();
1✔
1293
   result.test_success("ECDH public key export was successful");
1✔
1294

1295
   pk.destroy();
1✔
1296

1297
   return result;
2✔
1298
}
3✔
1299

1300
Test::Result test_ecdh_generate_private_key() {
1✔
1301
   Test::Result result("PKCS11 generate ECDH private key");
1✔
1302
   const TestSession test_session(true);
1✔
1303

1304
   EC_PrivateKeyGenerationProperties props;
1✔
1305
   props.set_token(true);
1✔
1306
   props.set_private(true);
1✔
1307
   props.set_derive(true);
1✔
1308

1309
   const PKCS11_ECDH_PrivateKey pk(test_session.session(), EC_Group::from_name("secp256r1").DER_encode(), props);
2✔
1310
   result.test_success("ECDH private key generation was successful");
1✔
1311

1312
   pk.destroy();
1✔
1313

1314
   return result;
1✔
1315
}
1✔
1316

1317
PKCS11_ECDH_KeyPair generate_ecdh_keypair(const TestSession& test_session, const std::string& label) {
3✔
1318
   EC_PublicKeyGenerationProperties pub_props(EC_Group::from_name("secp256r1").DER_encode());
6✔
1319
   pub_props.set_label(label + "_PUB_KEY");
3✔
1320
   pub_props.set_token(true);
3✔
1321
   pub_props.set_derive(true);
3✔
1322
   pub_props.set_private(false);
3✔
1323
   pub_props.set_modifiable(true);
3✔
1324

1325
   EC_PrivateKeyGenerationProperties priv_props;
3✔
1326
   priv_props.set_label(label + "_PRIV_KEY");
3✔
1327
   priv_props.set_token(true);
3✔
1328
   priv_props.set_private(true);
3✔
1329
   priv_props.set_sensitive(true);
3✔
1330
   priv_props.set_extractable(false);
3✔
1331
   priv_props.set_derive(true);
3✔
1332
   priv_props.set_modifiable(true);
3✔
1333

1334
   return PKCS11::generate_ecdh_keypair(test_session.session(), pub_props, priv_props);
6✔
1335
}
3✔
1336

1337
Test::Result test_ecdh_generate_keypair() {
1✔
1338
   Test::Result result("PKCS11 generate ECDH key pair");
1✔
1339
   const TestSession test_session(true);
1✔
1340

1341
   const PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
1✔
1342
   result.test_success("ECDH key pair generation was successful");
1✔
1343

1344
   keypair.first.destroy();
1✔
1345
   keypair.second.destroy();
1✔
1346

1347
   return result;
2✔
1348
}
1✔
1349

1350
Test::Result test_ecdh_derive() {
1✔
1351
   Test::Result result("PKCS11 ECDH derive");
1✔
1352
   const TestSession test_session(true);
1✔
1353

1354
   const PKCS11_ECDH_KeyPair keypair = generate_ecdh_keypair(test_session, "Botan test ECDH key1");
1✔
1355
   const PKCS11_ECDH_KeyPair keypair2 = generate_ecdh_keypair(test_session, "Botan test ECDH key2");
1✔
1356

1357
   auto rng = Test::new_rng(__func__);
1✔
1358

1359
   // SoftHSMv2 only supports CKD_NULL KDF at the moment
1360
   const Botan::PK_Key_Agreement ka(keypair.second, *rng, "Raw");
1✔
1361
   const Botan::PK_Key_Agreement kb(keypair2.second, *rng, "Raw");
1✔
1362

1363
   const Botan::SymmetricKey alice_key = ka.derive_key(32, keypair2.first.raw_public_key_bits());
1✔
1364
   const Botan::SymmetricKey bob_key = kb.derive_key(32, keypair.first.raw_public_key_bits());
1✔
1365

1366
   const bool eq = alice_key == bob_key;
1✔
1367
   result.test_is_true("same secret key derived", eq);
1✔
1368

1369
   keypair.first.destroy();
1✔
1370
   keypair.second.destroy();
1✔
1371
   keypair2.first.destroy();
1✔
1372
   keypair2.second.destroy();
1✔
1373

1374
   return result;
2✔
1375
}
5✔
1376

1377
class PKCS11_ECDH_Tests final : public Test {
1✔
1378
   public:
1379
      std::vector<Test::Result> run() override {
1✔
1380
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1381
            {STRING_AND_FUNCTION(test_ecdh_privkey_import)},
1382
            {STRING_AND_FUNCTION(test_ecdh_privkey_export)},
1383
            {STRING_AND_FUNCTION(test_ecdh_pubkey_import)},
1384
            {STRING_AND_FUNCTION(test_ecdh_pubkey_export)},
1385
            {STRING_AND_FUNCTION(test_ecdh_generate_private_key)},
1386
            {STRING_AND_FUNCTION(test_ecdh_generate_keypair)},
1387
            {STRING_AND_FUNCTION(test_ecdh_derive)}};
8✔
1388

1389
         return run_pkcs11_tests("PKCS11 ECDH", fns);
2✔
1390
      }
2✔
1391
};
1392

1393
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-ecdh", PKCS11_ECDH_Tests);
1394

1395
   #endif
1396

1397
/***************************** PKCS11 RNG *****************************/
1398

1399
Test::Result test_rng_generate_random() {
1✔
1400
   Test::Result result("PKCS11 RNG generate random");
1✔
1401
   const TestSession test_session(true);
1✔
1402

1403
   PKCS11_RNG p11_rng(test_session.session());
1✔
1404
   result.test_is_true("RNG already seeded", p11_rng.is_seeded());
1✔
1405

1406
   std::vector<uint8_t> random(20);
1✔
1407
   p11_rng.randomize(random.data(), random.size());
1✔
1408
   result.test_bin_ne("random data generated", random, std::vector<uint8_t>(20));
1✔
1409

1410
   return result;
2✔
1411
}
1✔
1412

1413
Test::Result test_rng_add_entropy() {
1✔
1414
   Test::Result result("PKCS11 RNG add entropy random");
1✔
1415
   const TestSession test_session(true);
1✔
1416

1417
   PKCS11_RNG p11_rng(test_session.session());
1✔
1418

1419
   result.test_is_true("RNG already seeded", p11_rng.is_seeded());
1✔
1420
   p11_rng.clear();
1✔
1421
   result.test_is_true("RNG ignores call to clear", p11_rng.is_seeded());
1✔
1422

1423
   #if defined(BOTAN_HAS_ENTROPY_SOURCE)
1424
   result.test_sz_eq(
1✔
1425
      "RNG ignores calls to reseed", p11_rng.reseed_from_sources(Botan::Entropy_Sources::global_sources(), 256), 0);
1426
   #endif
1427

1428
   auto rng = Test::new_rng(__func__);
1✔
1429
   auto random = rng->random_vec(20);
1✔
1430
   p11_rng.add_entropy(random.data(), random.size());
1✔
1431
   result.test_success("entropy added");
1✔
1432

1433
   return result;
2✔
1434
}
2✔
1435

1436
   #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
1437

1438
Test::Result test_pkcs11_hmac_drbg() {
1✔
1439
   Test::Result result("PKCS11 HMAC_DRBG using PKCS11_RNG");
1✔
1440
   const TestSession test_session(true);
1✔
1441

1442
   PKCS11_RNG p11_rng(test_session.session());
1✔
1443
   HMAC_DRBG drbg(MessageAuthenticationCode::create("HMAC(SHA-512)"), p11_rng);
1✔
1444
   // result.test_success("HMAC_DRBG(HMAC(SHA512)) instantiated with PKCS11_RNG");
1445

1446
   result.test_is_false("HMAC_DRBG is not seeded yet.", drbg.is_seeded());
1✔
1447
   const secure_vector<uint8_t> rnd = drbg.random_vec(64);
1✔
1448
   result.test_is_true("HMAC_DRBG is seeded now", drbg.is_seeded());
1✔
1449

1450
   std::string personalization_string = "Botan PKCS#11 Tests";
1✔
1451
   std::vector<uint8_t> personalization_data(personalization_string.begin(), personalization_string.end());
1✔
1452
   drbg.add_entropy(personalization_data.data(), personalization_data.size());
1✔
1453

1454
   auto rnd_vec = drbg.random_vec(256);
1✔
1455
   result.test_bin_ne("HMAC_DRBG generated a random vector", rnd_vec, std::vector<uint8_t>(256));
1✔
1456

1457
   return result;
2✔
1458
}
3✔
1459
   #endif
1460

1461
class PKCS11_RNG_Tests final : public Test {
1✔
1462
   public:
1463
      std::vector<Test::Result> run() override {
1✔
1464
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1465
   #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_64)
1466
            {STRING_AND_FUNCTION(test_pkcs11_hmac_drbg)},
1467
   #endif
1468
            {STRING_AND_FUNCTION(test_rng_generate_random)},
1469
            {STRING_AND_FUNCTION(test_rng_add_entropy)}
1470
         };
4✔
1471

1472
         return run_pkcs11_tests("PKCS11 RNG", fns);
2✔
1473
      }
2✔
1474
};
1475

1476
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-rng", PKCS11_RNG_Tests);
1477

1478
/***************************** PKCS11 token management *****************************/
1479

1480
Test::Result test_set_pin() {
1✔
1481
   Test::Result result("PKCS11 set pin");
1✔
1482

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

1487
   PKCS11::set_pin(slot, SO_PIN(), TEST_PIN());
3✔
1488
   result.test_success("PIN set with SO_PIN to TEST_PIN");
1✔
1489

1490
   PKCS11::set_pin(slot, SO_PIN(), PIN());
3✔
1491
   result.test_success("PIN changed back with SO_PIN");
1✔
1492

1493
   return result;
2✔
1494
}
1✔
1495

1496
Test::Result test_initialize() {
1✔
1497
   Test::Result result("PKCS11 initialize token");
1✔
1498

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

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

1506
   return result;
2✔
1507
}
1✔
1508

1509
Test::Result test_change_pin() {
1✔
1510
   Test::Result result("PKCS11 change pin");
1✔
1511

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

1516
   PKCS11::change_pin(slot, PIN(), TEST_PIN());
3✔
1517
   result.test_success("PIN changed with PIN to TEST_PIN");
1✔
1518

1519
   PKCS11::change_pin(slot, TEST_PIN(), PIN());
3✔
1520
   result.test_success("PIN changed back with TEST_PIN to PIN");
1✔
1521

1522
   return result;
2✔
1523
}
1✔
1524

1525
Test::Result test_change_so_pin() {
1✔
1526
   Test::Result result("PKCS11 change so_pin");
1✔
1527

1528
   Module module(Test::pkcs11_lib());
1✔
1529
   std::vector<SlotId> slot_vec = Slot::get_available_slots(module, true);
1✔
1530
   Slot slot(module, slot_vec.at(0));
1✔
1531

1532
   PKCS11::change_so_pin(slot, SO_PIN(), TEST_SO_PIN());
3✔
1533
   result.test_success("SO_PIN changed with SO_PIN to TEST_SO_PIN");
1✔
1534

1535
   PKCS11::change_so_pin(slot, TEST_SO_PIN(), SO_PIN());
3✔
1536
   result.test_success("SO_PIN changed back with TEST_SO_PIN to SO_PIN");
1✔
1537

1538
   return result;
2✔
1539
}
1✔
1540

1541
class PKCS11_Token_Management_Tests final : public Test {
1✔
1542
   public:
1543
      std::vector<Test::Result> run() override {
1✔
1544
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1545
            {STRING_AND_FUNCTION(test_set_pin)},
1546
            {STRING_AND_FUNCTION(test_initialize)},
1547
            {STRING_AND_FUNCTION(test_change_pin)},
1548
            {STRING_AND_FUNCTION(test_change_so_pin)}};
5✔
1549

1550
         return run_pkcs11_tests("PKCS11 token management", fns);
2✔
1551
      }
2✔
1552
};
1553

1554
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-manage", PKCS11_Token_Management_Tests);
1555

1556
/***************************** PKCS11 token management *****************************/
1557

1558
   #if defined(BOTAN_HAS_X509_CERTIFICATES)
1559

1560
Test::Result test_x509_import() {
1✔
1561
   Test::Result result("PKCS11 X509 cert import");
1✔
1562

1563
      #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1564
   const TestSession test_session(true);
1✔
1565

1566
   const X509_Certificate root(Test::data_file("x509/nist/test01/end.crt"));
2✔
1567
   X509_CertificateProperties props(root);
1✔
1568
   props.set_label("Botan PKCS#11 test certificate");
1✔
1569
   props.set_private(false);
1✔
1570
   props.set_token(true);
1✔
1571

1572
   const PKCS11_X509_Certificate pkcs11_cert(test_session.session(), props);
1✔
1573
   result.test_success("X509 certificate imported");
1✔
1574

1575
   const PKCS11_X509_Certificate pkcs11_cert2(test_session.session(), pkcs11_cert.handle());
1✔
1576
   result.test_is_true("X509 certificate by handle", pkcs11_cert == pkcs11_cert2);
1✔
1577

1578
   pkcs11_cert.destroy();
1✔
1579
      #endif
1580

1581
   return result;
2✔
1582
}
1✔
1583

1584
class PKCS11_X509_Tests final : public Test {
1✔
1585
   public:
1586
      std::vector<Test::Result> run() override {
1✔
1587
         std::vector<std::pair<std::string, std::function<Test::Result()>>> fns = {
1✔
1588
            {STRING_AND_FUNCTION(test_x509_import)}};
2✔
1589

1590
         return run_pkcs11_tests("PKCS11 X509", fns);
2✔
1591
      }
2✔
1592
};
1593

1594
BOTAN_REGISTER_SERIALIZED_TEST("pkcs11", "pkcs11-x509", PKCS11_X509_Tests);
1595

1596
   #endif
1597

1598
}  // namespace
1599

1600
#endif
1601

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