mirror of
https://github.com/openwrt/packages.git
synced 2025-12-23 05:54:33 +04:00
nginx-util: add package
This can do the main work of nginx/nginx-ssl init script. For nginx-ssl it can create selfsigned certificates, too. It uses libpcre and libopenssl iff nginx(-ssl) uses them. Signed-off-by: Peter Stadler <peter.stadler@student.uibk.ac.at>
This commit is contained in:
451
net/nginx-util/src/px5g.cpp
Normal file
451
net/nginx-util/src/px5g.cpp
Normal file
@@ -0,0 +1,451 @@
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unistd.h>
|
||||
#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;
|
||||
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.c_str()));
|
||||
}
|
||||
|
||||
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.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
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.c_str()));
|
||||
}
|
||||
} 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::string{"usage: \n"} ;
|
||||
for (auto cmd : cmds) {
|
||||
usage += 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;
|
||||
}
|
||||
Reference in New Issue
Block a user