summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2015-03-26 19:52:36 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2015-03-26 19:52:36 +0000
commit5bbc02b037f252e64791fb7893aecc7070880917 (patch)
tree54355122a2f27f391913a34daf154197b29b40e2 /sbin
parent8ec8a98046a1296045e16eb3c678256f752ad8e3 (diff)
initial support for RFC 7427 signatures, so we are no longer
restricted to SHA1 for RSA signatures. ok mikeb@
Diffstat (limited to 'sbin')
-rw-r--r--sbin/iked/ca.c8
-rw-r--r--sbin/iked/crypto.c141
-rw-r--r--sbin/iked/iked.h5
-rw-r--r--sbin/iked/ikev2.c70
-rw-r--r--sbin/iked/ikev2.h14
-rw-r--r--sbin/iked/ikev2_msg.c6
-rw-r--r--sbin/iked/ikev2_pld.c33
7 files changed, 259 insertions, 18 deletions
diff --git a/sbin/iked/ca.c b/sbin/iked/ca.c
index 357bb57ba4c..d1eb3dd5e1e 100644
--- a/sbin/iked/ca.c
+++ b/sbin/iked/ca.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ca.c,v 1.34 2015/02/06 10:39:01 deraadt Exp $ */
+/* $OpenBSD: ca.c,v 1.35 2015/03/26 19:52:35 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -302,6 +302,12 @@ ca_setauth(struct iked *env, struct iked_sa *sa,
struct iked_policy *policy = sa->sa_policy;
u_int8_t type = policy->pol_auth.auth_method;
+ /* switch encoding to IKEV2_AUTH_SIG if SHA2 is supported */
+ if (sa->sa_sigsha2 && type == IKEV2_AUTH_RSA_SIG) {
+ log_debug("%s: switching from RSA_SIG to SIG", __func__);
+ type = IKEV2_AUTH_SIG;
+ }
+
if (type == IKEV2_AUTH_SHARED_KEY_MIC) {
sa->sa_stateflags |= IKED_REQ_AUTH;
return (ikev2_msg_authsign(env, sa,
diff --git a/sbin/iked/crypto.c b/sbin/iked/crypto.c
index 3d6f6a29583..2fd6f356d29 100644
--- a/sbin/iked/crypto.c
+++ b/sbin/iked/crypto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: crypto.c,v 1.15 2015/01/16 06:39:58 deraadt Exp $ */
+/* $OpenBSD: crypto.c,v 1.16 2015/03/26 19:52:35 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -39,6 +39,34 @@
#include "iked.h"
#include "ikev2.h"
+/* RFC 7427, A.1 */
+static const u_int8_t sha256WithRSAEncryption[] = {
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00
+};
+static const u_int8_t sha384WithRSAEncryption[] = {
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00
+};
+static const u_int8_t sha512WithRSAEncryption[] = {
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00
+};
+
+struct {
+ u_int8_t sc_len;
+ const u_int8_t *sc_oid;
+ const EVP_MD *(*sc_md)(void);
+} schemes[] = {
+ { sizeof(sha256WithRSAEncryption), sha256WithRSAEncryption, EVP_sha256 },
+ { sizeof(sha384WithRSAEncryption), sha384WithRSAEncryption, EVP_sha384 },
+ { sizeof(sha512WithRSAEncryption), sha512WithRSAEncryption, EVP_sha512 },
+};
+
+int _dsa_verify_init(struct iked_dsa *, const u_int8_t *, size_t);
+size_t _dsa_verify_offset(struct iked_dsa *, u_int8_t *);
+int _dsa_sign_encode(struct iked_dsa *, u_int8_t *, size_t *);
+
struct iked_hash *
hash_new(u_int8_t type, u_int16_t id)
{
@@ -442,6 +470,12 @@ dsa_new(u_int16_t id, struct iked_hash *prf, int sign)
bzero(&dsa, sizeof(dsa));
switch (id) {
+ case IKEV2_AUTH_SIG:
+ if (sign)
+ dsa.dsa_priv = EVP_sha256(); /* XXX should be passed */
+ else
+ dsa.dsa_priv = NULL; /* set later by dsa_init() */
+ break;
case IKEV2_AUTH_RSA_SIG:
/* RFC5996 says we SHOULD use SHA1 here */
dsa.dsa_priv = EVP_sha1();
@@ -603,9 +637,54 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, u_int8_t type)
}
int
-dsa_init(struct iked_dsa *dsa)
+_dsa_verify_init(struct iked_dsa *dsa, const u_int8_t *sig, size_t len)
+{
+ u_int8_t oidlen;
+ size_t i;
+
+ if (dsa->dsa_priv != NULL)
+ return (0);
+ /*
+ * For IKEV2_AUTH_SIG the oid of the authentication signature
+ * is encoded in the first bytes of the auth message.
+ */
+ if (dsa->dsa_method != IKEV2_AUTH_SIG) {
+ log_debug("%s: dsa_priv not set for %s", __func__,
+ print_map(dsa->dsa_method, ikev2_auth_map));
+ return (-1);
+ }
+ if (sig == NULL) {
+ log_debug("%s: signature missing", __func__);
+ return (-1);
+ }
+ if (len < 1) {
+ log_debug("%s: signature (%zu) too small for oid length",
+ __func__, len);
+ return (-1);
+ }
+ memcpy(&oidlen, sig, sizeof(oidlen));
+ if (len < (size_t)oidlen + 1) {
+ log_debug("%s: signature (%zu) too small for oid (%u)",
+ __func__, len, oidlen);
+ return (-1);
+ }
+ for (i = 0; i < nitems(schemes); i++) {
+ if (oidlen == schemes[i].sc_len &&
+ memcmp(sig + 1, schemes[i].sc_oid, schemes[i].sc_len) == 0) {
+ dsa->dsa_priv = (*schemes[i].sc_md)();
+ log_debug("%s: signature scheme %zd selected",
+ __func__, i);
+ return (0);
+ }
+ }
+ log_debug("%s: unsupported signature (%d)", __func__, oidlen);
+ return (-1);
+}
+
+int
+dsa_init(struct iked_dsa *dsa, const void *buf, size_t len)
{
- int ret;
+ int ret;
if (dsa->dsa_hmac) {
if (!HMAC_Init_ex(dsa->dsa_ctx, ibuf_data(dsa->dsa_keydata),
@@ -616,8 +695,11 @@ dsa_init(struct iked_dsa *dsa)
if (dsa->dsa_sign)
ret = EVP_SignInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL);
- else
+ else {
+ if ((ret = _dsa_verify_init(dsa, buf, len)) != 0)
+ return (ret);
ret = EVP_VerifyInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL);
+ }
return (ret ? 0 : -1);
}
@@ -637,18 +719,44 @@ dsa_update(struct iked_dsa *dsa, const void *buf, size_t len)
return (ret ? 0 : -1);
}
+/* Prefix signature hash with encoded type */
+int
+_dsa_sign_encode(struct iked_dsa *dsa, u_int8_t *ptr, size_t *offp)
+{
+ if (offp)
+ *offp = 0;
+ if (dsa->dsa_method != IKEV2_AUTH_SIG)
+ return (0);
+ if (dsa->dsa_priv != EVP_sha256())
+ return (-1);
+ if (ptr) {
+ ptr[0] = sizeof(sha256WithRSAEncryption);
+ memcpy(ptr + 1, sha256WithRSAEncryption,
+ sizeof(sha256WithRSAEncryption));
+ }
+ if (offp)
+ *offp = 1 + sizeof(sha256WithRSAEncryption);
+ return (0);
+}
+
size_t
dsa_length(struct iked_dsa *dsa)
{
+ size_t off = 0;
+
if (dsa->dsa_hmac)
return (EVP_MD_size(dsa->dsa_priv));
- return (EVP_PKEY_size(dsa->dsa_key));
+ if (_dsa_sign_encode(dsa, NULL, &off) < 0)
+ fatal("dsa_length: internal error");
+ return (EVP_PKEY_size(dsa->dsa_key) + off);
}
ssize_t
dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len)
{
u_int siglen;
+ size_t off = 0;
+ u_int8_t *ptr = buf;
if (len < dsa_length(dsa))
return (-1);
@@ -657,19 +765,36 @@ dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len)
if (!HMAC_Final(dsa->dsa_ctx, buf, &siglen))
return (-1);
} else {
- if (!EVP_SignFinal(dsa->dsa_ctx, buf, &siglen,
+ if (_dsa_sign_encode(dsa, ptr, &off) < 0)
+ return (-1);
+ if (!EVP_SignFinal(dsa->dsa_ctx, ptr + off, &siglen,
dsa->dsa_key))
return (-1);
+ siglen += off;
}
return (siglen);
}
+size_t
+_dsa_verify_offset(struct iked_dsa *dsa, u_int8_t *ptr)
+{
+ /*
+ * XXX assumes that _dsa_verify_init() has already checked
+ * the encoded method.
+ */
+ if (dsa->dsa_method == IKEV2_AUTH_SIG)
+ return (ptr[0] + 1);
+ return (0);
+}
+
ssize_t
dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len)
{
u_int8_t sig[EVP_MAX_MD_SIZE];
u_int siglen = sizeof(sig);
+ u_int8_t *ptr = buf;
+ size_t off = 0;
if (dsa->dsa_hmac) {
if (!HMAC_Final(dsa->dsa_ctx, sig, &siglen))
@@ -677,7 +802,9 @@ dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len)
if (siglen != len || memcmp(buf, sig, siglen) != 0)
return (-1);
} else {
- if (EVP_VerifyFinal(dsa->dsa_ctx, buf, len,
+ if ((off = _dsa_verify_offset(dsa, ptr)) >= len)
+ return (-1);
+ if (EVP_VerifyFinal(dsa->dsa_ctx, ptr + off, len - off,
dsa->dsa_key) != 1) {
ca_sslerror(__func__);
return (-1);
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h
index ab0525c6776..e9da417d39a 100644
--- a/sbin/iked/iked.h
+++ b/sbin/iked/iked.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: iked.h,v 1.83 2015/01/16 06:39:58 deraadt Exp $ */
+/* $OpenBSD: iked.h,v 1.84 2015/03/26 19:52:35 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -407,6 +407,7 @@ struct iked_sa {
struct ibuf *sa_1stmsg; /* for initiator AUTH */
struct ibuf *sa_2ndmsg; /* for responder AUTH */
struct iked_id sa_localauth; /* local AUTH message */
+ int sa_sigsha2; /* use SHA2 for signatures */
struct iked_id sa_iid; /* initiator id */
struct iked_id sa_rid; /* responder id */
@@ -732,7 +733,7 @@ struct iked_dsa *
struct ibuf *
dsa_setkey(struct iked_dsa *, void *, size_t, u_int8_t);
void dsa_free(struct iked_dsa *);
-int dsa_init(struct iked_dsa *);
+int dsa_init(struct iked_dsa *, const void *, size_t);
size_t dsa_length(struct iked_dsa *);
int dsa_update(struct iked_dsa *, const void *, size_t);
ssize_t dsa_sign_final(struct iked_dsa *, void *, size_t);
diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c
index d6a7235cee1..a2c94622a8b 100644
--- a/sbin/iked/ikev2.c
+++ b/sbin/iked/ikev2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.c,v 1.119 2015/02/06 10:39:01 deraadt Exp $ */
+/* $OpenBSD: ikev2.c,v 1.120 2015/03/26 19:52:35 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -54,6 +54,7 @@ struct iked_sa *
u_int8_t *, u_int8_t **, size_t *);
void ikev2_recv(struct iked *, struct iked_message *);
+int ikev2_ike_auth_compatible(struct iked_sa *, u_int8_t, u_int8_t);
int ikev2_ike_auth_recv(struct iked *, struct iked_sa *,
struct iked_message *);
int ikev2_ike_auth(struct iked *, struct iked_sa *);
@@ -123,6 +124,9 @@ int ikev2_cp_setaddr(struct iked *, struct iked_sa *);
int ikev2_cp_fixaddr(struct iked_sa *, struct iked_addr *,
struct iked_addr *);
+ssize_t ikev2_add_sighashnotify(struct ibuf *, struct ikev2_payload **,
+ ssize_t);
+
static struct privsep_proc procs[] = {
{ "parent", PROC_PARENT, ikev2_dispatch_parent },
{ "ikev1", PROC_IKEV1, ikev2_dispatch_ikev1 },
@@ -494,6 +498,17 @@ done:
}
int
+ikev2_ike_auth_compatible(struct iked_sa *sa, u_int8_t want, u_int8_t have)
+{
+ if (want == have)
+ return (0);
+ if (sa->sa_sigsha2 &&
+ have == IKEV2_AUTH_SIG && want == IKEV2_AUTH_RSA_SIG)
+ return (0);
+ return (-1);
+}
+
+int
ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa,
struct iked_message *msg)
{
@@ -579,11 +594,13 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa,
ikeauth.auth_length = ibuf_size(sa->sa_eapmsk);
}
- if (msg->msg_auth.id_type != ikeauth.auth_method) {
+ if (ikev2_ike_auth_compatible(sa,
+ ikeauth.auth_method, msg->msg_auth.id_type) < 0) {
log_warnx("%s: unexpected auth method %s", __func__,
- print_map(ikeauth.auth_method, ikev2_auth_map));
+ print_map(msg->msg_auth.id_type, ikev2_auth_map));
return (-1);
}
+ ikeauth.auth_method = msg->msg_auth.id_type;
if ((authmsg = ikev2_msg_auth(env, sa,
sa->sa_hdr.sh_initiator)) == NULL) {
@@ -908,6 +925,9 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol,
len += sizeof(*n);
}
+ if ((len = ikev2_add_sighashnotify(buf, &pld, len)) == -1)
+ goto done;
+
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1)
goto done;
@@ -1477,6 +1497,46 @@ ikev2_add_ipcompnotify(struct iked *env, struct ibuf *e,
return (len);
}
+ssize_t
+ikev2_add_sighashnotify(struct ibuf *e, struct ikev2_payload **pld,
+ ssize_t len)
+{
+ struct ikev2_notify *n;
+ u_int8_t *ptr;
+ size_t i;
+ u_int16_t hash, signature_hashes[] = {
+ IKEV2_SIGHASH_SHA2_256,
+ IKEV2_SIGHASH_SHA2_384,
+ IKEV2_SIGHASH_SHA2_512
+ };
+
+ if (ikev2_next_payload(*pld, len, IKEV2_PAYLOAD_NOTIFY) == -1)
+ return (-1);
+
+ /* XXX signature_hashes are hardcoded for now */
+ len = sizeof(*n) + nitems(signature_hashes) * sizeof(hash);
+
+ /* NOTIFY payload */
+ if ((*pld = ikev2_add_payload(e)) == NULL)
+ return (-1);
+ if ((ptr = ibuf_advance(e, len)) == NULL)
+ return (-1);
+
+ n = (struct ikev2_notify *)ptr;
+ n->n_protoid = 0;
+ n->n_spisize = 0;
+ n->n_type = htobe16(IKEV2_N_SIGNATURE_HASH_ALGORITHMS);
+ ptr += sizeof(*n);
+
+ for (i = 0; i < nitems(signature_hashes); i++) {
+ hash = htobe16(signature_hashes[i]);
+ memcpy(ptr, &hash, sizeof(hash));
+ ptr += sizeof(hash);
+ }
+
+ return (len);
+}
+
int
ikev2_next_payload(struct ikev2_payload *pld, size_t length,
u_int8_t nextpayload)
@@ -2085,6 +2145,10 @@ ikev2_resp_ike_sa_init(struct iked *env, struct iked_message *msg)
goto done;
}
+ if (sa->sa_sigsha2 &&
+ (len = ikev2_add_sighashnotify(buf, &pld, len)) == -1)
+ goto done;
+
if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1)
goto done;
diff --git a/sbin/iked/ikev2.h b/sbin/iked/ikev2.h
index 8d307a41eeb..62831f71be7 100644
--- a/sbin/iked/ikev2.h
+++ b/sbin/iked/ikev2.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.h,v 1.17 2014/11/07 14:02:32 mikeb Exp $ */
+/* $OpenBSD: ikev2.h,v 1.18 2015/03/26 19:52:35 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -350,6 +350,7 @@ struct ikev2_notify {
#define IKEV2_N_PSK_CONFIRM 16426 /* RFC6631 */
#define IKEV2_N_ERX_SUPPORTED 16427 /* RFC6867 */
#define IKEV2_N_IFOM_CAPABILITY 16428 /* OA3GPP */
+#define IKEV2_N_SIGNATURE_HASH_ALGORITHMS 16431 /* RFC7427 */
extern struct iked_constmap ikev2_n_map[];
@@ -454,9 +455,20 @@ struct ikev2_auth {
#define IKEV2_AUTH_ECDSA_384 10 /* RFC4754 */
#define IKEV2_AUTH_ECDSA_512 11 /* RFC4754 */
#define IKEV2_AUTH_GSPM 12 /* RFC6467 */
+#define IKEV2_AUTH_SIG 14 /* RFC7427 */
extern struct iked_constmap ikev2_auth_map[];
+/* Notifications used together with IKEV2_AUTH_SIG */
+
+#define IKEV2_SIGHASH_RESERVED 0 /* RFC7427 */
+#define IKEV2_SIGHASH_SHA1 1 /* RFC7427 */
+#define IKEV2_SIGHASH_SHA2_256 2 /* RFC7427 */
+#define IKEV2_SIGHASH_SHA2_384 3 /* RFC7427 */
+#define IKEV2_SIGHASH_SHA2_512 4 /* RFC7427 */
+
+extern struct iked_constmap ikev2_sighash_map[];
+
/*
* CP payload
*/
diff --git a/sbin/iked/ikev2_msg.c b/sbin/iked/ikev2_msg.c
index d08fd93660a..88ffefc55c6 100644
--- a/sbin/iked/ikev2_msg.c
+++ b/sbin/iked/ikev2_msg.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2_msg.c,v 1.41 2015/02/15 01:56:42 tedu Exp $ */
+/* $OpenBSD: ikev2_msg.c,v 1.42 2015/03/26 19:52:35 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -761,7 +761,7 @@ ikev2_msg_authverify(struct iked *env, struct iked_sa *sa,
print_map(id->id_type, ikev2_cert_map));
if (dsa_setkey(dsa, key, keylen, keytype) == NULL ||
- dsa_init(dsa) != 0 ||
+ dsa_init(dsa, buf, len) != 0 ||
dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) {
log_debug("%s: failed to compute digital signature", __func__);
goto done;
@@ -833,7 +833,7 @@ ikev2_msg_authsign(struct iked *env, struct iked_sa *sa,
}
if (dsa_setkey(dsa, key, keylen, keytype) == NULL ||
- dsa_init(dsa) != 0 ||
+ dsa_init(dsa, NULL, 0) != 0 ||
dsa_update(dsa, ibuf_data(authmsg), ibuf_size(authmsg))) {
log_debug("%s: failed to compute digital signature", __func__);
goto done;
diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c
index 301c2e101b5..766aefc92a3 100644
--- a/sbin/iked/ikev2_pld.c
+++ b/sbin/iked/ikev2_pld.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2_pld.c,v 1.49 2015/02/06 10:39:01 deraadt Exp $ */
+/* $OpenBSD: ikev2_pld.c,v 1.50 2015/03/26 19:52:35 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -1104,6 +1104,7 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld,
u_int16_t type;
u_int16_t group;
u_int16_t cpi;
+ u_int16_t signature_hash;
u_int8_t transform;
if (ikev2_validate_notify(msg, offset, left, pld, &n))
@@ -1253,6 +1254,36 @@ ikev2_pld_notify(struct iked *env, struct ikev2_payload *pld,
msg->msg_sa->sa_cpi_out = betoh16(cpi);
}
break;
+ case IKEV2_N_SIGNATURE_HASH_ALGORITHMS:
+ if (msg->msg_e) {
+ log_debug("%s: SIGNATURE_HASH_ALGORITHMS: encrypted",
+ __func__);
+ return (-1);
+ }
+ if (msg->msg_sa == NULL ||
+ msg->msg_sa->sa_sigsha2) {
+ log_debug("%s: SIGNATURE_HASH_ALGORITHMS: no SA or "
+ "duplicate notify", __func__);
+ return (-1);
+ }
+ if (len < sizeof(signature_hash) ||
+ len % sizeof(signature_hash)) {
+ log_debug("%s: malformed signature hash notification"
+ "(%zu bytes)", __func__, len);
+ return (0);
+ }
+ while (len >= sizeof(signature_hash)) {
+ memcpy(&signature_hash, buf, sizeof(signature_hash));
+ signature_hash = betoh16(signature_hash);
+ log_debug("%s: signature hash %s (%x)", __func__,
+ print_map(signature_hash, ikev2_sighash_map),
+ signature_hash);
+ len -= sizeof(signature_hash);
+ buf += sizeof(signature_hash);
+ if (signature_hash == IKEV2_SIGHASH_SHA2_256)
+ msg->msg_sa->sa_sigsha2 = 1;
+ }
+ break;
}
return (0);