Skip to content

Commit

Permalink
http/client: add set functions for client certificate and private key
Browse files Browse the repository at this point in the history
Adds functions that sets the client certificate and private key for HTTPS. The
certificate and key can be specified as:
- file with http_client_set_cert(), http_client_set_key() or
- directly as PEM string with http_client_set_certpem(),
  http_client_set_keypem().
The function http_client_set_cert() and http_client_set_certpem() accept PEM
file/data where certificate and private key are combined or only certificate
is contained. If the key is not contained then also http_client_set_key() or
http_client_set_keypem() has to be used.
  • Loading branch information
cspiel1 committed Oct 15, 2020
1 parent 2e5835f commit 3a22f91
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 3 deletions.
8 changes: 6 additions & 2 deletions include/re_http.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@ typedef void (http_conn_h)(struct tcp_conn *tc, struct tls_conn *sc,
void *arg);

int http_client_alloc(struct http_cli **clip, struct dnsc *dnsc);
int http_client_set_tls_hostname(struct http_cli *cli,
const struct pl *hostname);
int http_client_set_timeout(struct http_cli *cli, uint32_t ms);
int http_request(struct http_req **reqp, struct http_cli *cli, const char *met,
const char *uri, http_resp_h *resph, http_data_h *datah,
Expand All @@ -147,6 +145,12 @@ void http_client_set_laddr6(struct http_cli *cli, const struct sa *addr);
#ifdef USE_TLS
int http_client_add_ca(struct http_cli *cli, const char *tls_ca);
int http_client_add_capem(struct http_cli *cli, const char *capem);
int http_client_set_tls_hostname(struct http_cli *cli,
const struct pl *hostname);
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);
#endif

/* Server */
Expand Down
145 changes: 144 additions & 1 deletion src/http/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
#include "http.h"


#define DEBUG_MODULE "http_client"
#define DEBUG_LEVEL 5
#include <re_dbg.h>


enum {
CONN_TIMEOUT = 30000,
RECV_TIMEOUT = 60000,
Expand All @@ -38,6 +43,8 @@ struct http_cli {
struct dnsc *dnsc;
struct tls *tls;
char *tls_hostname;
char *cert;
char *key;
struct sa laddr;
#ifdef HAVE_INET6
struct sa laddr6;
Expand Down Expand Up @@ -102,6 +109,8 @@ static void cli_destructor(void *arg)

hash_flush(cli->ht_conn);
mem_deref(cli->ht_conn);
mem_deref(cli->cert);
mem_deref(cli->key);
mem_deref(cli->dnsc);
mem_deref(cli->tls);
mem_deref(cli->tls_hostname);
Expand Down Expand Up @@ -558,6 +567,46 @@ static void query_handler(int err, const struct dnshdr *hdr, struct list *ansl,
}


#ifdef USE_TLS
static int read_file(char **buf, const char *path)
{
FILE *f = NULL;
size_t s = 0;
size_t n = 0;

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

f = fopen(path, "r");
if (!f) {
DEBUG_WARNING("Could not open cert file '%s'\n", path);
return EIO;
}

fseek(f, 0L, SEEK_END);
s = ftell(f);
fseek(f, 0L, SEEK_SET);

*buf = mem_alloc(s + 1, NULL);
if (!buf) {
DEBUG_WARNING("Could not allocate cert file buffer\n");
fclose(f);
return ENOMEM;
}

n = fread(buf, 1, s, f);
fclose(f);
buf[s] = 0;
if (n < s) {
*buf = mem_deref(*buf);
return EIO;
}

return 0;
}
#endif


int http_uri_decode(struct http_uri *hu, const struct pl *uri)
{
if (!hu)
Expand Down Expand Up @@ -633,7 +682,8 @@ int http_request(struct http_req **reqp, struct http_cli *cli, const char *met,

req->cli = cli;
req->secure = secure;
req->port = pl_isset(&http_uri.port) ? pl_u32(&http_uri.port) : defport;
req->port = pl_isset(&http_uri.port) ? pl_u32(&http_uri.port) :
defport;
req->resph = resph;
req->datah = datah;
req->arg = arg;
Expand Down Expand Up @@ -665,6 +715,18 @@ int http_request(struct http_req **reqp, struct http_cli *cli, const char *met,

req->mbreq->pos = 0;

#ifdef USE_TLS
if (cli->cert && cli->key) {
err = tls_set_certificate_pem(cli->tls,
cli->cert, strlen(cli->cert),
cli->key, strlen(cli->key));
}
else if (cli->cert) {
err = tls_set_certificate(cli->tls,
cli->cert, strlen(cli->cert));
}
#endif

if (!sa_set_str(&req->srvv[0], req->host, req->port)) {

req->srvc = 1;
Expand Down Expand Up @@ -791,6 +853,87 @@ int http_client_add_capem(struct http_cli *cli, const char *capem)
}


/**
* Set client certificate
* @param cli HTTP Client
* @param path File path to client certificate
*
* @return 0 for success, error code otherwise.
*/
int http_client_set_cert(struct http_cli *cli, const char *path)
{
int err = 0;

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

cli->cert = mem_deref(cli->cert);
err = read_file(&cli->cert, path);
if (err) {
cli->cert = mem_deref(cli->cert);
return err;
}

return 0;
}


/**
* Set client certificate in PEM format
* @param cli HTTP Client
* @param pem Client certificate in PEM format
*
* @return 0 for success, error code otherwise.
*/
/* ------------------------------------------------------------------------- */
int http_client_set_certpem(struct http_cli *cli, const char *pem)
{
if (!cli || !str_isset(pem))
return EINVAL;

cli->cert = mem_deref(cli->cert);
cli->cert = mem_zalloc(strlen(pem) + 1, NULL);
if (!cli->cert)
return ENOMEM;

strcpy(cli->cert, pem);
return 0;
}


int http_client_set_key(struct http_cli *cli, const char *path)
{
int err = 0;

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

cli->key = mem_deref(cli->key);
err = read_file(&cli->key, path);
if (err) {
cli->key = mem_deref(cli->key);
return err;
}

return 0;
}


int http_client_set_keypem(struct http_cli *cli, const char *pem)
{
if (!cli || !str_isset(pem))
return EINVAL;

cli->key = mem_deref(cli->key);
cli->key = mem_zalloc(strlen(pem) + 1, NULL);
if (!cli->key)
return ENOMEM;

strcpy(cli->key, pem);
return 0;
}


/**
* Set verify host name
*
Expand Down

0 comments on commit 3a22f91

Please sign in to comment.