#include "driver-ssl.hpp" #include #include #include #include extern std::string strerror_str(int err); namespace drvssl { const char *dummy_cert = "-----BEGIN CERTIFICATE-----\n" "MIIDezCCAmOgAwIBAgIUajKmxrLMr9zBMlphrTJU5qKG8FgwDQYJKoZIhvcNAQEL\n" "BQAwTDELMAkGA1UEBhMCVVMxFTATBgNVBAgMDFBlbm5zeWx2YW5pYTESMBAGA1UE\n" "CgwJbG9jYWxob3N0MRIwEAYDVQQDDAlsb2NhbGhvc3QwIBcNMjIwMzIyMTczMzA4\n" "WhgPMjEyMjAyMjYxNzMzMDhaMEwxCzAJBgNVBAYTAlVTMRUwEwYDVQQIDAxQZW5u\n" "c3lsdmFuaWExEjAQBgNVBAoMCWxvY2FsaG9zdDESMBAGA1UEAwwJbG9jYWxob3N0\n" "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5OWIaKqYae4nPxvu5EP3\n" "VilcjApYcMT4+2ypfQoB6PEep5lwguA929rNsTKnhGsEiQAZ0eZPEZN7VhUwf/hz\n" "26jIyTT43ELkt6k97wwSZSXuT65RpSiemwEs6g2mMwzpgP6nv+yam4HjE9AKiHGN\n" "YeTV72Nw1EN70t6IjIf4jsJRXqDJkUx5sSSD6j0WBTOhzozIDgZHTDwiLhatE66m\n" "SNoD8oWC0PscbUgOJkFpbaCAS8RJmpsdgkTFae2rzL9cOFLGw6OgV/BV1J1s0ks8\n" "+veoMMtIO6fese+OZ+DyQbuGaoaltZUXzY6QjD5l34m2mGplelT7BrpcqJTBHwmh\n" "CwIDAQABo1MwUTAdBgNVHQ4EFgQUXQM5TVfJ9gpUXg8fZ8yfuUVcBP8wHwYDVR0j\n" "BBgwFoAUXQM5TVfJ9gpUXg8fZ8yfuUVcBP8wDwYDVR0TAQH/BAUwAwEB/zANBgkq\n" "hkiG9w0BAQsFAAOCAQEAqYX/ZGv0Qh/xdXppjnqojm8mH0giDW4tvwMqHcW3YRa3\n" "9J2yYot+rHjU5g4n6HEmWDBE0eqLz9n3Y3fkFzT8RWZwBaST965CgsfGofyuA2hC\n" "Ddn4Am3B5tTPmi8WWRZg8amhpGVD/mwkoVFIK0M337b1aZUJYPE+Kc9WetSL2KqB\n" "EhqSQpkAWhVadzP85dq2T9EDjAvhlFTFlDEBx1GDUcc8M0KQ9NEvLT7LgoUcbMiT\n" "PerlSZQTB0crchXTRSERgiwu80r7D6STn/RcPL9Fg5PkA94/d87jGbmV4sxSRsvM\n" "z+DnJGjHrV1J/jHPrnVvVLpigBlGno3C5O/sRw3gcQ==\n" "-----END CERTIFICATE-----\n"; const char *dummy_key = "-----BEGIN PRIVATE KEY-----\n" "MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDk5Yhoqphp7ic/\n" "G+7kQ/dWKVyMClhwxPj7bKl9CgHo8R6nmXCC4D3b2s2xMqeEawSJABnR5k8Rk3tW\n" "FTB/+HPbqMjJNPjcQuS3qT3vDBJlJe5PrlGlKJ6bASzqDaYzDOmA/qe/7JqbgeMT\n" "0AqIcY1h5NXvY3DUQ3vS3oiMh/iOwlFeoMmRTHmxJIPqPRYFM6HOjMgOBkdMPCIu\n" "Fq0TrqZI2gPyhYLQ+xxtSA4mQWltoIBLxEmamx2CRMVp7avMv1w4UsbDo6BX8FXU\n" "nWzSSzz696gwy0g7p96x745n4PJBu4ZqhqW1lRfNjpCMPmXfibaYamV6VPsGulyo\n" "lMEfCaELAgMBAAECggEBAJa1AiFX4U4tva1xqNKmZV1XklWqIhzts7lnDBkF08gZ\n" "qcNT5Z5mIpR09eVropwvEidZ56Yp63l5D0XYYbyAS1gfQ0QnGot7h7fdOKgB3MK4\n" "PLY94gfKPNN17KqWHg2SvNNv1+cn04v78xUCb0zy5tHDp5Acexdm70ohtupARElJ\n" "LSHdS7ebsqZUFXbbM3BpPEsQLi3PrzNs1DrKkZ3rR6eMGrsDqExXx8/foi9aZKsd\n" "BGM2/kcTJ5aY6NhSv5iqO1oK46sbMrjVW/bYNsOyl0eFjwTRahn+Zhp/JMewZYeu\n" "715g6kzbZNwEzBLgrhNPF6E2ycEr/C6z5bE78g5QCkECgYEA8s07UUY25bjYiWWy\n" "W38pT7d/OXBSyKnq16N6MjVahl29r7nezFiDeLhLC0QiwXu/+qyxVZkB95MMGZXS\n" "AsaKFNis3AJ6eR4SYyhpSScYKNvlKIiW37TtR4FDcy7y5LL6tFpiDDIGH3LuyWNo\n" "d76142MBpv5aStnLGYU3pcZj43sCgYEA8VbNM4nqgSCQcbnHYjvsgphEMNSaoVie\n" "xob2uigXdV6Te0ayoUFBnVNKVsRhk+sswuTV4k1pK/On+USVl2tQ16tcaVMjTfSD\n" "HLYTJLmt6s4DcywWj5dfkbDoe5PulGXNZE960qXmOC62Lf0VMRwJ5x4FBRvGTjKC\n" "zvekI2/kO7ECgYEAhBGeclb/BXXGUvY+TgadMf9d9KBkZ0IFu8Xwcd8TnoLe6vbv\n" "ebery75zE228egIWKwREcYsIxuH1cvVLhrb35N73J7UxaTAyUD1rB598RL1XqPSj\n" "HIwNhReK2NxwwnWYaQHA02FiczjRKjooWPojdcwk2fEArDZLg1YzLrj7HIECgYEA\n" "htdx1Y8ESFtyeShMv5UtoxYCW6oeL3H9XH0CE6bc3IYYLvOkULbOO2HTEkGtJ2Fp\n" "5AbJfiS0U4tS2dI5Jp4eUDH9cxexjRfFvd/5ODbKdnver5X9kQMJsbQ/YPSZg66R\n" "oK9Lt7Bbvh5TScSy93psCgba1SzckspkDdGNkwMsaTECgYEAnFWaxormLUpXQRLs\n" "tKzMMHgVnHlsHiqXH432zmT2fpGZHYoWbsGuQjjrHGnSiu3QbDhnzM6y/T2GRs6z\n" "zHteIo/tzIyxg4MvJGJ9qANA7HoiKBdQ7G/I/NLJIyWAjj+e7/hgzKFcf+dpjpDq\n" "HcKc9a4WXhC7yu79e5BnKWltHXY=\n" "-----END PRIVATE KEY-----\n"; std::string errors_string(bool lastonly) { std::string err; const char *file, *data; int line, flags; // const char *func; while (true) { // Newer versions of the SSL API support this. // unsigned long code = // ERR_get_error_all(&file, &line, &func, &data, &flags); // Older versions of the SSL API support this. unsigned long code = ERR_get_error_line_data(&file, &line, &data, &flags); if (code == 0) break; std::string reason; const char *rc = ERR_reason_error_string(code); if (rc != nullptr) { reason = rc; } else { reason = "sys:" + strerror_str(ERR_GET_REASON(code)); } if (err.empty() || lastonly) { err = reason; } else { err = err + ", " + reason; } if ((data != nullptr) && (data[0] != 0)) { err = err + " " + data; } } return err; } void assert_errors_empty() { int code = ERR_peek_error(); if (code != 0) { std::cerr << "SSL should not have errors at this point." << std::endl; ERR_print_errors_fp(stderr); exit(1); } } SSL_CTX *new_context(int verify) { SSL_CTX *ctx = SSL_CTX_new(TLS_method()); SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); SSL_CTX_set_verify(ctx, verify, nullptr); return ctx; } static int ctx_use_certificate_str(SSL_CTX *ctx, const char *str) { UniqueBIO bio(BIO_new(BIO_s_mem())); BIO_puts(bio.get(), str); UniqueX509 certificate(PEM_read_bio_X509(bio.get(), NULL, NULL, NULL)); return SSL_CTX_use_certificate(ctx, certificate.get()); } static int ctx_use_privatekey_str(SSL_CTX *ctx, const char *str) { UniqueBIO bio(BIO_new(BIO_s_mem())); BIO_puts(bio.get(), str); UniquePKEY pkey(PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL)); return SSL_CTX_use_PrivateKey(ctx, pkey.get()); } void ctx_load_dummy_cert(SSL_CTX *ctx) { ERR_clear_error(); if (ctx_use_certificate_str(ctx, dummy_cert) <= 0) { ERR_print_errors_fp(stderr); exit(1); } if (ctx_use_privatekey_str(ctx, dummy_key) <= 0) { ERR_print_errors_fp(stderr); exit(1); } } static int count_certificates(const char *fn) { static char null_passwd; ErrClearErrorOnExit ece; UniqueBIO bio(BIO_new(BIO_s_file())); assert(bio != nullptr); if (BIO_read_filename(bio.get(), fn) <= 0) { std::cerr << "Cannot open file: " << fn << std::endl; exit(1); } int total = 0; while (true) { UniqueX509 x(PEM_read_bio_X509_AUX(bio.get(), nullptr, nullptr, &null_passwd)); if (x == nullptr) break; total += 1; } return total; } static bool contains_privatekey(const char *fn) { static char null_passwd; ErrClearErrorOnExit ece; UniqueBIO bio(BIO_new(BIO_s_file())); assert(bio != nullptr); if (BIO_read_filename(bio.get(), fn) <= 0) { std::cerr << "Cannot open file: " << fn << std::endl; exit(1); } UniquePKEY k(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, &null_passwd)); return k != nullptr; } void ctx_load_cert_from_directory(SSL_CTX *ctx, const std::string &dir) { std::vector key_paths; std::vector cert_paths; for (const auto & entry : std::filesystem::directory_iterator(dir)) { std::string fn = entry.path(); if (count_certificates(fn.c_str()) >= 1) { cert_paths.push_back(fn); } if (contains_privatekey(fn.c_str())) { key_paths.push_back(fn); } } if (cert_paths.size() > 1) { std::cerr << "Directory contains multiple certs: " << dir << std::endl; exit(1); } if (key_paths.size() > 1) { std::cerr << "Directory contains multiple keys: " << dir << std::endl; exit(1); } if (cert_paths.empty()) { std::cerr << "Directory doesn't contain a cert: " << dir << std::endl; exit(1); } if (key_paths.empty()) { std::cerr << "Directory doesn't contain a key: " << dir << std::endl; exit(1); } int status; status = SSL_CTX_use_PrivateKey_file(ctx, key_paths[0].c_str(), SSL_FILETYPE_PEM); assert(status == 1); status = SSL_CTX_use_certificate_chain_file(ctx, cert_paths[0].c_str()); assert(status == 1); } } // namespace drvssl