> On Sun, Jul 03, 2016 at 11:07:27AM +0200, Ren?? Ammerlaan wrote:
> > I???ve created a patch for ecdsa support in iked. Also found a bug
> > in handling auth_eap, because that value is never initialised to 0. I
> > also updated the dsa sign functions with the newer EVP_Digest so
> > it???s aligned with the rest of the code, but it???s not required for
> > ecdsa support.
> > 
> > The ecdsa signature should contain only plain r and s, so the
> > signature is converted to that format. I???ve tested compatibility
> > with OSX and IOS and both seem to be working fine. 
> > 
> 

The first auth_eap diff has been committed. 
I'm re-sending your remaining diff with minor changes:
- style, wrap long lines, tabs instead of spaces
- sort man page entry

There are open questions:
- why aren't the p2d_ecdsa_sig() and d2p_ecdsa_sig in ikev2_msg.c in crypto.c?
- why not using the new flexible ike signature type?
- aren't there other encoding formats?

Comments?

Reyk

Index: sbin/iked/ca.c
===================================================================
RCS file: /cvs/src/sbin/iked/ca.c,v
retrieving revision 1.40
diff -u -p -u -p -r1.40 ca.c
--- sbin/iked/ca.c      7 Dec 2015 12:46:37 -0000       1.40
+++ sbin/iked/ca.c      20 Jul 2016 12:47:38 -0000
@@ -378,6 +378,9 @@ ca_getcert(struct iked *env, struct 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, struc
 
                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, struc
  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, stru
 
                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, stru
  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, str
 {
        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,17 @@ ca_validate_pubkey(struct iked *env, str
                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 +1142,17 @@ ca_validate_pubkey(struct iked *env, str
                /* 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 +1177,12 @@ ca_validate_pubkey(struct iked *env, str
                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);
 
Index: sbin/iked/crypto.c
===================================================================
RCS file: /cvs/src/sbin/iked/crypto.c,v
retrieving revision 1.19
diff -u -p -u -p -r1.19 crypto.c
--- sbin/iked/crypto.c  31 Oct 2015 19:28:19 -0000      1.19
+++ sbin/iked/crypto.c  20 Jul 2016 12:48:26 -0000
@@ -573,6 +573,7 @@ dsa_setkey(struct iked_dsa *dsa, void *k
        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 *k
                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 *k
 
        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,13 @@ dsa_init(struct iked_dsa *dsa, const voi
        }
 
        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 +737,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 +782,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 +832,79 @@ dsa_verify_final(struct iked_dsa *dsa, v
        } 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);
 }
Index: sbin/iked/iked.8
===================================================================
RCS file: /cvs/src/sbin/iked/iked.8,v
retrieving revision 1.19
diff -u -p -u -p -r1.19 iked.8
--- sbin/iked/iked.8    10 Nov 2014 13:57:32 -0000      1.19
+++ sbin/iked/iked.8    20 Jul 2016 12:48:26 -0000
@@ -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
Index: sbin/iked/iked.conf.5
===================================================================
RCS file: /cvs/src/sbin/iked/iked.conf.5,v
retrieving revision 1.44
diff -u -p -u -p -r1.44 iked.conf.5
--- sbin/iked/iked.conf.5       9 Dec 2015 21:41:49 -0000       1.44
+++ sbin/iked/iked.conf.5       20 Jul 2016 12:48:27 -0000
@@ -471,7 +471,7 @@ Please note that rekeying must happen at
 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,11 @@ 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 ecdsa-256
+.It Ic ecdsa-384
+.It Ic ecdsa-521
+Use ECDSA public key authentication.
 .It Ic psk Ar string
 Use a pre-shared key
 .Ar string
Index: sbin/iked/iked.h
===================================================================
RCS file: /cvs/src/sbin/iked/iked.h,v
retrieving revision 1.96
diff -u -p -u -p -r1.96 iked.h
--- sbin/iked/iked.h    1 Jun 2016 11:16:41 -0000       1.96
+++ sbin/iked/iked.h    20 Jul 2016 12:48:27 -0000
@@ -744,6 +744,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 *);
Index: sbin/iked/ikev2.h
===================================================================
RCS file: /cvs/src/sbin/iked/ikev2.h,v
retrieving revision 1.23
diff -u -p -u -p -r1.23 ikev2.h
--- sbin/iked/ikev2.h   31 Oct 2015 19:28:19 -0000      1.23
+++ sbin/iked/ikev2.h   20 Jul 2016 12:48:28 -0000
@@ -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[];
 
Index: sbin/iked/ikev2_msg.c
===================================================================
RCS file: /cvs/src/sbin/iked/ikev2_msg.c,v
retrieving revision 1.45
diff -u -p -u -p -r1.45 ikev2_msg.c
--- sbin/iked/ikev2_msg.c       19 Oct 2015 11:25:35 -0000      1.45
+++ sbin/iked/ikev2_msg.c       20 Jul 2016 12:48:28 -0000
@@ -786,6 +786,16 @@ ikev2_msg_authverify(struct iked *env, 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 ((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 +882,20 @@ ikev2_msg_authsign(struct iked *env, str
                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);
Index: sbin/iked/parse.y
===================================================================
RCS file: /cvs/src/sbin/iked/parse.y,v
retrieving revision 1.56
diff -u -p -u -p -r1.56 parse.y
--- sbin/iked/parse.y   20 Jul 2016 12:31:00 -0000      1.56
+++ sbin/iked/parse.y   20 Jul 2016 12:48:29 -0000
@@ -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
@@ -819,6 +819,21 @@ ikeauth            : /* empty */                   {
                        $$.auth_eap = 0;
                        $$.auth_length = 0;
                }
+               | ECDSA_256                     {
+                       $$.auth_method = IKEV2_AUTH_ECDSA_256;
+                       $$.auth_eap = 0;
+                       $$.auth_length = 0;
+               }
+               | ECDSA_384                     {
+                       $$.auth_method = IKEV2_AUTH_ECDSA_384;
+                       $$.auth_eap = 0;
+                       $$.auth_length = 0;
+               }
+               | ECDSA_521                     {
+                       $$.auth_method = IKEV2_AUTH_ECDSA_521;
+                       $$.auth_eap = 0;
+                       $$.auth_length = 0;
+               }
                | PSK keyspec                   {
                        memcpy(&$$, &$2, sizeof($$));
                        $$.auth_method = IKEV2_AUTH_SHARED_KEY_MIC;
@@ -1097,6 +1112,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 },

Reply via email to