Skip to content
This repository has been archived by the owner on Jun 30, 2020. It is now read-only.

Commit

Permalink
Implement certificate authentication for GNUTLS
Browse files Browse the repository at this point in the history
This implements TLS certificate authentication in the GNUTLS
implementation.
It supports mutual authentication, and determining the peer
subject DN.

Signed-off-by: Patrick Uiterwijk <[email protected]>
  • Loading branch information
puiterwijk committed Apr 2, 2019
1 parent 72f2c71 commit 82c279e
Show file tree
Hide file tree
Showing 20 changed files with 1,088 additions and 37 deletions.
74 changes: 74 additions & 0 deletions bin/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,49 @@ clt_psk_cb(void *m, char **username, uint8_t **key)
return keydup(o, key);
}

static int
cert_cb(void *m,
char **cert_uri,
char **key_uri,
char **pin)
{
const options_t *o = m;

*cert_uri = strdup(o->crtf);
if (!*cert_uri)
return -1;
*key_uri = strdup(o->crtk);
if (!key_uri)
return -1;
*pin = strdup(o->crtkp);
if (!pin)
return -1;

return 0;
}

static int
clt_cert_cb(void *m,
const char **requested_ca_dn,
char **cert_uri,
char **key_uri,
char **pin)
{
// We just ignore "requested_ca_dn" for now.
return cert_cb(m, cert_uri, key_uri, pin);
}

static int
srv_cert_cb(void *m,
const char *servername,
char **cert_uri,
char **key_uri,
char **pin)
{
// We just ignore "servername" for now.
return cert_cb(m, cert_uri, key_uri, pin);
}

static status_t
on_conn(options_t *opts, int con, int in, int out, const struct addrinfo *ai)
{
Expand All @@ -160,6 +203,13 @@ on_conn(options_t *opts, int con, int in, int out, const struct addrinfo *ai)

if (opts->psku)
srv.psk = srv_psk_cb;
else if (opts->crtf)
{
srv.cert.getcert = srv_cert_cb;
srv.cert.client_certificate_request = opts->crtclientcert;
srv.cert.cafile = opts->crtca;
srv.cert.insecure = opts->crtinsec;
}

ret = non_setsockopt(con, IPPROTO_TLS,
TLS_SRV_HANDSHAKE, &srv, sizeof(srv));
Expand All @@ -168,6 +218,12 @@ on_conn(options_t *opts, int con, int in, int out, const struct addrinfo *ai)

if (opts->psku)
clt.psk = clt_psk_cb;
else if (opts->crtf) {
clt.cert.getcert = clt_cert_cb;
clt.cert.cafile = opts->crtca;
clt.cert.insecure = opts->crtinsec;
clt.cert.hostname = opts->host;
}

ret = non_setsockopt(con, IPPROTO_TLS,
TLS_CLT_HANDSHAKE, &clt, sizeof(clt));
Expand All @@ -178,6 +234,24 @@ on_conn(options_t *opts, int con, int in, int out, const struct addrinfo *ai)
shutdown(con, SHUT_RDWR);
return STATUS_FAILURE;
}

if (opts->expectpeer != NULL) {
socklen_t dnlen = 256;
char *peer_dn = malloc(sizeof(char) * dnlen);
ret = getsockopt(con, IPPROTO_TLS, TLS_OPT_PEER_SUBJECT_DN, peer_dn, &dnlen);
if (ret != 0) {
fprintf(stderr, "%m: Unable to get peer subject DN!\n");
shutdown(con, SHUT_RDWR);
return STATUS_FAILURE;
}
if (strcmp(peer_dn, opts->expectpeer) != 0) {
fprintf(stderr, "%m: Peer name (%s) does not match expected (%s)!\n",
peer_dn, opts->expectpeer);
shutdown(con, SHUT_RDWR);
return STATUS_FAILURE;
}
free(peer_dn);
}
}

while (poll(pfds, 2, -1) >= 0) {
Expand Down
56 changes: 53 additions & 3 deletions bin/opt.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,27 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "../lib/tlssock.h"
#include "opt.h"
#include "hex.h"

#include <getopt.h>
#include <stdio.h>
#include <string.h>

static const char *sopts = "46hlknubTc:e:U:K:";
typedef enum {
OPT_CERT = 1,
OPT_CERT_KEY = 2,
OPT_CERT_KEY_PASS = 3,
OPT_CERT_INSECURE = 4,
OPT_CERT_TRUSTFILE = 5,
OPT_CERT_CLIENT_CERT_REQUEST = 6,
OPT_CERT_CLIENT_CERT_REQUIRE = 7,
} long_opts_keys;

static const char *sopts = "46hlknubTc:e:U:K:vp";
static const struct option lopts[] = {
{ "verbose", no_argument, .val = 'v' },
{ "ipv4", no_argument, .val = '4' },
{ "ipv6", no_argument, .val = '6' },
{ "help", no_argument, .val = 'h' },
Expand All @@ -37,9 +49,19 @@ static const struct option lopts[] = {
{ "tls", no_argument, .val = 'T' },
{ "sh-exec", required_argument, .val = 'c' },
{ "exec", required_argument, .val = 'e' },
{ "expect-peer", required_argument, .val = 'p' },

{ "psk-user", required_argument, .val = 'U' },
{ "psk-key", required_argument, .val = 'K' },

{ "cert", required_argument, .val = OPT_CERT },
{ "cert-key", required_argument, .val = OPT_CERT_KEY },
{ "cert-key-pass", required_argument, .val = OPT_CERT_KEY_PASS },
{ "cert-insecure", no_argument, .val = OPT_CERT_INSECURE },
{ "cert-trustfile", required_argument, .val = OPT_CERT_TRUSTFILE },
{ "cert-client-cert-request", no_argument, .val = OPT_CERT_CLIENT_CERT_REQUEST },
{ "cert-client-cert-require", no_argument, .val = OPT_CERT_CLIENT_CERT_REQUIRE },

{}
};

Expand All @@ -59,6 +81,16 @@ static const struct {
{'T', "Use TLS or DTLS instead of TCP or UDP"},
{'U', "Pre-Shared Key authentication username", "NAME"},
{'K', "Pre-Shared Key authentication key (hex)", "HEX"},
{'p', "Expect peer name", "PEER"},

{OPT_CERT, "Certificate file"},
{OPT_CERT_KEY, "Certificate key"},
{OPT_CERT_KEY_PASS, "Certificate key passphrase"},
{OPT_CERT_INSECURE, "Disable certificate validation"},
{OPT_CERT_TRUSTFILE, "Certificate Authority trust file"},
{OPT_CERT_CLIENT_CERT_REQUEST, "Request client certificate"},
{OPT_CERT_CLIENT_CERT_REQUIRE, "Require client certificate"},

{}
};

Expand All @@ -85,6 +117,18 @@ opts_parse(options_t *opts, int argc, char **argv)
case 'c': opts->exec = optarg; opts->shell = true; break;
case 'e': opts->exec = optarg; opts->shell = false; break;
case 'U': opts->psku = optarg; break;
case 'p': opts->expectpeer = optarg; break;
case OPT_CERT: opts->crtf = optarg; break;
case OPT_CERT_KEY: opts->crtk = optarg; break;
case OPT_CERT_KEY_PASS: opts->crtkp = optarg; break;
case OPT_CERT_INSECURE: opts->crtinsec = true; break;
case OPT_CERT_TRUSTFILE: opts->crtca = optarg; break;
case OPT_CERT_CLIENT_CERT_REQUEST:
opts->crtclientcert = TLS_CLIENT_CERT_REQUEST;
break;
case OPT_CERT_CLIENT_CERT_REQUIRE:
opts->crtclientcert = TLS_CLIENT_CERT_REQUIRE;
break;

case 'K':
opts->pskk = optarg;
Expand Down Expand Up @@ -148,8 +192,14 @@ opts_parse(options_t *opts, int argc, char **argv)
sprintf(lterm, "%s[=%s]", lopts[i].name, docs[j].arg);
}

fprintf(stderr, " -%c%-7s --%-18s %s\n",
docs[j].val, sterm, lterm, docs[j].doc);
if ((docs[j].val >= 'a' && docs[j].val <= 'z')
|| (docs[j].val >= 'A' && docs[j].val <= 'Z')
|| (docs[j].val >= '0' && docs[j].val <= '9'))
fprintf(stderr, " -%c%-7s --%-18s %s\n",
docs[j].val, sterm, lterm, docs[j].doc);
else
fprintf(stderr, " --%-18s %s\n",
lterm, docs[j].doc);
}
}
return false;
Expand Down
8 changes: 8 additions & 0 deletions bin/opt.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,14 @@
typedef struct {
const char *host;
const char *port;
const char *expectpeer;
const char *exec;
const char *psku;
const char *pskk;
const char *crtf;
const char *crtk;
const char *crtkp;
const char *crtca;

bool listen : 1;
bool block : 1;
Expand All @@ -37,6 +42,9 @@ typedef struct {
bool ipv6 : 1;
bool udp : 1;
bool tls : 1;
bool printpeer : 1;
bool crtinsec : 1;
int crtclientcert;
} options_t;

bool
Expand Down
Loading

0 comments on commit 82c279e

Please sign in to comment.