43#include <openssl/bn.h>
44#include <openssl/err.h>
45#include <openssl/evp.h>
46#include <openssl/pem.h>
47#include <openssl/rsa.h>
48#include <openssl/x509.h>
49#include <openssl/x509v3.h>
57#if OPENSSL_VERSION_NUMBER < 0x10100000L
58#ifndef BN_RAND_TOP_ANY
60#define BN_RAND_TOP_ANY (-1)
62#ifndef BN_RAND_BOTTOM_ANY
64#define BN_RAND_BOTTOM_ANY 0
66#ifndef X509_getm_notBefore
68#define X509_getm_notBefore(x) X509_get_notBefore(x)
70#ifndef X509_getm_notAfter
72#define X509_getm_notAfter(x) X509_get_notAfter(x)
75#define N_X509_EXT_VALUE(v) ((char*)(uintptr_t)(v))
78#define N_X509_EXT_VALUE(v) (v)
81#if OPENSSL_VERSION_NUMBER < 0x10100000L
93 OpenSSL_add_all_algorithms();
94 ERR_load_crypto_strings();
98#define N_X509_INIT() ((void)pthread_once(&n_x509_once, n_x509_init_openssl))
101#define N_X509_INIT() ((void)0)
105#define N_X509_KEY_BITS 2048
107#define N_X509_SERIAL_BITS 64
109#define N_X509_SAN_BUF 300
115 BIO_get_mem_ptr(bio, &mem);
116 if (!mem || !mem->data || mem->length == 0)
126 BIO* bio = BIO_new(BIO_s_mem());
130 if (PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL) == 1)
138 BIO* bio = BIO_new(BIO_s_mem());
142 if (PEM_write_bio_X509(bio, x) == 1)
150 BIGNUM* bn = BN_new();
155 ASN1_INTEGER* serial = X509_get_serialNumber(x);
156 if (serial && BN_to_ASN1_INTEGER(bn, serial) != NULL)
164static int add_ext(X509* issuer, X509* subject,
int nid,
const char* value) {
168 X509V3_set_ctx_nodb(&ctx);
169 X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0);
172 if (X509_add_ext(subject, ext, -1) == 1)
174 X509_EXTENSION_free(ext);
180static int set_cn(X509_NAME* name,
const char* cn) {
181 if (X509_NAME_add_entry_by_txt(name,
"CN", MBSTRING_ASC, (
const unsigned char*)cn, -1, -1, 0) == 1)
188 unsigned char buf[16];
189 if (inet_pton(AF_INET, host, buf) == 1)
191 if (inet_pton(AF_INET6, host, buf) == 1)
199 EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
200 EVP_PKEY* pkey = NULL;
203 if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0 || EVP_PKEY_keygen(ctx, &pkey) <= 0)
205 EVP_PKEY_CTX_free(ctx);
218 n_log(
LOG_ERR,
"n_x509: RSA key generation failed (%d bits)", bits);
227 EVP_PKEY* pkey = NULL;
246 if (X509_set_version(x, 2) != 1)
252 if (X509_set_pubkey(x, pkey) != 1)
254 name = X509_get_subject_name(x);
255 if (
set_cn(name, cn) != 0)
257 if (X509_set_issuer_name(x, name) != 1)
259 if (
add_ext(x, x, NID_basic_constraints,
"critical,CA:TRUE") != 0)
261 if (
add_ext(x, x, NID_key_usage,
"critical,keyCertSign,cRLSign") != 0)
263 if (
add_ext(x, x, NID_subject_key_identifier,
"hash") != 0)
265 if (X509_sign(x, pkey, EVP_sha256()) == 0) {
286 EVP_PKEY* leaf_key = NULL;
287 EVP_PKEY* ca_key = NULL;
290 BIO* bio_cert = NULL;
304 bio_cert = BIO_new_mem_buf(ca_cert_pem->
data, (
int)ca_cert_pem->
written);
305 bio_key = BIO_new_mem_buf(ca_key_pem->
data, (
int)ca_key_pem->
written);
306 if (!bio_cert || !bio_key)
308 ca = PEM_read_bio_X509(bio_cert, NULL, NULL, NULL);
309 ca_key = PEM_read_bio_PrivateKey(bio_key, NULL, NULL, NULL);
310 if (!ca || !ca_key) {
311 n_log(
LOG_ERR,
"n_x509: could not parse CA certificate/key");
321 if (X509_set_version(x, 2) != 1)
327 if (X509_set_pubkey(x, leaf_key) != 1)
329 name = X509_get_subject_name(x);
330 if (
set_cn(name, host) != 0)
332 if (X509_set_issuer_name(x, X509_get_subject_name(ca)) != 1)
334 if (
add_ext(ca, x, NID_basic_constraints,
"critical,CA:FALSE") != 0)
336 if (
add_ext(ca, x, NID_key_usage,
"critical,digitalSignature,keyEncipherment") != 0)
338 if (
add_ext(ca, x, NID_ext_key_usage,
"serverAuth") != 0)
340 snprintf(san,
sizeof(san),
"%s:%s",
host_is_ip(host) ?
"IP" :
"DNS", host);
341 if (
add_ext(ca, x, NID_subject_alt_name, san) != 0)
343 if (X509_sign(x, ca_key, EVP_sha256()) == 0) {
361 EVP_PKEY_free(leaf_key);
363 EVP_PKEY_free(ca_key);
#define __n_assert(__ptr, __ret)
macro to assert things
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
#define LOG_ERR
error conditions
size_t written
number of meaningful bytes in data, excluding the null terminator; the size including the null termin...
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
int char_to_nstr_ex(const char *from, NSTRBYTE nboct, N_STR **to)
Convert a char into a N_STR, extended version.
A box including a string and his lenght.
int n_x509_generate_ca(const char *cn, int days, N_STR **ca_cert_pem, N_STR **ca_key_pem)
Generate a self-signed certificate authority (CA) keypair and cert.
int n_x509_keypair_pem(int bits, N_STR **key_pem)
Generate an RSA private key and return it as a PEM string.
int n_x509_mint_host_cert(const char *host, const N_STR *ca_cert_pem, const N_STR *ca_key_pem, int days, N_STR **leaf_cert_pem, N_STR **leaf_key_pem)
Mint a per-host leaf certificate signed by the given CA.
Common headers and low-level functions & define.
#define N_X509_INIT()
populate the EVP algorithm table once, no-op from 1.1.0 on
static int add_ext(X509 *issuer, X509 *subject, int nid, const char *value)
static int pkey_to_pem(EVP_PKEY *pkey, N_STR **out)
#define X509_getm_notAfter(x)
pre-1.1.0 spelling of the mutable notAfter accessor
static EVP_PKEY * gen_rsa(int bits)
static void n_x509_init_openssl(void)
static int x509_to_pem(X509 *x, N_STR **out)
static pthread_once_t n_x509_once
#define N_X509_SERIAL_BITS
random serial number size in bits
static int set_cn(X509_NAME *name, const char *cn)
#define BN_RAND_TOP_ANY
BN_rand(): leave the most significant bit unconstrained.
#define N_X509_EXT_VALUE(v)
pre-1.1.0 X509V3_EXT_conf_nid() declares value as char*, it does not write to it
static int set_random_serial(X509 *x)
#define N_X509_KEY_BITS
RSA modulus size in bits used for the CA and leaf keys.
static int host_is_ip(const char *host)
#define X509_getm_notBefore(x)
pre-1.1.0 spelling of the mutable notBefore accessor
static int bio_to_nstr(BIO *bio, N_STR **out)
#define N_X509_SAN_BUF
buffer size for a subjectAltName value string
#define BN_RAND_BOTTOM_ANY
BN_rand(): leave the least significant bit unconstrained.
X.509 helpers: self-signed CA generation and per-host leaf minting.