From 6780eee3e0dbe37640f72ed1e37a95c506e23f8c Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Tue, 18 May 2021 11:19:19 +0000 Subject: Prepare for 2.4.2.0; implement client certificates with bearssl Also send a bit more environment with libtls --- src/include/s6-networking/sbearssl.h | 5 ++ src/sbearssl/deps-lib/sbearssl | 3 + src/sbearssl/sbearssl-internal.h | 3 + src/sbearssl/sbearssl_client_init_and_run.c | 82 +++++++++++++--------- src/sbearssl/sbearssl_get_keycert.c | 36 ++++++++++ src/sbearssl/sbearssl_get_tas.c | 33 +++++++++ src/sbearssl/sbearssl_server_init_and_run.c | 64 +++++++---------- .../sbearssl_x509_minimal_init_with_engine.c | 25 +++++++ src/stls/stls_send_environment.c | 31 +++++--- 9 files changed, 199 insertions(+), 83 deletions(-) create mode 100644 src/sbearssl/sbearssl_get_keycert.c create mode 100644 src/sbearssl/sbearssl_get_tas.c create mode 100644 src/sbearssl/sbearssl_x509_minimal_init_with_engine.c (limited to 'src') diff --git a/src/include/s6-networking/sbearssl.h b/src/include/s6-networking/sbearssl.h index 5527696..e473e12 100644 --- a/src/include/s6-networking/sbearssl.h +++ b/src/include/s6-networking/sbearssl.h @@ -30,8 +30,13 @@ /* Utility functions */ extern int sbearssl_isder (unsigned char const *, size_t) ; + + + /* x509 QoL functions */ + extern int sbearssl_x509_minimal_set_tai (br_x509_minimal_context *, tai_t const *) ; #define sbearssl_x509_minimal_set_tain(ctx, a) sbearssl_x509_minimal_set_tai(ctx, tain_secp(a)) +extern void sbearssl_x509_minimal_init_with_engine (br_x509_minimal_context *, br_ssl_engine_context *, br_x509_trust_anchor const *, size_t) ; /* Cipher suites */ diff --git a/src/sbearssl/deps-lib/sbearssl b/src/sbearssl/deps-lib/sbearssl index dfa4f29..a1ccbb7 100644 --- a/src/sbearssl/deps-lib/sbearssl +++ b/src/sbearssl/deps-lib/sbearssl @@ -11,6 +11,8 @@ sbearssl_ec_pkey_to.o sbearssl_ec_skey_from.o sbearssl_ec_skey_to.o sbearssl_error_str.o +sbearssl_get_keycert.o +sbearssl_get_tas.o sbearssl_isder.o sbearssl_pem_decode_from_buffer.o sbearssl_pem_decode_from_string.o @@ -38,6 +40,7 @@ sbearssl_ta_readfile.o sbearssl_ta_to.o sbearssl_x500_name_len.o sbearssl_x500_from_ta.o +sbearssl_x509_minimal_init_with_engine.o sbearssl_x509_minimal_set_tai.o -lbearssl -lskarnet diff --git a/src/sbearssl/sbearssl-internal.h b/src/sbearssl/sbearssl-internal.h index bfaad73..21a28d7 100644 --- a/src/sbearssl/sbearssl-internal.h +++ b/src/sbearssl/sbearssl-internal.h @@ -65,6 +65,9 @@ struct sbearssl_suiteinfo_s uint16_t bits ; } ; +extern size_t sbearssl_get_tas (genalloc *, stralloc *) ; +extern size_t sbearssl_get_keycert (sbearssl_skey *, genalloc *, stralloc *) ; + extern void sbearssl_drop (void) ; extern void sbearssl_append (void *, void const *, size_t) ; extern int sbearssl_pem_push (br_pem_decoder_context *, char const *, size_t, sbearssl_pemobject *, genalloc *, sbearssl_strallocerr *, int *) ; diff --git a/src/sbearssl/sbearssl_client_init_and_run.c b/src/sbearssl/sbearssl_client_init_and_run.c index d7bedec..db68096 100644 --- a/src/sbearssl/sbearssl_client_init_and_run.c +++ b/src/sbearssl/sbearssl_client_init_and_run.c @@ -15,50 +15,64 @@ void sbearssl_client_init_and_run (int *fds, tain_t const *tto, uint32_t preoptions, uint32_t options, unsigned int verbosity, char const *servername, sbearssl_handshake_cb_t_ref cb, unsigned int notif) { + sbearssl_skey skey ; + genalloc certs = GENALLOC_ZERO ; /* sbearssl_cert */ + genalloc tas = GENALLOC_ZERO ; /* sbearssl_ta */ stralloc storage = STRALLOC_ZERO ; - genalloc tas = GENALLOC_ZERO ; - size_t talen ; - - if (preoptions & 1) - strerr_dief1x(100, "client certificates are not supported yet") ; - - { - int r ; - char const *x = getenv("CADIR") ; - if (x) - r = sbearssl_ta_readdir(x, &tas, &storage) ; - else - { - x = getenv("CAFILE") ; - if (!x) strerr_dienotset(100, "CADIR or CAFILE") ; - r = sbearssl_ta_readfile(x, &tas, &storage) ; - } - - if (r < 0) - strerr_diefu2sys(111, "read trust anchors in ", x) ; - else if (r) - strerr_diefu4x(96, "read trust anchors in ", x, ": ", sbearssl_error_str(r)) ; - - talen = genalloc_len(sbearssl_ta, &tas) ; - if (!talen) - strerr_dief2x(96, "no trust anchor found in ", x) ; - } + size_t chainlen = preoptions & 1 ? sbearssl_get_keycert(&skey, &certs, &storage) : 0 ; + size_t n = sbearssl_get_tas(&tas, &storage) ; sbearssl_drop() ; + stralloc_shrink(&storage) ; { sbearssl_handshake_cb_context_t cbarg = { .notif = notif } ; - unsigned char buf[BR_SSL_BUFSIZE_BIDI] ; - br_x509_minimal_context xc ; + union br_skey_u key ; br_ssl_client_context cc ; - br_x509_trust_anchor btas[talen] ; - size_t i = talen ; + br_x509_minimal_context xc ; + br_x509_certificate chain[chainlen ? chainlen : 1] ; + br_x509_trust_anchor btas[n] ; + unsigned char buf[BR_SSL_BUFSIZE_BIDI] ; + + for (size_t i = 0 ; i < chainlen ; i++) + sbearssl_cert_to(genalloc_s(sbearssl_cert, &certs) + i, chain + i, storage.s) ; + genalloc_free(sbearssl_cert, &certs) ; - stralloc_shrink(&storage) ; - while (i--) + for (size_t i = 0 ; i < n ; i++) sbearssl_ta_to(genalloc_s(sbearssl_ta, &tas) + i, btas + i, storage.s) ; genalloc_free(sbearssl_ta, &tas) ; - br_ssl_client_init_full(&cc, &xc, btas, talen) ; + + br_ssl_client_init_full(&cc, &xc, btas, n) ; + + if (chainlen) + { + switch (skey.type) + { + case BR_KEYTYPE_RSA : + sbearssl_rsa_skey_to(&skey.data.rsa, &key.rsa, storage.s) ; + br_ssl_client_set_single_rsa(&cc, chain, chainlen, &key.rsa, br_rsa_pkcs1_sign_get_default()) ; + break ; + case BR_KEYTYPE_EC : + { + int kt, r ; + sbearssl_ec_skey_to(&skey.data.ec, &key.ec, storage.s) ; + r = sbearssl_ec_issuer_keytype(&kt, &chain[0]) ; + switch (r) + { + case -2 : strerr_dief1x(96, "certificate issuer key type not recognized") ; + case -1 : strerr_diefu1sys(111, "get certificate issuer key type") ; + case 0 : break ; + default : strerr_diefu3x(96, "get certificate issuer key type", ": ", sbearssl_error_str(r)) ; + } + + br_ssl_client_set_single_ec(&cc, chain, chainlen, &key.ec, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, kt, br_ec_get_default(), br_ecdsa_sign_asn1_get_default()) ; + break ; + } + default : + strerr_dief1x(96, "unsupported private key type") ; + } + } + br_ssl_engine_add_flags(&cc.eng, BR_OPT_NO_RENEGOTIATION) ; random_string((char *)buf, 32) ; random_finish() ; diff --git a/src/sbearssl/sbearssl_get_keycert.c b/src/sbearssl/sbearssl_get_keycert.c new file mode 100644 index 0000000..96e826c --- /dev/null +++ b/src/sbearssl/sbearssl_get_keycert.c @@ -0,0 +1,36 @@ +/* ISC license. */ + +#include + +#include +#include +#include + +#include +#include "sbearssl-internal.h" + +size_t sbearssl_get_keycert (sbearssl_skey *skey, genalloc *certs, stralloc *storage) +{ + size_t chainlen ; + int r ; + char const *x = getenv("CERTFILE") ; + if (!x) strerr_dienotset(100, "CERTFILE") ; + r = sbearssl_cert_readbigpem(x, certs, storage) ; + if (r < 0) + strerr_diefu2sys(111, "read certificate chain in ", x) ; + else if (r) + strerr_diefu4sys(96, "read certificate chain in ", x, ": ", sbearssl_error_str(r)) ; + chainlen = genalloc_len(sbearssl_cert, certs) ; + if (!chainlen) + strerr_diefu2x(96, "find a certificate in ", x) ; + + x = getenv("KEYFILE") ; + if (!x) strerr_dienotset(100, "KEYFILE") ; + r = sbearssl_skey_readfile(x, skey, storage) ; + if (r < 0) + strerr_diefu2sys(111, "read private key in ", x) ; + else if (r) + strerr_diefu4x(96, "decode private key in ", x, ": ", sbearssl_error_str(r)) ; + + return chainlen ; +} diff --git a/src/sbearssl/sbearssl_get_tas.c b/src/sbearssl/sbearssl_get_tas.c new file mode 100644 index 0000000..aa8f63b --- /dev/null +++ b/src/sbearssl/sbearssl_get_tas.c @@ -0,0 +1,33 @@ +/* ISC license. */ + +#include + +#include +#include +#include + +#include +#include "sbearssl-internal.h" + +size_t sbearssl_get_tas (genalloc *tas, stralloc *storage) +{ + size_t talen ; + int r ; + char const *x = getenv("CADIR") ; + if (x) r = sbearssl_ta_readdir(x, tas, storage) ; + else + { + x = getenv("CAFILE") ; + if (!x) strerr_dienotset(100, "CADIR or CAFILE") ; + r = sbearssl_ta_readfile(x, tas, storage) ; + } + + if (r < 0) + strerr_diefu2sys(111, "read trust anchors in ", x) ; + else if (r) + strerr_diefu4x(96, "read trust anchors in ", x, ": ", sbearssl_error_str(r)) ; + + talen = genalloc_len(sbearssl_ta, tas) ; + if (!talen) strerr_dief2x(96, "no trust anchor found in ", x) ; + return talen ; +} diff --git a/src/sbearssl/sbearssl_server_init_and_run.c b/src/sbearssl/sbearssl_server_init_and_run.c index a7ae22b..e6df30e 100644 --- a/src/sbearssl/sbearssl_server_init_and_run.c +++ b/src/sbearssl/sbearssl_server_init_and_run.c @@ -15,51 +15,33 @@ void sbearssl_server_init_and_run (int *fds, tain_t const *tto, uint32_t preoptions, uint32_t options, unsigned int verbosity, sbearssl_handshake_cb_t_ref cb, unsigned int notif) { - stralloc storage = STRALLOC_ZERO ; sbearssl_skey skey ; - genalloc certs = GENALLOC_ZERO ; - size_t chainlen ; - - if (preoptions & 1) - strerr_dief1x(100, "client certificates are not supported yet") ; - - { - char const *x = getenv("KEYFILE") ; - int r ; - if (!x) strerr_dienotset(100, "KEYFILE") ; - r = sbearssl_skey_readfile(x, &skey, &storage) ; - if (r < 0) - strerr_diefu2sys(111, "read private key in ", x) ; - else if (r) - strerr_diefu4x(96, "decode private key in ", x, ": ", sbearssl_error_str(r)) ; - - x = getenv("CERTFILE") ; - if (!x) strerr_dienotset(100, "CERTFILE") ; - r = sbearssl_cert_readbigpem(x, &certs, &storage) ; - if (r < 0) - strerr_diefu2sys(111, "read certificate chain in ", x) ; - else if (r) - strerr_diefu4sys(96, "read certificate chain in ", x, ": ", sbearssl_error_str(r)) ; - chainlen = genalloc_len(sbearssl_cert, &certs) ; - if (!chainlen) - strerr_diefu2x(96, "find a certificate in ", x) ; - } + genalloc certs = GENALLOC_ZERO ; /* sbearssl_cert */ + genalloc tas = GENALLOC_ZERO ; /* sbearssl_ta */ + stralloc storage = STRALLOC_ZERO ; + size_t chainlen = sbearssl_get_keycert(&skey, &certs, &storage) ; + size_t n = preoptions & 1 ? sbearssl_get_tas(&tas, &storage) : 0 ; sbearssl_drop() ; + stralloc_shrink(&storage) ; { sbearssl_handshake_cb_context_t cbarg = { .notif = notif } ; - unsigned char buf[BR_SSL_BUFSIZE_BIDI] ; - br_ssl_server_context sc ; union br_skey_u key ; + br_ssl_server_context sc ; + br_x509_minimal_context xc ; br_x509_certificate chain[chainlen] ; - size_t i = chainlen ; + br_x509_trust_anchor btas[n ? n : 1] ; + unsigned char buf[BR_SSL_BUFSIZE_BIDI] ; - stralloc_shrink(&storage) ; - while (i--) + for (size_t i = 0 ; i < chainlen ; i++) sbearssl_cert_to(genalloc_s(sbearssl_cert, &certs) + i, chain + i, storage.s) ; genalloc_free(sbearssl_cert, &certs) ; + for (size_t i = 0 ; i < n ; i++) + sbearssl_ta_to(genalloc_s(sbearssl_ta, &tas) + i, btas + i, storage.s) ; + genalloc_free(sbearssl_ta, &tas) ; + switch (skey.type) { case BR_KEYTYPE_RSA : @@ -82,19 +64,23 @@ void sbearssl_server_init_and_run (int *fds, tain_t const *tto, uint32_t preopti break ; } default : - strerr_dief1x(96, "unsupported private key type") ; + strerr_dief1x(96, "unsupported private key type") ; } { uint32_t flags = BR_OPT_ENFORCE_SERVER_PREFERENCES | BR_OPT_NO_RENEGOTIATION ; - if (preoptions & 1) - { - /* br_ssl_server_set_trust_anchor_names(&sc, x500names, x500n) ; */ - if (!(preoptions & 2)) flags |= BR_OPT_TOLERATE_NO_CLIENT_AUTH ; - } + if (!(preoptions & 2)) flags |= BR_OPT_TOLERATE_NO_CLIENT_AUTH ; br_ssl_engine_add_flags(&sc.eng, flags) ; } + if (n) + { + sbearssl_x509_minimal_init_with_engine(&xc, &sc.eng, btas, n) ; + if (!sbearssl_x509_minimal_set_tain(&xc, &STAMP)) + strerr_diefu1sys(111, "initialize validation time") ; + br_ssl_server_set_trust_anchor_names_alt(&sc, btas, n) ; + } + random_string((char *)buf, 32) ; random_finish() ; br_ssl_engine_inject_entropy(&sc.eng, buf, 32) ; diff --git a/src/sbearssl/sbearssl_x509_minimal_init_with_engine.c b/src/sbearssl/sbearssl_x509_minimal_init_with_engine.c new file mode 100644 index 0000000..1b5c7a5 --- /dev/null +++ b/src/sbearssl/sbearssl_x509_minimal_init_with_engine.c @@ -0,0 +1,25 @@ +/* ISC license. */ + +#include + +#include + +void sbearssl_x509_minimal_init_with_engine (br_x509_minimal_context *xc, br_ssl_engine_context *eng, br_x509_trust_anchor const *btas, size_t n) +{ + static const br_hash_class *hashes[] = + { + &br_md5_vtable, + &br_sha1_vtable, + &br_sha224_vtable, + &br_sha256_vtable, + &br_sha384_vtable, + &br_sha512_vtable + } ; + + br_x509_minimal_init(xc, &br_sha256_vtable, btas, n) ; + br_x509_minimal_set_rsa(xc, br_ssl_engine_get_rsavrfy(eng)) ; + br_x509_minimal_set_ecdsa(xc, br_ssl_engine_get_ec(eng), br_ssl_engine_get_ecdsa(eng)) ; + for (unsigned int id = br_md5_ID ; id <= br_sha512_ID ; id++) + br_x509_minimal_set_hash(xc, id, hashes[id-1]) ; + br_ssl_engine_set_x509(eng, &xc->vtable) ; +} diff --git a/src/stls/stls_send_environment.c b/src/stls/stls_send_environment.c index c7cb9c7..ab7fba2 100644 --- a/src/stls/stls_send_environment.c +++ b/src/stls/stls_send_environment.c @@ -9,9 +9,22 @@ #include +static int add (buffer *b, int h, char const *key, char const *value) +{ + if (buffer_puts(b, key) < 0) return 0 ; + if (h && value && value[0]) + { + if (buffer_put(b, "=", 1) < 0 + || buffer_puts(b, value) < 0) + return 0 ; + } + if (buffer_put(b, "", 1) < 0) return 0 ; + return 1 ; +} + + int stls_send_environment (struct tls *ctx, int fd) { - char const *name = tls_conn_servername(ctx) ; char buf[4096] ; buffer b = BUFFER_INIT(&buffer_write, fd, buf, 4096) ; if (buffer_puts(&b, "SSL_PROTOCOL=") < 0 @@ -19,15 +32,13 @@ int stls_send_environment (struct tls *ctx, int fd) || buffer_put(&b, "", 1) < 0 || buffer_puts(&b, "SSL_CIPHER=") < 0 || buffer_puts(&b, tls_conn_cipher(ctx)) < 0 - || buffer_put(&b, "", 1) < 0 - || buffer_puts(&b, "SSL_TLS_SNI_SERVERNAME") < 0) + || buffer_put(&b, "", 1) < 0) return 0 ; - if (name && name[0]) - { - if (buffer_put(&b, "=", 1) < 0 - || buffer_puts(&b, name) < 0) - return 0 ; - } - if (buffer_putflush(&b, "\0", 2) < 0) return 0 ; + + if (!add(&b, 1, "SSL_TLS_SNI_SERVERNAME", tls_conn_servername(ctx))) return 0 ; + if (!add(&b, tls_peer_cert_provided(ctx), "SSL_PEER_CERT_HASH", tls_peer_cert_hash(ctx))) return 0 ; + if (!add(&b, tls_peer_cert_provided(ctx), "SSL_PEER_CERT_SUBJECT", tls_peer_cert_subject(ctx))) return 0 ; + + if (buffer_putflush(&b, "", 1) < 0) return 0 ; return 1 ; } -- cgit v1.2.3