Skip to content

Commit

Permalink
Get common name and subject alternative names of peer certificate (na…
Browse files Browse the repository at this point in the history
…nomsg#1617)


Co-authored-by: Christian Fischbach <[email protected]>
  • Loading branch information
fishbach and Christian Fischbach authored Feb 8, 2023
1 parent 481436f commit 8e1836f
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 15 deletions.
2 changes: 2 additions & 0 deletions docs/man/nng_tls.7.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ Note that setting these must be done before the transport is started.
* xref:nng_tls_options.5.adoc#NNG_OPT_TLS_CERT_KEY_FILE[`NNG_OPT_TLS_CERT_KEY_FILE`]
* xref:nng_tls_options.5.adoc#NNG_OPT_TLS_CONFIG[`NNG_OPT_TLS_CONFIG`]
* xref:nng_tls_options.5.adoc#NNG_OPT_TLS_VERIFIED[`NNG_OPT_TLS_VERIFIED_`]
* xref:nng_tls_options.5.adoc#NNG_OPT_TLS_PEER_CN[`NNG_OPT_TLS_PEER_CN`]
* xref:nng_tls_options.5.adoc#NNG_OPT_TLS_PEER_ALT_NAMES[`NNG_OPT_TLS_PEER_ALT_NAMES`]
* xref:nng_options.5.adoc#NNG_OPT_URL[`NNG_OPT_URL`]

== SEE ALSO
Expand Down
24 changes: 18 additions & 6 deletions docs/man/nng_tls_options.5.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ nng_tls_options - TLS-specific options
----
#include <nng/nng.h>
#define NNG_OPT_TLS_AUTH_MODE "tls-authmode"
#define NNG_OPT_TLS_CA_FILE "tls-ca-file"
#define NNG_OPT_TLS_CERT_KEY_FILE "tls-cert-key-file"
#define NNG_OPT_TLS_CONFIG "tls-config"
#define NNG_OPT_TLS_SERVER_NAME "tls-server-name"
#define NNG_OPT_TLS_VERIFIED "tls-verified"
#define NNG_OPT_TLS_AUTH_MODE "tls-authmode"
#define NNG_OPT_TLS_CA_FILE "tls-ca-file"
#define NNG_OPT_TLS_CERT_KEY_FILE "tls-cert-key-file"
#define NNG_OPT_TLS_CONFIG "tls-config"
#define NNG_OPT_TLS_SERVER_NAME "tls-server-name"
#define NNG_OPT_TLS_VERIFIED "tls-verified"
#define NNG_OPT_TLS_PEER_CN "tls-peer-cn"
#define NNG_OPT_TLS_PEER_ALT_NAMES "tls-peer-alt-names"
----

== DESCRIPTION
Expand Down Expand Up @@ -91,6 +93,16 @@ This read-only option indicates whether the remote peer has been properly verifi
authentication.
May return incorrect results if peer authentication is disabled.

[[NNG_OPT_TLS_PEER_CN]]((`NNG_OPT_TLS_PEER_CN`))::
(string)
This read-only option returns the common name of the peer certificate.
May return incorrect results if peer authentication is disabled.

[[NNG_OPT_TLS_PEER_ALT_NAMES]]((`NNG_OPT_TLS_PEER_ALT_NAMES`))::
(string)
This read-only option returns string list with the subject alternative names of the
peer certificate. May return incorrect results if peer authentication is disabled.

=== Inherited Options

Generally, the following option values are also available for TLS objects,
Expand Down
9 changes: 9 additions & 0 deletions docs/man/nng_ws.7.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,15 @@ more details.
authentication.
May return incorrect results if peer authentication is disabled.

`NNG_OPT_TLS_PEER_CN`::
(string) This read-only option returns the common name of the peer certificate.
May return incorrect results if peer authentication is disabled.

`NNG_OPT_TLS_PEER_ALT_NAMES`::
(string list) returns string list with the subject alternative names of the
peer certificate. May return incorrect results if peer authentication
is disabled.

// We should also look at a hook mechanism for listeners. Probably this could
// look like NNG_OPT_WS_LISTEN_HOOK_FUNC which would take a function pointer
// along the lines of int hook(void *, char *req_headers, char **res_headers),
Expand Down
13 changes: 13 additions & 0 deletions include/nng/nng.h
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,19 @@ NNG_DECL nng_listener nng_pipe_listener(nng_pipe);
// peer authentication is disabled with `NNG_TLS_AUTH_MODE_NONE`.
#define NNG_OPT_TLS_VERIFIED "tls-verified"

// NNG_OPT_TLS_PEER_CN returns the string with the common name
// of the peer certificate. Typically this is read-only and
// only available for pipes. This option may return incorrect results if
// peer authentication is disabled with `NNG_TLS_AUTH_MODE_NONE`.
#define NNG_OPT_TLS_PEER_CN "tls-peer-cn"

// NNG_OPT_TLS_PEER_ALT_NAMES returns string list with the
// subject alternative names of the peer certificate. Typically this is
// read-only and only available for pipes. This option may return
// incorrect results if peer authentication is disabled with
// `NNG_TLS_AUTH_MODE_NONE`.
#define NNG_OPT_TLS_PEER_ALT_NAMES "tls-peer-alt-names"

// TCP options. These may be supported on various transports that use
// TCP underneath such as TLS, or not.

Expand Down
8 changes: 8 additions & 0 deletions include/nng/supplemental/tls/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ typedef struct nng_tls_engine_conn_ops_s {
// verified returns true if the connection is fully
// TLS verified, false otherwise.
bool (*verified)(nng_tls_engine_conn *);

// peer_cn returns the common name of the peer
// The return string needs to be freed.
char *(*peer_cn)(nng_tls_engine_conn *);

// peer_alt_names returns the subject alternative names.
// The return string list and its strings need to be freed.
char **(*peer_alt_names)(nng_tls_engine_conn *);
} nng_tls_engine_conn_ops;

typedef struct nng_tls_engine_config_ops_s {
Expand Down
86 changes: 78 additions & 8 deletions src/supplemental/tls/mbedtls/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,74 @@ conn_verified(nng_tls_engine_conn *ec)
return (mbedtls_ssl_get_verify_result(&ec->ctx) == 0);
}

static char *
conn_peer_cn(nng_tls_engine_conn *ec)
{
const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&ec->ctx);
if (!crt) {
return (NULL);
}

char buf[0x400];
int len = mbedtls_x509_dn_gets(buf, sizeof(buf), &crt->subject);
if (len <= 0) {
return (NULL);
}

const char *pos = strstr(buf, "CN=");
if (!pos) {
return (NULL);
}

pos += 3;
len -= pos - buf - 1;
if (len <= 1) {
return (NULL);
}

char *rv = malloc(len);
memcpy(rv, pos, len);
return (rv);
}

static char **
conn_peer_alt_names(nng_tls_engine_conn *ec)
{
const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&ec->ctx);
if (!crt) {
return (NULL);
}

const mbedtls_asn1_sequence * seq = &crt->subject_alt_names;

// get count
int count = 0;
do {
if (seq->buf.len > 0) ++count;
seq = seq->next;
} while (seq);
if (count == 0) return NULL;

seq = &crt->subject_alt_names;

// copy strings
char ** rv = malloc((count + 1) * sizeof(char *));
int i = 0;
do {
if (seq->buf.len == 0) continue;

rv[i] = malloc(seq->buf.len + 1);
memcpy(rv[i], seq->buf.p, seq->buf.len);
rv[i][seq->buf.len] = 0;
++i;

seq = seq->next;
} while (seq);
rv[i] = NULL;

return rv;
}

static void
config_fini(nng_tls_engine_config *cfg)
{
Expand Down Expand Up @@ -526,14 +594,16 @@ static nng_tls_engine_config_ops config_ops = {
};

static nng_tls_engine_conn_ops conn_ops = {
.size = sizeof(nng_tls_engine_conn),
.init = conn_init,
.fini = conn_fini,
.close = conn_close,
.recv = conn_recv,
.send = conn_send,
.handshake = conn_handshake,
.verified = conn_verified,
.size = sizeof(nng_tls_engine_conn),
.init = conn_init,
.fini = conn_fini,
.close = conn_close,
.recv = conn_recv,
.send = conn_send,
.handshake = conn_handshake,
.verified = conn_verified,
.peer_cn = conn_peer_cn,
.peer_alt_names = conn_peer_alt_names,
};

static nng_tls_engine tls_engine_mbed = {
Expand Down
42 changes: 41 additions & 1 deletion src/supplemental/tls/tls_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -756,11 +756,51 @@ tls_get_verified(void *arg, void *buf, size_t *szp, nni_type t)
return (nni_copyout_bool(v, buf, szp, t));
}

static int
tls_get_peer_cn(void *arg, void *buf, size_t *szp, nni_type t)
{
NNI_ARG_UNUSED(szp);

if (t != NNI_TYPE_STRING) {
return (NNG_EBADTYPE);
}

tls_conn *conn = arg;
nni_mtx_lock(&conn->lock);
*(char **) buf = conn->ops.peer_cn((void *) (conn + 1));
nni_mtx_unlock(&conn->lock);
return (0);
}

static int
tls_get_peer_alt_names(void *arg, void *buf, size_t *szp, nni_type t)
{
NNI_ARG_UNUSED(szp);

if (t != NNI_TYPE_POINTER) {
return (NNG_EBADTYPE);
}

tls_conn *conn = arg;
nni_mtx_lock(&conn->lock);
*(char ***) buf = conn->ops.peer_alt_names((void *) (conn + 1));
nni_mtx_unlock(&conn->lock);
return (0);
}

static const nni_option tls_options[] = {
{
.o_name = NNG_OPT_TLS_VERIFIED,
.o_get = tls_get_verified,
},
{
.o_name = NNG_OPT_TLS_PEER_CN,
.o_get = tls_get_peer_cn,
},
{
.o_name = NNG_OPT_TLS_PEER_ALT_NAMES,
.o_get = tls_get_peer_alt_names,
},
{
.o_name = NULL,
},
Expand Down Expand Up @@ -1680,4 +1720,4 @@ nni_tls_sys_fini(void)
{
}

#endif // !NNG_SUPP_TLS
#endif // !NNG_SUPP_TLS

0 comments on commit 8e1836f

Please sign in to comment.