[openssl-commits] [openssl] master update

Dr. Stephen Henson steve at openssl.org
Wed Jun 21 13:13:18 UTC 2017


The branch master has been updated
       via  d2916a5b29b3ef83126cfbc7be5c16e0c3c9a521 (commit)
       via  29b0cab0174e1c1d02e549c0aaa2b08ab3051bd2 (commit)
       via  fbe1af9dfe021610e32d29e9c1c81eb5ce38e0ac (commit)
       via  60bbed3ff6716e8f1358396acc772908a758a0a0 (commit)
       via  bc88fc79289a40a469d654ff0df896b903b09ed4 (commit)
       via  b2021556e4b838f451459deab2b2eee9b40c9169 (commit)
       via  72ceb6a6923456d9ff036cd81014024cf54280c4 (commit)
       via  03327c8bf2af2db937a7d39268ea70ab90819279 (commit)
       via  881d2c5ed2aed08aa671ff0f79f895bf5fbf307c (commit)
       via  168067b6316896233f4e5a396c6dc8b9d4276322 (commit)
       via  3d234c9e5c88b8d5ac21c1c49a32cb4644616623 (commit)
       via  b04d4e38b7920c6eccd5899734c2c5ff47839989 (commit)
       via  07afa3d8809f312e79340fcca117abccb61c8e8f (commit)
       via  65e89736b3c05c2b2c83c26586efb95616caf40e (commit)
       via  d3c094ca712594eeb42d732642f4a3ffc5ffc59a (commit)
      from  c80149d9f09b3a5a5b1621fa705e900d455334d4 (commit)


- Log -----------------------------------------------------------------
commit d2916a5b29b3ef83126cfbc7be5c16e0c3c9a521
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Tue Jun 20 16:32:44 2017 +0100

    Use EVP_PKEY_X25519, EVP_PKEY_ED25519 instead of NIDs where appropriate.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit 29b0cab0174e1c1d02e549c0aaa2b08ab3051bd2
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Sat Jun 17 17:15:11 2017 +0100

    Update test config file
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit fbe1af9dfe021610e32d29e9c1c81eb5ce38e0ac
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Thu Jun 15 00:34:20 2017 +0100

    Add Ed25519 TLS 1.3 and 1.2 tests
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit 60bbed3ff6716e8f1358396acc772908a758a0a0
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed Jun 14 16:37:48 2017 +0100

    Add Ed25519 EE certificates
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit bc88fc79289a40a469d654ff0df896b903b09ed4
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed Jun 14 16:37:06 2017 +0100

    Ed25519 support for mkcert.sh
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit b2021556e4b838f451459deab2b2eee9b40c9169
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Jun 16 18:55:28 2017 +0100

    Allow Ed25519 in TLS 1.2
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit 72ceb6a6923456d9ff036cd81014024cf54280c4
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Fri Jun 16 19:23:47 2017 +0100

    Convert key exchange to one shot call
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit 03327c8bf2af2db937a7d39268ea70ab90819279
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed May 24 14:56:17 2017 +0100

    Print Ed25519 in s_client/s_server
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit 881d2c5ed2aed08aa671ff0f79f895bf5fbf307c
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed May 24 15:28:40 2017 +0100

    Add Ed25519 to trace output
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit 168067b6316896233f4e5a396c6dc8b9d4276322
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed Jun 14 16:54:08 2017 +0100

    Handle signature algorithms with no associated digest
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit 3d234c9e5c88b8d5ac21c1c49a32cb4644616623
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed May 24 21:56:38 2017 +0100

    Add Ed25519 signature algorithm
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit b04d4e38b7920c6eccd5899734c2c5ff47839989
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed May 24 15:28:26 2017 +0100

    Add Ed25519 to signature algorithm table
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit 07afa3d8809f312e79340fcca117abccb61c8e8f
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed May 24 21:54:03 2017 +0100

    Add index for ED25519
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit 65e89736b3c05c2b2c83c26586efb95616caf40e
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed May 24 22:01:00 2017 +0100

    Use X509_get_signature_info to get signature strength.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

commit d3c094ca712594eeb42d732642f4a3ffc5ffc59a
Author: Dr. Stephen Henson <steve at openssl.org>
Date:   Wed May 24 21:52:31 2017 +0100

    Recognise Ed25519 in X509_certificate_type
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3585)

-----------------------------------------------------------------------

Summary of changes:
 apps/s_cb.c                                        |  15 +-
 crypto/ec/ecx_meth.c                               |  19 +-
 crypto/x509/x509type.c                             |   3 +
 doc/man7/Ed25519.pod                               |   4 +-
 doc/man7/X25519.pod                                |   4 +-
 include/openssl/evp.h                              |   2 +
 ssl/ssl_lib.c                                      |   5 +
 ssl/ssl_locl.h                                     |  10 +-
 ssl/statem/statem_clnt.c                           |  41 +--
 ssl/statem/statem_lib.c                            |  29 +-
 ssl/statem/statem_locl.h                           |   2 +
 ssl/statem/statem_srvr.c                           |  29 +-
 ssl/t1_lib.c                                       | 110 +++++---
 ssl/t1_trce.c                                      |   1 +
 ...sa-client-chain.pem => client-ed25519-cert.pem} |  25 +-
 test/certs/client-ed25519-key.pem                  |   3 +
 test/certs/mkcert.sh                               |   1 +
 test/certs/server-ed25519-cert.pem                 |  14 +
 test/certs/server-ed25519-key.pem                  |   3 +
 test/ssl-tests/20-cert-select.conf                 | 299 +++++++++++++--------
 test/ssl-tests/20-cert-select.conf.in              |  71 ++++-
 21 files changed, 477 insertions(+), 213 deletions(-)
 copy test/certs/{ee-ecdsa-client-chain.pem => client-ed25519-cert.pem} (58%)
 create mode 100644 test/certs/client-ed25519-key.pem
 create mode 100644 test/certs/server-ed25519-cert.pem
 create mode 100644 test/certs/server-ed25519-key.pem

diff --git a/apps/s_cb.c b/apps/s_cb.c
index f2906a5..38a410b 100644
--- a/apps/s_cb.c
+++ b/apps/s_cb.c
@@ -230,6 +230,9 @@ static const char *get_sigtype(int nid)
      case EVP_PKEY_EC:
         return "ECDSA";
 
+     case NID_ED25519:
+        return "Ed25519";
+
     default:
         return NULL;
     }
@@ -265,13 +268,13 @@ static int do_print_sigalgs(BIO *out, SSL *s, int shared)
             BIO_puts(out, ":");
         sstr = get_sigtype(sign_nid);
         if (sstr)
-            BIO_printf(out, "%s+", sstr);
+            BIO_printf(out, "%s", sstr);
         else
-            BIO_printf(out, "0x%02X+", (int)rsign);
+            BIO_printf(out, "0x%02X", (int)rsign);
         if (hash_nid != NID_undef)
-            BIO_printf(out, "%s", OBJ_nid2sn(hash_nid));
-        else
-            BIO_printf(out, "0x%02X", (int)rhash);
+            BIO_printf(out, "+%s", OBJ_nid2sn(hash_nid));
+        else if (sstr == NULL)
+            BIO_printf(out, "+0x%02X", (int)rhash);
     }
     BIO_puts(out, "\n");
     return 1;
@@ -284,7 +287,7 @@ int ssl_print_sigalgs(BIO *out, SSL *s)
         ssl_print_client_cert_types(out, s);
     do_print_sigalgs(out, s, 0);
     do_print_sigalgs(out, s, 1);
-    if (SSL_get_peer_signature_nid(s, &nid))
+    if (SSL_get_peer_signature_nid(s, &nid) && nid != NID_undef)
         BIO_printf(out, "Peer signing digest: %s\n", OBJ_nid2sn(nid));
     if (SSL_get_peer_signature_type_nid(s, &nid))
         BIO_printf(out, "Peer signature type: %s\n", get_sigtype(nid));
diff --git a/crypto/ec/ecx_meth.c b/crypto/ec/ecx_meth.c
index 715fe06..b001196 100644
--- a/crypto/ec/ecx_meth.c
+++ b/crypto/ec/ecx_meth.c
@@ -78,7 +78,7 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg,
                 OPENSSL_free(xkey);
                 return 0;
             }
-            if (id == NID_X25519) {
+            if (id == EVP_PKEY_X25519) {
                 xkey->privkey[0] &= 248;
                 xkey->privkey[31] &= 127;
                 xkey->privkey[31] |= 64;
@@ -86,7 +86,7 @@ static int ecx_key_op(EVP_PKEY *pkey, int id, const X509_ALGOR *palg,
         } else {
             memcpy(xkey->privkey, p, X25519_KEYLEN);
         }
-        if (id == NID_X25519)
+        if (id == EVP_PKEY_X25519)
             X25519_public_from_private(xkey->pubkey, xkey->privkey);
         else
             ED25519_public_from_private(xkey->pubkey, xkey->privkey);
@@ -282,7 +282,8 @@ static int ecx_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
     switch (op) {
 
     case ASN1_PKEY_CTRL_SET1_TLS_ENCPT:
-        return ecx_key_op(pkey, NID_X25519, NULL, arg2, arg1, X25519_PUBLIC);
+        return ecx_key_op(pkey, EVP_PKEY_X25519, NULL, arg2, arg1,
+                          X25519_PUBLIC);
 
     case ASN1_PKEY_CTRL_GET1_TLS_ENCPT:
         if (pkey->pkey.ptr != NULL) {
@@ -305,8 +306,8 @@ static int ecx_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
 }
 
 const EVP_PKEY_ASN1_METHOD ecx25519_asn1_meth = {
-    NID_X25519,
-    NID_X25519,
+    EVP_PKEY_X25519,
+    EVP_PKEY_X25519,
     0,
     "X25519",
     "OpenSSL X25519 algorithm",
@@ -380,8 +381,8 @@ static int ecd_sig_info_set(X509_SIG_INFO *siginf, const X509_ALGOR *alg,
 }
 
 const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = {
-    NID_ED25519,
-    NID_ED25519,
+    EVP_PKEY_ED25519,
+    EVP_PKEY_ED25519,
     0,
     "ED25519",
     "OpenSSL ED25519 algorithm",
@@ -451,7 +452,7 @@ static int pkey_ecx_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
 }
 
 const EVP_PKEY_METHOD ecx25519_pkey_meth = {
-    NID_X25519,
+    EVP_PKEY_X25519,
     0, 0, 0, 0, 0, 0, 0,
     pkey_ecx_keygen,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -510,7 +511,7 @@ static int pkey_ecd_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
 }
 
 const EVP_PKEY_METHOD ed25519_pkey_meth = {
-    NID_ED25519, EVP_PKEY_FLAG_SIGCTX_CUSTOM,
+    EVP_PKEY_ED25519, EVP_PKEY_FLAG_SIGCTX_CUSTOM,
     0, 0, 0, 0, 0, 0,
     pkey_ecx_keygen,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
diff --git a/crypto/x509/x509type.c b/crypto/x509/x509type.c
index aca8355..a93e26e 100644
--- a/crypto/x509/x509type.c
+++ b/crypto/x509/x509type.c
@@ -41,6 +41,9 @@ int X509_certificate_type(const X509 *x, const EVP_PKEY *pkey)
     case EVP_PKEY_EC:
         ret = EVP_PK_EC | EVP_PKT_SIGN | EVP_PKT_EXCH;
         break;
+    case EVP_PKEY_ED25519:
+        ret = EVP_PKT_SIGN;
+        break;
     case EVP_PKEY_DH:
         ret = EVP_PK_DH | EVP_PKT_EXCH;
         break;
diff --git a/doc/man7/Ed25519.pod b/doc/man7/Ed25519.pod
index 39a1f19..e9c4f2f 100644
--- a/doc/man7/Ed25519.pod
+++ b/doc/man7/Ed25519.pod
@@ -31,7 +31,7 @@ or X509_sign_ctx() in the usual way.
 
 A context for the B<Ed25519> algorithm can be obtained by calling:
 
- EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(NID_ED25519, NULL);
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL);
 
 =head1 EXAMPLE
 
@@ -42,7 +42,7 @@ output in PEM format:
  #include <openssl/pem.h>
  ...
  EVP_PKEY *pkey = NULL;
- EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(NID_ED25519, NULL);
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL);
  EVP_PKEY_keygen_init(pctx);
  EVP_PKEY_keygen(pctx, &pkey);
  EVP_PKEY_CTX_free(pctx);
diff --git a/doc/man7/X25519.pod b/doc/man7/X25519.pod
index 61c9047..96522c5 100644
--- a/doc/man7/X25519.pod
+++ b/doc/man7/X25519.pod
@@ -19,7 +19,7 @@ performing key derivation.
 
 A context for the B<X25519> algorithm can be obtained by calling:
 
- EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(NID_X25519, NULL);
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
 
 =head1 EXAMPLE
 
@@ -30,7 +30,7 @@ output in PEM format:
  #include <openssl/pem.h>
  ...
  EVP_PKEY *pkey = NULL;
- EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(NID_X25519, NULL);
+ EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
  EVP_PKEY_keygen_init(pctx);
  EVP_PKEY_keygen(pctx, &pkey);
  EVP_PKEY_CTX_free(pctx);
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 4d7326b..89a64ae 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -56,6 +56,8 @@
 # define EVP_PKEY_HKDF   NID_hkdf
 # define EVP_PKEY_POLY1305 NID_poly1305
 # define EVP_PKEY_SIPHASH NID_siphash
+# define EVP_PKEY_X25519 NID_X25519
+# define EVP_PKEY_ED25519 NID_ED25519
 
 #ifdef  __cplusplus
 extern "C" {
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a535e13..a46ede1 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2969,6 +2969,11 @@ void ssl_set_masks(SSL *s)
         if (ecdsa_ok)
             mask_a |= SSL_aECDSA;
     }
+    /* Allow Ed25519 for TLS 1.2 if peer supports it */
+    if (!(mask_a & SSL_aECDSA) && ssl_has_cert(s, SSL_PKEY_ED25519)
+            && pvalid[SSL_PKEY_ED25519] & CERT_PKEY_EXPLICIT_SIGN
+            && TLS1_get_version(s) == TLS1_2_VERSION)
+            mask_a |= SSL_aECDSA;
 #endif
 
 #ifndef OPENSSL_NO_EC
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 83c4805..7dc6cd6 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -364,7 +364,8 @@
 # define SSL_PKEY_GOST01         3
 # define SSL_PKEY_GOST12_256     4
 # define SSL_PKEY_GOST12_512     5
-# define SSL_PKEY_NUM            6
+# define SSL_PKEY_ED25519        6
+# define SSL_PKEY_NUM            7
 /*
  * Pseudo-constant. GOST cipher suites can use different certs for 1
  * SSL_CIPHER. So let's see which one we have in fact.
@@ -1317,9 +1318,9 @@ typedef struct sigalg_lookup_st {
     const char *name;
     /* Raw value used in extension */
     uint16_t sigalg;
-    /* NID of hash algorithm */
+    /* NID of hash algorithm or NID_undef if no hash */
     int hash;
-    /* Index of hash algorithm */
+    /* Index of hash algorithm or -1 if no hash algorithm */
     int hash_idx;
     /* NID of signature algorithm */
     int sig;
@@ -1848,6 +1849,8 @@ typedef enum downgrade_en {
 #define TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512       0xefef
 #define TLSEXT_SIGALG_gostr34102001_gostr3411                   0xeded
 
+#define TLSEXT_SIGALG_ed25519                                   0x0807
+
 /* Known PSK key exchange modes */
 #define TLSEXT_KEX_MODE_KE                                      0x00
 #define TLSEXT_KEX_MODE_KE_DHE                                  0x01
@@ -2379,6 +2382,7 @@ __owur int tls12_copy_sigalgs(SSL *s, WPACKET *pkt,
 __owur int tls1_save_sigalgs(SSL *s, PACKET *pkt);
 __owur int tls1_process_sigalgs(SSL *s);
 __owur int tls1_set_peer_legacy_sigalg(SSL *s, const EVP_PKEY *pkey);
+__owur int tls1_lookup_md(const SIGALG_LOOKUP *lu, const EVP_MD **pmd);
 __owur size_t tls12_get_psigalgs(SSL *s, int sent, const uint16_t **psigs);
 __owur int tls12_check_peer_sigalg(SSL *s, uint16_t, EVP_PKEY *pkey);
 void ssl_set_client_disabled(SSL *s);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 9629c10..711680e 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1790,9 +1790,10 @@ MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
     if (!SSL_IS_TLS13(s)) {
         exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher);
         if (exp_idx >= 0 && i != exp_idx
-            && (exp_idx != SSL_PKEY_GOST_EC ||
-                (i != SSL_PKEY_GOST12_512 && i != SSL_PKEY_GOST12_256
-                 && i != SSL_PKEY_GOST01))) {
+                && (exp_idx != SSL_PKEY_ECC || i != SSL_PKEY_ED25519)
+                && (exp_idx != SSL_PKEY_GOST_EC ||
+                    (i != SSL_PKEY_GOST12_512 && i != SSL_PKEY_GOST12_256
+                    && i != SSL_PKEY_GOST01))) {
             x = NULL;
             al = SSL_AD_ILLEGAL_PARAMETER;
             SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE,
@@ -2170,6 +2171,9 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
         PACKET params;
         int maxsig;
         const EVP_MD *md = NULL;
+        unsigned char *tbs;
+        size_t tbslen;
+        int rv;
 
         /*
          * |pkt| now points to the beginning of the signature, so the difference
@@ -2185,7 +2189,6 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
 
         if (SSL_USE_SIGALGS(s)) {
             unsigned int sigalg;
-            int rv;
 
             if (!PACKET_get_net_2(pkt, &sigalg)) {
                 al = SSL_AD_DECODE_ERROR;
@@ -2208,7 +2211,10 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
             goto err;
         }
 
-        md = ssl_md(s->s3->tmp.peer_sigalg->hash_idx);
+        if (!tls1_lookup_md(s->s3->tmp.peer_sigalg, &md)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            goto err;
+        }
 
         if (!PACKET_get_length_prefixed_2(pkt, &signature)
             || PACKET_remaining(pkt) != 0) {
@@ -2255,19 +2261,22 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
                 goto err;
             }
         }
-        if (EVP_DigestVerifyUpdate(md_ctx, &(s->s3->client_random[0]),
-                                   SSL3_RANDOM_SIZE) <= 0
-                || EVP_DigestVerifyUpdate(md_ctx, &(s->s3->server_random[0]),
-                                          SSL3_RANDOM_SIZE) <= 0
-                || EVP_DigestVerifyUpdate(md_ctx, PACKET_data(&params),
-                                          PACKET_remaining(&params)) <= 0) {
+        tbslen = construct_key_exchange_tbs(s, &tbs, PACKET_data(&params),
+                                            PACKET_remaining(&params));
+        if (tbslen == 0) {
             al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EVP_LIB);
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
             goto err;
         }
-        if (EVP_DigestVerifyFinal(md_ctx, PACKET_data(&signature),
-                                  PACKET_remaining(&signature)) <= 0) {
-            /* bad signature */
+
+        rv = EVP_DigestVerify(md_ctx, PACKET_data(&signature),
+                              PACKET_remaining(&signature), tbs, tbslen);
+        OPENSSL_free(tbs);
+        if (rv < 0) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EVP_LIB);
+            goto err;
+        } else if (rv == 0) {
             al = SSL_AD_DECRYPT_ERROR;
             SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
             goto err;
@@ -3347,7 +3356,7 @@ int ssl3_check_cert_and_algorithm(SSL *s)
 
 #ifndef OPENSSL_NO_EC
     idx = s->session->peer_type;
-    if (idx == SSL_PKEY_ECC) {
+    if (idx == SSL_PKEY_ECC || idx == SSL_PKEY_ED25519) {
         if (ssl_check_srvr_ecc_cert_and_alg(s->session->peer, s) == 0) {
             /* check failed */
             SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_BAD_ECC_CERT);
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 0a5d7b4..63d8953 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -221,9 +221,8 @@ int tls_construct_cert_verify(SSL *s, WPACKET *pkt)
         goto err;
     }
     pkey = s->s3->tmp.cert->privatekey;
-    md = ssl_md(lu->hash_idx);
 
-    if (pkey == NULL || md == NULL) {
+    if (pkey == NULL || !tls1_lookup_md(lu, &md)) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
         goto err;
     }
@@ -369,7 +368,11 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
             goto f_err;
     }
 
-    md = ssl_md(s->s3->tmp.peer_sigalg->hash_idx);
+    if (!tls1_lookup_md(s->s3->tmp.peer_sigalg, &md)) {
+        SSLerr(SSL_F_TLS_PROCESS_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+        al = SSL_AD_INTERNAL_ERROR;
+        goto f_err;
+    }
 
     /* Check for broken implementations of GOST ciphersuites */
     /*
@@ -1248,6 +1251,8 @@ int ssl_cert_type(const X509 *x, const EVP_PKEY *pk)
 #ifndef OPENSSL_NO_EC
     case EVP_PKEY_EC:
         return SSL_PKEY_ECC;
+    case EVP_PKEY_ED25519:
+        return SSL_PKEY_ED25519;
 #endif
 #ifndef OPENSSL_NO_GOST
     case NID_id_GostR3410_2001:
@@ -2127,3 +2132,21 @@ int construct_ca_names(SSL *s, WPACKET *pkt)
 
     return 1;
 }
+
+/* Create a buffer containing data to be signed for server key exchange */
+size_t construct_key_exchange_tbs(const SSL *s, unsigned char **ptbs,
+                                  const void *param, size_t paramlen)
+{
+    size_t tbslen = 2 * SSL3_RANDOM_SIZE + paramlen;
+    unsigned char *tbs = OPENSSL_malloc(tbslen);
+
+    if (tbs == NULL)
+        return 0;
+    memcpy(tbs, s->s3->client_random, SSL3_RANDOM_SIZE);
+    memcpy(tbs + SSL3_RANDOM_SIZE, s->s3->server_random, SSL3_RANDOM_SIZE);
+
+    memcpy(tbs + SSL3_RANDOM_SIZE * 2, param, paramlen);
+
+    *ptbs = tbs;
+    return tbslen;
+}
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index 673822a..b6ce4cc 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -63,6 +63,8 @@ int check_in_list(SSL *s, unsigned int group_id, const unsigned char *groups,
 int create_synthetic_message_hash(SSL *s);
 int parse_ca_names(SSL *s, PACKET *pkt, int *al);
 int construct_ca_names(SSL *s, WPACKET *pkt);
+size_t construct_key_exchange_tbs(const SSL *s, unsigned char **ptbs,
+                                  const void *param, size_t paramlen);
 
 /*
  * TLS/DTLS client state machine functions
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 1cde8c8..05405b0 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -2410,11 +2410,12 @@ int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
     /* not anonymous */
     if (lu != NULL) {
         EVP_PKEY *pkey = s->s3->tmp.cert->privatekey;
-        const EVP_MD *md = ssl_md(lu->hash_idx);
-        unsigned char *sigbytes1, *sigbytes2;
-        size_t siglen;
+        const EVP_MD *md;
+        unsigned char *sigbytes1, *sigbytes2, *tbs;
+        size_t siglen, tbslen;
+        int rv;
 
-        if (pkey == NULL || md == NULL) {
+        if (pkey == NULL || !tls1_lookup_md(lu, &md)) {
             /* Should never happen */
             al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
@@ -2456,15 +2457,17 @@ int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
                 goto f_err;
             }
         }
-        if (EVP_DigestSignUpdate(md_ctx, &(s->s3->client_random[0]),
-                                 SSL3_RANDOM_SIZE) <= 0
-            || EVP_DigestSignUpdate(md_ctx, &(s->s3->server_random[0]),
-                                        SSL3_RANDOM_SIZE) <= 0
-            || EVP_DigestSignUpdate(md_ctx,
-                                        s->init_buf->data + paramoffset,
-                                        paramlen) <= 0
-            || EVP_DigestSignFinal(md_ctx, sigbytes1, &siglen) <= 0
-            || !WPACKET_sub_allocate_bytes_u16(pkt, siglen, &sigbytes2)
+        tbslen = construct_key_exchange_tbs(s, &tbs,
+                                            s->init_buf->data + paramoffset,
+                                            paramlen);
+        if (tbslen == 0) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
+                   ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+        rv = EVP_DigestSign(md_ctx, sigbytes1, &siglen, tbs, tbslen);
+        OPENSSL_free(tbs);
+        if (rv <= 0 || !WPACKET_sub_allocate_bytes_u16(pkt, siglen, &sigbytes2)
             || sigbytes1 != sigbytes2) {
             SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE,
                    ERR_R_INTERNAL_ERROR);
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 3c5e155..0a39b97 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -169,7 +169,7 @@ static const tls_curve_info nid_list[] = {
     {NID_brainpoolP256r1, 128, TLS_CURVE_PRIME}, /* brainpoolP256r1 (26) */
     {NID_brainpoolP384r1, 192, TLS_CURVE_PRIME}, /* brainpoolP384r1 (27) */
     {NID_brainpoolP512r1, 256, TLS_CURVE_PRIME}, /* brainpool512r1 (28) */
-    {NID_X25519, 128, TLS_CURVE_CUSTOM}, /* X25519 (29) */
+    {EVP_PKEY_X25519, 128, TLS_CURVE_CUSTOM}, /* X25519 (29) */
 };
 
 static const unsigned char ecformats_default[] = {
@@ -673,6 +673,7 @@ static const uint16_t tls12_sigalgs[] = {
     TLSEXT_SIGALG_ecdsa_secp256r1_sha256,
     TLSEXT_SIGALG_ecdsa_secp384r1_sha384,
     TLSEXT_SIGALG_ecdsa_secp521r1_sha512,
+    TLSEXT_SIGALG_ed25519,
 #endif
 
     TLSEXT_SIGALG_rsa_pss_sha256,
@@ -717,6 +718,9 @@ static const SIGALG_LOOKUP sigalg_lookup_tbl[] = {
     {"ecdsa_secp521r1_sha512", TLSEXT_SIGALG_ecdsa_secp521r1_sha512,
      NID_sha512, SSL_MD_SHA512_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
      NID_ecdsa_with_SHA512, NID_secp521r1},
+    {"ed25519", TLSEXT_SIGALG_ed25519,
+     NID_undef, -1, EVP_PKEY_ED25519, SSL_PKEY_ED25519,
+     NID_undef, NID_undef},
     {NULL, TLSEXT_SIGALG_ecdsa_sha224,
      NID_sha224, SSL_MD_SHA224_IDX, EVP_PKEY_EC, SSL_PKEY_ECC,
      NID_ecdsa_with_SHA224, NID_undef},
@@ -798,7 +802,8 @@ static const uint16_t tls_default_sigalg[] = {
     TLSEXT_SIGALG_ecdsa_sha1, /* SSL_PKEY_ECC */
     TLSEXT_SIGALG_gostr34102001_gostr3411, /* SSL_PKEY_GOST01 */
     TLSEXT_SIGALG_gostr34102012_256_gostr34112012_256, /* SSL_PKEY_GOST12_256 */
-    TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512 /* SSL_PKEY_GOST12_512 */
+    TLSEXT_SIGALG_gostr34102012_512_gostr34112012_512, /* SSL_PKEY_GOST12_512 */
+    0 /* SSL_PKEY_ED25519 */
 };
 
 /* Lookup TLS signature algorithm */
@@ -814,6 +819,25 @@ static const SIGALG_LOOKUP *tls1_lookup_sigalg(uint16_t sigalg)
     }
     return NULL;
 }
+/* Lookup hash: return 0 if invalid or not enabled */
+int tls1_lookup_md(const SIGALG_LOOKUP *lu, const EVP_MD **pmd)
+{
+    const EVP_MD *md;
+    if (lu == NULL)
+        return 0;
+    /* lu->hash == NID_undef means no associated digest */
+    if (lu->hash == NID_undef) {
+        md = NULL;
+    } else {
+        md = ssl_md(lu->hash_idx);
+        if (md == NULL)
+            return 0;
+    }
+    if (pmd)
+        *pmd = md;
+    return 1;
+}
+
 /*
  * Return a signature algorithm for TLS < 1.2 where the signature type
  * is fixed by the certificate type.
@@ -825,9 +849,8 @@ static const SIGALG_LOOKUP *tls1_get_legacy_sigalg(const SSL *s, int idx)
     if (SSL_USE_SIGALGS(s) || idx != SSL_PKEY_RSA) {
         const SIGALG_LOOKUP *lu = tls1_lookup_sigalg(tls_default_sigalg[idx]);
 
-        if (lu == NULL || ssl_md(lu->hash_idx) == NULL) {
+        if (!tls1_lookup_md(lu, NULL))
             return NULL;
-        }
         return lu;
     }
     return &legacy_rsa_sigalg;
@@ -985,22 +1008,23 @@ int tls12_check_peer_sigalg(SSL *s, uint16_t sig, EVP_PKEY *pkey)
         SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE);
         return 0;
     }
-    md = ssl_md(lu->hash_idx);
-    if (md == NULL) {
-        SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_UNKNOWN_DIGEST);
-        return 0;
+    if (!tls1_lookup_md(lu, &md)) {
+            SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_UNKNOWN_DIGEST);
+            return 0;
     }
-    /*
-     * Make sure security callback allows algorithm. For historical reasons we
-     * have to pass the sigalg as a two byte char array.
-     */
-    sigalgstr[0] = (sig >> 8) & 0xff;
-    sigalgstr[1] = sig & 0xff;
-    if (!ssl_security(s, SSL_SECOP_SIGALG_CHECK,
-                      EVP_MD_size(md) * 4, EVP_MD_type(md),
-                      (void *)sigalgstr)) {
-        SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE);
-        return 0;
+    if (md != NULL) {
+        /*
+         * Make sure security callback allows algorithm. For historical
+         * reasons we have to pass the sigalg as a two byte char array.
+         */
+        sigalgstr[0] = (sig >> 8) & 0xff;
+        sigalgstr[1] = sig & 0xff;
+        if (!ssl_security(s, SSL_SECOP_SIGALG_CHECK,
+                    EVP_MD_size(md) * 4, EVP_MD_type(md),
+                    (void *)sigalgstr)) {
+            SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE);
+            return 0;
+        }
     }
     /* Store the sigalg the peer uses */
     s->s3->tmp.peer_sigalg = lu;
@@ -1394,6 +1418,8 @@ static int tls12_get_pkey_idx(int sig_nid)
 #ifndef OPENSSL_NO_EC
     case EVP_PKEY_EC:
         return SSL_PKEY_ECC;
+    case EVP_PKEY_ED25519:
+        return SSL_PKEY_ED25519;
 #endif
 #ifndef OPENSSL_NO_GOST
     case NID_id_GostR3410_2001:
@@ -1416,7 +1442,7 @@ static int tls12_sigalg_allowed(SSL *s, int op, const SIGALG_LOOKUP *lu)
     int secbits;
 
     /* See if sigalgs is recognised and if hash is enabled */
-    if (lu == NULL || ssl_md(lu->hash_idx) == NULL)
+    if (!tls1_lookup_md(lu, NULL))
         return 0;
     /* DSA is not allowed in TLS 1.3 */
     if (SSL_IS_TLS13(s) && lu->sig == EVP_PKEY_DSA)
@@ -1424,6 +1450,8 @@ static int tls12_sigalg_allowed(SSL *s, int op, const SIGALG_LOOKUP *lu)
     /* See if public key algorithm allowed */
     if (tls12_get_pkey_idx(lu->sig) == -1)
         return 0;
+    if (lu->hash == NID_undef)
+        return 1;
     /* Security bits: half digest bits */
     secbits = EVP_MD_size(ssl_md(lu->hash_idx)) * 4;
     /* Finally see if security callback allows it */
@@ -1470,6 +1498,7 @@ void ssl_set_sig_mask(uint32_t *pmask_a, SSL *s, int op)
             break;
 #endif
 #ifndef OPENSSL_NO_EC
+        case EVP_PKEY_ED25519:
         case EVP_PKEY_EC:
             if (!have_ecdsa && tls12_sigalg_allowed(s, op, lu))
                 have_ecdsa = 1;
@@ -1765,7 +1794,7 @@ static int sig_cb(const char *elem, int len, void *arg)
         get_sigorhash(&sig_alg, &hash_alg, p);
     }
 
-    if (sig_alg == NID_undef || hash_alg == NID_undef)
+    if (sig_alg == NID_undef || (p != NULL && hash_alg == NID_undef))
         return 0;
 
     for (i = 0; i < sarg->sigalgcnt; i += 2) {
@@ -2130,6 +2159,7 @@ void tls1_set_cert_validity(SSL *s)
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST01);
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST12_256);
     tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_GOST12_512);
+    tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ED25519);
 }
 
 /* User level utility function to check a chain is suitable */
@@ -2203,20 +2233,19 @@ static int ssl_security_cert_key(SSL *s, SSL_CTX *ctx, X509 *x, int op)
 static int ssl_security_cert_sig(SSL *s, SSL_CTX *ctx, X509 *x, int op)
 {
     /* Lookup signature algorithm digest */
-    int secbits = -1, md_nid = NID_undef, sig_nid;
+    int secbits, nid, pknid;
     /* Don't check signature if self signed */
     if ((X509_get_extension_flags(x) & EXFLAG_SS) != 0)
         return 1;
-    sig_nid = X509_get_signature_nid(x);
-    if (sig_nid && OBJ_find_sigid_algs(sig_nid, &md_nid, NULL)) {
-        const EVP_MD *md;
-        if (md_nid && (md = EVP_get_digestbynid(md_nid)))
-            secbits = EVP_MD_size(md) * 4;
-    }
+    if (!X509_get_signature_info(x, &nid, &pknid, &secbits, NULL))
+        secbits = -1;
+    /* If digest NID not defined use signature NID */
+    if (nid == NID_undef)
+        nid = pknid;
     if (s)
-        return ssl_security(s, op, secbits, md_nid, x);
+        return ssl_security(s, op, secbits, nid, x);
     else
-        return ssl_ctx_security(ctx, op, secbits, md_nid, x);
+        return ssl_ctx_security(ctx, op, secbits, nid, x);
 }
 
 int ssl_security_cert(SSL *s, SSL_CTX *ctx, X509 *x, int vfy, int is_ee)
@@ -2298,7 +2327,7 @@ int tls_choose_sigalg(SSL *s, int *al)
                 || lu->sig == EVP_PKEY_DSA
                 || lu->sig == EVP_PKEY_RSA)
                 continue;
-            if (ssl_md(lu->hash_idx) == NULL)
+            if (!tls1_lookup_md(lu, NULL))
                 continue;
             idx = lu->sig_idx;
             if (!ssl_has_cert(s, idx))
@@ -2352,11 +2381,16 @@ int tls_choose_sigalg(SSL *s, int *al)
                     return 0;
                 }
             } else if (!ssl_has_cert(s, idx)) {
-                if (al == NULL)
-                    return 1;
-                *al = SSL_AD_INTERNAL_ERROR;
-                SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
-                return 0;
+                /* Allow Ed25519 if no EC certificate */
+                if (idx == SSL_PKEY_ECC && ssl_has_cert(s, SSL_PKEY_ED25519)) {
+                    idx = SSL_PKEY_ED25519;
+                } else {
+                    if (al == NULL)
+                        return 1;
+                    *al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_TLS_CHOOSE_SIGALG, ERR_R_INTERNAL_ERROR);
+                    return 0;
+                }
             }
         } else {
             /* Find index for client certificate */
@@ -2393,6 +2427,10 @@ int tls_choose_sigalg(SSL *s, int *al)
                     if (lu->sig_idx == idx
                         && (curve == -1 || lu->curve == curve))
                         break;
+                    if (idx == SSL_PKEY_ECC && lu->sig == EVP_PKEY_ED25519) {
+                        idx = SSL_PKEY_ED25519;
+                        break;
+                    }
 #endif
                     if (idx == SSL_PKEY_RSA && lu->sig == EVP_PKEY_RSA_PSS)
                         break;
diff --git a/ssl/t1_trce.c b/ssl/t1_trce.c
index 2e9c430..e879bf1 100644
--- a/ssl/t1_trce.c
+++ b/ssl/t1_trce.c
@@ -534,6 +534,7 @@ static ssl_trace_tbl ssl_sigalg_tbl[] = {
     {TLSEXT_SIGALG_ecdsa_secp384r1_sha384, "ecdsa_secp384r1_sha384"},
     {TLSEXT_SIGALG_ecdsa_secp521r1_sha512, "ecdsa_secp521r1_sha512"},
     {TLSEXT_SIGALG_ecdsa_sha224, "ecdsa_sha224"},
+    {TLSEXT_SIGALG_ed25519, "ed25519"},
     {TLSEXT_SIGALG_ecdsa_sha1, "ecdsa_sha1"},
     {TLSEXT_SIGALG_rsa_pss_sha256, "rsa_pss_sha256"},
     {TLSEXT_SIGALG_rsa_pss_sha384, "rsa_pss_sha384"},
diff --git a/test/certs/ee-ecdsa-client-chain.pem b/test/certs/client-ed25519-cert.pem
similarity index 58%
copy from test/certs/ee-ecdsa-client-chain.pem
copy to test/certs/client-ed25519-cert.pem
index ba04fdb..5cd01f6 100644
--- a/test/certs/ee-ecdsa-client-chain.pem
+++ b/test/certs/client-ed25519-cert.pem
@@ -1,17 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIICXDCCAUSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJDQTAg
-Fw0xNzAyMTUxOTMxMTBaGA8yMTE3MDIxNjE5MzExMFowHDEaMBgGA1UEAwwRRUNE
-U0EgQ2xpZW50IEF1dGgwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATpeZcBUFBT
-zmRIEaNlNcLA3+dvPgc5T3y2/Cut6ixNHjGCM1KzMSyZC2LwBhtKAl1CJxAfPvoP
-WECveS18FWXWo4GAMH4wHQYDVR0OBBYEFKP225wj9a3okk5Y2GvNHvJqH8sAMB8G
-A1UdIwQYMBaAFLQRM/HX4l73U54gIhBPhga/H8leMAkGA1UdEwQCMAAwEwYDVR0l
-BAwwCgYIKwYBBQUHAwIwHAYDVR0RBBUwE4IRRUNEU0EgQ2xpZW50IEF1dGgwDQYJ
-KoZIhvcNAQELBQADggEBAG8P/XEQnwHrd3O6GIAE5/Yloxqrjw5CoxbKmmVwrojz
-JGMHXPqE+V+RGUUnvP9Za8mIxtTi6hfvPRGNxRUhsPHXcQ52kwYf6r/ZeSXT0yFF
-ITVFFXM63p/jfF1NQgeEQ2NgPYJ9H6WTQbOu7EkaF/2E//DPUf93is8DKUgFLtdM
-p5Afb4yMul64wS2nHZIa3oR+15BDCQJ0FQtYX5bM2+6AZ0EZZT6q6t1cRRW8Tk4d
-YyUS5SSfxEdhdxnLPM5n88IYFhHV5klhgfp42CRXOWgLSBQeBZ8LqgUs7buHSxv5
-duOKJn5+mGvktlxvThrXpKgBx3yApThRKmBvb6Avrq8=
+MIICJjCCAQ6gAwIBAgIBAjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJDQTAg
+Fw0xNzA2MTgxNjMzMjBaGA8yMTE3MDYxOTE2MzMyMFowGTEXMBUGA1UEAwwOQ2xp
+ZW50LUVkMjU1MTkwKjAFBgMrZXADIQDWm1IkIasMcyVYSiKuFl6zZMRM4x7h/Qbf
+fmpdgcM8/6N9MHswHQYDVR0OBBYEFDAIOfJie9HYZehOjFLE+amS8RH7MB8GA1Ud
+IwQYMBaAFLQRM/HX4l73U54gIhBPhga/H8leMAkGA1UdEwQCMAAwEwYDVR0lBAww
+CgYIKwYBBQUHAwIwGQYDVR0RBBIwEIIOQ2xpZW50LUVkMjU1MTkwDQYJKoZIhvcN
+AQELBQADggEBAFvF2AWOELLBafWwmemtFALQcJbXndS8QyBAkBSPwIp6Q8Oledeh
+gynamdc+66c5Ozdl4lNknXPGVGcNaW0RmlkqcqSMksuL11OGba0iIZkiUU2QPA07
+BRunnV4/pgFsy0ewYKEdaSplyfoBoIJwuxPHL1ExlzAmhSYWYYOFMgD302Be4dXr
+pm0c4hj1XcJmtsD5wBcBCRrvOj+uCdqIwtWgdwo6poqzsO1AofuAgsjE9WWyi/NQ
+ule8nVKIVbwVFP8/dI240v0RF1VLyE+8lPf2nYuFAXbzL/8MRwJeeFVIYNiy+51B
+10ZVx5WtbbMjbr7e+xSU5jIAPZQS0r/4M8U=
 -----END CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
 MIIC7DCCAdSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
diff --git a/test/certs/client-ed25519-key.pem b/test/certs/client-ed25519-key.pem
new file mode 100644
index 0000000..3f673b3
--- /dev/null
+++ b/test/certs/client-ed25519-key.pem
@@ -0,0 +1,3 @@
+-----BEGIN PRIVATE KEY-----
+MC4CAQAwBQYDK2VwBCIEINZzpIpIiXXsKx4M7mUr2cb+DMfgHyu2msRAgNa5CxJJ
+-----END PRIVATE KEY-----
diff --git a/test/certs/mkcert.sh b/test/certs/mkcert.sh
index e547274..f5312ba 100755
--- a/test/certs/mkcert.sh
+++ b/test/certs/mkcert.sh
@@ -49,6 +49,7 @@ key() {
         ec)  args=("${args[@]}" -pkeyopt "ec_paramgen_curve:$bits")
                args=("${args[@]}" -pkeyopt ec_param_enc:named_curve);;
         dsa)  args=(-paramfile "$bits");;
+        ed25519)  ;;
         *) printf "Unsupported key algorithm: %s\n" "$alg" >&2; return 1;;
         esac
         stderr_onerror \
diff --git a/test/certs/server-ed25519-cert.pem b/test/certs/server-ed25519-cert.pem
new file mode 100644
index 0000000..729ccfb
--- /dev/null
+++ b/test/certs/server-ed25519-cert.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICHTCCAQWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
+IENBMCAXDTE3MDYxNDIzMzExOVoYDzIxMTcwNjE1MjMzMTE5WjASMRAwDgYDVQQD
+DAdFZDI1NTE5MCowBQYDK2VwAyEACkEMj+SRLjZSth3SIrG013cyYVN9frrVnfbN
+M2IqaT6jdjB0MB0GA1UdDgQWBBQqd22ipNHF0d+yJjFDgI/Jruq3rjAfBgNVHSME
+GDAWgBRwfy6ug2hZmAQjKs3rPhfNJN0BSTAJBgNVHRMEAjAAMBMGA1UdJQQMMAoG
+CCsGAQUFBwMBMBIGA1UdEQQLMAmCB0VkMjU1MTkwDQYJKoZIhvcNAQELBQADggEB
+AIdNMPRa2sgUW/qtCBWxmi0iVRoazl5pjU35cRl/ahBpI4pL5+fDVYuBzSOgEh7W
+6FUVix9mGvY9CK3ZkqrXCGRKeWnKrmdql5jrra5Qew43B+aZqa63639TGWqtm7Rk
+rWT14P7gma4K9Ea8eiXcT5NJ8sT7D2BOL0sL2alUmRT+k3YDUxiih7AiTkpo7f2Q
+x5l9f8qoRb6Skec+kuMQ4hIjBIe/3C+j4nqq9kDkJs8+VEaW7+7shSQzv0tnzBOl
+v5ty89x7LYAbGKvZNi8Z3814AWBWbYTskF0kW2/f6aZDpt239llYDazdErU1dEsS
+cc1gKHOG3zgz9wfih55M0dE=
+-----END CERTIFICATE-----
diff --git a/test/certs/server-ed25519-key.pem b/test/certs/server-ed25519-key.pem
new file mode 100644
index 0000000..f9f150e
--- /dev/null
+++ b/test/certs/server-ed25519-key.pem
@@ -0,0 +1,3 @@
+-----BEGIN PRIVATE KEY-----
+MC4CAQAwBQYDK2VwBCIEINa5/E1IzuSLg1rwoHxl1VV7BdcnmMeul9pvsvzKorjm
+-----END PRIVATE KEY-----
diff --git a/test/ssl-tests/20-cert-select.conf b/test/ssl-tests/20-cert-select.conf
index f84d9b1..f34a6de 100644
--- a/test/ssl-tests/20-cert-select.conf
+++ b/test/ssl-tests/20-cert-select.conf
@@ -1,20 +1,22 @@
 # Generated with generate_ssl_tests.pl
 
-num_tests = 13
+num_tests = 15
 
 test-0 = 0-ECDSA CipherString Selection
-test-1 = 1-RSA CipherString Selection
-test-2 = 2-ECDSA CipherString Selection, no ECDSA certificate
-test-3 = 3-ECDSA Signature Algorithm Selection
-test-4 = 4-ECDSA Signature Algorithm Selection SHA384
-test-5 = 5-ECDSA Signature Algorithm Selection SHA1
-test-6 = 6-ECDSA Signature Algorithm Selection compressed point
-test-7 = 7-ECDSA Signature Algorithm Selection, no ECDSA certificate
-test-8 = 8-RSA Signature Algorithm Selection
-test-9 = 9-RSA-PSS Signature Algorithm Selection
-test-10 = 10-Suite B P-256 Hash Algorithm Selection
-test-11 = 11-Suite B P-384 Hash Algorithm Selection
-test-12 = 12-TLS 1.2 DSA Certificate Test
+test-1 = 1-Ed25519 CipherString and Signature Algorithm Selection
+test-2 = 2-RSA CipherString Selection
+test-3 = 3-ECDSA CipherString Selection, no ECDSA certificate
+test-4 = 4-ECDSA Signature Algorithm Selection
+test-5 = 5-ECDSA Signature Algorithm Selection SHA384
+test-6 = 6-ECDSA Signature Algorithm Selection SHA1
+test-7 = 7-ECDSA Signature Algorithm Selection compressed point
+test-8 = 8-ECDSA Signature Algorithm Selection, no ECDSA certificate
+test-9 = 9-RSA Signature Algorithm Selection
+test-10 = 10-RSA-PSS Signature Algorithm Selection
+test-11 = 11-Suite B P-256 Hash Algorithm Selection
+test-12 = 12-Suite B P-384 Hash Algorithm Selection
+test-13 = 13-TLS 1.2 Ed25519 Client Auth
+test-14 = 14-TLS 1.2 DSA Certificate Test
 # ===========================================================
 
 [0-ECDSA CipherString Selection]
@@ -29,6 +31,8 @@ Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
 ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ecdsa-cert.pem
 ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ecdsa-key.pem
+EdDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ed25519-cert.pem
+EdDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed25519-key.pem
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
@@ -48,82 +52,120 @@ ExpectedServerSignType = EC
 
 # ===========================================================
 
-[1-RSA CipherString Selection]
-ssl_conf = 1-RSA CipherString Selection-ssl
+[1-Ed25519 CipherString and Signature Algorithm Selection]
+ssl_conf = 1-Ed25519 CipherString and Signature Algorithm Selection-ssl
 
-[1-RSA CipherString Selection-ssl]
-server = 1-RSA CipherString Selection-server
-client = 1-RSA CipherString Selection-client
+[1-Ed25519 CipherString and Signature Algorithm Selection-ssl]
+server = 1-Ed25519 CipherString and Signature Algorithm Selection-server
+client = 1-Ed25519 CipherString and Signature Algorithm Selection-client
 
-[1-RSA CipherString Selection-server]
+[1-Ed25519 CipherString and Signature Algorithm Selection-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
 ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ecdsa-cert.pem
 ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ecdsa-key.pem
+EdDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ed25519-cert.pem
+EdDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed25519-key.pem
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[1-RSA CipherString Selection-client]
-CipherString = aRSA
+[1-Ed25519 CipherString and Signature Algorithm Selection-client]
+CipherString = aECDSA
 MaxProtocol = TLSv1.2
+RequestCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
+SignatureAlgorithms = ed25519:ECDSA+SHA256
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-1]
 ExpectedResult = Success
+ExpectedServerCANames = empty
+ExpectedServerCertType = Ed25519
+ExpectedServerSignType = Ed25519
+
+
+# ===========================================================
+
+[2-RSA CipherString Selection]
+ssl_conf = 2-RSA CipherString Selection-ssl
+
+[2-RSA CipherString Selection-ssl]
+server = 2-RSA CipherString Selection-server
+client = 2-RSA CipherString Selection-client
+
+[2-RSA CipherString Selection-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ecdsa-cert.pem
+ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ecdsa-key.pem
+EdDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ed25519-cert.pem
+EdDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed25519-key.pem
+MaxProtocol = TLSv1.2
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+
+[2-RSA CipherString Selection-client]
+CipherString = aRSA
+MaxProtocol = TLSv1.2
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-2]
+ExpectedResult = Success
 ExpectedServerCertType = RSA
 ExpectedServerSignType = RSA-PSS
 
 
 # ===========================================================
 
-[2-ECDSA CipherString Selection, no ECDSA certificate]
-ssl_conf = 2-ECDSA CipherString Selection, no ECDSA certificate-ssl
+[3-ECDSA CipherString Selection, no ECDSA certificate]
+ssl_conf = 3-ECDSA CipherString Selection, no ECDSA certificate-ssl
 
-[2-ECDSA CipherString Selection, no ECDSA certificate-ssl]
-server = 2-ECDSA CipherString Selection, no ECDSA certificate-server
-client = 2-ECDSA CipherString Selection, no ECDSA certificate-client
+[3-ECDSA CipherString Selection, no ECDSA certificate-ssl]
+server = 3-ECDSA CipherString Selection, no ECDSA certificate-server
+client = 3-ECDSA CipherString Selection, no ECDSA certificate-client
 
-[2-ECDSA CipherString Selection, no ECDSA certificate-server]
+[3-ECDSA CipherString Selection, no ECDSA certificate-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[2-ECDSA CipherString Selection, no ECDSA certificate-client]
+[3-ECDSA CipherString Selection, no ECDSA certificate-client]
 CipherString = aECDSA
 MaxProtocol = TLSv1.2
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
-[test-2]
+[test-3]
 ExpectedResult = ServerFail
 
 
 # ===========================================================
 
-[3-ECDSA Signature Algorithm Selection]
-ssl_conf = 3-ECDSA Signature Algorithm Selection-ssl
+[4-ECDSA Signature Algorithm Selection]
+ssl_conf = 4-ECDSA Signature Algorithm Selection-ssl
 
-[3-ECDSA Signature Algorithm Selection-ssl]
-server = 3-ECDSA Signature Algorithm Selection-server
-client = 3-ECDSA Signature Algorithm Selection-client
+[4-ECDSA Signature Algorithm Selection-ssl]
+server = 4-ECDSA Signature Algorithm Selection-server
+client = 4-ECDSA Signature Algorithm Selection-client
 
-[3-ECDSA Signature Algorithm Selection-server]
+[4-ECDSA Signature Algorithm Selection-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
 ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ecdsa-cert.pem
 ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ecdsa-key.pem
+EdDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ed25519-cert.pem
+EdDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed25519-key.pem
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[3-ECDSA Signature Algorithm Selection-client]
+[4-ECDSA Signature Algorithm Selection-client]
 CipherString = DEFAULT
 SignatureAlgorithms = ECDSA+SHA256
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
-[test-3]
+[test-4]
 ExpectedResult = Success
 ExpectedServerCertType = P-256
 ExpectedServerSignHash = SHA256
@@ -132,28 +174,30 @@ ExpectedServerSignType = EC
 
 # ===========================================================
 
-[4-ECDSA Signature Algorithm Selection SHA384]
-ssl_conf = 4-ECDSA Signature Algorithm Selection SHA384-ssl
+[5-ECDSA Signature Algorithm Selection SHA384]
+ssl_conf = 5-ECDSA Signature Algorithm Selection SHA384-ssl
 
-[4-ECDSA Signature Algorithm Selection SHA384-ssl]
-server = 4-ECDSA Signature Algorithm Selection SHA384-server
-client = 4-ECDSA Signature Algorithm Selection SHA384-client
+[5-ECDSA Signature Algorithm Selection SHA384-ssl]
+server = 5-ECDSA Signature Algorithm Selection SHA384-server
+client = 5-ECDSA Signature Algorithm Selection SHA384-client
 
-[4-ECDSA Signature Algorithm Selection SHA384-server]
+[5-ECDSA Signature Algorithm Selection SHA384-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
 ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ecdsa-cert.pem
 ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ecdsa-key.pem
+EdDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ed25519-cert.pem
+EdDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed25519-key.pem
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[4-ECDSA Signature Algorithm Selection SHA384-client]
+[5-ECDSA Signature Algorithm Selection SHA384-client]
 CipherString = DEFAULT
 SignatureAlgorithms = ECDSA+SHA384
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
-[test-4]
+[test-5]
 ExpectedResult = Success
 ExpectedServerCertType = P-256
 ExpectedServerSignHash = SHA384
@@ -162,28 +206,30 @@ ExpectedServerSignType = EC
 
 # ===========================================================
 
-[5-ECDSA Signature Algorithm Selection SHA1]
-ssl_conf = 5-ECDSA Signature Algorithm Selection SHA1-ssl
+[6-ECDSA Signature Algorithm Selection SHA1]
+ssl_conf = 6-ECDSA Signature Algorithm Selection SHA1-ssl
 
-[5-ECDSA Signature Algorithm Selection SHA1-ssl]
-server = 5-ECDSA Signature Algorithm Selection SHA1-server
-client = 5-ECDSA Signature Algorithm Selection SHA1-client
+[6-ECDSA Signature Algorithm Selection SHA1-ssl]
+server = 6-ECDSA Signature Algorithm Selection SHA1-server
+client = 6-ECDSA Signature Algorithm Selection SHA1-client
 
-[5-ECDSA Signature Algorithm Selection SHA1-server]
+[6-ECDSA Signature Algorithm Selection SHA1-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
 ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ecdsa-cert.pem
 ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ecdsa-key.pem
+EdDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ed25519-cert.pem
+EdDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed25519-key.pem
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[5-ECDSA Signature Algorithm Selection SHA1-client]
+[6-ECDSA Signature Algorithm Selection SHA1-client]
 CipherString = DEFAULT
 SignatureAlgorithms = ECDSA+SHA1
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
-[test-5]
+[test-6]
 ExpectedResult = Success
 ExpectedServerCertType = P-256
 ExpectedServerSignHash = SHA1
@@ -192,14 +238,14 @@ ExpectedServerSignType = EC
 
 # ===========================================================
 
-[6-ECDSA Signature Algorithm Selection compressed point]
-ssl_conf = 6-ECDSA Signature Algorithm Selection compressed point-ssl
+[7-ECDSA Signature Algorithm Selection compressed point]
+ssl_conf = 7-ECDSA Signature Algorithm Selection compressed point-ssl
 
-[6-ECDSA Signature Algorithm Selection compressed point-ssl]
-server = 6-ECDSA Signature Algorithm Selection compressed point-server
-client = 6-ECDSA Signature Algorithm Selection compressed point-client
+[7-ECDSA Signature Algorithm Selection compressed point-ssl]
+server = 7-ECDSA Signature Algorithm Selection compressed point-server
+client = 7-ECDSA Signature Algorithm Selection compressed point-client
 
-[6-ECDSA Signature Algorithm Selection compressed point-server]
+[7-ECDSA Signature Algorithm Selection compressed point-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
 ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-cecdsa-cert.pem
@@ -207,13 +253,13 @@ ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-cecdsa-key.pem
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[6-ECDSA Signature Algorithm Selection compressed point-client]
+[7-ECDSA Signature Algorithm Selection compressed point-client]
 CipherString = DEFAULT
 SignatureAlgorithms = ECDSA+SHA256
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
-[test-6]
+[test-7]
 ExpectedResult = Success
 ExpectedServerCertType = P-256
 ExpectedServerSignHash = SHA256
@@ -222,53 +268,55 @@ ExpectedServerSignType = EC
 
 # ===========================================================
 
-[7-ECDSA Signature Algorithm Selection, no ECDSA certificate]
-ssl_conf = 7-ECDSA Signature Algorithm Selection, no ECDSA certificate-ssl
+[8-ECDSA Signature Algorithm Selection, no ECDSA certificate]
+ssl_conf = 8-ECDSA Signature Algorithm Selection, no ECDSA certificate-ssl
 
-[7-ECDSA Signature Algorithm Selection, no ECDSA certificate-ssl]
-server = 7-ECDSA Signature Algorithm Selection, no ECDSA certificate-server
-client = 7-ECDSA Signature Algorithm Selection, no ECDSA certificate-client
+[8-ECDSA Signature Algorithm Selection, no ECDSA certificate-ssl]
+server = 8-ECDSA Signature Algorithm Selection, no ECDSA certificate-server
+client = 8-ECDSA Signature Algorithm Selection, no ECDSA certificate-client
 
-[7-ECDSA Signature Algorithm Selection, no ECDSA certificate-server]
+[8-ECDSA Signature Algorithm Selection, no ECDSA certificate-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[7-ECDSA Signature Algorithm Selection, no ECDSA certificate-client]
+[8-ECDSA Signature Algorithm Selection, no ECDSA certificate-client]
 CipherString = DEFAULT
 SignatureAlgorithms = ECDSA+SHA256
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
-[test-7]
+[test-8]
 ExpectedResult = ServerFail
 
 
 # ===========================================================
 
-[8-RSA Signature Algorithm Selection]
-ssl_conf = 8-RSA Signature Algorithm Selection-ssl
+[9-RSA Signature Algorithm Selection]
+ssl_conf = 9-RSA Signature Algorithm Selection-ssl
 
-[8-RSA Signature Algorithm Selection-ssl]
-server = 8-RSA Signature Algorithm Selection-server
-client = 8-RSA Signature Algorithm Selection-client
+[9-RSA Signature Algorithm Selection-ssl]
+server = 9-RSA Signature Algorithm Selection-server
+client = 9-RSA Signature Algorithm Selection-client
 
-[8-RSA Signature Algorithm Selection-server]
+[9-RSA Signature Algorithm Selection-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
 ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ecdsa-cert.pem
 ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ecdsa-key.pem
+EdDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ed25519-cert.pem
+EdDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed25519-key.pem
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[8-RSA Signature Algorithm Selection-client]
+[9-RSA Signature Algorithm Selection-client]
 CipherString = DEFAULT
 SignatureAlgorithms = RSA+SHA256
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
-[test-8]
+[test-9]
 ExpectedResult = Success
 ExpectedServerCertType = RSA
 ExpectedServerSignHash = SHA256
@@ -277,28 +325,30 @@ ExpectedServerSignType = RSA
 
 # ===========================================================
 
-[9-RSA-PSS Signature Algorithm Selection]
-ssl_conf = 9-RSA-PSS Signature Algorithm Selection-ssl
+[10-RSA-PSS Signature Algorithm Selection]
+ssl_conf = 10-RSA-PSS Signature Algorithm Selection-ssl
 
-[9-RSA-PSS Signature Algorithm Selection-ssl]
-server = 9-RSA-PSS Signature Algorithm Selection-server
-client = 9-RSA-PSS Signature Algorithm Selection-client
+[10-RSA-PSS Signature Algorithm Selection-ssl]
+server = 10-RSA-PSS Signature Algorithm Selection-server
+client = 10-RSA-PSS Signature Algorithm Selection-client
 
-[9-RSA-PSS Signature Algorithm Selection-server]
+[10-RSA-PSS Signature Algorithm Selection-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = DEFAULT
 ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ecdsa-cert.pem
 ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ecdsa-key.pem
+EdDSA.Certificate = ${ENV::TEST_CERTS_DIR}/server-ed25519-cert.pem
+EdDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/server-ed25519-key.pem
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[9-RSA-PSS Signature Algorithm Selection-client]
+[10-RSA-PSS Signature Algorithm Selection-client]
 CipherString = DEFAULT
 SignatureAlgorithms = RSA-PSS+SHA256
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
-[test-9]
+[test-10]
 ExpectedResult = Success
 ExpectedServerCertType = RSA
 ExpectedServerSignHash = SHA256
@@ -307,14 +357,14 @@ ExpectedServerSignType = RSA-PSS
 
 # ===========================================================
 
-[10-Suite B P-256 Hash Algorithm Selection]
-ssl_conf = 10-Suite B P-256 Hash Algorithm Selection-ssl
+[11-Suite B P-256 Hash Algorithm Selection]
+ssl_conf = 11-Suite B P-256 Hash Algorithm Selection-ssl
 
-[10-Suite B P-256 Hash Algorithm Selection-ssl]
-server = 10-Suite B P-256 Hash Algorithm Selection-server
-client = 10-Suite B P-256 Hash Algorithm Selection-client
+[11-Suite B P-256 Hash Algorithm Selection-ssl]
+server = 11-Suite B P-256 Hash Algorithm Selection-server
+client = 11-Suite B P-256 Hash Algorithm Selection-client
 
-[10-Suite B P-256 Hash Algorithm Selection-server]
+[11-Suite B P-256 Hash Algorithm Selection-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = SUITEB128
 ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/p256-server-cert.pem
@@ -322,13 +372,13 @@ ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/p256-server-key.pem
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[10-Suite B P-256 Hash Algorithm Selection-client]
+[11-Suite B P-256 Hash Algorithm Selection-client]
 CipherString = DEFAULT
 SignatureAlgorithms = ECDSA+SHA384:ECDSA+SHA256
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/p384-root.pem
 VerifyMode = Peer
 
-[test-10]
+[test-11]
 ExpectedResult = Success
 ExpectedServerCertType = P-256
 ExpectedServerSignHash = SHA256
@@ -337,14 +387,14 @@ ExpectedServerSignType = EC
 
 # ===========================================================
 
-[11-Suite B P-384 Hash Algorithm Selection]
-ssl_conf = 11-Suite B P-384 Hash Algorithm Selection-ssl
+[12-Suite B P-384 Hash Algorithm Selection]
+ssl_conf = 12-Suite B P-384 Hash Algorithm Selection-ssl
 
-[11-Suite B P-384 Hash Algorithm Selection-ssl]
-server = 11-Suite B P-384 Hash Algorithm Selection-server
-client = 11-Suite B P-384 Hash Algorithm Selection-client
+[12-Suite B P-384 Hash Algorithm Selection-ssl]
+server = 12-Suite B P-384 Hash Algorithm Selection-server
+client = 12-Suite B P-384 Hash Algorithm Selection-client
 
-[11-Suite B P-384 Hash Algorithm Selection-server]
+[12-Suite B P-384 Hash Algorithm Selection-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = SUITEB128
 ECDSA.Certificate = ${ENV::TEST_CERTS_DIR}/p384-server-cert.pem
@@ -352,13 +402,13 @@ ECDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/p384-server-key.pem
 MaxProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[11-Suite B P-384 Hash Algorithm Selection-client]
+[12-Suite B P-384 Hash Algorithm Selection-client]
 CipherString = DEFAULT
 SignatureAlgorithms = ECDSA+SHA256:ECDSA+SHA384
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/p384-root.pem
 VerifyMode = Peer
 
-[test-11]
+[test-12]
 ExpectedResult = Success
 ExpectedServerCertType = P-384
 ExpectedServerSignHash = SHA384
@@ -367,14 +417,45 @@ ExpectedServerSignType = EC
 
 # ===========================================================
 
-[12-TLS 1.2 DSA Certificate Test]
-ssl_conf = 12-TLS 1.2 DSA Certificate Test-ssl
+[13-TLS 1.2 Ed25519 Client Auth]
+ssl_conf = 13-TLS 1.2 Ed25519 Client Auth-ssl
 
-[12-TLS 1.2 DSA Certificate Test-ssl]
-server = 12-TLS 1.2 DSA Certificate Test-server
-client = 12-TLS 1.2 DSA Certificate Test-client
+[13-TLS 1.2 Ed25519 Client Auth-ssl]
+server = 13-TLS 1.2 Ed25519 Client Auth-server
+client = 13-TLS 1.2 Ed25519 Client Auth-client
 
-[12-TLS 1.2 DSA Certificate Test-server]
+[13-TLS 1.2 Ed25519 Client Auth-server]
+Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
+CipherString = DEFAULT
+PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/root-cert.pem
+VerifyMode = Require
+
+[13-TLS 1.2 Ed25519 Client Auth-client]
+CipherString = DEFAULT
+EdDSA.Certificate = ${ENV::TEST_CERTS_DIR}/client-ed25519-cert.pem
+EdDSA.PrivateKey = ${ENV::TEST_CERTS_DIR}/client-ed25519-key.pem
+MaxProtocol = TLSv1.2
+MinProtocol = TLSv1.2
+VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
+VerifyMode = Peer
+
+[test-13]
+ExpectedClientCertType = Ed25519
+ExpectedClientSignType = Ed25519
+ExpectedResult = Success
+
+
+# ===========================================================
+
+[14-TLS 1.2 DSA Certificate Test]
+ssl_conf = 14-TLS 1.2 DSA Certificate Test-ssl
+
+[14-TLS 1.2 DSA Certificate Test-ssl]
+server = 14-TLS 1.2 DSA Certificate Test-server
+client = 14-TLS 1.2 DSA Certificate Test-client
+
+[14-TLS 1.2 DSA Certificate Test-server]
 Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem
 CipherString = ALL
 DHParameters = ${ENV::TEST_CERTS_DIR}/dhp2048.pem
@@ -384,13 +465,13 @@ MaxProtocol = TLSv1.2
 MinProtocol = TLSv1.2
 PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
 
-[12-TLS 1.2 DSA Certificate Test-client]
+[14-TLS 1.2 DSA Certificate Test-client]
 CipherString = ALL
 SignatureAlgorithms = DSA+SHA256:DSA+SHA1
 VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
-[test-12]
+[test-14]
 ExpectedResult = Success
 
 
diff --git a/test/ssl-tests/20-cert-select.conf.in b/test/ssl-tests/20-cert-select.conf.in
index 5937f9a..90bc5a2 100644
--- a/test/ssl-tests/20-cert-select.conf.in
+++ b/test/ssl-tests/20-cert-select.conf.in
@@ -12,6 +12,8 @@ use OpenSSL::Test::Utils;
 my $server = {
     "ECDSA.Certificate" => test_pem("server-ecdsa-cert.pem"),
     "ECDSA.PrivateKey" => test_pem("server-ecdsa-key.pem"),
+    "EdDSA.Certificate" => test_pem("server-ed25519-cert.pem"),
+    "EdDSA.PrivateKey" => test_pem("server-ed25519-key.pem"),
     "MaxProtocol" => "TLSv1.2"
 };
 
@@ -33,6 +35,23 @@ our @tests = (
         },
     },
     {
+        name => "Ed25519 CipherString and Signature Algorithm Selection",
+        server => $server,
+        client => {
+            "CipherString" => "aECDSA",
+            "MaxProtocol" => "TLSv1.2",
+            "SignatureAlgorithms" => "ed25519:ECDSA+SHA256",
+            "RequestCAFile" => test_pem("root-cert.pem"),
+        },
+        test   => {
+            "ExpectedServerCertType" =>, "Ed25519",
+            "ExpectedServerSignType" =>, "Ed25519",
+            # Note: certificate_authorities not sent for TLS < 1.3
+            "ExpectedServerCANames" =>, "empty",
+            "ExpectedResult" => "Success"
+        },
+    },
+    {
         name => "RSA CipherString Selection",
         server => $server,
         client => {
@@ -189,13 +208,33 @@ our @tests = (
             "ExpectedServerSignType" => "EC",
             "ExpectedResult" => "Success"
         },
-    }
+    },
+    {
+        name => "TLS 1.2 Ed25519 Client Auth",
+        server => {
+            "VerifyCAFile" => test_pem("root-cert.pem"),
+            "VerifyMode" => "Require"
+        },
+        client => {
+            "EdDSA.Certificate" => test_pem("client-ed25519-cert.pem"),
+            "EdDSA.PrivateKey" => test_pem("client-ed25519-key.pem"),
+            "MinProtocol" => "TLSv1.2",
+            "MaxProtocol" => "TLSv1.2"
+        },
+        test   => {
+            "ExpectedClientCertType" => "Ed25519",
+            "ExpectedClientSignType" => "Ed25519",
+            "ExpectedResult" => "Success"
+        },
+    },
 );
 
 
 my $server_tls_1_3 = {
     "ECDSA.Certificate" => test_pem("server-ecdsa-cert.pem"),
     "ECDSA.PrivateKey" => test_pem("server-ecdsa-key.pem"),
+    "EdDSA.Certificate" => test_pem("server-ed25519-cert.pem"),
+    "EdDSA.PrivateKey" => test_pem("server-ed25519-key.pem"),
     "MinProtocol" => "TLSv1.3",
     "MaxProtocol" => "TLSv1.3"
 };
@@ -314,6 +353,18 @@ my @tests_tls_1_3 = (
         },
     },
     {
+        name => "TLS 1.3 Ed25519 Signature Algorithm Selection",
+        server => $server_tls_1_3,
+        client => {
+            "SignatureAlgorithms" => "ed25519",
+        },
+        test   => {
+            "ExpectedServerCertType" => "Ed25519",
+            "ExpectedServerSignType" => "Ed25519",
+            "ExpectedResult" => "Success"
+        },
+    },
+    {
         name => "TLS 1.3 RSA Client Auth Signature Algorithm Selection",
         server => {
             "ClientSignatureAlgorithms" => "PSS+SHA256",
@@ -362,6 +413,24 @@ my @tests_tls_1_3 = (
         },
     },
     {
+        name => "TLS 1.3 Ed25519 Client Auth",
+        server => {
+            "VerifyCAFile" => test_pem("root-cert.pem"),
+            "VerifyMode" => "Require"
+        },
+        client => {
+            "EdDSA.Certificate" => test_pem("client-ed25519-cert.pem"),
+            "EdDSA.PrivateKey" => test_pem("client-ed25519-key.pem"),
+            "MinProtocol" => "TLSv1.3",
+            "MaxProtocol" => "TLSv1.3"
+        },
+        test   => {
+            "ExpectedClientCertType" => "Ed25519",
+            "ExpectedClientSignType" => "Ed25519",
+            "ExpectedResult" => "Success"
+        },
+    },
+    {
         name => "TLS 1.3 Client Auth No TLS 1.3 Signature Algorithms",
         server => {
             "ClientSignatureAlgorithms" => "ECDSA+SHA1:DSA+SHA256:RSA+SHA256",


More information about the openssl-commits mailing list