Use openssl library instead of CLI to generate certificates
This commit is contained in:
parent
dbf56a9375
commit
aa3afa9062
|
@ -0,0 +1 @@
|
|||
Barrier no longer uses openssl CLI tool for any operations and hooks into the openssl library directly.
|
|
@ -1,65 +0,0 @@
|
|||
#
|
||||
# Barrier OpenSSL configuration file.
|
||||
# Used for generation of certificate requests.
|
||||
#
|
||||
|
||||
dir = .
|
||||
|
||||
[ca]
|
||||
default_ca = CA_default
|
||||
|
||||
[CA_default]
|
||||
serial = $dir/serial
|
||||
database = $dir/certindex.txt
|
||||
new_certs_dir = $dir/certs
|
||||
certificate = $dir/cacert.pem
|
||||
private_key = $dir/private/cakey.pem
|
||||
default_days = 365
|
||||
default_md = md5
|
||||
preserve = no
|
||||
email_in_dn = no
|
||||
nameopt = default_ca
|
||||
certopt = default_ca
|
||||
policy = policy_match
|
||||
|
||||
[policy_match]
|
||||
countryName = match
|
||||
stateOrProvinceName = match
|
||||
organizationName = match
|
||||
organizationalUnitName = optional
|
||||
commonName = supplied
|
||||
emailAddress = optional
|
||||
|
||||
[req]
|
||||
default_bits = 2048 # Size of keys
|
||||
default_keyfile = key.pem # name of generated keys
|
||||
default_md = md5 # message digest algorithm
|
||||
string_mask = nombstr # permitted characters
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = v3_req
|
||||
|
||||
[req_distinguished_name]
|
||||
0.organizationName = Organization Name (company)
|
||||
organizationalUnitName = Organizational Unit Name (department, division)
|
||||
emailAddress = Email Address
|
||||
emailAddress_max = 40
|
||||
localityName = Locality Name (city, district)
|
||||
stateOrProvinceName = State or Province Name (full name)
|
||||
countryName = Country Name (2 letter code)
|
||||
countryName_min = 2
|
||||
countryName_max = 2
|
||||
commonName = Common Name (hostname, IP, or your name)
|
||||
commonName_max = 64
|
||||
0.organizationName_default = My Company
|
||||
localityName_default = My Town
|
||||
stateOrProvinceName_default = State or Providence
|
||||
countryName_default = US
|
||||
|
||||
[v3_ca]
|
||||
basicConstraints = CA:TRUE
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer:always
|
||||
|
||||
[v3_req]
|
||||
basicConstraints = CA:FALSE
|
||||
subjectKeyIdentifier = hash
|
|
@ -30,16 +30,8 @@
|
|||
#include <openssl/pem.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
static const char kCertificateLifetime[] = "365";
|
||||
static const char kCertificateSubjectInfo[] = "/CN=Barrier";
|
||||
static const char kCertificateFilename[] = "Barrier.pem";
|
||||
static const char kSslDir[] = "SSL";
|
||||
static const char kUnixOpenSslCommand[] = "openssl";
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
static const char kWinOpenSslBinary[] = "openssl.exe";
|
||||
static const char kConfigFile[] = "barrier.conf";
|
||||
#endif
|
||||
|
||||
SslCertificate::SslCertificate(QObject *parent) :
|
||||
QObject(parent)
|
||||
|
@ -50,93 +42,21 @@ SslCertificate::SslCertificate(QObject *parent) :
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> SslCertificate::runTool(const QStringList& args)
|
||||
{
|
||||
QString program;
|
||||
#if defined(Q_OS_WIN)
|
||||
program = QCoreApplication::applicationDirPath();
|
||||
program.append("\\").append(kWinOpenSslBinary);
|
||||
#else
|
||||
program = kUnixOpenSslCommand;
|
||||
#endif
|
||||
|
||||
|
||||
QStringList environment;
|
||||
#if defined(Q_OS_WIN)
|
||||
environment << QString("OPENSSL_CONF=%1\\%2")
|
||||
.arg(QCoreApplication::applicationDirPath())
|
||||
.arg(kConfigFile);
|
||||
#endif
|
||||
|
||||
QProcess process;
|
||||
process.setEnvironment(environment);
|
||||
process.start(program, args);
|
||||
|
||||
bool success = process.waitForStarted();
|
||||
std::string output;
|
||||
|
||||
QString standardError;
|
||||
if (success && process.waitForFinished())
|
||||
{
|
||||
output = process.readAllStandardOutput().trimmed().toStdString();
|
||||
standardError = process.readAllStandardError().trimmed();
|
||||
}
|
||||
|
||||
int code = process.exitCode();
|
||||
if (!success || code != 0)
|
||||
{
|
||||
emit error(
|
||||
QString("SSL tool failed: %1\n\nCode: %2\nError: %3")
|
||||
.arg(program)
|
||||
.arg(process.exitCode())
|
||||
.arg(standardError.isEmpty() ? "Unknown" : standardError));
|
||||
return {false, output};
|
||||
}
|
||||
|
||||
return {true, output};
|
||||
}
|
||||
|
||||
void SslCertificate::generateCertificate()
|
||||
{
|
||||
auto filename = QString::fromStdString(getCertificatePath());
|
||||
|
||||
QFile file(filename);
|
||||
if (!file.exists() || !isCertificateValid(filename)) {
|
||||
QStringList arguments;
|
||||
|
||||
// self signed certificate
|
||||
arguments.append("req");
|
||||
arguments.append("-x509");
|
||||
arguments.append("-nodes");
|
||||
|
||||
// valid duration
|
||||
arguments.append("-days");
|
||||
arguments.append(kCertificateLifetime);
|
||||
|
||||
// subject information
|
||||
arguments.append("-subj");
|
||||
|
||||
QString subInfo(kCertificateSubjectInfo);
|
||||
arguments.append(subInfo);
|
||||
|
||||
// private key
|
||||
arguments.append("-newkey");
|
||||
arguments.append("rsa:2048");
|
||||
|
||||
QDir sslDir(QString::fromStdString(getCertificateDirectory()));
|
||||
if (!sslDir.exists()) {
|
||||
sslDir.mkpath(".");
|
||||
}
|
||||
|
||||
// key output filename
|
||||
arguments.append("-keyout");
|
||||
arguments.append(filename);
|
||||
|
||||
// certificate output filename
|
||||
arguments.append("-out");
|
||||
arguments.append(filename);
|
||||
|
||||
if (!runTool(arguments).first) {
|
||||
try {
|
||||
barrier::generate_pem_self_signed_cert(filename.toStdString());
|
||||
} catch (const std::exception& e) {
|
||||
emit error(QString("SSL tool failed: %1").arg(e.what()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "base/finally.h"
|
||||
#include "io/fstream.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/pem.h>
|
||||
|
@ -97,4 +98,48 @@ std::vector<std::uint8_t> get_pem_file_cert_fingerprint(const std::string& path,
|
|||
return get_ssl_cert_fingerprint(cert, type);
|
||||
}
|
||||
|
||||
void generate_pem_self_signed_cert(const std::string& path)
|
||||
{
|
||||
auto expiration_days = 365;
|
||||
|
||||
auto* private_key = EVP_PKEY_new();
|
||||
if (!private_key) {
|
||||
throw std::runtime_error("Could not allocate private key for certificate");
|
||||
}
|
||||
auto private_key_free = finally([private_key](){ EVP_PKEY_free(private_key); });
|
||||
|
||||
auto* rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
|
||||
if (!rsa) {
|
||||
throw std::runtime_error("Failed to generate RSA key");
|
||||
}
|
||||
EVP_PKEY_assign_RSA(private_key, rsa);
|
||||
|
||||
auto* cert = X509_new();
|
||||
if (!cert) {
|
||||
throw std::runtime_error("Could not allocate certificate");
|
||||
}
|
||||
auto cert_free = finally([cert]() { X509_free(cert); });
|
||||
|
||||
ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
|
||||
X509_gmtime_adj(X509_get_notBefore(cert), 0);
|
||||
X509_gmtime_adj(X509_get_notAfter(cert), expiration_days * 24 * 3600);
|
||||
X509_set_pubkey(cert, private_key);
|
||||
|
||||
auto* name = X509_get_subject_name(cert);
|
||||
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
|
||||
reinterpret_cast<const unsigned char *>("Barrier"), -1, -1, 0);
|
||||
X509_set_issuer_name(cert, name);
|
||||
|
||||
X509_sign(cert, private_key, EVP_sha256());
|
||||
|
||||
auto fp = fopen_utf8_path(path.c_str(), "r");
|
||||
if (!fp) {
|
||||
throw std::runtime_error("Could not open certificate output path");
|
||||
}
|
||||
auto file_close = finally([fp]() { std::fclose(fp); });
|
||||
|
||||
PEM_write_PrivateKey(fp, private_key, nullptr, nullptr, 0, nullptr, nullptr);
|
||||
PEM_write_X509(fp, cert);
|
||||
}
|
||||
|
||||
} // namespace barrier
|
||||
|
|
|
@ -38,6 +38,8 @@ std::vector<std::uint8_t> get_ssl_cert_fingerprint(X509* cert, FingerprintType t
|
|||
std::vector<std::uint8_t> get_pem_file_cert_fingerprint(const std::string& path,
|
||||
FingerprintType type);
|
||||
|
||||
void generate_pem_self_signed_cert(const std::string& path);
|
||||
|
||||
} // namespace barrier
|
||||
|
||||
#endif // BARRIER_LIB_NET_SECUREUTILS_H
|
||||
|
|
Loading…
Reference in New Issue