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:
+115
-13
@@ -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
@@ -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);
|
||||
|
||||
@@ -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 .
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user