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

randombit / botan / 19012754211

02 Nov 2025 01:10PM UTC coverage: 90.677% (+0.006%) from 90.671%
19012754211

push

github

web-flow
Merge pull request #5137 from randombit/jack/clang-tidy-includes

Remove various unused includes flagged by clang-tidy misc-include-cleaner

100457 of 110786 relevant lines covered (90.68%)

12189873.8 hits per line

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

74.8
/src/cli/pubkey.cpp
1
/*
2
* (C) 2010,2014,2015,2019 Jack Lloyd
3
* (C) 2019 Matthias Gierlings
4
* (C) 2015 René Korthaus
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include "cli.h"
10

11
#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO)
12

13
   #include <botan/base64.h>
14
   #include <botan/data_src.h>
15
   #include <botan/hash.h>
16
   #include <botan/hex.h>
17
   #include <botan/pk_algs.h>
18
   #include <botan/pk_keys.h>
19
   #include <botan/pkcs8.h>
20
   #include <botan/pubkey.h>
21
   #include <botan/x509_key.h>
22
   #include <botan/internal/workfactor.h>
23
   #include <fstream>
24
   #include <sstream>
25

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

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

34
namespace Botan_CLI {
35

36
class PK_Keygen final : public Command {
37
   public:
38
      PK_Keygen() :
21✔
39
            Command(
40
               "keygen --algo=RSA --params= --passphrase= --cipher= --pbkdf= --pbkdf-ms=300 --pbkdf-iter= --provider= --der-out") {
21✔
41
      }
21✔
42

43
      std::string group() const override { return "pubkey"; }
1✔
44

45
      std::string description() const override { return "Generate a PKCS #8 private key"; }
1✔
46

47
      void go() override {
20✔
48
         const std::string algo = get_arg("algo");
20✔
49
         const std::string params = get_arg("params");
20✔
50
         const std::string provider = get_arg("provider");
20✔
51

52
         std::unique_ptr<Botan::Private_Key> key = Botan::create_private_key(algo, rng(), params, provider);
20✔
53

54
         if(!key) {
20✔
55
            throw CLI_Error_Unsupported("keygen", algo);
×
56
         }
57

58
         const std::string pass = get_passphrase_arg("Key passphrase", "passphrase");
40✔
59
         const bool der_out = flag_set("der-out");
20✔
60

61
         const std::chrono::milliseconds pbkdf_ms(get_arg_sz("pbkdf-ms"));
20✔
62

63
         if(der_out) {
20✔
64
            if(pass.empty()) {
×
65
               write_output(Botan::PKCS8::BER_encode(*key));
×
66
            } else {
67
               if(get_arg("pbkdf-iter").empty()) {
×
68
                  write_output(Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(
×
69
                     *key, rng(), pass, pbkdf_ms, nullptr, get_arg("cipher"), get_arg("pbkdf")));
×
70
               } else {
71
                  write_output(Botan::PKCS8::BER_encode_encrypted_pbkdf_iter(
×
72
                     *key, rng(), pass, get_arg_sz("pbkdf-iter"), get_arg("cipher"), get_arg("pbkdf")));
×
73
               }
74
            }
75
         } else {
76
            if(pass.empty()) {
20✔
77
               output() << Botan::PKCS8::PEM_encode(*key);
40✔
78
            } else {
79
               if(get_arg("pbkdf-iter").empty()) {
×
80
                  output() << Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(
×
81
                     *key, rng(), pass, pbkdf_ms, nullptr, get_arg("cipher"), get_arg("pbkdf"));
×
82
               } else {
83
                  output() << Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter(
×
84
                     *key, rng(), pass, get_arg_sz("pbkdf-iter"), get_arg("cipher"), get_arg("pbkdf"));
×
85
               }
86
            }
87
         }
88
      }
40✔
89
};
90

91
BOTAN_REGISTER_COMMAND("keygen", PK_Keygen);
21✔
92

93
   #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
94

95
namespace {
96

97
std::string choose_sig_padding(const std::string& key, const std::string& padding, const std::string& hash) {
7✔
98
   if(key == "RSA") {
7✔
99
      std::ostringstream oss;
×
100
      if(padding.empty()) {
×
101
         oss << "PSS";
×
102
      } else {
103
         oss << padding;
×
104
      }
105

106
      oss << "(" << hash << ")";
×
107
      return oss.str();
×
108
   } else if(padding.empty()) {
7✔
109
      return hash;
7✔
110
   } else if(hash.empty()) {
×
111
      return padding;
×
112
   } else {
113
      std::ostringstream oss;
×
114
      oss << padding << "(" << hash << ")";
×
115
      return oss.str();
×
116
   }
×
117
}
118

119
}  // namespace
120

121
class PK_Fingerprint final : public Command {
122
   public:
123
      PK_Fingerprint() : Command("fingerprint --no-fsname --algo=SHA-256 *keys") {}
16✔
124

125
      std::string group() const override { return "pubkey"; }
1✔
126

127
      std::string description() const override { return "Calculate a public key fingerprint"; }
1✔
128

129
      void go() override {
7✔
130
         const std::string hash_algo = get_arg("algo");
7✔
131
         const bool no_fsname = flag_set("no-fsname");
7✔
132

133
         for(const std::string& key_file : get_arg_list("keys")) {
15✔
134
            std::unique_ptr<Botan::Public_Key> key(key_file == "-" ? Botan::X509::load_key(this->slurp_file("-", 4096))
18✔
135
                                                                   : Botan::X509::load_key(key_file));
8✔
136

137
            const std::string fprint = key->fingerprint_public(hash_algo);
8✔
138

139
            if(no_fsname || key_file == "-") {
8✔
140
               output() << fprint << "\n";
7✔
141
            } else {
142
               output() << key_file << ": " << fprint << "\n";
1✔
143
            }
144
         }
23✔
145
      }
7✔
146
};
147

148
BOTAN_REGISTER_COMMAND("fingerprint", PK_Fingerprint);
8✔
149

150
namespace {
151

152
std::unique_ptr<Botan::Private_Key> load_private_key(const std::string& key_filename, const std::string& passphrase) {
3✔
153
   std::string err_string;
3✔
154

155
   try {
3✔
156
      Botan::DataSource_Stream input(key_filename);
3✔
157
      return Botan::PKCS8::load_key(input, passphrase);
3✔
158
   } catch(Botan::Exception& e) {
3✔
159
      err_string = e.what();
×
160
   }
×
161

162
   if(passphrase.empty()) {
×
163
      try {
×
164
         Botan::DataSource_Stream input(key_filename);
×
165
         return Botan::PKCS8::load_key(input);
×
166
      } catch(Botan::Exception& e) {
×
167
         err_string = e.what();
×
168
      }
×
169
   }
170

171
   throw CLI_Error("Loading private key failed (" + err_string + ")");
×
172
}
3✔
173

174
}  // namespace
175

176
class PK_Sign final : public Command {
177
   public:
178
      PK_Sign() : Command("sign --der-format --passphrase= --hash=SHA-256 --padding= --provider= key file") {}
8✔
179

180
      std::string group() const override { return "pubkey"; }
1✔
181

182
      std::string description() const override { return "Sign arbitrary data"; }
1✔
183

184
      void go() override {
3✔
185
         const std::string key_file = get_arg("key");
3✔
186
         const std::string passphrase = get_passphrase_arg("Passphrase for " + key_file, "passphrase");
6✔
187

188
         auto key = load_private_key(key_file, passphrase);
3✔
189

190
         const std::string hash_fn = get_arg("hash");
3✔
191

192
         if(!hash_fn.empty() && !Botan::HashFunction::create(hash_fn)) {
6✔
193
            throw CLI_Error_Unsupported("hashing", hash_fn);
×
194
         }
195

196
         const std::string sig_padding = choose_sig_padding(key->algo_name(), get_arg("padding"), hash_fn);
6✔
197

198
         auto format = Botan::Signature_Format::Standard;
3✔
199

200
         if(flag_set("der-format")) {
3✔
201
            if(!key->_signature_element_size_for_DER_encoding()) {
×
202
               throw CLI_Usage_Error("Key type " + key->algo_name() +
×
203
                                     " does not support DER formatting for signatures");
×
204
            }
205
            format = Botan::Signature_Format::DerSequence;
206
         }
207

208
         const std::string provider = get_arg("provider");
3✔
209

210
         Botan::PK_Signer signer(*key, rng(), sig_padding, format, provider);
3✔
211

212
         auto onData = [&signer](const uint8_t b[], size_t l) { signer.update(b, l); };
3✔
213
         Command::read_file(get_arg("file"), onData);
6✔
214

215
         std::vector<uint8_t> sig{signer.signature(rng())};
3✔
216

217
         if(key->stateful_operation()) {
3✔
218
            std::ofstream updated_key(key_file);
2✔
219
            if(passphrase.empty()) {
2✔
220
               updated_key << Botan::PKCS8::PEM_encode(*key);
4✔
221
            } else {
222
               updated_key << Botan::PKCS8::PEM_encode(*key, rng(), passphrase);
×
223
            }
224
         }
2✔
225

226
         output() << Botan::base64_encode(sig) << "\n";
6✔
227
      }
6✔
228
};
229

230
BOTAN_REGISTER_COMMAND("sign", PK_Sign);
4✔
231

232
class PK_Verify final : public Command {
233
   public:
234
      PK_Verify() : Command("verify --der-format --hash=SHA-256 --padding= pubkey file signature") {}
10✔
235

236
      std::string group() const override { return "pubkey"; }
1✔
237

238
      std::string description() const override {
1✔
239
         return "Verify the authenticity of the given file with the provided signature";
1✔
240
      }
241

242
      void go() override {
4✔
243
         auto key = Botan::X509::load_key(get_arg("pubkey"));
8✔
244
         if(!key) {
4✔
245
            throw CLI_Error("Unable to load public key");
×
246
         }
247

248
         const std::string hash_fn = get_arg("hash");
4✔
249

250
         if(!hash_fn.empty() && !Botan::HashFunction::create(hash_fn)) {
8✔
251
            throw CLI_Error_Unsupported("hashing", hash_fn);
×
252
         }
253

254
         const std::string sig_padding = choose_sig_padding(key->algo_name(), get_arg("padding"), hash_fn);
8✔
255

256
         auto format = Botan::Signature_Format::Standard;
4✔
257
         if(flag_set("der-format")) {
4✔
258
            if(key->message_parts() == 1) {
×
259
               throw CLI_Usage_Error("Key type " + key->algo_name() +
×
260
                                     " does not support DER formatting for signatures");
×
261
            }
262
            format = Botan::Signature_Format::DerSequence;
263
         }
264

265
         Botan::PK_Verifier verifier(*key, sig_padding, format);
4✔
266
         auto onData = [&verifier](const uint8_t b[], size_t l) { verifier.update(b, l); };
4✔
267
         Command::read_file(get_arg("file"), onData);
8✔
268

269
         const Botan::secure_vector<uint8_t> signature =
4✔
270
            Botan::base64_decode(this->slurp_file_as_str(get_arg("signature")));
8✔
271

272
         const bool valid = verifier.check_signature(signature);
4✔
273

274
         output() << "Signature is " << (valid ? "valid" : "invalid") << "\n";
5✔
275
      }
8✔
276
};
277

278
BOTAN_REGISTER_COMMAND("verify", PK_Verify);
5✔
279

280
class PKCS8_Tool final : public Command {
281
   public:
282
      PKCS8_Tool() :
10✔
283
            Command(
284
               "pkcs8 --pass-in= --pub-out --der-out --pass-out= --cipher= --pbkdf= --pbkdf-ms=300 --pbkdf-iter= key") {
10✔
285
      }
10✔
286

287
      std::string group() const override { return "pubkey"; }
1✔
288

289
      std::string description() const override { return "Open a PKCS #8 formatted key"; }
1✔
290

291
      void go() override {
9✔
292
         const std::string key_file = get_arg("key");
9✔
293
         const std::string pass_in = get_passphrase_arg("Password for " + key_file, "pass-in");
18✔
294

295
         Botan::DataSource_Memory key_src(slurp_file(key_file));
18✔
296
         std::unique_ptr<Botan::Private_Key> key;
9✔
297

298
         if(pass_in.empty()) {
9✔
299
            key = Botan::PKCS8::load_key(key_src);
7✔
300
         } else {
301
            key = Botan::PKCS8::load_key(key_src, pass_in);
2✔
302
         }
303

304
         const std::chrono::milliseconds pbkdf_ms(get_arg_sz("pbkdf-ms"));
9✔
305
         const bool der_out = flag_set("der-out");
9✔
306

307
         if(flag_set("pub-out")) {
9✔
308
            auto pk = key->public_key();
5✔
309
            if(der_out) {
5✔
310
               write_output(Botan::X509::BER_encode(*pk));
2✔
311
            } else {
312
               output() << Botan::X509::PEM_encode(*pk);
8✔
313
            }
314
         } else {
5✔
315
            const std::string pass_out = get_passphrase_arg("Passphrase to encrypt key", "pass-out");
8✔
316

317
            if(der_out) {
4✔
318
               if(pass_out.empty()) {
1✔
319
                  write_output(Botan::PKCS8::BER_encode(*key));
×
320
               } else {
321
                  if(get_arg("pbkdf-iter").empty()) {
1✔
322
                     write_output(Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(
2✔
323
                        *key, rng(), pass_out, pbkdf_ms, nullptr, get_arg("cipher"), get_arg("pbkdf")));
3✔
324
                  } else {
325
                     write_output(Botan::PKCS8::BER_encode_encrypted_pbkdf_iter(
×
326
                        *key, rng(), pass_out, get_arg_sz("pbkdf-iter"), get_arg("cipher"), get_arg("pbkdf")));
×
327
                  }
328
               }
329
            } else {
330
               if(pass_out.empty()) {
3✔
331
                  output() << Botan::PKCS8::PEM_encode(*key);
4✔
332
               } else {
333
                  if(get_arg("pbkdf-iter").empty()) {
1✔
334
                     output() << Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(
3✔
335
                        *key, rng(), pass_out, pbkdf_ms, nullptr, get_arg("cipher"), get_arg("pbkdf"));
4✔
336
                  } else {
337
                     output() << Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter(
×
338
                        *key, rng(), pass_out, get_arg_sz("pbkdf-iter"), get_arg("cipher"), get_arg("pbkdf"));
×
339
                  }
340
               }
341
            }
342
         }
4✔
343
      }
18✔
344
};
345

346
BOTAN_REGISTER_COMMAND("pkcs8", PKCS8_Tool);
10✔
347

348
   #endif
349

350
   #if defined(BOTAN_HAS_ECC_GROUP)
351

352
class EC_Group_Info final : public Command {
353
   public:
354
      EC_Group_Info() : Command("ec_group_info --pem name") {}
6✔
355

356
      std::string group() const override { return "pubkey"; }
1✔
357

358
      std::string description() const override {
1✔
359
         return "Print raw elliptic curve domain parameters of the standardized curve name";
1✔
360
      }
361

362
      void go() override {
2✔
363
         const auto ec_group = Botan::EC_Group::from_name(get_arg("name"));
4✔
364

365
         if(flag_set("pem")) {
2✔
366
            output() << ec_group.PEM_encode(Botan::EC_Group_Encoding::NamedCurve);
2✔
367
         } else {
368
            output() << "P = " << std::hex << ec_group.get_p() << "\n"
1✔
369
                     << "A = " << std::hex << ec_group.get_a() << "\n"
1✔
370
                     << "B = " << std::hex << ec_group.get_b() << "\n"
1✔
371
                     << "N = " << std::hex << ec_group.get_order() << "\n"
1✔
372
                     << "G = " << ec_group.get_g_x() << "," << ec_group.get_g_y() << "\n";
1✔
373
         }
374
      }
2✔
375
};
376

377
BOTAN_REGISTER_COMMAND("ec_group_info", EC_Group_Info);
3✔
378

379
   #endif
380

381
   #if defined(BOTAN_HAS_DL_GROUP)
382

383
class DL_Group_Info final : public Command {
384
   public:
385
      DL_Group_Info() : Command("dl_group_info --pem name") {}
16✔
386

387
      std::string group() const override { return "pubkey"; }
1✔
388

389
      std::string description() const override {
1✔
390
         return "Print raw Diffie-Hellman parameters (p,g) of the standardized DH group name";
1✔
391
      }
392

393
      void go() override {
7✔
394
         auto dl_group = Botan::DL_Group::from_name(get_arg("name"));
14✔
395

396
         if(flag_set("pem")) {
7✔
397
            output() << dl_group.PEM_encode(Botan::DL_Group_Format::ANSI_X9_42_DH_PARAMETERS);
×
398
         } else {
399
            output() << "P = " << std::hex << dl_group.get_p() << "\n"
7✔
400
                     << "G = " << dl_group.get_g() << "\n";
7✔
401
         }
402
      }
7✔
403
};
404

405
BOTAN_REGISTER_COMMAND("dl_group_info", DL_Group_Info);
8✔
406

407
class PK_Workfactor final : public Command {
408
   public:
409
      PK_Workfactor() : Command("pk_workfactor --type=rsa bits") {}
12✔
410

411
      std::string group() const override { return "pubkey"; }
1✔
412

413
      std::string description() const override { return "Provide estimate of strength of public key based on size"; }
1✔
414

415
      void go() override {
5✔
416
         const size_t bits = get_arg_sz("bits");
5✔
417
         const std::string type = get_arg("type");
5✔
418

419
         if(type == "rsa") {
5✔
420
            output() << Botan::if_work_factor(bits) << "\n";
3✔
421
         } else if(type == "dl") {
2✔
422
            output() << Botan::dl_work_factor(bits) << "\n";
1✔
423
         } else if(type == "dl_exp") {
1✔
424
            output() << Botan::dl_exponent_size(bits) << "\n";
1✔
425
         } else {
426
            throw CLI_Usage_Error("Unknown type for pk_workfactor (rsa, dl, dl_exp)");
×
427
         }
428
      }
5✔
429
};
430

431
BOTAN_REGISTER_COMMAND("pk_workfactor", PK_Workfactor);
6✔
432

433
class Gen_DL_Group final : public Command {
434
   public:
435
      Gen_DL_Group() : Command("gen_dl_group --pbits=2048 --qbits=0 --seed= --type=subgroup") {}
6✔
436

437
      std::string group() const override { return "pubkey"; }
1✔
438

439
      std::string description() const override { return "Generate ANSI X9.42 encoded Diffie-Hellman group parameters"; }
1✔
440

441
      void go() override {
2✔
442
         const size_t pbits = get_arg_sz("pbits");
2✔
443
         const size_t qbits = get_arg_sz("qbits");
2✔
444

445
         const std::string type = get_arg("type");
2✔
446
         const std::string seed_str = get_arg("seed");
2✔
447

448
         if(type == "strong") {
2✔
449
            if(!seed_str.empty()) {
×
450
               throw CLI_Usage_Error("Seed only supported for DSA param gen");
×
451
            }
452
            Botan::DL_Group grp(rng(), Botan::DL_Group::Strong, pbits);
×
453
            output() << grp.PEM_encode(Botan::DL_Group_Format::ANSI_X9_42);
×
454
         } else if(type == "subgroup") {
2✔
455
            if(!seed_str.empty()) {
1✔
456
               throw CLI_Usage_Error("Seed only supported for DSA param gen");
×
457
            }
458
            Botan::DL_Group grp(rng(), Botan::DL_Group::Prime_Subgroup, pbits, qbits);
1✔
459
            output() << grp.PEM_encode(Botan::DL_Group_Format::ANSI_X9_42);
2✔
460
         } else if(type == "dsa") {
2✔
461
            size_t dsa_qbits = qbits;
1✔
462
            if(dsa_qbits == 0) {
1✔
463
               if(pbits == 1024) {
1✔
464
                  dsa_qbits = 160;
465
               } else if(pbits == 2048 || pbits == 3072) {
×
466
                  dsa_qbits = 256;
467
               } else {
468
                  throw CLI_Usage_Error("Invalid DSA p/q sizes");
×
469
               }
470
            }
471

472
            if(seed_str.empty()) {
1✔
473
               Botan::DL_Group grp(rng(), Botan::DL_Group::DSA_Kosherizer, pbits, dsa_qbits);
1✔
474
               output() << grp.PEM_encode(Botan::DL_Group_Format::ANSI_X9_57);
2✔
475
            } else {
1✔
476
               const std::vector<uint8_t> seed = Botan::hex_decode(seed_str);
×
477
               Botan::DL_Group grp(rng(), seed, pbits, dsa_qbits);
×
478
               output() << grp.PEM_encode(Botan::DL_Group_Format::ANSI_X9_57);
×
479
            }
×
480

481
         } else {
482
            throw CLI_Usage_Error("Invalid DL type '" + type + "'");
×
483
         }
484
      }
2✔
485
};
486

487
BOTAN_REGISTER_COMMAND("gen_dl_group", Gen_DL_Group);
3✔
488

489
   #endif
490

491
}  // namespace Botan_CLI
492

493
#endif
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