Skip to content

Commit

Permalink
tls/http: add certificate chain setters
Browse files Browse the repository at this point in the history
  • Loading branch information
maximilianfridrich committed May 22, 2024
1 parent 25b1e40 commit ebef0df
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/re_http.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ int http_client_set_cert(struct http_cli *cli, const char *path);
int http_client_set_certpem(struct http_cli *cli, const char *pem);
int http_client_set_key(struct http_cli *cli, const char *path);
int http_client_set_keypem(struct http_cli *cli, const char *pem);
int http_client_use_chain(struct http_cli *cli, const char *path);
int http_client_use_chainpem(struct http_cli *cli, const char *chain,
size_t len_chain);

int http_client_set_session_reuse(struct http_cli *cli, bool enabled);
int http_client_set_tls_min_version(struct http_cli *cli, int version);
Expand Down
3 changes: 3 additions & 0 deletions include/re_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ int tls_set_certificate_der(struct tls *tls, enum tls_keytype keytype,
const uint8_t *cert, size_t len_cert,
const uint8_t *key, size_t len_key);
int tls_set_certificate(struct tls *tls, const char *cert, size_t len);
int tls_set_certificate_chain_pem(struct tls *tls, const char *chain,
size_t len_chain);
int tls_set_certificate_chain(struct tls *tls, const char *path);
void tls_set_verify_client(struct tls *tls);
void tls_set_verify_client_trust_all(struct tls *tls);
int tls_set_verify_client_handler(struct tls_conn *tc, int depth,
Expand Down
54 changes: 54 additions & 0 deletions src/http/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1312,3 +1312,57 @@ size_t http_client_get_bufsize_max(struct http_cli *cli)

return cli->bufsize_max;
}


/**
* Change used certificate+key of TLS connection
*
* @param cli HTTP Client
* @param chain Cert (chain) + Key (PEM format)
* @param len_chain Length of certificate + key PEM string
*
* @return int 0 if success, otherwise errorcode
*/
int http_client_use_chainpem(struct http_cli *cli, const char *chain,
size_t len_chain)
{
int err;

if (!cli || !cli->tls)
return EINVAL;

err = tls_set_certificate_chain_pem(cli->tls, chain, len_chain);
if (err)
return err;

cli->cert = mem_deref(cli->cert);
cli->key = mem_deref(cli->key);

return 0;
}


/**
* Change used certificate+key of TLS connection
*
* @param cli HTTP Client
* @param path Path to Cert (chain) + Key file (PEM format)
*
* @return int 0 if success, otherwise errorcode
*/
int http_client_use_chain(struct http_cli *cli, const char *path)
{
int err;

if (!cli || !cli->tls)
return EINVAL;

err = tls_set_certificate_chain(cli->tls, path);
if (err)
return err;

cli->cert = mem_deref(cli->cert);
cli->key = mem_deref(cli->key);

return 0;
}
153 changes: 153 additions & 0 deletions src/tls/openssl/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <re_types.h>
Expand Down Expand Up @@ -2214,3 +2215,155 @@ int tls_set_resumption(struct tls *tls, const enum tls_resume_mode mode)

return 0;
}


/**
* Change used certificate+key of an existing SSL object
*
* @param tls TLS Object
* @param chain Cert (chain) + Key in PEM format
* @param len_chain Length of certificate + key PEM string
*
* @return int 0 if success, otherwise errorcode
*/
int tls_set_certificate_chain_pem(struct tls *tls, const char *chain,
size_t len_chain)
{
STACK_OF(X509) *cert_stack = NULL;
EVP_PKEY *pkey = NULL;
BIO *bio_mem = NULL;
X509 *cert = NULL;
X509 *leaf_cert = NULL;
int err = ENOMEM;
int ok = 0;

if (!tls || !chain || !len_chain)
return EINVAL;

bio_mem = BIO_new_mem_buf(chain, len_chain);
cert_stack = sk_X509_new_null();
if (!bio_mem || !cert_stack)
goto out;

while ((cert = PEM_read_bio_X509(bio_mem, NULL, NULL, NULL)) != NULL) {
int n = sk_X509_push(cert_stack, cert);
if (n < 1) {
X509_free(cert);
goto out;
}
}

err = EINVAL;

if (sk_X509_num(cert_stack) == 0)
goto out;

leaf_cert = sk_X509_shift(cert_stack);
ok = SSL_CTX_use_certificate(tls->ctx, leaf_cert);
if (ok <= 0) {
X509_free(leaf_cert);
goto out;
}

if (sk_X509_num(cert_stack)) {
ok = SSL_CTX_clear_chain_certs(tls->ctx);
if (!ok)
goto out;

while((cert = sk_X509_shift(cert_stack)) != NULL){
ok = SSL_CTX_add0_chain_cert(tls->ctx, cert);
if (!ok) {
X509_free(cert);
goto out;
}
}
}

BIO_free(bio_mem);
bio_mem = BIO_new_mem_buf(chain, len_chain);
if (!bio_mem) {
err = ENOMEM;
goto out;
}

pkey = PEM_read_bio_PrivateKey(bio_mem, NULL, NULL, NULL);
if (!pkey)
goto out;

ok = SSL_CTX_use_PrivateKey(tls->ctx, pkey);
if (ok <= 0) {
err = EKEYREJECTED;
goto out;
}

ok = SSL_CTX_check_private_key(tls->ctx);
if (ok <= 0)
goto out;

if (tls->cert)
X509_free(tls->cert);

tls->cert = leaf_cert;
leaf_cert = NULL;

err = 0;

out:
if (bio_mem)
BIO_free(bio_mem);
if (leaf_cert)
X509_free(leaf_cert);
if (cert_stack)
sk_X509_pop_free(cert_stack, X509_free);
if (pkey)
EVP_PKEY_free(pkey);
if (err)
ERR_clear_error();

return err;
}


/**
* Change used certificate+key of an existing SSL object
*
* @param tls TLS Object
* @param path Path to Cert (chain) + Key file (PEM format)
*
* @return int 0 if success, otherwise errorcode
*/
int tls_set_certificate_chain(struct tls *tls, const char *path)
{
X509 *cert;
int ok = 0;

if (!tls || !path)
return EINVAL;

ok = SSL_CTX_use_certificate_chain_file(tls->ctx, path);
if (ok <= 0) {
ERR_clear_error();
return ENOENT;
}

ok = SSL_CTX_use_PrivateKey_file(tls->ctx, path, SSL_FILETYPE_PEM);
if (ok <= 0) {
ERR_clear_error();
return EKEYREJECTED;
}

cert = SSL_CTX_get0_certificate(tls->ctx);
if (!cert) {
ERR_clear_error();
return ENOENT;
}

X509_up_ref(cert);

if (tls->cert)
X509_free(tls->cert);

tls->cert = cert;

return 0;
}

0 comments on commit ebef0df

Please sign in to comment.