1
0
Fork 0
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:
Andy Green 2017-10-28 11:33:34 +08:00
parent a798db0e2b
commit 1f37ec0be9
8 changed files with 203 additions and 9 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)
{
}

View file

@ -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

View file

@ -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
{

View file

@ -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);
}

View file

@ -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