diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2017-03-27 10:06:42 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2017-03-27 10:06:42 +0000 |
commit | e3affe111fdf78b3b570254f4a8bcac92e8e2264 (patch) | |
tree | 73ccda4a2c611b5451af51e88ec416c476c3f7fd /sbin/iked | |
parent | 650ec76b079154b185c886970968e2cc614b4e65 (diff) |
Add support for RFC4754 (ECDSA) and RFC7427 authentication.
These modes provide stronger and more flexible ways for
authentication: while RSA public key auth relies on SHA-1 hashes, the
news modes use SHA2-256 and up to SHA2-512 hashes.
Original diff from markus@ with patches from mikeb@ and me.
OK mikeb@ patrick@
Diffstat (limited to 'sbin/iked')
-rw-r--r-- | sbin/iked/ca.c | 150 | ||||
-rw-r--r-- | sbin/iked/crypto.c | 263 | ||||
-rw-r--r-- | sbin/iked/iked.8 | 7 | ||||
-rw-r--r-- | sbin/iked/iked.conf.5 | 29 | ||||
-rw-r--r-- | sbin/iked/iked.h | 3 | ||||
-rw-r--r-- | sbin/iked/ikev2.c | 49 | ||||
-rw-r--r-- | sbin/iked/ikev2.h | 14 | ||||
-rw-r--r-- | sbin/iked/ikev2_msg.c | 15 | ||||
-rw-r--r-- | sbin/iked/parse.y | 223 |
9 files changed, 641 insertions, 112 deletions
diff --git a/sbin/iked/ca.c b/sbin/iked/ca.c index 9fe18d75df0..7ecd75143f0 100644 --- a/sbin/iked/ca.c +++ b/sbin/iked/ca.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ca.c,v 1.42 2017/01/20 14:08:08 mikeb Exp $ */ +/* $OpenBSD: ca.c,v 1.43 2017/03/27 10:06:41 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -61,6 +61,7 @@ int ca_validate_pubkey(struct iked *, struct iked_static_id *, void *, size_t); int ca_validate_cert(struct iked *, struct iked_static_id *, void *, size_t); +int ca_privkey_to_method(struct iked_id *); struct ibuf * ca_x509_serialize(X509 *); int ca_x509_subjectaltname_cmp(X509 *, struct iked_static_id *); @@ -82,6 +83,8 @@ struct ca_store { struct iked_id ca_privkey; struct iked_id ca_pubkey; + + uint8_t ca_privkey_method; }; pid_t @@ -125,6 +128,10 @@ ca_getkey(struct privsep *ps, struct iked_id *key, enum imsg_type type) if (type == IMSG_PRIVKEY) { name = "private"; id = &store->ca_privkey; + + store->ca_privkey_method = ca_privkey_to_method(key); + if (store->ca_privkey_method == IKEV2_AUTH_NONE) + fatalx("ca: failed to get auth method for privkey"); } else if (type == IMSG_PUBKEY) { name = "public"; id = &store->ca_pubkey; @@ -323,10 +330,18 @@ ca_setauth(struct iked *env, struct iked_sa *sa, struct iked_policy *policy = sa->sa_policy; uint8_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 (id == PROC_CERT) { + /* switch encoding to IKEV2_AUTH_SIG if SHA2 is supported */ + if (sa->sa_sigsha2 && type == IKEV2_AUTH_RSA_SIG) { + log_debug("%s: switching RSA_SIG to SIG", __func__); + type = IKEV2_AUTH_SIG; + } else if (!sa->sa_sigsha2 && type == IKEV2_AUTH_SIG_ANY) { + log_debug("%s: switching SIG to RSA_SIG(*)", __func__); + /* XXX ca might auto-switch to ECDSA */ + type = IKEV2_AUTH_RSA_SIG; + } else if (type == IKEV2_AUTH_SIG) { + log_debug("%s: using SIG (RFC7427)", __func__); + } } if (type == IKEV2_AUTH_SHARED_KEY_MIC) { @@ -389,6 +404,7 @@ ca_getcert(struct iked *env, struct imsg *imsg) } break; case IKEV2_CERT_RSA_KEY: + case IKEV2_CERT_ECDSA: ret = ca_validate_pubkey(env, &id, ptr, len); break; default: @@ -439,6 +455,7 @@ ca_getreq(struct iked *env, struct imsg *imsg) switch (type) { case IKEV2_CERT_RSA_KEY: + case IKEV2_CERT_ECDSA: if (store->ca_pubkey.id_type != type || (buf = store->ca_pubkey.id_buf) == NULL) return (-1); @@ -525,12 +542,13 @@ ca_getauth(struct iked *env, struct imsg *imsg) bzero(&policy, sizeof(policy)); memcpy(&sa.sa_hdr, &sh, sizeof(sh)); sa.sa_policy = &policy; - policy.pol_auth.auth_method = method; if (sh.sh_initiator) id = &sa.sa_icert; else id = &sa.sa_rcert; memcpy(id, &store->ca_privkey, sizeof(*id)); + policy.pol_auth.auth_method = method == IKEV2_AUTH_SIG ? + method : store->ca_privkey_method; if (ikev2_msg_authsign(env, &sa, &policy.pol_auth, authmsg) != 0) { log_debug("%s: AUTH sign failed", __func__); @@ -833,6 +851,7 @@ int ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id) { RSA *rsa = NULL; + EC_KEY *ec = NULL; uint8_t *d; int len = 0; int ret = -1; @@ -842,6 +861,7 @@ ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id) id->id_type = 0; id->id_offset = 0; ibuf_release(id->id_buf); + id->id_buf = NULL; if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL) goto done; @@ -853,11 +873,34 @@ ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id) d = ibuf_data(id->id_buf); if (i2d_RSAPublicKey(rsa, &d) != len) { ibuf_release(id->id_buf); + id->id_buf = NULL; goto done; } id->id_type = IKEV2_CERT_RSA_KEY; break; + case EVP_PKEY_EC: + id->id_type = 0; + id->id_offset = 0; + ibuf_release(id->id_buf); + id->id_buf = NULL; + + if ((ec = EVP_PKEY_get1_EC_KEY(key)) == NULL) + goto done; + if ((len = i2d_EC_PUBKEY(ec, NULL)) <= 0) + goto done; + if ((id->id_buf = ibuf_new(NULL, len)) == NULL) + goto done; + + d = ibuf_data(id->id_buf); + if (i2d_EC_PUBKEY(ec, &d) != len) { + ibuf_release(id->id_buf); + id->id_buf = NULL; + goto done; + } + + id->id_type = IKEV2_CERT_ECDSA; + break; default: log_debug("%s: unsupported key type %d", __func__, key->type); return (-1); @@ -870,6 +913,8 @@ ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id) done: if (rsa != NULL) RSA_free(rsa); + if (ec != NULL) + EC_KEY_free(ec); return (ret); } @@ -877,6 +922,7 @@ int ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) { RSA *rsa = NULL; + EC_KEY *ec = NULL; uint8_t *d; int len = 0; int ret = -1; @@ -886,6 +932,7 @@ ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) id->id_type = 0; id->id_offset = 0; ibuf_release(id->id_buf); + id->id_buf = NULL; if ((rsa = EVP_PKEY_get1_RSA(key)) == NULL) goto done; @@ -897,11 +944,34 @@ ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) d = ibuf_data(id->id_buf); if (i2d_RSAPrivateKey(rsa, &d) != len) { ibuf_release(id->id_buf); + id->id_buf = NULL; goto done; } id->id_type = IKEV2_CERT_RSA_KEY; break; + case EVP_PKEY_EC: + id->id_type = 0; + id->id_offset = 0; + ibuf_release(id->id_buf); + id->id_buf = NULL; + + if ((ec = EVP_PKEY_get1_EC_KEY(key)) == NULL) + goto done; + if ((len = i2d_ECPrivateKey(ec, NULL)) <= 0) + goto done; + if ((id->id_buf = ibuf_new(NULL, len)) == NULL) + goto done; + + d = ibuf_data(id->id_buf); + if (i2d_ECPrivateKey(ec, &d) != len) { + ibuf_release(id->id_buf); + id->id_buf = NULL; + goto done; + } + + id->id_type = IKEV2_CERT_ECDSA; + break; default: log_debug("%s: unsupported key type %d", __func__, key->type); return (-1); @@ -914,9 +984,57 @@ ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id) done: if (rsa != NULL) RSA_free(rsa); + if (ec != NULL) + EC_KEY_free(ec); return (ret); } +int +ca_privkey_to_method(struct iked_id *privkey) +{ + BIO *rawcert = NULL; + EC_KEY *ec = NULL; + const EC_GROUP *group = NULL; + uint8_t method = IKEV2_AUTH_NONE; + + switch (privkey->id_type) { + case IKEV2_CERT_RSA_KEY: + method = IKEV2_AUTH_RSA_SIG; + break; + case IKEV2_CERT_ECDSA: + if ((rawcert = BIO_new_mem_buf(ibuf_data(privkey->id_buf), + ibuf_length(privkey->id_buf))) == NULL) + goto out; + if ((ec = d2i_ECPrivateKey_bio(rawcert, NULL)) == NULL) + goto out; + if ((group = EC_KEY_get0_group(ec)) == NULL) + goto out; + switch (EC_GROUP_get_degree(group)) { + case 256: + method = IKEV2_AUTH_ECDSA_256; + break; + case 384: + method = IKEV2_AUTH_ECDSA_384; + break; + case 521: + method = IKEV2_AUTH_ECDSA_521; + break; + } + } + + log_debug("%s: type %s method %s", __func__, + print_map(privkey->id_type, ikev2_cert_map), + print_map(method, ikev2_auth_map)); + + out: + if (ec != NULL) + EC_KEY_free(ec); + if (rawcert != NULL) + BIO_free(rawcert); + + return (method); +} + char * ca_asn1_name(uint8_t *asn1, size_t len) { @@ -1047,6 +1165,7 @@ ca_validate_pubkey(struct iked *env, struct iked_static_id *id, { BIO *rawcert = NULL; RSA *peerrsa = NULL, *localrsa = NULL; + EC_KEY *peerec = NULL; EVP_PKEY *peerkey = NULL, *localkey = NULL; int ret = -1; FILE *fp = NULL; @@ -1084,12 +1203,21 @@ ca_validate_pubkey(struct iked *env, struct iked_static_id *id, if ((rawcert = BIO_new_mem_buf(data, len)) == NULL) goto done; - if ((peerrsa = d2i_RSAPublicKey_bio(rawcert, NULL)) == NULL) - goto sslerr; if ((peerkey = EVP_PKEY_new()) == NULL) goto sslerr; - if (!EVP_PKEY_set1_RSA(peerkey, peerrsa)) + if ((peerrsa = d2i_RSAPublicKey_bio(rawcert, NULL))) { + if (!EVP_PKEY_set1_RSA(peerkey, peerrsa)) { + goto sslerr; + } + } else if (BIO_reset(rawcert) == 1 && + (peerec = d2i_EC_PUBKEY_bio(rawcert, NULL))) { + if (!EVP_PKEY_set1_EC_KEY(peerkey, peerec)) { + goto sslerr; + } + } else { + log_debug("%s: unknown key type received", __func__); goto sslerr; + } } lc_string(idstr); @@ -1101,7 +1229,7 @@ ca_validate_pubkey(struct iked *env, struct iked_static_id *id, goto done; localkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL); if (localkey == NULL) { - /* reading PKCS #8 failed, try PEM */ + /* reading PKCS #8 failed, try PEM RSA */ rewind(fp); localrsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL); fclose(fp); @@ -1134,6 +1262,8 @@ ca_validate_pubkey(struct iked *env, struct iked_static_id *id, EVP_PKEY_free(localkey); if (peerrsa != NULL) RSA_free(peerrsa); + if (peerec != NULL) + EC_KEY_free(peerec); if (localrsa != NULL) RSA_free(localrsa); if (rawcert != NULL) diff --git a/sbin/iked/crypto.c b/sbin/iked/crypto.c index fdd7163e7b5..ebee0cb71d4 100644 --- a/sbin/iked/crypto.c +++ b/sbin/iked/crypto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: crypto.c,v 1.19 2015/10/31 19:28:19 naddy Exp $ */ +/* $OpenBSD: crypto.c,v 1.20 2017/03/27 10:06:41 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -39,36 +39,52 @@ #include "iked.h" #include "ikev2.h" -/* RFC 7427, A.1 */ -static const uint8_t sha256WithRSAEncryption[] = { +/* RFC 7427, A.1 RSA */ +static const uint8_t sha256WithRSA[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00 }; -static const uint8_t sha384WithRSAEncryption[] = { +static const uint8_t sha384WithRSA[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00 }; -static const uint8_t sha512WithRSAEncryption[] = { +static const uint8_t sha512WithRSA[] = { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00 }; +/* RFC 7427, A.3 ECDSA */ +static const uint8_t ecdsa_sha256[] = { + 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x03, 0x02 +}; +static const uint8_t ecdsa_sha384[] = { + 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x03, 0x03 +}; +static const uint8_t ecdsa_sha512[] = { + 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x04, 0x03, 0x04 +}; -struct { +static const struct { + int sc_keytype; + const EVP_MD *(*sc_md)(void); uint8_t sc_len; const uint8_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 }, + { EVP_PKEY_RSA, EVP_sha256, sizeof(sha256WithRSA), sha256WithRSA }, + { EVP_PKEY_RSA, EVP_sha384, sizeof(sha384WithRSA), sha384WithRSA }, + { EVP_PKEY_RSA, EVP_sha512, sizeof(sha512WithRSA), sha512WithRSA }, + { EVP_PKEY_EC, EVP_sha256, sizeof(ecdsa_sha256), ecdsa_sha256 }, + { EVP_PKEY_EC, EVP_sha384, sizeof(ecdsa_sha384), ecdsa_sha384 }, + { EVP_PKEY_EC, EVP_sha512, sizeof(ecdsa_sha512), ecdsa_sha512 }, }; int _dsa_verify_init(struct iked_dsa *, const uint8_t *, size_t); -size_t _dsa_verify_offset(struct iked_dsa *, uint8_t *); +int _dsa_verify_prepare(struct iked_dsa *, uint8_t **, size_t *, + uint8_t **); int _dsa_sign_encode(struct iked_dsa *, uint8_t *, size_t *); +int _dsa_sign_ecdsa(struct iked_dsa *, uint8_t *, size_t); struct iked_hash * hash_new(uint8_t type, uint16_t id) @@ -358,6 +374,7 @@ struct ibuf * cipher_setiv(struct iked_cipher *encr, void *iv, size_t len) { ibuf_release(encr->encr_iv); + encr->encr_iv = NULL; if (iv != NULL) { if (len < encr->encr_ivlength) { log_debug("%s: invalid IV length %zu", __func__, len); @@ -573,6 +590,7 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) BIO *rawcert = NULL; X509 *cert = NULL; RSA *rsa = NULL; + EC_KEY *ec = NULL; EVP_PKEY *pkey = NULL; ibuf_release(dsa->dsa_keydata); @@ -609,7 +627,25 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) if (!EVP_PKEY_set1_RSA(pkey, rsa)) goto sslerr; - RSA_free(rsa); /* pkey now has the reference */ + RSA_free(rsa); /* pkey now has the reference */ + dsa->dsa_cert = NULL; + dsa->dsa_key = pkey; + break; + case IKEV2_CERT_ECDSA: + if (dsa->dsa_sign) { + if ((ec = d2i_ECPrivateKey_bio(rawcert, NULL)) == NULL) + goto sslerr; + } else { + if ((ec = d2i_EC_PUBKEY_bio(rawcert, NULL)) == NULL) + goto sslerr; + } + + if ((pkey = EVP_PKEY_new()) == NULL) + goto sslerr; + if (!EVP_PKEY_set1_EC_KEY(pkey, ec)) + goto sslerr; + + EC_KEY_free(ec); /* pkey now has the reference */ dsa->dsa_cert = NULL; dsa->dsa_key = pkey; break; @@ -629,6 +665,8 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) if (rsa != NULL) RSA_free(rsa); + if (ec != NULL) + EC_KEY_free(ec); if (pkey != NULL) EVP_PKEY_free(pkey); if (cert != NULL) @@ -636,6 +674,7 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t keylen, uint8_t type) if (rawcert != NULL) BIO_free(rawcert); ibuf_release(dsa->dsa_keydata); + dsa->dsa_keydata = NULL; return (NULL); } @@ -644,6 +683,7 @@ _dsa_verify_init(struct iked_dsa *dsa, const uint8_t *sig, size_t len) { uint8_t oidlen; size_t i; + int keytype; if (dsa->dsa_priv != NULL) return (0); @@ -656,23 +696,30 @@ _dsa_verify_init(struct iked_dsa *dsa, const uint8_t *sig, size_t len) print_map(dsa->dsa_method, ikev2_auth_map)); return (-1); } + if (dsa->dsa_key == NULL) { + log_debug("%s: dsa_key not set for %s", __func__, + print_map(dsa->dsa_method, ikev2_auth_map)); + return (-1); + } + keytype = EVP_PKEY_type(((EVP_PKEY *)dsa->dsa_key)->type); if (sig == NULL) { log_debug("%s: signature missing", __func__); return (-1); } - if (len < 1) { + if (len < sizeof(oidlen)) { 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) { + if (len < (size_t)oidlen + sizeof(oidlen)) { 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 && + if (keytype == schemes[i].sc_keytype && + oidlen == schemes[i].sc_len && memcmp(sig + 1, schemes[i].sc_oid, schemes[i].sc_len) == 0) { dsa->dsa_priv = (*schemes[i].sc_md)(); @@ -727,32 +774,98 @@ dsa_update(struct iked_dsa *dsa, const void *buf, size_t len) int _dsa_sign_encode(struct iked_dsa *dsa, uint8_t *ptr, size_t *offp) { + int keytype; + size_t i; + if (offp) *offp = 0; if (dsa->dsa_method != IKEV2_AUTH_SIG) return (0); - if (dsa->dsa_priv != EVP_sha256()) + if (dsa->dsa_key == NULL) + return (-1); + keytype = EVP_PKEY_type(((EVP_PKEY *)dsa->dsa_key)->type); + for (i = 0; i < nitems(schemes); i++) { + /* XXX should avoid calling sc_md() each time... */ + if (keytype == schemes[i].sc_keytype && + (dsa->dsa_priv == (*schemes[i].sc_md)())) + break; + } + if (i >= nitems(schemes)) return (-1); if (ptr) { - ptr[0] = sizeof(sha256WithRSAEncryption); - memcpy(ptr + 1, sha256WithRSAEncryption, - sizeof(sha256WithRSAEncryption)); + ptr[0] = schemes[i].sc_len; + memcpy(ptr + sizeof(ptr[0]), schemes[i].sc_oid, + schemes[i].sc_len); } if (offp) - *offp = 1 + sizeof(sha256WithRSAEncryption); + *offp = sizeof(ptr[0]) + schemes[i].sc_len; return (0); } +/* Export size of encoded signature hash type */ size_t -dsa_length(struct iked_dsa *dsa) +dsa_prefix(struct iked_dsa *dsa) { size_t off = 0; + if (_dsa_sign_encode(dsa, NULL, &off) < 0) + fatal("dsa_prefix: internal error"); + return off; +} + +size_t +dsa_length(struct iked_dsa *dsa) +{ if (dsa->dsa_hmac) return (EVP_MD_size(dsa->dsa_priv)); - if (_dsa_sign_encode(dsa, NULL, &off) < 0) - fatal("dsa_length: internal error"); - return (EVP_PKEY_size(dsa->dsa_key) + off); + switch (dsa->dsa_method) { + case IKEV2_AUTH_ECDSA_256: + case IKEV2_AUTH_ECDSA_384: + case IKEV2_AUTH_ECDSA_521: + /* size of concat(r|s) */ + return (2 * ((EVP_PKEY_bits(dsa->dsa_key) + 7) / 8)); + } + return (dsa_prefix(dsa) + EVP_PKEY_size(dsa->dsa_key)); +} + +int +_dsa_sign_ecdsa(struct iked_dsa *dsa, uint8_t *ptr, size_t len) +{ + ECDSA_SIG *obj = NULL; + uint8_t *otmp = NULL, *tmp; + unsigned int tmplen; + int ret = -1; + int bnlen, off; + + if (len % 2) + goto done; /* must be even */ + bnlen = len/2; + /* + * (a) create DER signature into 'tmp' buffer + * (b) convert buffer to ECDSA_SIG object + * (c) concatenate the padded r|s BIGNUMS into 'ptr' + */ + if ((tmplen = EVP_PKEY_size(dsa->dsa_key)) == 0) + goto done; + if ((otmp = tmp = calloc(1, tmplen)) == NULL) + goto done; + if (!EVP_SignFinal(dsa->dsa_ctx, tmp, &tmplen, dsa->dsa_key)) + goto done; + if (d2i_ECDSA_SIG(&obj, (const uint8_t **)&tmp, tmplen) == NULL) + goto done; + if (BN_num_bytes(obj->r) > bnlen || BN_num_bytes(obj->s) > bnlen) + goto done; + memset(ptr, 0, len); + off = bnlen - BN_num_bytes(obj->r); + BN_bn2bin(obj->r, ptr + off); + off = 2 * bnlen - BN_num_bytes(obj->s); + BN_bn2bin(obj->s, ptr + off); + ret = 0; + done: + free(otmp); + if (obj) + ECDSA_SIG_free(obj); + return (ret); } ssize_t @@ -769,36 +882,92 @@ dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len) if (!HMAC_Final(dsa->dsa_ctx, buf, &siglen)) return (-1); } else { - 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; + switch (dsa->dsa_method) { + case IKEV2_AUTH_ECDSA_256: + case IKEV2_AUTH_ECDSA_384: + case IKEV2_AUTH_ECDSA_521: + if (_dsa_sign_ecdsa(dsa, buf, len) < 0) + return (-1); + siglen = len; + break; + default: + 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; + break; + } } return (siglen); } -size_t -_dsa_verify_offset(struct iked_dsa *dsa, uint8_t *ptr) +int +_dsa_verify_prepare(struct iked_dsa *dsa, uint8_t **sigp, size_t *lenp, + uint8_t **freemep) { - /* - * 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); + ECDSA_SIG *obj = NULL; + uint8_t *ptr = NULL; + size_t bnlen, len, off; + int ret = -1; + + *freemep = NULL; /* don't return garbage in case of an error */ + + switch (dsa->dsa_method) { + case IKEV2_AUTH_SIG: + /* + * The first byte of the signature encodes the OID + * prefix length which we need to skip. + */ + off = (*sigp)[0] + 1; + *sigp = *sigp + off; + *lenp = *lenp - off; + *freemep = NULL; + ret = 0; + break; + case IKEV2_AUTH_ECDSA_256: + case IKEV2_AUTH_ECDSA_384: + case IKEV2_AUTH_ECDSA_521: + /* + * sigp points to concatenation r|s, while EVP_VerifyFinal() + * expects the signature as a DER-encoded blob (of the two + * values), so we need to convert the signature in a new + * buffer (we cannot override the given buffer) and the caller + * has to free this buffer ('freeme'). + */ + if (*lenp < 64 || *lenp > 132 || *lenp % 2) + goto done; + bnlen = (*lenp)/2; + /* sigp points to concatenation: r|s */ + if ((obj = ECDSA_SIG_new()) == NULL || + BN_bin2bn(*sigp, bnlen, obj->r) == NULL || + BN_bin2bn(*sigp+bnlen, bnlen, obj->s) == NULL || + (len = i2d_ECDSA_SIG(obj, &ptr)) == 0) + goto done; + *lenp = len; + *sigp = ptr; + *freemep = ptr; + ptr = NULL; + ret = 0; + break; + default: + return (0); + } + done: + free(ptr); + if (obj) + ECDSA_SIG_free(obj); + return (ret); } ssize_t dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len) { uint8_t sig[EVP_MAX_MD_SIZE]; + uint8_t *ptr = buf, *freeme = NULL; unsigned int siglen = sizeof(sig); - uint8_t *ptr = buf; - size_t off = 0; if (dsa->dsa_hmac) { if (!HMAC_Final(dsa->dsa_ctx, sig, &siglen)) @@ -806,13 +975,15 @@ dsa_verify_final(struct iked_dsa *dsa, void *buf, size_t len) if (siglen != len || memcmp(buf, sig, siglen) != 0) return (-1); } else { - if ((off = _dsa_verify_offset(dsa, ptr)) >= len) + if (_dsa_verify_prepare(dsa, &ptr, &len, &freeme) < 0) return (-1); - if (EVP_VerifyFinal(dsa->dsa_ctx, ptr + off, len - off, + if (EVP_VerifyFinal(dsa->dsa_ctx, ptr, len, dsa->dsa_key) != 1) { + free(freeme); ca_sslerror(__func__); return (-1); } + free(freeme); } return (0); diff --git a/sbin/iked/iked.8 b/sbin/iked/iked.8 index c03ec117a5f..c1a0f0c15c2 100644 --- a/sbin/iked/iked.8 +++ b/sbin/iked/iked.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: iked.8,v 1.19 2014/11/10 13:57:32 jmc Exp $ +.\" $OpenBSD: iked.8,v 1.20 2017/03/27 10:06:41 reyk Exp $ .\" .\" Copyright (c) 2010 - 2014 Reyk Floeter <reyk@openbsd.org> .\" @@ -14,7 +14,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: November 10 2014 $ +.Dd $Mdocdate: March 27 2017 $ .Dt IKED 8 .Os .Sh NAME @@ -44,7 +44,8 @@ is provided by .Xr isakmpd 8 . .Pp .Nm -supports mutual authentication using RSA public keys and X.509 certificates. +supports mutual authentication using RSA or ECDSA public keys and X.509 +certificates. See the .Sx PUBLIC KEY AUTHENTICATION section below and PKI AND CERTIFICATE AUTHORITY COMMANDS in diff --git a/sbin/iked/iked.conf.5 b/sbin/iked/iked.conf.5 index a4b60844e78..68784f45161 100644 --- a/sbin/iked/iked.conf.5 +++ b/sbin/iked/iked.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: iked.conf.5,v 1.47 2017/03/13 15:07:51 patrick Exp $ +.\" $OpenBSD: iked.conf.5,v 1.48 2017/03/27 10:06:41 reyk Exp $ .\" .\" Copyright (c) 2010 - 2014 Reyk Floeter <reyk@openbsd.org> .\" Copyright (c) 2004 Mathieu Sauve-Frankel All rights reserved. @@ -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: March 13 2017 $ +.Dd $Mdocdate: March 27 2017 $ .Dt IKED.CONF 5 .Os .Sh NAME @@ -477,9 +477,14 @@ for kilo-, mega- and gigabytes accordingly. Please note that rekeying must happen at least several times a day as IPsec security heavily depends on frequent key renewals. .It Op Ar ikeauth -Specify the mode to mutually authenticate the peers. -Non-psk modes will require to set up certificates and RSA public keys; -see +Specify a method to be used to authenticate the remote peer. +.Xr iked 8 +will automatically determine a method based on public keys or certificates +configured for the peer. +.Ar ikeauth +can be used to override this behaviour. +Non-psk modes will require to set up certificates and RSA or ECDSA public +keys; see .Xr iked 8 for more information. .Pp @@ -491,14 +496,24 @@ The only supported EAP is currently .Ar MSCHAP-V2 . The responder will use RSA public key authentication. +.It Ic ecdsa256 +Use ECDSA with a 256-bit elliptic curve key and SHA2-256 for authentication. +.It Ic ecdsa384 +Use ECDSA with a 384-bit elliptic curve key and SHA2-384 for authentication. +.It Ic ecdsa521 +Use ECDSA with a 521-bit elliptic curve key and SHA2-512 for authentication. .It Ic psk Ar string Use a pre-shared key .Ar string or hex value (starting with 0x) for authentication. +.It Ic rfc7427 +Only use RFC 7427 signatures for authentication. +RFC 7427 signatures currently only support SHA2-256 as the hash. .It Ic rsa -Use RSA public key authentication. -This is the default mode if no option is specified. +Use RSA public key authentication with SHA1 as the hash. .El +.Pp +The default is to allow any signature authentication. .It Ic config Ar option address Send one or more optional configuration payloads (CP) to the peer. The configuration diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h index d16404c75bb..b2bda61d145 100644 --- a/sbin/iked/iked.h +++ b/sbin/iked/iked.h @@ -1,4 +1,4 @@ -/* $OpenBSD: iked.h,v 1.109 2017/03/13 18:49:20 mikeb Exp $ */ +/* $OpenBSD: iked.h,v 1.110 2017/03/27 10:06:41 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -753,6 +753,7 @@ struct ibuf * dsa_setkey(struct iked_dsa *, void *, size_t, uint8_t); void dsa_free(struct iked_dsa *); int dsa_init(struct iked_dsa *, const void *, size_t); +size_t dsa_prefix(struct iked_dsa *); 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 15d57ba3806..6f01901925d 100644 --- a/sbin/iked/ikev2.c +++ b/sbin/iked/ikev2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.c,v 1.143 2017/03/13 18:49:20 mikeb Exp $ */ +/* $OpenBSD: ikev2.c,v 1.144 2017/03/27 10:06:41 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -323,6 +323,7 @@ ikev2_dispatch_cert(int fd, struct privsep_proc *p, struct imsg *imsg) id->id_type = type; id->id_offset = 0; ibuf_release(id->id_buf); + id->id_buf = NULL; if (type != IKEV2_AUTH_NONE) { if (len <= 0 || @@ -498,13 +499,39 @@ done: } int -ikev2_ike_auth_compatible(struct iked_sa *sa, uint8_t want, uint8_t have) +ikev2_ike_auth_compatible(struct iked_sa *sa, uint8_t policy, uint8_t wire) { - if (want == have) - return (0); - if (sa->sa_sigsha2 && - have == IKEV2_AUTH_SIG && want == IKEV2_AUTH_RSA_SIG) + if (wire == IKEV2_AUTH_SIG_ANY) /* internal, not on wire */ + return (-1); + if (policy == wire || policy == IKEV2_AUTH_NONE) return (0); + switch (policy) { + case IKEV2_AUTH_SIG_ANY: + switch (wire) { + case IKEV2_AUTH_SIG: + case IKEV2_AUTH_RSA_SIG: + case IKEV2_AUTH_ECDSA_256: + case IKEV2_AUTH_ECDSA_384: + case IKEV2_AUTH_ECDSA_521: + return (0); + } + break; + case IKEV2_AUTH_SIG: + case IKEV2_AUTH_RSA_SIG: + case IKEV2_AUTH_ECDSA_256: + case IKEV2_AUTH_ECDSA_384: + case IKEV2_AUTH_ECDSA_521: + switch (wire) { + /* + * XXX Maybe we need an indication saying: + * XXX Accept AUTH_SIG as long as its DSA? + */ + case IKEV2_AUTH_SIG: + if (sa->sa_sigsha2) + return (0); + } + break; + } return (-1); } @@ -592,8 +619,10 @@ ikev2_ike_auth_recv(struct iked *env, struct iked_sa *sa, 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(msg->msg_auth.id_type, ikev2_auth_map)); + log_warnx("%s: unexpected auth method %s, was " + "expecting %s", __func__, + print_map(msg->msg_auth.id_type, ikev2_auth_map), + print_map(ikeauth.auth_method, ikev2_auth_map)); return (-1); } ikeauth.auth_method = msg->msg_auth.id_type; @@ -1177,6 +1206,7 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) if (inet_pton(AF_INET, (char *)polid->id_data, &in4) != 1 || ibuf_add(id->id_buf, &in4, sizeof(in4)) != 0) { ibuf_release(id->id_buf); + id->id_buf = NULL; return (-1); } break; @@ -1184,6 +1214,7 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) if (inet_pton(AF_INET6, (char *)polid->id_data, &in6) != 1 || ibuf_add(id->id_buf, &in6, sizeof(in6)) != 0) { ibuf_release(id->id_buf); + id->id_buf = NULL; return (-1); } break; @@ -1196,6 +1227,7 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) if (name) X509_NAME_free(name); ibuf_release(id->id_buf); + id->id_buf = NULL; return (-1); } X509_NAME_free(name); @@ -1204,6 +1236,7 @@ ikev2_policy2id(struct iked_static_id *polid, struct iked_id *id, int srcid) if (ibuf_add(id->id_buf, polid->id_data, polid->id_length) != 0) { ibuf_release(id->id_buf); + id->id_buf = NULL; return (-1); } break; diff --git a/sbin/iked/ikev2.h b/sbin/iked/ikev2.h index 2dc0e6dd98a..683fd47845d 100644 --- a/sbin/iked/ikev2.h +++ b/sbin/iked/ikev2.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2.h,v 1.25 2017/01/20 13:46:10 mikeb Exp $ */ +/* $OpenBSD: ikev2.h,v 1.26 2017/03/27 10:06:41 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -409,6 +409,12 @@ struct ikev2_cert { #define IKEV2_CERT_HASHURL_X509 12 /* RFC4306 */ #define IKEV2_CERT_HASHURL_X509_BUNDLE 13 /* RFC4306 */ #define IKEV2_CERT_OCSP 14 /* RFC4806 */ +/* + * As of November 2014, work was still in progress to add a more generic + * format for raw public keys (RFC7296), so we use a number in IANA's private + * use range (201-255, same RFC) for ECDSA. + */ +#define IKEV2_CERT_ECDSA 201 /* Private */ extern struct iked_constmap ikev2_cert_map[]; @@ -456,6 +462,12 @@ struct ikev2_auth { #define IKEV2_AUTH_GSPM 12 /* RFC6467 */ #define IKEV2_AUTH_NULL 13 /* RFC7619 */ #define IKEV2_AUTH_SIG 14 /* RFC7427 */ +#define IKEV2_AUTH_SIG_ANY 255 /* Internal (any signature) */ +/* + * AUTH_SIG also serves as an indication that a given policy has + * been configured to accept RSA or ECDSA payloads, as long as it + * successfully authenticates against a configured CA. + */ extern struct iked_constmap ikev2_auth_map[]; diff --git a/sbin/iked/ikev2_msg.c b/sbin/iked/ikev2_msg.c index ba603e06934..37bb8995425 100644 --- a/sbin/iked/ikev2_msg.c +++ b/sbin/iked/ikev2_msg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ikev2_msg.c,v 1.49 2017/03/13 17:41:14 reyk Exp $ */ +/* $OpenBSD: ikev2_msg.c,v 1.50 2017/03/27 10:06:41 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -814,7 +814,7 @@ ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, struct iked_auth *auth, struct ibuf *authmsg) { uint8_t *key, *psk = NULL; - ssize_t keylen; + ssize_t keylen, siglen; struct iked_hash *prf = sa->sa_prf; struct iked_id *id; struct iked_dsa *dsa = NULL; @@ -872,13 +872,20 @@ ikev2_msg_authsign(struct iked *env, struct iked_sa *sa, goto done; } - if ((ret = dsa_sign_final(dsa, - ibuf_data(buf), ibuf_size(buf))) == -1) { + if ((siglen = dsa_sign_final(dsa, + ibuf_data(buf), ibuf_size(buf))) < 0) { log_debug("%s: failed to create auth signature", __func__); ibuf_release(buf); goto done; } + if (ibuf_setsize(buf, siglen) < 0) { + log_debug("%s: failed to set auth signature size to %zd", + __func__, siglen); + ibuf_release(buf); + goto done; + } + sa->sa_localauth.id_type = auth->auth_method; sa->sa_localauth.id_buf = buf; diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y index 548686779fb..58b0b825abc 100644 --- a/sbin/iked/parse.y +++ b/sbin/iked/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.61 2017/01/20 13:56:51 mikeb Exp $ */ +/* $OpenBSD: parse.y,v 1.62 2017/03/27 10:06:41 reyk Exp $ */ /* * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> @@ -31,6 +31,9 @@ #include <netinet/in.h> #include <arpa/inet.h> +#include <openssl/pem.h> +#include <openssl/evp.h> + #include <ctype.h> #include <err.h> #include <errno.h> @@ -59,10 +62,14 @@ static struct file { int lineno; int errors; } *file; +EVP_PKEY *wrap_pubkey(FILE *); +EVP_PKEY *find_pubkey(const char *); +int set_policy(char *, int, struct iked_policy *); +int set_policy_auth_method(const char *, EVP_PKEY *, + struct iked_policy *); 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 *, ...) @@ -242,11 +249,13 @@ const struct ipsec_xf groupxfs[] = { }; const struct ipsec_xf methodxfs[] = { + { "none", IKEV2_AUTH_NONE }, { "rsa", IKEV2_AUTH_RSA_SIG }, - { "dss", IKEV2_AUTH_DSS_SIG }, - { "ecdsa-256", IKEV2_AUTH_ECDSA_256 }, - { "ecdsa-384", IKEV2_AUTH_ECDSA_384 }, - { "ecdsa-521", IKEV2_AUTH_ECDSA_521 }, + { "ecdsa256", IKEV2_AUTH_ECDSA_256 }, + { "ecdsa384", IKEV2_AUTH_ECDSA_384 }, + { "ecdsa521", IKEV2_AUTH_ECDSA_521 }, + { "rfc7427", IKEV2_AUTH_SIG }, + { "signature", IKEV2_AUTH_SIG_ANY }, { NULL } }; @@ -805,12 +814,7 @@ ipcomp : /* empty */ { $$ = 0; } ; ikeauth : /* empty */ { - $$.auth_method = IKEV2_AUTH_RSA_SIG; - $$.auth_eap = 0; - $$.auth_length = 0; - } - | RSA { - $$.auth_method = IKEV2_AUTH_RSA_SIG; + $$.auth_method = IKEV2_AUTH_SIG_ANY; /* default */ $$.auth_eap = 0; $$.auth_length = 0; } @@ -837,6 +841,21 @@ ikeauth : /* empty */ { $$.auth_eap = EAP_TYPE_MSCHAP_V2; $$.auth_length = 0; } + | STRING { + const struct ipsec_xf *xf; + + if ((xf = parse_xf($1, 0, methodxfs)) == NULL || + xf->id == IKEV2_AUTH_NONE) { + yyerror("not a valid authentication mode"); + free($1); + YYERROR; + } + free($1); + + $$.auth_method = xf->id; + $$.auth_eap = 0; + $$.auth_length = 0; + } ; byte_spec : NUMBER { @@ -1662,44 +1681,178 @@ get_id_type(char *string) return (IKEV2_ID_FQDN); } +EVP_PKEY * +wrap_pubkey(FILE *fp) +{ + EVP_PKEY *key = NULL; + struct rsa_st *rsa = NULL; + + key = PEM_read_PUBKEY(fp, NULL, NULL, NULL); + if (key == NULL) { + /* reading PKCS #8 failed, try PEM */ + rewind(fp); + rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL); + fclose(fp); + if (rsa == NULL) + return (NULL); + if ((key = EVP_PKEY_new()) == NULL) { + RSA_free(rsa); + return (NULL); + } + if (!EVP_PKEY_set1_RSA(key, rsa)) { + RSA_free(rsa); + EVP_PKEY_free(key); + return (NULL); + } + /* Always free RSA *rsa */ + RSA_free(rsa); + } else { + fclose(fp); + } + + return (key); +} + +EVP_PKEY * +find_pubkey(const char *keyfile) +{ + FILE *fp = NULL; + if ((fp = fopen(keyfile, "r")) == NULL) + return (NULL); + + return (wrap_pubkey(fp)); +} + int -check_pubkey(char *idstr, int type) +set_policy_auth_method(const char *peerid, EVP_PKEY *key, + struct iked_policy *pol) +{ + struct rsa_st *rsa; + EC_KEY *ec_key; + u_int8_t method; + u_int8_t cert_type; + struct iked_auth *ikeauth; + + method = IKEV2_AUTH_NONE; + cert_type = IKEV2_CERT_NONE; + + if (key != NULL) { + /* infer policy from key type */ + if ((rsa = EVP_PKEY_get1_RSA(key)) != NULL) { + method = IKEV2_AUTH_RSA_SIG; + cert_type = IKEV2_CERT_RSA_KEY; + RSA_free(rsa); + } else if ((ec_key = EVP_PKEY_get1_EC_KEY(key)) != NULL) { + const EC_GROUP *group = EC_KEY_get0_group(ec_key); + if (group == NULL) { + EC_KEY_free(ec_key); + return (-1); + } + switch (EC_GROUP_get_degree(group)) { + case 256: + method = IKEV2_AUTH_ECDSA_256; + break; + case 384: + method = IKEV2_AUTH_ECDSA_384; + break; + case 521: + method = IKEV2_AUTH_ECDSA_521; + break; + default: + EC_KEY_free(ec_key); + return (-1); + } + cert_type = IKEV2_CERT_ECDSA; + EC_KEY_free(ec_key); + } + + if (method == IKEV2_AUTH_NONE || cert_type == IKEV2_CERT_NONE) + return (-1); + } else { + /* default to IKEV2_CERT_X509_CERT otherwise */ + method = IKEV2_AUTH_SIG; + cert_type = IKEV2_CERT_X509_CERT; + } + + ikeauth = &pol->pol_auth; + + if (ikeauth->auth_method == IKEV2_AUTH_SHARED_KEY_MIC) { + if (key != NULL && + method != IKEV2_AUTH_RSA_SIG) + goto mismatch; + return (0); + } + + if (ikeauth->auth_method != IKEV2_AUTH_NONE && + ikeauth->auth_method != IKEV2_AUTH_SIG_ANY && + ikeauth->auth_method != method) + goto mismatch; + + ikeauth->auth_method = method; + pol->pol_certreqtype = cert_type; + + log_debug("%s: using %s for peer %s", __func__, + print_xf(method, 0, methodxfs), peerid); + + return (0); + + mismatch: + log_warnx("%s: ikeauth policy mismatch, %s specified, but only %s " + "possible", __func__, print_xf(ikeauth->auth_method, 0, methodxfs), + print_xf(method, 0, methodxfs)); + return (-1); +} + +int +set_policy(char *idstr, int type, struct iked_policy *pol) { char keyfile[PATH_MAX]; - FILE *fp = NULL; - const char *suffix = NULL; + const char *prefix = NULL; + EVP_PKEY *key; switch (type) { case IKEV2_ID_IPV4: - suffix = "ipv4"; + prefix = "ipv4"; break; case IKEV2_ID_IPV6: - suffix = "ipv6"; + prefix = "ipv6"; break; case IKEV2_ID_FQDN: - suffix = "fqdn"; + prefix = "fqdn"; break; case IKEV2_ID_UFQDN: - suffix = "ufqdn"; + prefix = "ufqdn"; break; default: /* Unspecified ID or public key not supported for this type */ + log_debug("%s: unknown type = %d", __func__, type); return (-1); } lc_string(idstr); if ((size_t)snprintf(keyfile, sizeof(keyfile), - IKED_CA IKED_PUBKEY_DIR "%s/%s", suffix, + IKED_CA IKED_PUBKEY_DIR "%s/%s", prefix, idstr) >= sizeof(keyfile)) { log_warnx("%s: public key path is too long", __func__); return (-1); } - if ((fp = fopen(keyfile, "r")) == NULL) + if ((key = find_pubkey(keyfile)) == NULL) { + log_warnx("%s: could not find pubkey for %s", __func__, + keyfile); + } + + if (set_policy_auth_method(keyfile, key, pol) < 0) { + EVP_PKEY_free(key); + log_warnx("%s: failed to set policy auth method for %s", + __func__, keyfile); return (-1); - fclose(fp); + } - log_debug("%s: found public key file %s", __func__, keyfile); + if (key != NULL) { + EVP_PKEY_free(key); + log_debug("%s: found pubkey for %s", __func__, keyfile); + } return (0); } @@ -2341,12 +2494,16 @@ print_policy(struct iked_policy *pol) print_verbose(" lifetime %llu bytes %llu", pol->pol_lifetime.lt_seconds, pol->pol_lifetime.lt_bytes); - if (pol->pol_auth.auth_method == IKEV2_AUTH_SHARED_KEY_MIC) { - print_verbose(" psk 0x"); - for (i = 0; i < pol->pol_auth.auth_length; i++) - print_verbose("%02x", - pol->pol_auth.auth_data[i]); - } else { + switch (pol->pol_auth.auth_method) { + case IKEV2_AUTH_NONE: + print_verbose (" none"); + break; + case IKEV2_AUTH_SHARED_KEY_MIC: + print_verbose(" psk 0x"); + for (i = 0; i < pol->pol_auth.auth_length; i++) + print_verbose("%02x", pol->pol_auth.auth_data[i]); + break; + default: if (pol->pol_auth.auth_eap) print_verbose(" eap \"%s\"", print_map(pol->pol_auth.auth_eap, eap_type_map)); @@ -2695,9 +2852,11 @@ create_ike(char *name, int af, uint8_t ipproto, struct ipsec_hosts *hosts, } } - /* Check if we have a raw public key for this peer */ - if (check_pubkey(idstr, idtype) != -1) - pol.pol_certreqtype = IKEV2_CERT_RSA_KEY; + /* Make sure that we know how to authenticate this peer */ + if (idtype && set_policy(idstr, idtype, &pol) < 0) { + log_debug("%s: set_policy failed", __func__); + return (-1); + } config_setpolicy(env, &pol, PROC_IKEV2); |