1
0
mirror of https://github.com/openbsd/src.git synced 2026-06-18 15:23:33 +02:00

relayd: allow explicit paths for certificates, keys and OCSP staples

Extend the "keypair" keyword in relayd.conf to support optional explicit paths.
Previously, relayd enforced a naming convention, looking up files in /etc/ssl
and /etc/ssl/private based on the keypair name.

This change allows other applications to manage their certificates without
having to comply with relayd's internal naming logic.

Input and OK kirill@, help form tb@
This commit is contained in:
rsadowski
2026-05-15 13:57:24 +00:00
parent bc45653046
commit bb05e5515c
4 changed files with 212 additions and 43 deletions
+115 -13
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: parse.y,v 1.262 2026/04/06 09:14:54 kirill Exp $ */
/* $OpenBSD: parse.y,v 1.263 2026/05/15 13:57:24 rsadowski Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -140,6 +140,7 @@ int relay_id(struct relay *);
struct relay *relay_inherit(struct relay *, struct relay *);
int getservice(char *);
int is_if_in_group(const char *, const char *);
static struct keyname *proto_keyname(char *);
typedef struct {
union {
@@ -1342,20 +1343,93 @@ tlsflags : SESSION TICKETS { proto->tickets = 1; }
free($3);
}
| KEYPAIR STRING {
struct keyname *name;
struct keyname *kname = NULL;
if (strlen($2) >= PATH_MAX) {
yyerror("keypair name too long");
if ((kname = proto_keyname($2)) == NULL) {
free($2);
YYERROR;
}
if ((name = calloc(1, sizeof(*name))) == NULL) {
yyerror("calloc");
free($2);
}
| KEYPAIR STRING CERTIFICATE STRING {
struct keyname *kname = NULL;
if ((kname = proto_keyname($2)) == NULL) {
free($2);
free($4);
YYERROR;
}
name->name = $2;
TAILQ_INSERT_TAIL(&proto->tlscerts, name, entry);
if (strlen($4) >= PATH_MAX) {
yyerror("keypair cert too long");
free($2);
free($4);
YYERROR;
}
if (strlcpy(kname->certificate, $4,
sizeof(kname->certificate)) >=
sizeof(kname->certificate)) {
yyerror("keypair certificate truncated");
free($2);
free($4);
YYERROR;
}
free($2);
free($4);
}
| KEYPAIR STRING KEY STRING {
struct keyname *kname = NULL;
if ((kname = proto_keyname($2)) == NULL) {
free($2);
free($4);
YYERROR;
}
if (strlen($4) >= PATH_MAX) {
yyerror("keypair certificate key too long");
free($2);
free($4);
YYERROR;
}
if (strlcpy(kname->key, $4,
sizeof(kname->key)) >=
sizeof(kname->key)) {
yyerror("keypair certificate key truncated");
free($2);
free($4);
YYERROR;
}
free($2);
free($4);
}
| KEYPAIR STRING OCSP STRING {
struct keyname *kname = NULL;
if ((kname = proto_keyname($2)) == NULL) {
free($2);
free($4);
YYERROR;
}
if (strlen($4) >= PATH_MAX) {
yyerror("keypair ocsp file too long");
free($2);
free($4);
YYERROR;
}
if (strlcpy(kname->ocsp, $4,
sizeof(kname->ocsp)) >=
sizeof(kname->ocsp)) {
yyerror("ocsp truncated");
free($2);
free($4);
YYERROR;
}
free($2);
free($4);
}
| CLIENT CA STRING {
if (strlcpy(proto->tlsclientca, $3,
@@ -1850,7 +1924,7 @@ relay : RELAY STRING {
} '{' optnl relayopts_l '}' {
struct relay *r;
struct relay_config *rlconf = &rlay->rl_conf;
struct keyname *name;
struct keyname *kname;
if (relay_findbyname(conf, rlconf->name) != NULL ||
relay_findbyaddr(conf, rlconf) != NULL) {
@@ -1888,11 +1962,11 @@ relay : RELAY STRING {
rlay->rl_conf.name);
YYERROR;
}
TAILQ_FOREACH(name, &rlay->rl_proto->tlscerts, entry) {
TAILQ_FOREACH(kname, &rlay->rl_proto->tlscerts, entry) {
if (relay_load_certfiles(conf,
rlay, name->name) == -1) {
rlay, kname) == -1) {
yyerror("cannot load keypair %s"
" for relay %s", name->name,
" for relay %s", kname->name,
rlay->rl_conf.name);
YYERROR;
}
@@ -3452,7 +3526,7 @@ relay_inherit(struct relay *ra, struct relay *rb)
goto err;
}
TAILQ_FOREACH(name, &rb->rl_proto->tlscerts, entry) {
if (relay_load_certfiles(conf, rb, name->name) == -1) {
if (relay_load_certfiles(conf, rb, name) == -1) {
yyerror("cannot load keypair %s for relay %s",
name->name, rb->rl_conf.name);
goto err;
@@ -3551,3 +3625,31 @@ end:
close(s);
return (ret);
}
struct keyname*
proto_keyname(char *name)
{
struct keyname *kname = NULL, *key;
if (strlen(name) >= PATH_MAX) {
yyerror("keypair name too long");
return NULL;
}
TAILQ_FOREACH(key, &proto->tlscerts, entry) {
if (strcmp(key->name, name) == 0)
return key;
}
if ((kname = calloc(1, sizeof(*kname))) == NULL) {
return NULL;
}
if ((kname->name = strdup(name)) == NULL) {
free(kname);
return NULL;
}
TAILQ_INSERT_TAIL(&proto->tlscerts, kname, entry);
return kname;
}
+66 -23
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: relayd.c,v 1.197 2026/03/02 19:28:01 rsadowski Exp $ */
/* $OpenBSD: relayd.c,v 1.198 2026/05/15 13:57:24 rsadowski Exp $ */
/*
* Copyright (c) 2007 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -1335,14 +1335,14 @@ relay_load_fd(int fd, off_t *len)
}
int
relay_load_certfiles(struct relayd *env, struct relay *rlay, const char *name)
relay_load_certfiles(struct relayd *env, struct relay *rlay, const struct keyname *name)
{
char certfile[PATH_MAX];
char hbuf[PATH_MAX];
struct protocol *proto = rlay->rl_proto;
struct relay_cert *cert;
int useport = htons(rlay->rl_conf.port);
int cert_fd = -1, key_fd = -1, ocsp_fd = -1;
int cert_fd = -1, key_fd = -1, ocsp_fd = -1, ret = 0;
if (rlay->rl_conf.flags & F_TLSCLIENT) {
if (strlen(proto->tlsca) && rlay->rl_tls_ca_fd == -1) {
@@ -1385,15 +1385,29 @@ relay_load_certfiles(struct relayd *env, struct relay *rlay, const char *name)
print_host(&rlay->rl_conf.ss, hbuf, sizeof(hbuf)) == NULL)
goto fail;
else if (name != NULL &&
strlcpy(hbuf, name, sizeof(hbuf)) >= sizeof(hbuf))
strlcpy(hbuf, name->name, sizeof(hbuf)) >= sizeof(hbuf))
goto fail;
if (snprintf(certfile, sizeof(certfile),
"/etc/ssl/%s:%u.crt", hbuf, useport) == -1)
goto fail;
if (name != NULL && strcmp(name->certificate, "") != 0) {
if (strlcpy(certfile, name->certificate, sizeof(certfile))
>= sizeof(certfile)) {
log_warnx("certificate truncated");
goto fail;
}
}
else {
ret = snprintf(certfile, sizeof(certfile),
"/etc/ssl/%s:%u.crt", hbuf, useport);
if (ret < 0 || (size_t)ret >= sizeof(certfile))
goto fail;
}
if ((cert_fd = open(certfile, O_RDONLY)) == -1) {
if (snprintf(certfile, sizeof(certfile),
"/etc/ssl/%s.crt", hbuf) == -1)
ret = snprintf(certfile, sizeof(certfile),
"/etc/ssl/%s.crt", hbuf);
if (ret < 0 || (size_t)ret >= sizeof(certfile))
goto fail;
if ((cert_fd = open(certfile, O_RDONLY)) == -1)
goto fail;
@@ -1401,27 +1415,56 @@ relay_load_certfiles(struct relayd *env, struct relay *rlay, const char *name)
}
log_debug("%s: using certificate %s", __func__, certfile);
if (useport) {
if (snprintf(certfile, sizeof(certfile),
"/etc/ssl/private/%s:%u.key", hbuf, useport) == -1)
goto fail;
} else {
if (snprintf(certfile, sizeof(certfile),
"/etc/ssl/private/%s.key", hbuf) == -1)
if (name != NULL && strcmp(name->key, "") != 0) {
if (strlcpy(certfile, name->key, sizeof(certfile))
>= sizeof(certfile)) {
log_warnx("certificate key truncated");
goto fail;
}
}
else {
if (useport) {
ret = snprintf(certfile, sizeof(certfile),
"/etc/ssl/private/%s:%u.key",
hbuf, useport);
if (ret < 0 || (size_t)ret >= sizeof(certfile))
goto fail;
} else {
ret = snprintf(certfile, sizeof(certfile),
"/etc/ssl/private/%s.key", hbuf);
if (ret < 0 || (size_t)ret >= sizeof(certfile))
goto fail;
}
}
if ((key_fd = open(certfile, O_RDONLY)) == -1)
goto fail;
log_debug("%s: using private key %s", __func__, certfile);
if (useport) {
if (snprintf(certfile, sizeof(certfile),
"/etc/ssl/%s:%u.ocsp", hbuf, useport) == -1)
goto fail;
} else {
if (snprintf(certfile, sizeof(certfile),
"/etc/ssl/%s.ocsp", hbuf) == -1)
if (name != NULL && strcmp(name->ocsp, "") != 0) {
if (strlcpy(certfile, name->ocsp, sizeof(certfile))
>= sizeof(certfile)) {
log_warnx("certificate ocsp truncated");
goto fail;
}
}
else {
if (useport) {
ret = snprintf(certfile, sizeof(certfile),
"/etc/ssl/%s:%u.ocsp",
hbuf, useport);
if (ret < 0 || (size_t)ret >= sizeof(certfile))
goto fail;
} else {
ret = snprintf(certfile, sizeof(certfile),
"/etc/ssl/%s.ocsp", hbuf);
if (ret < 0 || (size_t)ret >= sizeof(certfile))
goto fail;
}
}
if ((ocsp_fd = open(certfile, O_RDONLY)) != -1)
log_debug("%s: using OCSP staple file %s", __func__, certfile);
+26 -5
View File
@@ -1,4 +1,4 @@
.\" $OpenBSD: relayd.conf.5,v 1.215 2026/02/18 22:27:03 kirill Exp $
.\" $OpenBSD: relayd.conf.5,v 1.216 2026/05/15 13:57:24 rsadowski Exp $
.\"
.\" Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
.\" Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: February 18 2026 $
.Dd $Mdocdate: May 15 2026 $
.Dt RELAYD.CONF 5
.Os
.Sh NAME
@@ -998,7 +998,16 @@ is used.
The default is
.Ic no edh .
.It Ic keypair Ar name
The relay will attempt to look up a private key in
.It Ic keypair Ar name Op Ic cert Ar "path"
.It Ic keypair Ar name Op Ic key Ar "path"
.It Ic keypair Ar name Op Ic ocsp Ar "path"
The relay will attempt to look up the TLS assets associated with
.Ar name .
The optional
.Ar path
arguments must be enclosed in double quotes and specify the absolute path to
the respective file.
By default, it searches for a private key in
.Pa /etc/ssl/private/name:port.key
and a public certificate in
.Pa /etc/ssl/name:port.crt ,
@@ -1009,6 +1018,16 @@ If these files are not present, the relay will continue to look in
.Pa /etc/ssl/private/name.key
and
.Pa /etc/ssl/name.crt .
.Pp
If the
.Ic cert ,
.Ic key ,
or
.Ic ocsp
keywords are followed by an explicit
.Ar path ,
that file will be used instead of the default location.
.Pp
This option can be specified multiple times for TLS Server Name Indication.
If not specified,
a keypair will be loaded using the specified IP address of the relay as
@@ -1017,8 +1036,10 @@ See
.Xr ssl 8
for details about TLS server certificates.
.Pp
An optional OCSP staple file will be used during TLS handshakes with
this server if it is found as a non-empty file in
An optional OCSP staple file will be used during TLS handshakes.
If no explicit
.Ic ocsp Ar path
is given, it will be searched as a non-empty file in
.Pa /etc/ssl/name:port.ocsp
or
.Pa /etc/ssl/name.ocsp .
+5 -2
View File
@@ -1,4 +1,4 @@
/* $OpenBSD: relayd.h,v 1.278 2026/03/02 19:28:01 rsadowski Exp $ */
/* $OpenBSD: relayd.h,v 1.279 2026/05/15 13:57:24 rsadowski Exp $ */
/*
* Copyright (c) 2006 - 2016 Reyk Floeter <reyk@openbsd.org>
@@ -726,6 +726,9 @@ struct relay_ticket_key {
struct keyname {
TAILQ_ENTRY(keyname) entry;
char *name;
char certificate[PATH_MAX];
char key[PATH_MAX];
char ocsp[PATH_MAX];
};
TAILQ_HEAD(keynamelist, keyname);
@@ -1323,7 +1326,7 @@ struct relay_cert *cert_add(struct relayd *, objid_t);
struct relay_cert *cert_find(struct relayd *, objid_t);
char *relay_load_fd(int, off_t *);
int relay_load_certfiles(struct relayd *, struct relay *,
const char *);
const struct keyname *);
int expand_string(char *, size_t, const char *, const char *);
void translate_string(char *);
void purge_key(char **, off_t);