mirror of
https://github.com/coolsnowwolf/packages.git
synced 2025-05-02 04:51:52 +08:00
459 lines
13 KiB
C++
459 lines
13 KiB
C++
#include <unistd.h>
|
|
#include <array>
|
|
#include <iostream>
|
|
#include <numeric>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include "px5g-openssl.hpp"
|
|
|
|
class argv_view { // TODO(pst): use std::span when available.
|
|
|
|
private:
|
|
std::basic_string_view<const char*> data;
|
|
|
|
public:
|
|
argv_view(const argv_view&) = delete;
|
|
|
|
argv_view(argv_view&&) = delete;
|
|
|
|
auto operator=(const argv_view&) -> argv_view& = delete;
|
|
|
|
auto operator=(argv_view &&) -> argv_view& = delete;
|
|
|
|
argv_view(const char** argv, int argc) : data{argv, static_cast<size_t>(argc)} {}
|
|
|
|
inline auto operator[](size_t pos) const -> std::string_view
|
|
{
|
|
return std::string_view{data[pos]};
|
|
}
|
|
|
|
[[nodiscard]] inline constexpr auto size() const noexcept -> size_t
|
|
{
|
|
return data.size();
|
|
}
|
|
|
|
~argv_view() = default;
|
|
};
|
|
|
|
static const auto default_validity = 30;
|
|
|
|
auto checkend(const argv_view& argv) -> int;
|
|
|
|
void eckey(const argv_view& argv);
|
|
|
|
void rsakey(const argv_view& argv);
|
|
|
|
void selfsigned(const argv_view& argv);
|
|
|
|
inline auto parse_int(const std::string_view& arg) -> int
|
|
{
|
|
size_t pos = 0;
|
|
int ret = stoi(std::string{arg}, &pos);
|
|
if (pos < arg.size()) {
|
|
throw std::runtime_error("number has trailing char");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
inline auto parse_curve(const std::string_view& name) -> int
|
|
{
|
|
if (name == "P-384") {
|
|
return NID_secp384r1;
|
|
}
|
|
if (name == "P-521") {
|
|
return NID_secp521r1;
|
|
}
|
|
if (name == "P-256" || name == "secp256r1") {
|
|
return NID_X9_62_prime256v1;
|
|
}
|
|
if (name == "secp192r1") {
|
|
return NID_X9_62_prime192v1;
|
|
}
|
|
return OBJ_sn2nid(name.data());
|
|
// not: if (curve == 0) { curve = EC_curve_nist2nid(name.c_str()); }
|
|
}
|
|
|
|
auto checkend(const argv_view& argv) -> int
|
|
{
|
|
bool use_pem = true;
|
|
std::string crtpath{};
|
|
time_t seconds = 0;
|
|
|
|
for (size_t i = 2; i < argv.size(); ++i) {
|
|
if (argv[i] == "-der") {
|
|
use_pem = false;
|
|
}
|
|
else if (argv[i] == "-in") {
|
|
++i;
|
|
|
|
if (i >= argv.size()) {
|
|
throw std::runtime_error("checkend error: -in misses filename");
|
|
}
|
|
|
|
if (!crtpath.empty()) {
|
|
if (argv[i] == crtpath) {
|
|
std::cerr << "checkend warning: repeated same -in file\n";
|
|
}
|
|
else {
|
|
throw std::runtime_error("checkend error: more than one -in file");
|
|
}
|
|
}
|
|
|
|
crtpath = argv[i];
|
|
}
|
|
|
|
else if (argv[i][0] == '-') {
|
|
std::cerr << "checkend warning: skipping option " << argv[i] << std::endl;
|
|
}
|
|
else { // main option:
|
|
intmax_t num = 0;
|
|
|
|
try {
|
|
num = parse_int(argv[i]);
|
|
}
|
|
catch (...) {
|
|
auto errmsg = std::string{"checkend error: invalid time "};
|
|
errmsg += argv[i];
|
|
std::throw_with_nested(std::runtime_error(errmsg));
|
|
}
|
|
|
|
seconds = static_cast<time_t>(num);
|
|
|
|
if (num != static_cast<intmax_t>(seconds)) {
|
|
auto errmsg = std::string{"checkend error: time too big "};
|
|
errmsg += argv[i];
|
|
throw std::runtime_error(errmsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool valid = checkend(crtpath, seconds, use_pem);
|
|
std::cout << "Certificate will" << (valid ? " not " : " ") << "expire" << std::endl;
|
|
|
|
return (valid ? 0 : 1);
|
|
}
|
|
|
|
void eckey(const argv_view& argv)
|
|
{
|
|
bool has_main_option = false;
|
|
bool use_pem = true;
|
|
std::string keypath{};
|
|
int curve = NID_X9_62_prime256v1;
|
|
|
|
for (size_t i = 2; i < argv.size(); ++i) {
|
|
if (argv[i] == "-der") {
|
|
use_pem = false;
|
|
}
|
|
else if (argv[i] == "-out") {
|
|
++i;
|
|
|
|
if (i >= argv.size()) {
|
|
throw std::runtime_error("eckey error: -out misses filename");
|
|
}
|
|
|
|
if (!keypath.empty()) {
|
|
if (argv[i] == keypath) {
|
|
std::cerr << "eckey warning: repeated same -out file\n";
|
|
}
|
|
else {
|
|
throw std::runtime_error("eckey error: more than one -out file");
|
|
}
|
|
}
|
|
|
|
keypath = argv[i];
|
|
}
|
|
|
|
else if (argv[i][0] == '-') {
|
|
std::cerr << "eckey warning: skipping option " << argv[i] << std::endl;
|
|
}
|
|
else { // main option:
|
|
|
|
if (has_main_option) {
|
|
throw std::runtime_error("eckey error: more than one main option");
|
|
} // else:
|
|
has_main_option = true;
|
|
|
|
curve = parse_curve(argv[i]);
|
|
}
|
|
}
|
|
|
|
write_key(gen_eckey(curve), keypath, use_pem);
|
|
}
|
|
|
|
void rsakey(const argv_view& argv)
|
|
{
|
|
bool has_main_option = false;
|
|
bool use_pem = true;
|
|
std::string keypath{};
|
|
BN_ULONG exponent = RSA_F4;
|
|
int keysize = rsa_min_modulus_bits;
|
|
|
|
for (size_t i = 2; i < argv.size(); ++i) {
|
|
if (argv[i] == "-der") {
|
|
use_pem = false;
|
|
}
|
|
else if (argv[i] == "-3") {
|
|
exponent = 3;
|
|
}
|
|
else if (argv[i] == "-out") {
|
|
++i;
|
|
|
|
if (i >= argv.size()) {
|
|
throw std::runtime_error("rsakey error: -out misses filename");
|
|
}
|
|
|
|
if (!keypath.empty()) {
|
|
if (argv[i] == keypath) {
|
|
std::cerr << "rsakey warning: repeated -out file" << std::endl;
|
|
}
|
|
else {
|
|
throw std::runtime_error("rsakey error: more than one -out file");
|
|
}
|
|
}
|
|
|
|
keypath = argv[i];
|
|
}
|
|
|
|
else if (argv[i][0] == '-') {
|
|
std::cerr << "rsakey warning: skipping option " << argv[i] << std::endl;
|
|
}
|
|
else { // main option:
|
|
|
|
if (has_main_option) {
|
|
throw std::runtime_error("rsakey error: more than one keysize");
|
|
} // else:
|
|
has_main_option = true;
|
|
|
|
try {
|
|
keysize = parse_int(argv[i]);
|
|
}
|
|
catch (...) {
|
|
std::string errmsg{"rsakey error: invalid keysize "};
|
|
errmsg += argv[i];
|
|
std::throw_with_nested(std::runtime_error(errmsg));
|
|
}
|
|
}
|
|
}
|
|
|
|
write_key(gen_rsakey(keysize, exponent), keypath, use_pem);
|
|
}
|
|
|
|
void selfsigned(const argv_view& argv)
|
|
{
|
|
bool use_pem = true;
|
|
int days = default_validity;
|
|
std::string keypath{};
|
|
std::string crtpath{};
|
|
std::string subject{};
|
|
|
|
bool use_rsa = true;
|
|
int keysize = rsa_min_modulus_bits;
|
|
BN_ULONG exponent = RSA_F4;
|
|
|
|
int curve = NID_X9_62_prime256v1;
|
|
|
|
for (size_t i = 2; i < argv.size(); ++i) {
|
|
if (argv[i] == "-der") {
|
|
use_pem = false;
|
|
}
|
|
else if (argv[i] == "-days") {
|
|
++i;
|
|
try {
|
|
days = parse_int(argv[i]);
|
|
}
|
|
catch (...) {
|
|
std::string errmsg{"selfsigned error: not a number for -days "};
|
|
errmsg += argv[i].substr(4);
|
|
std::throw_with_nested(std::runtime_error(errmsg));
|
|
}
|
|
}
|
|
|
|
else if (argv[i] == "-newkey") {
|
|
++i;
|
|
|
|
if (i >= argv.size()) {
|
|
throw std::runtime_error("selfsigned error: -newkey misses algorithm option");
|
|
}
|
|
|
|
static constexpr auto rsa_prefix = std::string_view{"rsa:"};
|
|
|
|
if (argv[i] == "ec") {
|
|
use_rsa = false;
|
|
}
|
|
else if (argv[i].rfind(rsa_prefix, 0) == 0) {
|
|
use_rsa = true;
|
|
try {
|
|
keysize = parse_int(argv[i].substr(rsa_prefix.size()));
|
|
}
|
|
catch (...) {
|
|
std::string errmsg{"selfsigned error: invalid keysize "};
|
|
errmsg += argv[i].substr(4);
|
|
std::throw_with_nested(std::runtime_error(errmsg));
|
|
}
|
|
}
|
|
else {
|
|
throw std::runtime_error("selfsigned error: invalid algorithm");
|
|
}
|
|
}
|
|
|
|
else if (argv[i] == "-pkeyopt") {
|
|
++i;
|
|
|
|
if (i >= argv.size()) {
|
|
throw std::runtime_error("selfsigned error: -pkeyopt misses value");
|
|
}
|
|
|
|
static constexpr auto curve_prefix = std::string_view{"ec_paramgen_curve:"};
|
|
|
|
if (argv[i].rfind(curve_prefix, 0) != 0) {
|
|
throw std::runtime_error("selfsigned error: -pkeyopt invalid");
|
|
}
|
|
|
|
curve = parse_curve(argv[i].substr(curve_prefix.size()));
|
|
}
|
|
|
|
else if (argv[i] == "-keyout") {
|
|
++i;
|
|
|
|
if (i >= argv.size()) {
|
|
throw std::runtime_error("selfsigned error: -keyout misses path");
|
|
}
|
|
|
|
if (!keypath.empty()) {
|
|
if (argv[i] == keypath) {
|
|
std::cerr << "selfsigned warning: repeated -keyout file\n";
|
|
}
|
|
else {
|
|
throw std::runtime_error("selfsigned error: more than one -keyout file");
|
|
}
|
|
}
|
|
|
|
keypath = argv[i];
|
|
}
|
|
|
|
else if (argv[i] == "-out") {
|
|
++i;
|
|
|
|
if (i >= argv.size()) {
|
|
throw std::runtime_error("selfsigned error: -out misses filename");
|
|
}
|
|
|
|
if (!crtpath.empty()) {
|
|
if (argv[i] == crtpath) {
|
|
std::cerr << "selfsigned warning: repeated same -out file\n";
|
|
}
|
|
else {
|
|
throw std::runtime_error("selfsigned error: more than one -out file");
|
|
}
|
|
}
|
|
|
|
crtpath = argv[i];
|
|
}
|
|
|
|
else if (argv[i] == "-subj") {
|
|
++i;
|
|
|
|
if (i >= argv.size()) {
|
|
throw std::runtime_error("selfsigned error: -subj misses value");
|
|
}
|
|
|
|
if (!subject.empty()) {
|
|
if (argv[i] == subject) {
|
|
std::cerr << "selfsigned warning: repeated same -subj\n";
|
|
}
|
|
else {
|
|
throw std::runtime_error("selfsigned error: more than one -subj value");
|
|
}
|
|
}
|
|
|
|
subject = argv[i];
|
|
}
|
|
|
|
else {
|
|
std::cerr << "selfsigned warning: skipping option " << argv[i] << std::endl;
|
|
}
|
|
}
|
|
|
|
auto pkey = use_rsa ? gen_rsakey(keysize, exponent) : gen_eckey(curve);
|
|
|
|
selfsigned(pkey, days, subject, crtpath, use_pem);
|
|
|
|
if (!keypath.empty()) {
|
|
write_key(pkey, keypath, use_pem);
|
|
}
|
|
}
|
|
|
|
auto main(int argc, const char** argv) -> int
|
|
{
|
|
auto args = argv_view{argv, argc};
|
|
|
|
auto cmds = std::array{
|
|
std::array<std::string, 2>{"checkend",
|
|
" [-der] [-in certificate_path] [seconds_remaining]"},
|
|
std::array<std::string, 2>{"eckey", " [-der] [-out key_path] [curve_name]"},
|
|
std::array<std::string, 2>{"rsakey", " [-der] [-out key_path] [-3] [key_size]"},
|
|
std::array<std::string, 2>{
|
|
"selfsigned",
|
|
" [-der] [-keyout key_path] [-out certificate_path]"
|
|
" [-newkey ec|rsa:key_size] [-pkeyopt ec_paramgen_curve:name]"
|
|
" [-days validity] [-subj /C=.../ST=.../L=.../O=.../CN=.../... ]"},
|
|
};
|
|
|
|
try {
|
|
if (argc < 2) {
|
|
throw std::runtime_error("error: no argument");
|
|
}
|
|
|
|
if (args[1] == cmds[0][0]) {
|
|
return checkend(args);
|
|
}
|
|
|
|
if (args[1] == cmds[1][0]) {
|
|
eckey(args);
|
|
}
|
|
|
|
else if (args[1] == cmds[2][0]) {
|
|
rsakey(args);
|
|
}
|
|
|
|
else if (args[1] == cmds[3][0]) {
|
|
selfsigned(args);
|
|
}
|
|
|
|
else {
|
|
throw std::runtime_error("error: argument not recognized");
|
|
}
|
|
}
|
|
|
|
catch (const std::exception& e) {
|
|
auto usage = std::accumulate(
|
|
cmds.begin(), cmds.end(), std::string{"usage: \n"},
|
|
[=](const auto& use, const auto& cmd) {
|
|
return use + std::string{4, ' '} + *argv + " " + cmd[0] + cmd[1] + "\n";
|
|
});
|
|
|
|
std::cerr << usage << std::flush;
|
|
|
|
auto print_nested = [](auto&& self, const std::exception& outer, int depth = 0) -> void {
|
|
std::cerr << std::string(depth, '\t') << outer.what() << std::endl;
|
|
try {
|
|
std::rethrow_if_nested(outer);
|
|
}
|
|
catch (const std::exception& inner) {
|
|
self(self, inner, depth + 1);
|
|
}
|
|
};
|
|
|
|
print_nested(print_nested, e);
|
|
|
|
return 1;
|
|
}
|
|
|
|
catch (...) {
|
|
std::cerr << *argv << " unknown error." << std::endl;
|
|
return 2;
|
|
}
|
|
|
|
return 0;
|
|
}
|