mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
add selfsigned cert generation api
This commit is contained in:
parent
a798db0e2b
commit
1f37ec0be9
8 changed files with 203 additions and 9 deletions
|
@ -1077,7 +1077,7 @@ enum lws_callback_reasons {
|
|||
* including OpenSSL support, this callback allows your user code
|
||||
* to load extra certifcates into the server which allow it to
|
||||
* verify the validity of certificates returned by clients. user
|
||||
* is the server's OpenSSL SSL_CTX* */
|
||||
* is the server's OpenSSL SSL_CTX* and in is the lws_vhost * */
|
||||
LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION = 23,
|
||||
/**< if the libwebsockets vhost was created with the option
|
||||
* LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this
|
||||
|
@ -1462,6 +1462,8 @@ lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
#define LWS_CB_REASON_AUX_BF__CGI_HEADERS 8
|
||||
///@}
|
||||
|
||||
struct lws_vhost;
|
||||
|
||||
/*! \defgroup generic hash
|
||||
* ## Generic Hash related functions
|
||||
*
|
||||
|
@ -2233,8 +2235,6 @@ struct lws_protocols {
|
|||
* This is part of the ABI, don't needlessly break compatibility */
|
||||
};
|
||||
|
||||
struct lws_vhost;
|
||||
|
||||
/**
|
||||
* lws_vhost_name_to_protocol() - get vhost's protocol object from its name
|
||||
*
|
||||
|
@ -5526,6 +5526,24 @@ lws_tls_peer_cert_info(struct lws *wsi, enum lws_tls_cert_info type,
|
|||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_tls_vhost_cert_info(struct lws_vhost *vhost, enum lws_tls_cert_info type,
|
||||
union lws_tls_cert_info_results *buf, size_t len);
|
||||
|
||||
/**
|
||||
* lws_tls_acme_sni_cert_create() - creates a temp selfsigned cert
|
||||
* and attaches to a vhost
|
||||
*
|
||||
* \param vhost: the vhost to acquire the selfsigned cert
|
||||
* \param san_a: SAN written into the certificate
|
||||
* \param san_b: second SAN written into the certificate
|
||||
*
|
||||
*
|
||||
* Returns 0 if created and attached to the vhost. Returns -1 if problems and
|
||||
* frees all allocations before returning.
|
||||
*
|
||||
* On success, any allocations are destroyed at vhost destruction automatically.
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
|
||||
const char *san_b);
|
||||
///@}
|
||||
|
||||
/** \defgroup lws_ring LWS Ringbuffer APIs
|
||||
|
|
|
@ -969,6 +969,8 @@ struct http2_settings {
|
|||
* SSL SNI -> wsi -> bind after SSL negotiation
|
||||
*/
|
||||
|
||||
struct lws_tls_ss_pieces;
|
||||
|
||||
struct lws_vhost {
|
||||
#if !defined(LWS_WITH_ESP8266)
|
||||
char http_proxy_address[128];
|
||||
|
@ -1004,6 +1006,7 @@ struct lws_vhost {
|
|||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
lws_tls_ctx *ssl_ctx;
|
||||
lws_tls_ctx *ssl_client_ctx;
|
||||
struct lws_tls_ss_pieces *ss; /* for acme tls certs */
|
||||
#endif
|
||||
#if defined(LWS_WITH_MBEDTLS)
|
||||
lws_tls_x509 *x509_client_CA;
|
||||
|
@ -2370,6 +2373,7 @@ LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
|
|||
#define lws_context_init_ssl_library(_a)
|
||||
#define lws_ssl_anybody_has_buffered_read_tsi(_a, _b) (0)
|
||||
#define lws_tls_check_all_cert_lifetimes(_a)
|
||||
#define lws_tls_acme_sni_cert_destroy(_a)
|
||||
#else
|
||||
#define LWS_SSL_ENABLED(context) (context->use_ssl)
|
||||
LWS_EXTERN int openssl_websocket_private_data_index;
|
||||
|
@ -2416,8 +2420,11 @@ lws_tls_check_all_cert_lifetimes(struct lws_context *context);
|
|||
LWS_EXTERN int
|
||||
lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
||||
struct lws_vhost *vhost);
|
||||
void
|
||||
lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost);
|
||||
#else
|
||||
#define lws_context_init_server_ssl(_a, _b) (0)
|
||||
#define lws_tls_acme_sni_cert_destroy(_a)
|
||||
#endif
|
||||
LWS_EXTERN void
|
||||
lws_ssl_destroy(struct lws_vhost *vhost);
|
||||
|
@ -2457,6 +2464,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh,
|
|||
const char *ca_filepath,
|
||||
const char *cert_filepath,
|
||||
const char *private_key_filepath);
|
||||
|
||||
LWS_EXTERN lws_tls_ctx *
|
||||
lws_tls_ctx_from_wsi(struct lws *wsi);
|
||||
LWS_EXTERN int
|
||||
|
|
|
@ -90,7 +90,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info,
|
|||
|
||||
vhost->protocols[0].callback(&wsi,
|
||||
LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
|
||||
vhost->ssl_ctx, NULL, 0);
|
||||
vhost->ssl_ctx, vhost, 0);
|
||||
}
|
||||
|
||||
if (vhost->use_ssl)
|
||||
|
|
|
@ -337,3 +337,20 @@ lws_tls_server_accept(struct lws *wsi)
|
|||
}
|
||||
|
||||
|
||||
struct lws_tls_ss_pieces {
|
||||
mbedtls_x509_crt x509;
|
||||
|
||||
};
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
|
||||
const char *san_b)
|
||||
{
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -278,6 +278,8 @@ lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
|
|||
|
||||
if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
|
||||
SSL_CTX_free(vhost->ssl_client_ctx);
|
||||
|
||||
lws_tls_acme_sni_cert_destroy(vhost);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -34,8 +34,7 @@ lws_jwk_destroy_genrsa_elements(struct lws_genrsa_elements *el)
|
|||
}
|
||||
|
||||
LWS_VISIBLE int
|
||||
lws_genrsa_create(struct lws_genrsa_ctx *ctx,
|
||||
struct lws_genrsa_elements *el)
|
||||
lws_genrsa_create(struct lws_genrsa_ctx *ctx, struct lws_genrsa_elements *el)
|
||||
{
|
||||
int n;
|
||||
|
||||
|
@ -129,7 +128,8 @@ lws_genrsa_new_keypair(struct lws_context *context, struct lws_genrsa_ctx *ctx,
|
|||
{
|
||||
const BIGNUM *mpi[5];
|
||||
|
||||
RSA_get0_key(ctx->rsa, &mpi[JWK_KEY_N], &mpi[JWK_KEY_E], &mpi[JWK_KEY_D]);
|
||||
RSA_get0_key(ctx->rsa, &mpi[JWK_KEY_N], &mpi[JWK_KEY_E],
|
||||
&mpi[JWK_KEY_D]);
|
||||
RSA_get0_factors(ctx->rsa, &mpi[JWK_KEY_P], &mpi[JWK_KEY_Q]);
|
||||
#else
|
||||
{
|
||||
|
|
|
@ -100,7 +100,8 @@ lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
|
|||
*/
|
||||
vh = context->vhost_list;
|
||||
while (vh) {
|
||||
if (!vh->being_destroyed && vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
|
||||
if (!vh->being_destroyed &&
|
||||
vh->ssl_ctx == SSL_get_SSL_CTX(ssl))
|
||||
break;
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
@ -125,7 +126,7 @@ lws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg)
|
|||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
lwsl_info("SNI: Found: %s:%d\n", servername, vh->listen_port);
|
||||
lwsl_notice("SNI: Found: %s:%d\n", servername, vh->listen_port);
|
||||
|
||||
/* select the ssl ctx from the selected vhost for this conn */
|
||||
SSL_set_SSL_CTX(ssl, vhost->ssl_ctx);
|
||||
|
@ -432,3 +433,149 @@ lws_tls_server_accept(struct lws *wsi)
|
|||
return LWS_SSL_CAPABLE_ERROR;
|
||||
}
|
||||
|
||||
struct lws_tls_ss_pieces {
|
||||
X509 *x509;
|
||||
EVP_PKEY *pkey;
|
||||
RSA *rsa;
|
||||
};
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a,
|
||||
const char *san_b)
|
||||
{
|
||||
GENERAL_NAMES *gens = sk_GENERAL_NAME_new_null();
|
||||
GENERAL_NAME *gen = NULL;
|
||||
ASN1_IA5STRING *ia5 = NULL;
|
||||
X509_NAME *name;
|
||||
BIGNUM *bn;
|
||||
int n;
|
||||
|
||||
if (!gens)
|
||||
return 1;
|
||||
|
||||
vhost->ss = lws_zalloc(sizeof(*vhost->ss), "sni cert");
|
||||
if (!vhost->ss) {
|
||||
GENERAL_NAMES_free(gens);
|
||||
return 1;
|
||||
}
|
||||
|
||||
vhost->ss->x509 = X509_new();
|
||||
if (!vhost->ss->x509)
|
||||
goto bail;
|
||||
|
||||
ASN1_INTEGER_set(X509_get_serialNumber(vhost->ss->x509), 1);
|
||||
X509_gmtime_adj(X509_get_notBefore(vhost->ss->x509), 0);
|
||||
X509_gmtime_adj(X509_get_notAfter(vhost->ss->x509), 3600);
|
||||
|
||||
vhost->ss->pkey = EVP_PKEY_new();
|
||||
if (!vhost->ss->pkey)
|
||||
goto bail0;
|
||||
|
||||
bn = BN_new();
|
||||
if (!bn)
|
||||
goto bail1;
|
||||
if (BN_set_word(bn, RSA_F4) != 1) {
|
||||
BN_free(bn);
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
vhost->ss->rsa = RSA_new();
|
||||
if (!vhost->ss->rsa) {
|
||||
BN_free(bn);
|
||||
goto bail1;
|
||||
}
|
||||
|
||||
n = RSA_generate_key_ex(vhost->ss->rsa, 4096, bn, NULL);
|
||||
BN_free(bn);
|
||||
if (n != 1)
|
||||
goto bail2;
|
||||
|
||||
if (!EVP_PKEY_assign_RSA(vhost->ss->pkey, vhost->ss->rsa))
|
||||
goto bail2;
|
||||
|
||||
X509_set_pubkey(vhost->ss->x509, vhost->ss->pkey);
|
||||
|
||||
name = X509_get_subject_name(vhost->ss->x509);
|
||||
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
|
||||
(unsigned char *)"GB", -1, -1, 0);
|
||||
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
|
||||
(unsigned char *)"somecompany", -1, -1, 0);
|
||||
if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_UTF8,
|
||||
(unsigned char *)"temp.acme.invalid",
|
||||
-1, -1, 0) != 1) {
|
||||
lwsl_notice("failed to add CN\n");
|
||||
goto bail2;
|
||||
}
|
||||
X509_set_issuer_name(vhost->ss->x509, name);
|
||||
|
||||
/* add the SAN payloads */
|
||||
|
||||
gen = GENERAL_NAME_new();
|
||||
ia5 = ASN1_IA5STRING_new();
|
||||
if (!ASN1_STRING_set(ia5, san_a, -1)) {
|
||||
lwsl_notice("failed to set ia5\n");
|
||||
GENERAL_NAME_free(gen);
|
||||
goto bail2;
|
||||
}
|
||||
GENERAL_NAME_set0_value(gen, GEN_DNS, ia5);
|
||||
sk_GENERAL_NAME_push(gens, gen);
|
||||
|
||||
if (X509_add1_ext_i2d(vhost->ss->x509, NID_subject_alt_name,
|
||||
gens, 0, X509V3_ADD_APPEND) != 1)
|
||||
goto bail2;
|
||||
|
||||
GENERAL_NAMES_free(gens);
|
||||
|
||||
if (san_b && san_b[0]) {
|
||||
gens = sk_GENERAL_NAME_new_null();
|
||||
gen = GENERAL_NAME_new();
|
||||
ia5 = ASN1_IA5STRING_new();
|
||||
if (!ASN1_STRING_set(ia5, san_a, -1)) {
|
||||
lwsl_notice("failed to set ia5\n");
|
||||
GENERAL_NAME_free(gen);
|
||||
goto bail2;
|
||||
}
|
||||
GENERAL_NAME_set0_value(gen, GEN_DNS, ia5);
|
||||
sk_GENERAL_NAME_push(gens, gen);
|
||||
|
||||
if (X509_add1_ext_i2d(vhost->ss->x509, NID_subject_alt_name,
|
||||
gens, 0, X509V3_ADD_APPEND) != 1)
|
||||
goto bail2;
|
||||
|
||||
GENERAL_NAMES_free(gens);
|
||||
}
|
||||
|
||||
/* sign it with our private key */
|
||||
if (!X509_sign(vhost->ss->x509, vhost->ss->pkey, EVP_sha256()))
|
||||
goto bail2;
|
||||
|
||||
/* tell the vhost to use our crafted certificate */
|
||||
SSL_CTX_use_certificate(vhost->ssl_ctx, vhost->ss->x509);
|
||||
/* and to use our generated private key */
|
||||
SSL_CTX_use_PrivateKey(vhost->ssl_ctx, vhost->ss->pkey);
|
||||
|
||||
return 0;
|
||||
|
||||
bail2:
|
||||
RSA_free(vhost->ss->rsa);
|
||||
bail1:
|
||||
EVP_PKEY_free(vhost->ss->pkey);
|
||||
bail0:
|
||||
X509_free(vhost->ss->x509);
|
||||
bail:
|
||||
lws_free(vhost->ss);
|
||||
GENERAL_NAMES_free(gens);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
lws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost)
|
||||
{
|
||||
if (!vhost->ss)
|
||||
return;
|
||||
|
||||
EVP_PKEY_free(vhost->ss->pkey);
|
||||
X509_free(vhost->ss->x509);
|
||||
lws_free_set_NULL(vhost->ss);
|
||||
}
|
||||
|
|
|
@ -416,6 +416,8 @@ lws_ssl_SSL_CTX_destroy(struct lws_vhost *vhost)
|
|||
|
||||
if (!vhost->user_supplied_ssl_ctx && vhost->ssl_client_ctx)
|
||||
SSL_CTX_free(vhost->ssl_client_ctx);
|
||||
|
||||
lws_tls_acme_sni_cert_destroy(vhost);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Add table
Reference in a new issue