summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2013-11-28 20:21:18 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2013-11-28 20:21:18 +0000
commit80934ed5126d3e0fd0ccafc16f70c897fc7bea82 (patch)
tree0c35f0bb84f27304e0cc8401e00bff3ce21bb0c6 /sbin
parent7fc50327b95cb08f5b4b12dea8c86347298fa0f9 (diff)
support raw pubkey authentication w/o x509 certificates;
mostly by Michael Cardell Widerkrantz, reyk@ and mikeb@; ok mike@
Diffstat (limited to 'sbin')
-rw-r--r--sbin/iked/ca.c193
-rw-r--r--sbin/iked/iked.h4
-rw-r--r--sbin/iked/ikev2.c116
-rw-r--r--sbin/iked/ikev2_pld.c20
-rw-r--r--sbin/iked/parse.y71
5 files changed, 305 insertions, 99 deletions
diff --git a/sbin/iked/ca.c b/sbin/iked/ca.c
index b22614bcdc7..a36ab7cd52c 100644
--- a/sbin/iked/ca.c
+++ b/sbin/iked/ca.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ca.c,v 1.23 2013/11/14 12:38:20 markus Exp $ */
+/* $OpenBSD: ca.c,v 1.24 2013/11/28 20:21:17 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -64,7 +64,8 @@ struct ibuf *
ca_x509_serialize(X509 *);
int ca_x509_subjectaltname_cmp(X509 *, struct iked_static_id *);
int ca_x509_subjectaltname(X509 *cert, struct iked_id *);
-int ca_key_serialize(EVP_PKEY *, struct iked_id *);
+int ca_privkey_serialize(EVP_PKEY *, struct iked_id *);
+int ca_pubkey_serialize(EVP_PKEY *, struct iked_id *);
int ca_dispatch_parent(int, struct privsep_proc *, struct imsg *);
int ca_dispatch_ikev1(int, struct privsep_proc *, struct imsg *);
int ca_dispatch_ikev2(int, struct privsep_proc *, struct imsg *);
@@ -83,6 +84,7 @@ struct ca_store {
X509_LOOKUP *ca_certlookup;
struct iked_id ca_privkey;
+ struct iked_id ca_pubkey;
};
pid_t
@@ -98,6 +100,7 @@ caproc(struct privsep *ps, struct privsep_proc *p)
if ((store = calloc(1, sizeof(*store))) == NULL)
fatal("ca: failed to allocate cert store");
+ /* Read private key */
if ((fp = fopen(IKED_PRIVKEY, "r")) == NULL)
fatal("ca: failed to open private key");
@@ -105,8 +108,12 @@ caproc(struct privsep *ps, struct privsep_proc *p)
fatalx("ca: failed to read private key");
fclose(fp);
- if (ca_key_serialize(key, &store->ca_privkey) != 0)
+ if (ca_privkey_serialize(key, &store->ca_privkey) != 0)
fatalx("ca: failed to serialize private key");
+ if (ca_pubkey_serialize(key, &store->ca_pubkey) != 0)
+ fatalx("ca: failed to serialize public key");
+
+ EVP_PKEY_free(key);
return (proc_run(ps, p, procs, nitems(procs), ca_reset, store));
}
@@ -390,40 +397,50 @@ ca_getreq(struct iked *env, struct imsg *imsg)
return (-1);
memcpy(&sh, ptr + sizeof(id), sizeof(sh));
memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t));
- if (type != IKEV2_CERT_X509_CERT)
- return (-1);
-
- for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) {
- if ((ca = ca_by_subjectpubkey(store->ca_cas,
- ptr + i, SHA_DIGEST_LENGTH)) == NULL) {
- log_debug("%s: CA %d not found", __func__, n);
- print_hex(ptr, i, SHA_DIGEST_LENGTH);
- continue;
- }
- log_debug("%s: found CA %s", __func__, ca->name);
+ switch (type) {
+ case IKEV2_CERT_RSA_KEY:
+ if (store->ca_pubkey.id_type != type ||
+ (buf = store->ca_pubkey.id_buf) == NULL)
+ return (-1);
- if ((cert = ca_by_issuer(store->ca_certs,
- X509_get_subject_name(ca), &id)) != NULL) {
- /* XXX should we re-validate our own cert here? */
- break;
- }
+ log_debug("%s: using local public key of type %s", __func__,
+ print_map(type, ikev2_cert_map));
+ break;
+ case IKEV2_CERT_X509_CERT:
+ for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) {
+ if ((ca = ca_by_subjectpubkey(store->ca_cas, ptr + i,
+ SHA_DIGEST_LENGTH)) == NULL)
+ continue;
- log_debug("%s: no valid certificate for this CA", __func__);
- }
- if (ca == NULL || cert == NULL) {
- log_warnx("%s: no valid local certificate found", __func__);
- type = IKEV2_CERT_NONE;
- ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2);
- return (0);
- }
+ log_debug("%s: found CA %s", __func__, ca->name);
- log_debug("%s: found local certificate %s", __func__, cert->name);
+ if ((cert = ca_by_issuer(store->ca_certs,
+ X509_get_subject_name(ca), &id)) != NULL) {
+ /* XXX
+ * should we re-validate our own cert here?
+ */
+ break;
+ }
+ }
+ if (ca == NULL || cert == NULL) {
+ log_warnx("%s: no valid local certificate found",
+ __func__);
+ type = IKEV2_CERT_NONE;
+ ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2);
+ return (0);
+ }
+ log_debug("%s: found local certificate %s", __func__,
+ cert->name);
- if ((buf = ca_x509_serialize(cert)) == NULL)
+ if ((buf = ca_x509_serialize(cert)) == NULL)
+ return (-1);
+ break;
+ default:
+ log_warnx("%s: unknown cert type requested", __func__);
return (-1);
+ }
- type = IKEV2_CERT_X509_CERT;
ca_setcert(env, &sh, NULL, type,
ibuf_data(buf), ibuf_size(buf), PROC_IKEV2);
@@ -492,17 +509,16 @@ ca_getauth(struct iked *env, struct imsg *imsg)
int
ca_reload(struct iked *env)
{
- struct ca_store *store = env->sc_priv;
- DIR *dir;
- struct dirent *entry;
+ struct ca_store *store = env->sc_priv;
+ u_int8_t md[EVP_MAX_MD_SIZE];
char file[PATH_MAX];
+ struct iovec iov[2];
+ struct dirent *entry;
STACK_OF(X509_OBJECT) *h;
X509_OBJECT *xo;
X509 *x509;
- int i, len;
- u_int8_t md[EVP_MAX_MD_SIZE];
- struct iovec iov[2];
- int iovcnt = 2;
+ DIR *dir;
+ int i, len, iovcnt = 2;
/*
* Load CAs
@@ -637,6 +653,17 @@ ca_reload(struct iked *env)
(void)ca_validate_cert(env, NULL, x509, 0);
}
+ if (!env->sc_certreqtype)
+ env->sc_certreqtype = store->ca_pubkey.id_type;
+
+ log_debug("%s: local cert type %s", __func__,
+ print_map(env->sc_certreqtype, ikev2_cert_map));
+
+ iov[0].iov_base = &env->sc_certreqtype;
+ iov[0].iov_len = sizeof(env->sc_certreqtype);
+ (void)proc_composev_imsg(env, PROC_IKEV2, IMSG_CERTREQ, -1,
+ iov, iovcnt);
+
return (0);
}
@@ -748,11 +775,54 @@ ca_x509_serialize(X509 *x509)
}
int
-ca_key_serialize(EVP_PKEY *key, struct iked_id *id)
+ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id)
{
- int len;
+ RSA *rsa;
+ BIO *out = NULL;
u_int8_t *d;
+ int len = 0;
+ int ret = -1;
+
+ switch (key->type) {
+ case EVP_PKEY_RSA:
+ id->id_type = 0;
+ id->id_offset = 0;
+ ibuf_release(id->id_buf);
+
+ if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL)
+ goto done;
+ if ((out = BIO_new(BIO_s_mem())) == NULL)
+ goto done;
+ if (!i2d_RSAPublicKey_bio(out, rsa))
+ goto done;
+
+ len = BIO_get_mem_data(out, &d);
+ if ((id->id_buf = ibuf_new(d, len)) == NULL)
+ goto done;
+
+ id->id_type = IKEV2_CERT_RSA_KEY;
+ break;
+ default:
+ log_debug("%s: unsupported key type %d", __func__, key->type);
+ return (-1);
+ }
+
+ log_debug("%s: type %s length %d", __func__,
+ print_map(id->id_type, ikev2_cert_map), len);
+
+ ret = 0;
+ done:
+ if (out != NULL)
+ BIO_free(out);
+ return (ret);
+}
+
+int
+ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id)
+{
RSA *rsa;
+ u_int8_t *d;
+ int len = 0;
switch (key->type) {
case EVP_PKEY_RSA:
@@ -780,6 +850,9 @@ ca_key_serialize(EVP_PKEY *key, struct iked_id *id)
return (-1);
}
+ log_debug("%s: type %s length %d", __func__,
+ print_map(id->id_type, ikev2_cert_map), len);
+
return (0);
}
@@ -817,7 +890,7 @@ ca_validate_pubkey(struct iked *env, struct iked_static_id *id,
void *data, size_t len)
{
BIO *rawcert = NULL;
- RSA *rsa = NULL;
+ RSA *peerrsa = NULL, *localrsa = NULL;
EVP_PKEY *peerkey = NULL, *localkey = NULL;
int ret = -1;
FILE *fp = NULL;
@@ -855,32 +928,44 @@ ca_validate_pubkey(struct iked *env, struct iked_static_id *id,
if ((rawcert = BIO_new_mem_buf(data, len)) == NULL)
goto done;
- if ((rsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL)
+ if ((peerrsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL)
goto sslerr;
if ((peerkey = EVP_PKEY_new()) == NULL)
goto sslerr;
- if (!EVP_PKEY_set1_RSA(peerkey, rsa))
+ if (!EVP_PKEY_set1_RSA(peerkey, peerrsa))
goto sslerr;
}
lc_string(idstr);
if (strlcpy(file, IKED_PUBKEY_DIR, sizeof(file)) >= sizeof(file) ||
- strlcpy(file, idstr, sizeof(file)) >= sizeof(file))
+ strlcat(file, idstr, sizeof(file)) >= sizeof(file))
goto done;
- log_debug("%s: looking up %s", __func__, file);
-
if ((fp = fopen(file, "r")) == NULL)
goto done;
-
localkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
- fclose(fp);
+ if (localkey == NULL) {
+ /* reading PKCS #8 failed, try PEM */
+ rewind(fp);
+ localrsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
+ fclose(fp);
+ if (localrsa == NULL)
+ goto sslerr;
+ if ((localkey = EVP_PKEY_new()) == NULL)
+ goto sslerr;
+ if (!EVP_PKEY_set1_RSA(localkey, localrsa))
+ goto sslerr;
+ } else {
+ fclose(fp);
+ }
if (localkey == NULL)
goto sslerr;
if (!EVP_PKEY_cmp(peerkey, localkey))
goto done;
+ log_debug("%s: valid public key in file %s", __func__, file);
+
ret = 0;
sslerr:
if (ret != 0)
@@ -889,8 +974,12 @@ ca_validate_pubkey(struct iked *env, struct iked_static_id *id,
ibuf_release(idp.id_buf);
if (peerkey != NULL)
EVP_PKEY_free(peerkey);
- if (rsa != NULL)
- RSA_free(rsa);
+ if (localkey != NULL)
+ EVP_PKEY_free(localkey);
+ if (peerrsa != NULL)
+ RSA_free(peerrsa);
+ if (localrsa != NULL)
+ RSA_free(localrsa);
if (rawcert != NULL)
BIO_free(rawcert);
@@ -931,7 +1020,7 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id,
if (id != NULL) {
if ((ret = ca_validate_pubkey(env, id, X509_get_pubkey(cert),
0)) == 0) {
- errstr = "public key found, ok";
+ errstr = "in public key file, ok";
goto done;
}
@@ -984,11 +1073,11 @@ ca_validate_cert(struct iked *env, struct iked_static_id *id,
/* Success */
ret = 0;
+ errstr = "ok";
done:
if (cert != NULL)
- log_debug("%s: %s %.100s", __func__, cert->name,
- ret == 0 ? "ok" : errstr);
+ log_debug("%s: %s %.100s", __func__, cert->name, errstr);
if (idname != NULL)
X509_NAME_free(idname);
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h
index d23ab9a5734..a1297ba649f 100644
--- a/sbin/iked/iked.h
+++ b/sbin/iked/iked.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: iked.h,v 1.58 2013/11/21 17:46:17 millert Exp $ */
+/* $OpenBSD: iked.h,v 1.59 2013/11/28 20:21:17 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -241,6 +241,8 @@ struct iked_policy {
int pol_refcnt;
+ u_int8_t pol_certreqtype;
+
int pol_af;
u_int8_t pol_saproto;
u_int pol_ipproto;
diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c
index 02e14621072..466cc3c716c 100644
--- a/sbin/iked/ikev2.c
+++ b/sbin/iked/ikev2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.c,v 1.83 2013/06/13 09:11:51 reyk Exp $ */
+/* $OpenBSD: ikev2.c,v 1.84 2013/11/28 20:21:17 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -97,6 +97,8 @@ ssize_t ikev2_add_transform(struct ibuf *,
u_int8_t, u_int8_t, u_int16_t, u_int16_t);
ssize_t ikev2_add_ts(struct ibuf *, struct ikev2_payload **, ssize_t,
struct iked_sa *, int);
+ssize_t ikev2_add_certreq(struct ibuf *, struct ikev2_payload **, ssize_t,
+ struct ibuf *, u_int8_t);
ssize_t ikev2_add_ts_payload(struct ibuf *, u_int, struct iked_sa *);
int ikev2_add_data(struct ibuf *, void *, size_t);
int ikev2_add_buf(struct ibuf *buf, struct ibuf *);
@@ -192,6 +194,7 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg)
u_int8_t *ptr;
size_t len;
struct iked_id *id = NULL;
+ int ignore = 0;
switch (imsg->hdr.type) {
case IMSG_CERTREQ:
@@ -206,8 +209,9 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg)
env->sc_certreq = ibuf_new(ptr,
IMSG_DATA_SIZE(imsg) - sizeof(type));
- log_debug("%s: updated local CERTREQ signatures length %d",
- __func__, ibuf_length(env->sc_certreq));
+ log_debug("%s: updated local CERTREQ type %s length %d",
+ __func__, print_map(type, ikev2_cert_map),
+ ibuf_length(env->sc_certreq));
break;
case IMSG_CERTVALID:
@@ -240,6 +244,21 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg)
break;
}
+ /*
+ * Ignore the message if we already got a valid certificate.
+ * This might happen if the peer sent multiple CERTREQs.
+ */
+ if (sa->sa_stateflags & IKED_REQ_CERT ||
+ type == IKEV2_CERT_NONE)
+ ignore = 1;
+
+ log_debug("%s: cert type %s length %d, %s", __func__,
+ print_map(type, ikev2_cert_map), len,
+ ignore ? "ignored" : "ok");
+
+ if (ignore)
+ break;
+
if (sh.sh_initiator)
id = &sa->sa_icert;
else
@@ -250,18 +269,12 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg)
ibuf_release(id->id_buf);
id->id_buf = NULL;
- if (type != IKEV2_CERT_NONE) {
- if (len <= 0 ||
- (id->id_buf = ibuf_new(ptr, len)) == NULL) {
- log_debug("%s: failed to get cert payload",
- __func__);
- break;
- }
+ if (len <= 0 || (id->id_buf = ibuf_new(ptr, len)) == NULL) {
+ log_debug("%s: failed to get cert payload",
+ __func__);
+ break;
}
-
- log_debug("%s: cert type %d length %d", __func__,
- id->id_type, ibuf_length(id->id_buf));
-
+
sa_stateflags(sa, IKED_REQ_CERT);
if (ikev2_ike_auth(env, sa, NULL) != 0)
@@ -921,21 +934,15 @@ ikev2_init_ike_auth(struct iked *env, struct iked_sa *sa)
goto done;
len = ibuf_size(certid->id_buf) + sizeof(*cert);
- if (env->sc_certreqtype) {
- if (ikev2_next_payload(pld, len,
- IKEV2_PAYLOAD_CERTREQ) == -1)
- goto done;
+ /* CERTREQ payload(s) */
+ if ((len = ikev2_add_certreq(e, &pld,
+ len, env->sc_certreq, env->sc_certreqtype)) == -1)
+ goto done;
- /* CERTREQ payload */
- if ((pld = ikev2_add_payload(e)) == NULL)
- goto done;
- if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL)
- goto done;
- cert->cert_type = env->sc_certreqtype;
- if (ikev2_add_buf(e, env->sc_certreq) == -1)
- goto done;
- len = ibuf_size(env->sc_certreq) + sizeof(*cert);
- }
+ if (env->sc_certreqtype != pol->pol_certreqtype &&
+ (len = ikev2_add_certreq(e, &pld,
+ len, NULL, pol->pol_certreqtype)) == -1)
+ goto done;
}
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_AUTH) == -1)
@@ -1261,6 +1268,41 @@ ikev2_add_ts(struct ibuf *e, struct ikev2_payload **pld, ssize_t len,
return (len);
}
+
+ssize_t
+ikev2_add_certreq(struct ibuf *e, struct ikev2_payload **pld, ssize_t len,
+ struct ibuf *certreq, u_int8_t type)
+{
+ struct ikev2_cert *cert;
+
+ if (type == IKEV2_CERT_NONE)
+ return (len);
+
+ if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_CERTREQ) == -1)
+ return (-1);
+
+ /* CERTREQ payload */
+ if ((*pld = ikev2_add_payload(e)) == NULL)
+ return (-1);
+
+ if ((cert = ibuf_advance(e, sizeof(*cert))) == NULL)
+ return (-1);
+
+ cert->cert_type = type;
+ len = sizeof(*cert);
+
+ if (certreq != NULL && cert->cert_type == IKEV2_CERT_X509_CERT) {
+ if (ikev2_add_buf(e, certreq) == -1)
+ return (-1);
+ len += ibuf_size(certreq);
+ }
+
+ log_debug("%s: type %s length %d", __func__,
+ print_map(type, ikev2_cert_map), len);
+
+ return (len);
+}
+
int
ikev2_next_payload(struct ikev2_payload *pld, size_t length,
u_int8_t nextpayload)
@@ -1737,7 +1779,6 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg)
struct iked_message resp;
struct ike_header *hdr;
struct ikev2_payload *pld;
- struct ikev2_cert *cert;
struct ikev2_keyexchange *ke;
struct ikev2_notify *n;
struct iked_sa *sa = msg->msg_sa;
@@ -1838,19 +1879,16 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg)
len += sizeof(*n);
}
- if (env->sc_certreqtype && (sa->sa_statevalid & IKED_REQ_CERT)) {
- if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_CERTREQ) == -1)
+ if (sa->sa_statevalid & IKED_REQ_CERT) {
+ /* CERTREQ payload(s) */
+ if ((len = ikev2_add_certreq(buf, &pld,
+ len, env->sc_certreq, env->sc_certreqtype)) == -1)
goto done;
- /* CERTREQ payload */
- if ((pld = ikev2_add_payload(buf)) == NULL)
- goto done;
- if ((cert = ibuf_advance(buf, sizeof(*cert))) == NULL)
- goto done;
- cert->cert_type = env->sc_certreqtype;
- if (ikev2_add_buf(buf, env->sc_certreq) == -1)
+ if (env->sc_certreqtype != sa->sa_policy->pol_certreqtype &&
+ (len = ikev2_add_certreq(buf, &pld,
+ len, NULL, sa->sa_policy->pol_certreqtype)) == -1)
goto done;
- len = ibuf_size(env->sc_certreq) + sizeof(*cert);
}
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1)
diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c
index 96654f067eb..75b78bfc1fe 100644
--- a/sbin/iked/ikev2_pld.c
+++ b/sbin/iked/ikev2_pld.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2_pld.c,v 1.31 2013/03/21 04:30:14 deraadt Exp $ */
+/* $OpenBSD: ikev2_pld.c,v 1.32 2013/11/28 20:21:17 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -526,7 +526,7 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld,
struct iked_sa *sa = msg->msg_sa;
struct ikev2_cert cert;
u_int8_t *buf;
- size_t len;
+ ssize_t len;
u_int8_t *msgbuf = ibuf_data(msg->msg_data);
memcpy(&cert, msgbuf + offset, sizeof(cert));
@@ -535,16 +535,24 @@ ikev2_pld_certreq(struct iked *env, struct ikev2_payload *pld,
buf = msgbuf + offset;
len = betoh16(pld->pld_length) - sizeof(*pld) - sizeof(cert);
- log_debug("%s: type %s signatures length %d",
+ log_debug("%s: type %s length %d",
__func__, print_map(cert.cert_type, ikev2_cert_map), len);
+
+ if (len < 0) {
+ log_debug("%s: invalid certificate request length", __func__);
+ return (-1);
+ }
+
print_hex(buf, 0, len);
if (!ikev2_msg_frompeer(msg))
return (0);
- if (!len || (len % SHA_DIGEST_LENGTH) != 0) {
- log_debug("%s: invalid certificate request", __func__);
- return (-1);
+ if (cert.cert_type == IKEV2_CERT_X509_CERT) {
+ if (!len || (len % SHA_DIGEST_LENGTH) != 0) {
+ log_debug("%s: invalid certificate request", __func__);
+ return (-1);
+ }
}
if (msg->msg_sa == NULL)
diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y
index b9dd157c62e..932eb9aa072 100644
--- a/sbin/iked/parse.y
+++ b/sbin/iked/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.32 2013/11/25 13:12:23 benno Exp $ */
+/* $OpenBSD: parse.y,v 1.33 2013/11/28 20:21:17 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -63,6 +63,7 @@ static struct file {
struct file *pushfile(const char *, int);
int popfile(void);
int check_file_secrecy(int, const char *);
+int check_pubkey(char *, int );
int yyparse(void);
int yylex(void);
int yyerror(const char *, ...);
@@ -1625,6 +1626,48 @@ get_id_type(char *string)
return (IKEV2_ID_FQDN);
}
+int
+check_pubkey(char *idstr, int type)
+{
+ char keyfile[MAXPATHLEN];
+ FILE *fp = NULL;
+ const char *suffix = NULL;
+
+ switch (type) {
+ case IKEV2_ID_IPV4:
+ suffix = "ipv4";
+ break;
+ case IKEV2_ID_IPV6:
+ suffix = "ipv6";
+ break;
+ case IKEV2_ID_FQDN:
+ suffix = "fqdn";
+ break;
+ case IKEV2_ID_UFQDN:
+ suffix = "ufqdn";
+ break;
+ default:
+ /* Unspecified ID or public key not supported for this type */
+ return (-1);
+ }
+
+ lc_string(idstr);
+ if ((size_t)snprintf(keyfile, sizeof(keyfile),
+ IKED_CA IKED_PUBKEY_DIR "%s/%s", suffix,
+ idstr) >= sizeof(keyfile)) {
+ log_warnx("%s: public key path is too long", __func__);
+ return (-1);
+ }
+
+ if ((fp = fopen(keyfile, "r")) == NULL)
+ return (-1);
+ fclose(fp);
+
+ log_debug("%s: found public key file %s", __func__, keyfile);
+
+ return (0);
+}
+
struct ipsec_addr_wrap *
host(const char *s)
{
@@ -2323,6 +2366,8 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts,
struct iked_auth *authtype, struct ipsec_filters *filter,
struct ipsec_addr_wrap *ikecfg)
{
+ char idstr[IKED_ID_SIZE];
+ u_int idtype = IKEV2_ID_NONE;
struct ipsec_addr_wrap *ipa, *ipb;
struct iked_policy pol;
struct iked_proposal prop[2];
@@ -2334,8 +2379,10 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts,
bzero(&pol, sizeof(pol));
bzero(&prop, sizeof(prop));
+ bzero(idstr, sizeof(idstr));
pol.pol_id = ++policy_id;
+ pol.pol_certreqtype = env->sc_certreqtype;
pol.pol_af = af;
pol.pol_saproto = saproto;
pol.pol_ipproto = ipproto;
@@ -2559,6 +2606,28 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts,
cfg->cfg.address.addr_af = ipa->af;
}
+ if (dstid) {
+ strlcpy(idstr, dstid, sizeof(idstr));
+ idtype = pol.pol_peerid.id_type;
+ } else if (!pol.pol_peer.addr_net) {
+ print_host(&pol.pol_peer.addr, idstr, sizeof(idstr));
+ switch (pol.pol_peer.addr.ss_family) {
+ case AF_INET:
+ idtype = IKEV2_ID_IPV4;
+ break;
+ case AF_INET6:
+ idtype = IKEV2_ID_IPV6;
+ break;
+ default:
+ log_warnx("%s: unknown address family", __func__);
+ break;
+ }
+ }
+
+ /* Check if we have a raw public key for this peer */
+ if (check_pubkey(idstr, idtype) != -1)
+ pol.pol_certreqtype = IKEV2_CERT_RSA_KEY;
+
config_setpolicy(env, &pol, PROC_IKEV2);
rules++;