Generate Private Key and Certificate if none exist

This commit is contained in:
loki 2020-01-23 16:00:44 +01:00
parent 1b49a9661e
commit f06f5dde2f
6 changed files with 150 additions and 53 deletions

View File

@ -1,22 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDsTCCApmgAwIBAgIULnRRHDUzdg4a9dwWi0/yV5LADLIwDQYJKoZIhvcNAQEL
BQAwaDELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEhMB8GCSqGSIb3DQEJARYSbG9raUBm
YWtlZW1haWwuY29tMB4XDTE5MDYwMzEwMzY0N1oXDTI5MDUzMTEwMzY0N1owaDEL
MAkGA1UEBhMCTkwxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVy
bmV0IFdpZGdpdHMgUHR5IEx0ZDEhMB8GCSqGSIb3DQEJARYSbG9raUBmYWtlZW1h
aWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4cyNQ7uH6tAE
EAD99oxR1CVYlOgRDEUqJCjkpIoVF5uE3/kfuvEJ+l7/WL51lqbq35uL5ta7EbJH
BvVyNH00FN2D/Yl0n/X+TlhRP88MS5F0d0rwyQEAh4wEGcUhdSoW9TfybmLaHeCC
bZlxC3kBWxr0e6YDlV9deM6j+OjCerQwkiiGwgE9dVrVCj1dLyzBhWnYGpYBvY+3
6kEy0Vmf2spGCB6meCAMrAMz75fUDuk8YRF0umb+SLA44AB/U6d6GXU2EjpTuPww
OMkUr8EmdbAI3l1tmWJTAkhFQ7681AyIWYOspc1biXZdBrvNBTV8kbDGlomNj19V
QhhN44d4ywIDAQABo1MwUTAdBgNVHQ4EFgQUFRktN33zyW4MR9Cy1Vcn+B+EdYAw
HwYDVR0jBBgwFoAUFRktN33zyW4MR9Cy1Vcn+B+EdYAwDwYDVR0TAQH/BAUwAwEB
/zANBgkqhkiG9w0BAQsFAAOCAQEAkpU+ALElNz+5jOnVAPyYXYsJKfevmKK9uK4v
V+l7GrFLIEhC2qr26S8Nd2pLkrgesCD4xfoOONiVOceU5igh9acFA3+NyOSFLdRN
bSdy0jvCuoiK46ieDAagQtdt0G7HGV4u+jWz0jaKUQI9zJqznOHdJV6RZFIqTYLG
KHnGP+mtXjW3E1djU9vFreYcB6UY+Ai1KB33dnBK9Es2fIQhikKZUPTh6BYsRZT6
U7c6fh+01fRhRPo/SCFmY993857NtoOHMeP0M2V65CG4VjpAPR0msChVQVv7csca
TvBvB23dFRTLbo5PUSWC9bhBrMjzJ7yylt1CNBBHv7ycw8yIPw==
-----END CERTIFICATE-----

View File

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDhzI1Du4fq0AQQ
AP32jFHUJViU6BEMRSokKOSkihUXm4Tf+R+68Qn6Xv9YvnWWpurfm4vm1rsRskcG
9XI0fTQU3YP9iXSf9f5OWFE/zwxLkXR3SvDJAQCHjAQZxSF1Khb1N/JuYtod4IJt
mXELeQFbGvR7pgOVX114zqP46MJ6tDCSKIbCAT11WtUKPV0vLMGFadgalgG9j7fq
QTLRWZ/aykYIHqZ4IAysAzPvl9QO6TxhEXS6Zv5IsDjgAH9Tp3oZdTYSOlO4/DA4
yRSvwSZ1sAjeXW2ZYlMCSEVDvrzUDIhZg6ylzVuJdl0Gu80FNXyRsMaWiY2PX1VC
GE3jh3jLAgMBAAECggEAdnHgoGkc8RXRK7v5fH0653f3sZTSbIdThchVt+IfElUo
LHz4Ig4S191BQQIXmMFSb52ek6aMVsoX7BSQpewPh+pzNGoIXWiiz+IQLNKldnaE
i5cqG6aE6pWOCR6ZYGaFyHhimXkNRaLhiDB3VjdReML5AGujcZWm6Jos9YLTkZ07
pYXs2S+/5oNbfDdAE8dgdD7vD9lNGrbtmJ9+J+VvgPOYM/4LaEAfZU0ALDm2Hl3n
CqkZCp+eWbQK3MC2+6Y4yS+jo7e5/nKX1De9StkX6KumAEIpxkHPZF2EnWXW64oD
k40tKXT+oMXF1RLb4scnv+J+uR4bdl+Xq/VTzKrtsQKBgQDyoOjrv+g5l0s0KKDJ
qPkLQNRCJpzU7Km3CjPuk8DOlmBCr4KUeVfjbYPxQQMkeNL9zFz/QYBmabTCE6Ih
E8BbzT/RQzVPSOOh//Hh4eN4umrYaOIkY4Bv2R2X3H0ELFq+G7pKdvTAkusGHcWu
OAUb2HO5rTiRYq8DvHy8b+qH7wKBgQDuPjR+DCVtkBXmBNf0FZkl7OW/EUQBq4+T
WoaYleq8Gd7ubJgz2Gud+0+L41VjFD9W3hkJAb/3wkASseQ+2hk3Sv/BzpAIdS9e
tN/xxp/8NK7tJGL63m6tAfX+Hi/kSDEp45Zp3PoOD08MEK0yIrpf7S8uJ++u49K4
tKXkGCIg5QKBgFujvPW2AQ8nfqcPpVMleBLxBHqLvPaLALr6poy4z7z3fRoS0j4j
6rcimRAZHwe6fu6PLpzWb5m+2R/obHcTz7acujreqJbuj9OTKRfIyrLBrjNYwfk+
f7c/CPdftvRJkGh3bpBLh7vogc5Ilm5sCDnxMhxyOYhn/nRpz68YkjuPAoGBAOQX
6DfZtyfLcDvV3U/SMdsOkPO6OwsCTya73+tMdP18I2TP0XSpunb5ebIrh7+hTfcE
EqH96+XwM1nyuNy4ALZgdrb95gZC84RP1axsBxX29pcSZDVdKkc3fmW6Tw3XVEKP
o51dNIarf3nEqZ07hIZ81dPx5lbhxgiS49SaimpFAoGBAKamKZFAfUHlaHV/Na1C
3SZji7PaDSj1EFmRkCySK9VqD7Tbh1abrpC2ImdhYHn5TcQQE2eidB+F0Nf6IhKN
upBTofg0ebaslo+BYAqAsRKnUQGDToGIIIdXJ6DnO3wxWu9GY4nKdl3jxqAv2A2x
d8SETw4wqlFFRO33opycuFS5
-----END PRIVATE KEY-----

View File

@ -8,9 +8,9 @@
#include "utility.h"
#include "config.h"
#define CA_DIR SUNSHINE_ASSETS_DIR "/demoCA"
#define PRIVATE_KEY_FILE CA_DIR "/cakey.pem"
#define CERTIFICATE_FILE CA_DIR "/cacert.pem"
#define CA_DIR "credentials"
#define PRIVATE_KEY_FILE CA_DIR "/cakey.pem"
#define CERTIFICATE_FILE CA_DIR "/cacert.pem"
#define APPS_JSON_PATH SUNSHINE_ASSETS_DIR "/" APPS_JSON
namespace config {

View File

@ -5,6 +5,10 @@
#include <openssl/pem.h>
#include "crypto.h"
namespace crypto {
using big_num_t = util::safe_ptr<BIGNUM, BN_free>;
//using rsa_t = util::safe_ptr<RSA, RSA_free>;
using asn1_string_t = util::safe_ptr<ASN1_STRING, ASN1_STRING_free>;
cert_chain_t::cert_chain_t() : _certs {}, _cert_ctx {X509_STORE_CTX_new() } {}
void cert_chain_t::add(x509_t &&cert) {
x509_store_t x509_store { X509_STORE_new() };
@ -200,6 +204,25 @@ pkey_t pkey(const std::string_view &k) {
return pkey_t { p };
}
std::string pem(x509_t &x509) {
bio_t bio { BIO_new(BIO_s_mem()) };
PEM_write_bio_X509(bio.get(), x509.get());
BUF_MEM *mem_ptr;
BIO_get_mem_ptr(bio.get(), &mem_ptr);
return { mem_ptr->data, mem_ptr->length };
}
std::string pem(pkey_t &pkey) {
bio_t bio { BIO_new(BIO_s_mem()) };
PEM_write_bio_PrivateKey(bio.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr);
BUF_MEM *mem_ptr;
BIO_get_mem_ptr(bio.get(), &mem_ptr);
return { mem_ptr->data, mem_ptr->length };
}
std::string_view signature(const x509_t &x) {
// X509_ALGOR *_ = nullptr;
@ -242,6 +265,48 @@ std::vector<uint8_t> sign(const pkey_t &pkey, const std::string_view &data, cons
return digest;
}
creds_t gen_creds(const std::string_view &cn, std::uint32_t key_bits) {
x509_t x509 { X509_new() };
pkey_t pkey { EVP_PKEY_new() };
big_num_t big_num { BN_new() };
BN_set_word(big_num.get(), RSA_F4);
auto rsa = RSA_new();
RSA_generate_key_ex(rsa, key_bits, big_num.get(), nullptr);
EVP_PKEY_assign_RSA(pkey.get(), rsa);
X509_set_version(x509.get(), 2);
ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), 0);
constexpr auto year = 60 * 60 * 24 * 365;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
X509_gmtime_adj(X509_get_notBefore(x509.get()), 0);
X509_gmtime_adj(X509_get_notAfter(x509.get()), 20 * year);
#else
asn1_string_t not_before { ASN1_STRING_dup(X509_get0_notBefore(x509.get())) };
asn1_string_t not_after { ASN1_STRING_dup(X509_get0_notAfter(x509.get())) };
X509_gmtime_adj(not_before.get(), 0);
X509_gmtime_adj(not_after.get(), 20 * year);
X509_set1_notBefore(x509.get(), not_before.get());
X509_set1_notAfter(x509.get(), not_after.get());
#endif
X509_set_pubkey(x509.get(), pkey.get());
auto name = X509_get_subject_name(x509.get());
X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_ASC,
(const std::uint8_t*)cn.data(), cn.size(),
-1, 0);
X509_set_issuer_name(x509.get(), name);
X509_sign(x509.get(), pkey.get(), EVP_sha256());
return { pem(x509), pem(pkey) };
}
std::vector<uint8_t> sign256(const pkey_t &pkey, const std::string_view &data) {
return sign(pkey, data, EVP_sha256());
}

View File

@ -15,6 +15,10 @@
#include "utility.h"
namespace crypto {
struct creds_t {
std::string x509;
std::string pkey;
};
constexpr std::size_t digest_size = 256;
void md_ctx_destroy(EVP_MD_CTX *);
@ -35,10 +39,13 @@ aes_t gen_aes_key(const std::array<uint8_t, 16> &salt, const std::string_view &p
x509_t x509(const std::string_view &x);
pkey_t pkey(const std::string_view &k);
std::string pem(x509_t &x509);
std::string pem(pkey_t &pkey);
std::vector<uint8_t> sign256(const pkey_t &pkey, const std::string_view &data);
bool verify256(const x509_t &x509, const std::string_view &data, const std::string_view &signature);
creds_t gen_creds(const std::string_view &cn, std::uint32_t key_bits);
std::string_view signature(const x509_t &x);

View File

@ -38,6 +38,7 @@ namespace fs = std::filesystem;
namespace pt = boost::property_tree;
std::string read_file(const char *path);
int write_file(const char *path, const std::string_view &contents);
using https_server_t = SimpleWeb::Server<SimpleWeb::HTTPS>;
using http_server_t = SimpleWeb::Server<SimpleWeb::HTTP>;
@ -652,7 +653,69 @@ void appasset(resp_https_t response, req_https_t request) {
response->write(SimpleWeb::StatusCode::success_ok, in);
}
int create_creds(const std::string &pkey, const std::string &cert) {
fs::path pkey_path = pkey;
fs::path cert_path = cert;
auto creds = crypto::gen_creds("Sunshine Gamestream Host"sv, 2048);
auto pkey_dir = pkey_path;
auto cert_dir = cert_path;
pkey_dir.remove_filename();
cert_dir.remove_filename();
std::error_code err_code{};
fs::create_directories(pkey_dir, err_code);
if (err_code) {
BOOST_LOG(fatal) << "Couldn't create directory ["sv << pkey_dir << "] :"sv << err_code.message();
return -1;
}
fs::create_directories(cert_dir, err_code);
if (err_code) {
BOOST_LOG(fatal) << "Couldn't create directory ["sv << cert_dir << "] :"sv << err_code.message();
return -1;
}
if (write_file(pkey.c_str(), creds.pkey)) {
BOOST_LOG(fatal) << "Couldn't open ["sv << config::nvhttp.pkey << ']';
return -1;
}
if (write_file(cert.c_str(), creds.x509)) {
BOOST_LOG(fatal) << "Couldn't open ["sv << config::nvhttp.cert << ']';
return -1;
}
fs::permissions(pkey_path,
fs::perms::owner_read | fs::perms::owner_write,
fs::perm_options::replace, err_code);
if (err_code) {
BOOST_LOG(fatal) << "Couldn't change permissions of ["sv << config::nvhttp.pkey << "] :"sv << err_code.message();
return -1;
}
fs::permissions(cert_path,
fs::perms::owner_read | fs::perms::group_read | fs::perms::others_read | fs::perms::owner_write,
fs::perm_options::replace, err_code);
if (err_code) {
BOOST_LOG(fatal) << "Couldn't change permissions of ["sv << config::nvhttp.cert << "] :"sv << err_code.message();
return -1;
}
return 0;
}
void start(std::shared_ptr<safe::event_t<bool>> shutdown_event) {
if(!fs::exists(config::nvhttp.pkey) || !fs::exists(config::nvhttp.cert)) {
if(create_creds(config::nvhttp.pkey, config::nvhttp.cert)) {
shutdown_event->raise(true);
return;
}
}
origin_pin_allowed = net::from_enum_string(config::nvhttp.origin_pin_allowed);
load_state();
@ -748,6 +811,18 @@ void start(std::shared_ptr<safe::event_t<bool>> shutdown_event) {
tcp.join();
}
int write_file(const char *path, const std::string_view &contents) {
std::ofstream out(path);
if(!out.is_open()) {
return -1;
}
out << contents;
return 0;
}
std::string read_file(const char *path) {
std::ifstream in(path);