--- /usr/src/sbin/iked/ca.c	Mon Dec  7 13:46:37 2015	1.40
+++ /usr/src/sbin/iked/ca.c	Sat Jul  2 21:21:20 2016
@@ -378,6 +378,9 @@ ca_getcert(struct iked *env, struct imsg *imsg)
 	case IKEV2_CERT_RSA_KEY:
 		ret = ca_validate_pubkey(env, &id, ptr, len);
 		break;
+	case IKEV2_CERT_ECDSA_KEY:
+		ret = ca_validate_pubkey(env, &id, ptr, len);
+		break;
 	default:
 		log_debug("%s: unsupported cert type %d", __func__, type);
 		ret = -1;
@@ -815,6 +818,7 @@ int
 ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id)
 {
 	RSA		*rsa = NULL;
+	EC_KEY		*ecdsa = NULL;
 	uint8_t		*d;
 	int		 len = 0;
 	int		 ret = -1;
@@ -840,6 +844,26 @@ ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id)
 
 		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);
+
+		if ((ecdsa = EVP_PKEY_get1_EC_KEY(key)) == NULL)
+			goto done;
+		if ((len = i2o_ECPublicKey(ecdsa, NULL)) <= 0)
+			goto done;
+		if ((id->id_buf = ibuf_new(NULL, len)) == NULL)
+			goto done;
+
+		d = ibuf_data(id->id_buf);
+		if (i2o_ECPublicKey(ecdsa, &d) != len) {
+			ibuf_release(id->id_buf);
+			goto done;
+		}
+
+		id->id_type = IKEV2_CERT_ECDSA_KEY;
+		break;
 	default:
 		log_debug("%s: unsupported key type %d", __func__, key->type);
 		return (-1);
@@ -852,6 +876,8 @@ ca_pubkey_serialize(EVP_PKEY *key, struct iked_id *id)
  done:
 	if (rsa != NULL)
 		RSA_free(rsa);
+	if (ecdsa != NULL)
+		EC_KEY_free(ecdsa);
 	return (ret);
 }
 
@@ -859,6 +885,7 @@ int
 ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id)
 {
 	RSA		*rsa = NULL;
+	EC_KEY		*ecdsa = NULL;
 	uint8_t		*d;
 	int		 len = 0;
 	int		 ret = -1;
@@ -884,6 +911,26 @@ ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id
 
 		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);
+
+		if ((ecdsa = EVP_PKEY_get1_EC_KEY(key)) == NULL)
+			goto done;
+		if ((len = i2d_ECPrivateKey(ecdsa, NULL)) <= 0)
+			goto done;
+		if ((id->id_buf = ibuf_new(NULL, len)) == NULL)
+			goto done;
+
+		d = ibuf_data(id->id_buf);
+		if (i2d_ECPrivateKey(ecdsa, &d) != len) {
+			ibuf_release(id->id_buf);
+			goto done;
+		}
+
+		id->id_type = IKEV2_CERT_ECDSA_KEY;
+		break;
 	default:
 		log_debug("%s: unsupported key type %d", __func__, key->type);
 		return (-1);
@@ -896,6 +943,8 @@ ca_privkey_serialize(EVP_PKEY *key, struct iked_id *id
  done:
 	if (rsa != NULL)
 		RSA_free(rsa);
+	if (ecdsa != NULL)
+		EC_KEY_free(ecdsa);
 	return (ret);
 }
 
@@ -1029,6 +1078,7 @@ ca_validate_pubkey(struct iked *env, struct iked_stati
 {
 	BIO		*rawcert = NULL;
 	RSA		*peerrsa = NULL, *localrsa = NULL;
+	EC_KEY		*peerecdsa = NULL, *localecdsa = NULL;
 	EVP_PKEY	*peerkey = NULL, *localkey = NULL;
 	int		 ret = -1;
 	FILE		*fp = NULL;
@@ -1066,11 +1116,16 @@ ca_validate_pubkey(struct iked *env, struct iked_stati
 		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)) != NULL) {
+			if (!EVP_PKEY_set1_RSA(peerkey, peerrsa))
+				goto sslerr;
+		} else if ((peerecdsa = d2i_EC_PUBKEY_bio(rawcert, NULL)) != NULL) {
+			if (!EVP_PKEY_set1_EC_KEY(peerkey, peerecdsa))
+				goto sslerr;
+		} else
 			goto sslerr;
 	}
 
@@ -1086,12 +1141,17 @@ ca_validate_pubkey(struct iked *env, struct iked_stati
 		/* reading PKCS #8 failed, try PEM */
 		rewind(fp);
 		localrsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
+		localecdsa = PEM_read_EC_PUBKEY(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))
+		if (localrsa != NULL) {
+			if (!EVP_PKEY_set1_RSA(localkey, localrsa))
+				goto sslerr;
+		} else if (localecdsa != NULL) {
+			if (!EVP_PKEY_set1_EC_KEY(localkey, localecdsa))
+				goto sslerr;
+		} else
 			goto sslerr;
 	} else {
 		fclose(fp);
@@ -1116,8 +1176,12 @@ ca_validate_pubkey(struct iked *env, struct iked_stati
 		EVP_PKEY_free(localkey);
 	if (peerrsa != NULL)
 		RSA_free(peerrsa);
+	if (peerecdsa != NULL)
+		EC_KEY_free(peerecdsa);
 	if (localrsa != NULL)
 		RSA_free(localrsa);
+	if (localecdsa != NULL)
+		EC_KEY_free(localecdsa);
 	if (rawcert != NULL)
 		BIO_free(rawcert);
 
--- /usr/src/sbin/iked/crypto.c	Sat Oct 31 20:28:19 2015	1.19
+++ /usr/src/sbin/iked/crypto.c	Sun Jul  3 10:34:33 2016
@@ -573,6 +573,7 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t key
 	BIO		*rawcert = NULL;
 	X509		*cert = NULL;
 	RSA		*rsa = NULL;
+	EC_KEY		*ecdsa = NULL;
 	EVP_PKEY	*pkey = NULL;
 
 	ibuf_release(dsa->dsa_keydata);
@@ -613,6 +614,26 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t key
 		dsa->dsa_cert = NULL;
 		dsa->dsa_key = pkey;
 		break;
+	case IKEV2_CERT_ECDSA_KEY:
+		if (dsa->dsa_sign) {
+			if ((ecdsa = d2i_ECPrivateKey_bio(rawcert,
+			    NULL)) == NULL)
+				goto sslerr;
+		} else {
+			if ((ecdsa = d2i_EC_PUBKEY_bio(rawcert,
+			    NULL)) == NULL)
+				goto sslerr;
+		}
+
+		if ((pkey = EVP_PKEY_new()) == NULL)
+			goto sslerr;
+		if (!EVP_PKEY_set1_EC_KEY(pkey, ecdsa))
+			goto sslerr;
+
+		EC_KEY_free(ecdsa);	/* pkey now has the reference */
+		dsa->dsa_cert = NULL;
+		dsa->dsa_key = pkey;
+		break;
 	default:
 		if (dsa->dsa_hmac)
 			break;
@@ -629,6 +650,8 @@ dsa_setkey(struct iked_dsa *dsa, void *key, size_t key
 
 	if (rsa != NULL)
 		RSA_free(rsa);
+	if (ecdsa != NULL)
+		EC_KEY_free(ecdsa);
 	if (pkey != NULL)
 		EVP_PKEY_free(pkey);
 	if (cert != NULL)
@@ -698,11 +721,11 @@ dsa_init(struct iked_dsa *dsa, const void *buf, size_t
 	}
 
 	if (dsa->dsa_sign)
-		ret = EVP_SignInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL);
+		ret = EVP_DigestSignInit(dsa->dsa_ctx, NULL, dsa->dsa_priv, NULL, dsa->dsa_key);
 	else {
 		if ((ret = _dsa_verify_init(dsa, buf, len)) != 0)
 			return (ret);
-		ret = EVP_VerifyInit_ex(dsa->dsa_ctx, dsa->dsa_priv, NULL);
+		ret = EVP_DigestVerifyInit(dsa->dsa_ctx, NULL, dsa->dsa_priv, NULL, dsa->dsa_key);
 	}
 
 	return (ret ? 0 : -1);
@@ -712,13 +735,12 @@ int
 dsa_update(struct iked_dsa *dsa, const void *buf, size_t len)
 {
 	int	ret = 1;
-
 	if (dsa->dsa_hmac)
 		ret = HMAC_Update(dsa->dsa_ctx, buf, len);
 	else if (dsa->dsa_sign)
-		ret = EVP_SignUpdate(dsa->dsa_ctx, buf, len);
+		ret = EVP_DigestSignUpdate(dsa->dsa_ctx, buf, len);
 	else
-		ret = EVP_VerifyUpdate(dsa->dsa_ctx, buf, len);
+		ret = EVP_DigestVerifyUpdate(dsa->dsa_ctx, buf, len);
 
 	return (ret ? 0 : -1);
 }
@@ -758,21 +780,21 @@ dsa_length(struct iked_dsa *dsa)
 ssize_t
 dsa_sign_final(struct iked_dsa *dsa, void *buf, size_t len)
 {
-	unsigned int	 siglen;
-	size_t		 off = 0;
+	unsigned int	 usiglen;
+	size_t		 siglen, off = 0;
 	uint8_t		*ptr = buf;
 
 	if (len < dsa_length(dsa))
 		return (-1);
 
 	if (dsa->dsa_hmac) {
-		if (!HMAC_Final(dsa->dsa_ctx, buf, &siglen))
+		if (!HMAC_Final(dsa->dsa_ctx, buf, &usiglen))
 			return (-1);
+		return (usiglen);
 	} else {
 		if (_dsa_sign_encode(dsa, ptr, &off) < 0)
 			return (-1);
-		if (!EVP_SignFinal(dsa->dsa_ctx, ptr + off, &siglen,
-		    dsa->dsa_key))
+		if (!EVP_DigestSignFinal(dsa->dsa_ctx, ptr + off, &siglen))
 			return (-1);
 		siglen += off;
 	}
@@ -808,12 +830,79 @@ dsa_verify_final(struct iked_dsa *dsa, void *buf, size
 	} else {
 		if ((off = _dsa_verify_offset(dsa, ptr)) >= len)
 			return (-1);
-		if (EVP_VerifyFinal(dsa->dsa_ctx, ptr + off, len - off,
-		    dsa->dsa_key) != 1) {
+		if (EVP_DigestVerifyFinal(dsa->dsa_ctx, ptr +off,
+		    len - off) != 1) {
 			ca_sslerror(__func__);
 			return (-1);
 		}
 	}
 
+	return (0);
+}
+
+size_t
+d2p_ecdsa_sig(void *buf, size_t len)
+{
+	ECDSA_SIG	*ecdsa_sig = NULL;
+	uint8_t		*ptr = buf;
+	const uint8_t	*cptr = ptr;
+	size_t		 rlen, slen, rslen, siglen;
+
+	ecdsa_sig = ECDSA_SIG_new();
+	if (!ecdsa_sig)
+		return (0);
+
+	if (!d2i_ECDSA_SIG(&ecdsa_sig, &cptr, len))
+		goto err;
+
+	rlen = BN_num_bytes(ecdsa_sig->r);
+	slen = BN_num_bytes(ecdsa_sig->s);
+	if ((rslen = rlen > slen ? rlen : slen) >= len)
+		goto err;
+
+	siglen = (rslen * 2);
+	bzero(ptr, len);
+	if (BN_bn2bin(ecdsa_sig->r, ptr + rslen - rlen) != (ssize_t)rlen)
+		goto err;
+	if (BN_bn2bin(ecdsa_sig->s, ptr + siglen - slen) != (ssize_t)slen)
+		goto err;
+
+	ECDSA_SIG_free(ecdsa_sig);
+	return (siglen);
+err:
+	if (ecdsa_sig)
+		ECDSA_SIG_free(ecdsa_sig);
+	return (0);
+}
+
+size_t
+p2d_ecdsa_sig(void *buf, size_t len)
+{
+        ECDSA_SIG	*ecdsa_sig;
+        size_t		 rslen, siglen;
+	uint8_t		*ptr = buf;
+
+        if ((len % 2) != 0)
+		return (0);
+
+	ecdsa_sig = ECDSA_SIG_new();
+        if (!ecdsa_sig)
+		return (0);
+
+	rslen = (len / 2);
+        ecdsa_sig->r = BN_bin2bn(ptr, rslen, ecdsa_sig->r);
+        ecdsa_sig->s = BN_bin2bn(ptr + rslen, rslen, ecdsa_sig->s);
+        if (!ecdsa_sig->r || !ecdsa_sig->s)
+                goto err;
+
+	bzero(ptr, len);
+        if ((siglen = i2d_ECDSA_SIG(ecdsa_sig, &ptr)) == 0)
+		goto err;
+
+	ECDSA_SIG_free(ecdsa_sig);
+	return (siglen);
+err:
+	if (ecdsa_sig)
+		ECDSA_SIG_free(ecdsa_sig);
 	return (0);
 }
--- /usr/src/sbin/iked/iked.8	Mon Nov 10 14:57:32 2014	1.19
+++ /usr/src/sbin/iked/iked.8	Mon Jun 27 20:37:53 2016
@@ -44,7 +44,7 @@ is provided by
 .Xr isakmpd 8 .
 .Pp
 .Nm
-supports mutual authentication using RSA public keys and X.509 certificates.
+supports mutual authentication using public keys and X.509 certificates.
 See the
 .Sx PUBLIC KEY AUTHENTICATION
 section below and PKI AND CERTIFICATE AUTHORITY COMMANDS in
--- /usr/src/sbin/iked/iked.conf.5	Wed Dec  9 22:41:49 2015	1.44
+++ /usr/src/sbin/iked/iked.conf.5	Mon Jun 27 20:37:53 2016
@@ -471,7 +471,7 @@ Please note that rekeying must happen at least several
 IPsec security heavily depends on the 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;
+Non-psk modes will require to set up certificates and public keys;
 see
 .Xr iked 8
 for more information.
@@ -483,7 +483,7 @@ The only supported EAP
 .Ar type
 is currently
 .Ar MSCHAP-V2 .
-The responder will use RSA public key authentication.
+The responder will use public key authentication.
 .It Ic psk Ar string
 Use a pre-shared key
 .Ar string
@@ -491,6 +491,10 @@ or hex value (starting with 0x) for authentication.
 .It Ic rsa
 Use RSA public key authentication.
 This is the default mode if no option is specified.
+.It Ic ecdsa-256
+.It Ic ecdsa-384
+.It Ic ecdsa-521
+Use ECDSA public key authentication.
 .El
 .It Ic config Ar option address
 Send one or more optional configuration payloads (CP) to the peer.
--- /usr/src/sbin/iked/iked.h	Mon Dec  7 13:46:37 2015	1.95
+++ /usr/src/sbin/iked/iked.h	Sun Jul  3 10:34:53 2016
@@ -738,6 +738,8 @@ 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);
 ssize_t	 dsa_verify_final(struct iked_dsa *, void *, size_t);
+size_t	 d2p_ecdsa_sig(void *, size_t);
+size_t	 p2d_ecdsa_sig(void *, size_t);
 
 /* ikev2.c */
 pid_t	 ikev2(struct privsep *, struct privsep_proc *);
--- /usr/src/sbin/iked/ikev2.h	Sat Oct 31 20:28:19 2015	1.23
+++ /usr/src/sbin/iked/ikev2.h	Mon Jun 27 20:37:53 2016
@@ -411,6 +411,7 @@ struct ikev2_cert {
 #define IKEV2_CERT_HASHURL_X509		12	/* RFC4306 */
 #define IKEV2_CERT_HASHURL_X509_BUNDLE	13	/* RFC4306 */
 #define IKEV2_CERT_OCSP			14	/* RFC4806 */
+#define IKEV2_CERT_ECDSA_KEY		201	/* RFC4754 */
 
 extern struct iked_constmap ikev2_cert_map[];
 
--- /usr/src/sbin/iked/ikev2_msg.c	Mon Oct 19 13:25:35 2015	1.45
+++ /usr/src/sbin/iked/ikev2_msg.c	Sun Jul  3 10:36:12 2016
@@ -786,6 +786,15 @@ ikev2_msg_authverify(struct iked *env, struct iked_sa 
 		goto done;
 	}
 
+	if ((dsa->dsa_method == IKEV2_AUTH_ECDSA_256) ||
+	    (dsa->dsa_method == IKEV2_AUTH_ECDSA_384) ||
+	    (dsa->dsa_method == IKEV2_AUTH_ECDSA_521)) {
+		if ((len = p2d_ecdsa_sig(buf, len)) == 0) {
+			log_debug("%s: failed to convert ecdsa signature to der format", __func__);
+			goto done;
+		}
+	}
+
 	if ((ret = dsa_verify_final(dsa, buf, len)) == 0) {
 		log_debug("%s: authentication successful", __func__);
 		sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS);
@@ -872,9 +881,18 @@ ikev2_msg_authsign(struct iked *env, struct iked_sa *s
 		goto done;
 	}
 
+	if ((dsa->dsa_method == IKEV2_AUTH_ECDSA_256) ||
+	    (dsa->dsa_method == IKEV2_AUTH_ECDSA_384) ||
+	    (dsa->dsa_method == IKEV2_AUTH_ECDSA_521)) {
+		if ((buf->wpos = d2p_ecdsa_sig(ibuf_data(buf), ibuf_size(buf))) == 0) {
+			log_debug("%s: failed to convert ecdsa signature to plain format", __func__);
+			ibuf_release(buf);
+			goto done;
+		}
+	}
+
 	sa->sa_localauth.id_type = auth->auth_method;
 	sa->sa_localauth.id_buf = buf;
-
 	ret = 0;
  done:
 	free(psk);
--- /usr/src/sbin/iked/parse.y	Wed Dec  9 22:41:49 2015	1.54
+++ /usr/src/sbin/iked/parse.y	Sat Jul  2 17:02:43 2016
@@ -382,7 +382,7 @@ typedef struct {
 %token	PASSIVE ACTIVE ANY TAG TAP PROTO LOCAL GROUP NAME CONFIG EAP USER
 %token	IKEV1 FLOW SA TCPMD5 TUNNEL TRANSPORT COUPLE DECOUPLE SET
 %token	INCLUDE LIFETIME BYTES INET INET6 QUICK SKIP DEFAULT
-%token	IPCOMP OCSP IKELIFETIME
+%token	IPCOMP OCSP IKELIFETIME ECDSA_256 ECDSA_384 ECDSA_521
 %token	<v.string>		STRING
 %token	<v.number>		NUMBER
 %type	<v.string>		string
@@ -812,14 +812,32 @@ ipcomp		: /* empty */			{ $$ = 0; }
 ikeauth		: /* empty */			{
 			$$.auth_method = IKEV2_AUTH_RSA_SIG;
 			$$.auth_length = 0;
+			$$.auth_eap = 0;
 		}
 		| RSA				{
 			$$.auth_method = IKEV2_AUTH_RSA_SIG;
 			$$.auth_length = 0;
+			$$.auth_eap = 0;
 		}
+		| ECDSA_256			{
+			$$.auth_method = IKEV2_AUTH_ECDSA_256;
+			$$.auth_length = 0;
+			$$.auth_eap = 0;
+		}
+		| ECDSA_384			{
+			$$.auth_method = IKEV2_AUTH_ECDSA_384;
+			$$.auth_length = 0;
+			$$.auth_eap = 0;
+		}
+		| ECDSA_521			{
+			$$.auth_method = IKEV2_AUTH_ECDSA_521;
+			$$.auth_length = 0;
+			$$.auth_eap = 0;
+		}
 		| PSK keyspec			{
 			memcpy(&$$, &$2, sizeof($$));
 			$$.auth_method = IKEV2_AUTH_SHARED_KEY_MIC;
+			$$.auth_eap = 0;
 		}
 		| EAP STRING			{
 			unsigned int i;
@@ -1085,6 +1103,9 @@ lookup(char *s)
 		{ "default",		DEFAULT },
 		{ "dstid",		DSTID },
 		{ "eap",		EAP },
+		{ "ecdsa-256",		ECDSA_256 },
+		{ "ecdsa-384",		ECDSA_384 },
+		{ "ecdsa-521",		ECDSA_521 },
 		{ "enc",		ENCXF },
 		{ "esp",		ESP },
 		{ "file",		FILENAME },
