Merge commit 'efad5b281a7417cf012e80915b3e8d16f05b23a7' into kazuho/cert-ed25519
diff --git a/include/picotls.h b/include/picotls.h
index fc605b7..a3050c1 100644
--- a/include/picotls.h
+++ b/include/picotls.h
@@ -576,9 +576,15 @@
  * The implementor of the callback should use that as the opportunity to free any temporary data allocated for the verify_sign
  * callback.
  */
-PTLS_CALLBACK_TYPE(int, verify_certificate, ptls_t *tls,
-                   int (**verify_sign)(void *verify_ctx, ptls_iovec_t data, ptls_iovec_t sign), void **verify_data,
-                   ptls_iovec_t *certs, size_t num_certs);
+typedef struct st_ptls_verify_certificate_t {
+    int (*cb)(struct st_ptls_verify_certificate_t *self, ptls_t *tls,
+              int (**verify_sign)(void *verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t sign), void **verify_data,
+              ptls_iovec_t *certs, size_t num_certs);
+    /**
+     * list of signature algorithms being supported, terminated by UINT16_MAX
+     */
+    const uint16_t *algos;
+} ptls_verify_certificate_t;
 /**
  * Encrypt-and-signs (or verify-and-decrypts) a ticket (server-only).
  * When used for encryption (i.e., is_encrypt being set), the function should return 0 if successful, or else a non-zero value.
diff --git a/include/picotls/openssl.h b/include/picotls/openssl.h
index 2cc8c96..e528fdd 100644
--- a/include/picotls/openssl.h
+++ b/include/picotls/openssl.h
@@ -52,7 +52,7 @@
 #endif
 #if defined(NID_X25519) && !defined(LIBRESSL_VERSION_NUMBER)
 #define PTLS_OPENSSL_HAVE_X25519 1
-#define PTLS_OPENSSL_HAS_X25519 1  /* deprecated; use HAVE_ */
+#define PTLS_OPENSSL_HAS_X25519 1 /* deprecated; use HAVE_ */
 extern ptls_key_exchange_algorithm_t ptls_openssl_x25519;
 #endif
 #ifndef OPENSSL_NO_BF
@@ -91,13 +91,13 @@
 
 struct st_ptls_openssl_signature_scheme_t {
     uint16_t scheme_id;
-    const EVP_MD *scheme_md;
+    const EVP_MD *(*scheme_md)(void);
 };
 
 typedef struct st_ptls_openssl_sign_certificate_t {
     ptls_sign_certificate_t super;
     EVP_PKEY *key;
-    struct st_ptls_openssl_signature_scheme_t schemes[4]; /* terminated by .scheme_id == UINT16_MAX */
+    const struct st_ptls_openssl_signature_scheme_t *schemes; /* terminated by .scheme_id == UINT16_MAX */
 } ptls_openssl_sign_certificate_t;
 
 int ptls_openssl_init_sign_certificate(ptls_openssl_sign_certificate_t *self, EVP_PKEY *key);
diff --git a/lib/openssl.c b/lib/openssl.c
index 153c3f0..4c5eaf0 100644
--- a/lib/openssl.c
+++ b/lib/openssl.c
@@ -88,6 +88,78 @@
 
 #endif
 
+static const struct st_ptls_openssl_signature_scheme_t rsa_signature_schemes[] = {{PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256, EVP_sha256},
+                                                                                  {PTLS_SIGNATURE_RSA_PSS_RSAE_SHA384, EVP_sha384},
+                                                                                  {PTLS_SIGNATURE_RSA_PSS_RSAE_SHA512, EVP_sha512},
+                                                                                  {UINT16_MAX, NULL}};
+static const struct st_ptls_openssl_signature_scheme_t secp256r1_signature_schemes[] = {
+    {PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256, EVP_sha256}, {UINT16_MAX, NULL}};
+#if PTLS_OPENSSL_HAVE_SECP384R1
+static const struct st_ptls_openssl_signature_scheme_t secp384r1_signature_schemes[] = {
+    {PTLS_SIGNATURE_ECDSA_SECP384R1_SHA384, EVP_sha384}, {UINT16_MAX, NULL}};
+#endif
+#if PTLS_OPENSSL_HAVE_SECP521R1
+static const struct st_ptls_openssl_signature_scheme_t secp521r1_signature_schemes[] = {
+    {PTLS_SIGNATURE_ECDSA_SECP521R1_SHA512, EVP_sha512}, {UINT16_MAX, NULL}};
+#endif
+#if defined EVP_PKEY_ED25519
+static const struct st_ptls_openssl_signature_scheme_t ed25519_signature_schemes[] = {{PTLS_SIGNATURE_ED25519, NULL}, {UINT16_MAX, NULL}};
+#endif
+
+/**
+ * The default list sent in ClientHello.signature_algorithms. ECDSA certificates are preferred.
+ */
+static const uint16_t default_signature_schemes[] = {PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256,
+#if PTLS_OPENSSL_HAVE_SECP384R1
+                                                     PTLS_SIGNATURE_ECDSA_SECP384R1_SHA384,
+#endif
+#if PTLS_OPENSSL_HAVE_SECP521R1
+                                                     PTLS_SIGNATURE_ECDSA_SECP521R1_SHA512,
+#endif
+                                                     PTLS_SIGNATURE_RSA_PSS_RSAE_SHA512,    PTLS_SIGNATURE_RSA_PSS_RSAE_SHA384,
+                                                     PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256,    UINT16_MAX};
+
+static const struct st_ptls_openssl_signature_scheme_t *lookup_signature_schemes(EVP_PKEY *key)
+{
+    const struct st_ptls_openssl_signature_scheme_t *schemes = NULL;
+
+    switch (EVP_PKEY_id(key)) {
+    case EVP_PKEY_RSA:
+        schemes = rsa_signature_schemes;
+        break;
+    case EVP_PKEY_EC: {
+        EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(key);
+        switch (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey))) {
+        case NID_X9_62_prime256v1:
+            schemes = secp256r1_signature_schemes;
+            break;
+#if PTLS_OPENSSL_HAVE_SECP384R1
+        case NID_secp384r1:
+            schemes = secp384r1_signature_schemes;
+            break;
+#endif
+#if PTLS_OPENSSL_HAVE_SECP521R1
+        case NID_secp521r1:
+            schemes = secp521r1_signature_schemes;
+            break;
+#endif
+        default:
+            break;
+        }
+        EC_KEY_free(eckey);
+    } break;
+#if defined EVP_PKEY_ED25519
+    case EVP_PKEY_ED25519:
+        schemes = ed25519_signature_schemes;
+        break;
+#endif
+    default:
+        break;
+    }
+
+    return schemes;
+}
+
 void ptls_openssl_random_bytes(void *buf, size_t len)
 {
     int ret = RAND_bytes(buf, (int)len);
@@ -658,7 +730,7 @@
                 ret = PTLS_ERROR_LIBRARY;
                 goto Exit;
             }
-            if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha256()) != 1) {
+            if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, md) != 1) {
                 ret = PTLS_ERROR_LIBRARY;
                 goto Exit;
             }
@@ -967,7 +1039,7 @@
     ptls_openssl_sign_certificate_t *self = (ptls_openssl_sign_certificate_t *)_self;
     const struct st_ptls_openssl_signature_scheme_t *scheme;
 
-    /* select the algorithm */
+    /* select the algorithm (driven by server-side preference of `self->schemes`) */
     for (scheme = self->schemes; scheme->scheme_id != UINT16_MAX; ++scheme) {
         size_t i;
         for (i = 0; i != num_algorithms; ++i)
@@ -978,7 +1050,7 @@
 
 Found:
     *selected_algorithm = scheme->scheme_id;
-    return do_sign(self->key, outbuf, input, scheme->scheme_md);
+    return do_sign(self->key, outbuf, input, scheme->scheme_md());
 }
 
 static X509 *to_x509(ptls_iovec_t vec)
@@ -987,9 +1059,10 @@
     return d2i_X509(NULL, &p, (long)vec.len);
 }
 
-static int verify_sign(void *verify_ctx, ptls_iovec_t data, ptls_iovec_t signature)
+static int verify_sign(void *verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t signature)
 {
     EVP_PKEY *key = verify_ctx;
+    const struct st_ptls_openssl_signature_scheme_t *scheme;
     EVP_MD_CTX *ctx = NULL;
     EVP_PKEY_CTX *pkey_ctx = NULL;
     int ret = 0;
@@ -997,6 +1070,17 @@
     if (data.base == NULL)
         goto Exit;
 
+    if ((scheme = lookup_signature_schemes(key)) == NULL) {
+        ret = PTLS_ERROR_LIBRARY;
+        goto Exit;
+    }
+    for (; scheme->scheme_id != UINT16_MAX; ++scheme)
+        if (scheme->scheme_id == algo)
+            goto SchemeFound;
+    ret = PTLS_ALERT_ILLEGAL_PARAMETER;
+    goto Exit;
+
+SchemeFound:
     if ((ctx = EVP_MD_CTX_create()) == NULL) {
         ret = PTLS_ERROR_NO_MEMORY;
         goto Exit;
@@ -1018,7 +1102,7 @@
     else
 #endif
     {
-        if (EVP_DigestVerifyInit(ctx, &pkey_ctx, EVP_sha256(), NULL, key) != 1) {
+        if (EVP_DigestVerifyInit(ctx, &pkey_ctx, scheme->scheme_md(), NULL, key) != 1) {
             ret = PTLS_ERROR_LIBRARY;
             goto Exit;
         }
@@ -1032,7 +1116,7 @@
                 ret = PTLS_ERROR_LIBRARY;
                 goto Exit;
             }
-            if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha256()) != 1) {
+            if (EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, scheme->scheme_md()) != 1) {
                 ret = PTLS_ERROR_LIBRARY;
                 goto Exit;
             }
@@ -1059,55 +1143,9 @@
 int ptls_openssl_init_sign_certificate(ptls_openssl_sign_certificate_t *self, EVP_PKEY *key)
 {
     *self = (ptls_openssl_sign_certificate_t){{sign_certificate}};
-    size_t scheme_index = 0;
 
-#define PUSH_SCHEME(id, md)                                                                                                        \
-    self->schemes[scheme_index++] = (struct st_ptls_openssl_signature_scheme_t)                                                    \
-    {                                                                                                                              \
-        id, md                                                                                                                     \
-    }
-
-    switch (EVP_PKEY_id(key)) {
-    case EVP_PKEY_RSA:
-        PUSH_SCHEME(PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256, EVP_sha256());
-        PUSH_SCHEME(PTLS_SIGNATURE_RSA_PSS_RSAE_SHA384, EVP_sha384());
-        PUSH_SCHEME(PTLS_SIGNATURE_RSA_PSS_RSAE_SHA512, EVP_sha512());
-        break;
-    case EVP_PKEY_EC: {
-        EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(key);
-        switch (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey))) {
-        case NID_X9_62_prime256v1:
-            PUSH_SCHEME(PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256, EVP_sha256());
-            break;
-#if defined(NID_secp384r1) && !OPENSSL_NO_SHA384
-        case NID_secp384r1:
-            PUSH_SCHEME(PTLS_SIGNATURE_ECDSA_SECP384R1_SHA384, EVP_sha384());
-            break;
-#endif
-#if defined(NID_secp384r1) && !OPENSSL_NO_SHA512
-        case NID_secp521r1:
-            PUSH_SCHEME(PTLS_SIGNATURE_ECDSA_SECP521R1_SHA512, EVP_sha512());
-            break;
-#endif
-        default:
-            EC_KEY_free(eckey);
-            return PTLS_ERROR_INCOMPATIBLE_KEY;
-        }
-        EC_KEY_free(eckey);
-    } break;
-#if defined EVP_PKEY_ED25519
-    case EVP_PKEY_ED25519:
-        PUSH_SCHEME(PTLS_SIGNATURE_ED25519, NULL);
-        break;
-#endif
-    default:
+    if ((self->schemes = lookup_signature_schemes(key)) == NULL)
         return PTLS_ERROR_INCOMPATIBLE_KEY;
-    }
-    PUSH_SCHEME(UINT16_MAX, NULL);
-    assert(scheme_index <= PTLS_ELEMENTSOF(self->schemes));
-
-#undef PUSH_SCHEME
-
     EVP_PKEY_up_ref(key);
     self->key = key;
 
@@ -1248,8 +1286,9 @@
     return ret;
 }
 
-static int verify_cert(ptls_verify_certificate_t *_self, ptls_t *tls, int (**verifier)(void *, ptls_iovec_t, ptls_iovec_t, const EVP_MD *),
-                       void **verify_data, ptls_iovec_t *certs, size_t num_certs)
+static int verify_cert(ptls_verify_certificate_t *_self, ptls_t *tls,
+                       int (**verifier)(void *, uint16_t, ptls_iovec_t, ptls_iovec_t), void **verify_data, ptls_iovec_t *certs,
+                       size_t num_certs)
 {
     ptls_openssl_verify_certificate_t *self = (ptls_openssl_verify_certificate_t *)_self;
     X509 *cert = NULL;
@@ -1294,7 +1333,7 @@
 
 int ptls_openssl_init_verify_certificate(ptls_openssl_verify_certificate_t *self, X509_STORE *store)
 {
-    *self = (ptls_openssl_verify_certificate_t){{verify_cert}};
+    *self = (ptls_openssl_verify_certificate_t){{verify_cert, default_signature_schemes}};
 
     if (store != NULL) {
         X509_STORE_up_ref(store);
@@ -1334,8 +1373,9 @@
     return NULL;
 }
 
-static int verify_raw_cert(ptls_verify_certificate_t *_self, ptls_t *tls, int (**verifier)(void *, ptls_iovec_t, ptls_iovec_t, const EVP_MD *),
-                           void **verify_data, ptls_iovec_t *certs, size_t num_certs)
+static int verify_raw_cert(ptls_verify_certificate_t *_self, ptls_t *tls,
+                           int (**verifier)(void *, uint16_t algo, ptls_iovec_t, ptls_iovec_t), void **verify_data,
+                           ptls_iovec_t *certs, size_t num_certs)
 {
     ptls_openssl_raw_pubkey_verify_certificate_t *self = (ptls_openssl_raw_pubkey_verify_certificate_t *)_self;
     int ret = PTLS_ALERT_BAD_CERTIFICATE;
@@ -1371,7 +1411,7 @@
 int ptls_openssl_raw_pubkey_init_verify_certificate(ptls_openssl_raw_pubkey_verify_certificate_t *self, EVP_PKEY *expected_pubkey)
 {
     EVP_PKEY_up_ref(expected_pubkey);
-    *self = (ptls_openssl_raw_pubkey_verify_certificate_t){{verify_raw_cert}, expected_pubkey};
+    *self = (ptls_openssl_raw_pubkey_verify_certificate_t){{verify_raw_cert, default_signature_schemes}, expected_pubkey};
     return 0;
 }
 void ptls_openssl_raw_pubkey_dispose_verify_certificate(ptls_openssl_raw_pubkey_verify_certificate_t *self)
diff --git a/lib/picotls.c b/lib/picotls.c
index 0f21196..210d530 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -257,7 +257,7 @@
      * will be used by the client and the server (if require_client_authentication is set).
      */
     struct {
-        int (*cb)(void *verify_ctx, ptls_iovec_t data, ptls_iovec_t signature);
+        int (*cb)(void *verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t signature);
         void *verify_ctx;
     } certificate_verify;
     /**
@@ -1519,15 +1519,16 @@
     return ret;
 }
 
-static int push_signature_algorithms(ptls_buffer_t *sendbuf)
+static int push_signature_algorithms(ptls_verify_certificate_t *vc, ptls_buffer_t *sendbuf)
 {
+    /* The list sent when verify callback is not registered */
+    static const uint16_t default_algos[] = {PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256, PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256,
+                                             PTLS_SIGNATURE_RSA_PKCS1_SHA256, PTLS_SIGNATURE_RSA_PKCS1_SHA1, UINT16_MAX};
     int ret;
 
     ptls_buffer_push_block(sendbuf, 2, {
-        ptls_buffer_push16(sendbuf, PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256);
-        ptls_buffer_push16(sendbuf, PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256);
-        ptls_buffer_push16(sendbuf, PTLS_SIGNATURE_RSA_PKCS1_SHA256);
-        ptls_buffer_push16(sendbuf, PTLS_SIGNATURE_RSA_PKCS1_SHA1);
+        for (const uint16_t *p = vc != NULL ? vc->algos : default_algos; *p != UINT16_MAX; ++p)
+            ptls_buffer_push16(sendbuf, *p);
     });
 
     ret = 0;
@@ -2059,7 +2060,7 @@
                 });
             });
             buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SIGNATURE_ALGORITHMS, {
-                if ((ret = push_signature_algorithms(sendbuf)) != 0)
+                if ((ret = push_signature_algorithms(tls->ctx->verify_certificate, sendbuf)) != 0)
                     goto Exit;
             });
             buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SUPPORTED_GROUPS, {
@@ -2867,19 +2868,10 @@
         src = end;
     });
 
-    /* validate */
-    switch (algo) {
-    case PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256:
-    case PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256:
-        /* ok */
-        break;
-    default:
-        ret = PTLS_ALERT_ILLEGAL_PARAMETER;
-        goto Exit;
-    }
     signdata_size = build_certificate_verify_signdata(signdata, tls->key_schedule, context_string);
     if (tls->certificate_verify.cb != NULL) {
-        ret = tls->certificate_verify.cb(tls->certificate_verify.verify_ctx, ptls_iovec_init(signdata, signdata_size), signature);
+        ret = tls->certificate_verify.cb(tls->certificate_verify.verify_ctx, algo, ptls_iovec_init(signdata, signdata_size),
+                                         signature);
     } else {
         ret = 0;
     }
@@ -4094,7 +4086,7 @@
                 /* extensions */
                 ptls_buffer_push_block(sendbuf, 2, {
                     buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SIGNATURE_ALGORITHMS, {
-                        if ((ret = push_signature_algorithms(sendbuf)) != 0)
+                        if ((ret = push_signature_algorithms(tls->ctx->verify_certificate, sendbuf)) != 0)
                             goto Exit;
                     });
                 });
@@ -4387,7 +4379,7 @@
             free(tls->client.certificate_request.context.base);
     }
     if (tls->certificate_verify.cb != NULL) {
-        tls->certificate_verify.cb(tls->certificate_verify.verify_ctx, ptls_iovec_init(NULL, 0), ptls_iovec_init(NULL, 0));
+        tls->certificate_verify.cb(tls->certificate_verify.verify_ctx, 0, ptls_iovec_init(NULL, 0), ptls_iovec_init(NULL, 0));
     }
     if (tls->pending_handshake_secret != NULL) {
         ptls_clear_memory(tls->pending_handshake_secret, PTLS_MAX_DIGEST_SIZE);
diff --git a/picotls.xcodeproj/project.pbxproj b/picotls.xcodeproj/project.pbxproj
index 3fe64e9..27453aa 100644
--- a/picotls.xcodeproj/project.pbxproj
+++ b/picotls.xcodeproj/project.pbxproj
@@ -1019,10 +1019,10 @@
 				EXECUTABLE_PREFIX = lib;
 				GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
 				HEADER_SEARCH_PATHS = (
-					"/usr/local/openssl-1.1.0/include",
+					/usr/local/opt/openssl/include,
 					include,
 				);
-				LIBRARY_SEARCH_PATHS = "/usr/local/openssl-1.1.0/lib";
+				LIBRARY_SEARCH_PATHS = /usr/local/opt/openssl/lib;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
 			name = Debug;
@@ -1033,10 +1033,10 @@
 				EXECUTABLE_PREFIX = lib;
 				GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
 				HEADER_SEARCH_PATHS = (
-					"/usr/local/openssl-1.1.0/include",
+					/usr/local/opt/openssl/include,
 					include,
 				);
-				LIBRARY_SEARCH_PATHS = "/usr/local/openssl-1.1.0/lib";
+				LIBRARY_SEARCH_PATHS = /usr/local/opt/openssl/lib;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
 			name = Release;
@@ -1143,10 +1143,10 @@
 			buildSettings = {
 				GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
 				HEADER_SEARCH_PATHS = (
-					"/usr/local/openssl-1.1.0/include",
+					/usr/local/opt/openssl/include,
 					include,
 				);
-				LIBRARY_SEARCH_PATHS = "/usr/local/openssl-1.1.0/lib";
+				LIBRARY_SEARCH_PATHS = /usr/local/opt/openssl/lib;
 				OTHER_LDFLAGS = "-lcrypto";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
@@ -1157,10 +1157,10 @@
 			buildSettings = {
 				GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
 				HEADER_SEARCH_PATHS = (
-					"/usr/local/openssl-1.1.0/include",
+					/usr/local/opt/openssl/include,
 					include,
 				);
-				LIBRARY_SEARCH_PATHS = "/usr/local/openssl-1.1.0/lib";
+				LIBRARY_SEARCH_PATHS = /usr/local/opt/openssl/lib;
 				OTHER_LDFLAGS = "-lcrypto";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
@@ -1193,11 +1193,11 @@
 				);
 				HEADER_SEARCH_PATHS = (
 					include,
-					"/usr/local/openssl-1.1.0/include",
+					/usr/local/opt/openssl/include,
 					/usr/local/include,
 				);
 				LIBRARY_SEARCH_PATHS = (
-					"/usr/local/openssl-1.1.0/lib",
+					/usr/local/opt/openssl/lib,
 					/usr/local/lib,
 				);
 				OTHER_LDFLAGS = (
@@ -1219,11 +1219,11 @@
 				);
 				HEADER_SEARCH_PATHS = (
 					include,
-					"/usr/local/openssl-1.1.0/include",
+					/usr/local/opt/openssl/include,
 					/usr/local/include,
 				);
 				LIBRARY_SEARCH_PATHS = (
-					"/usr/local/openssl-1.1.0/lib",
+					/usr/local/opt/openssl/lib,
 					/usr/local/lib,
 				);
 				OTHER_LDFLAGS = (
@@ -1259,10 +1259,10 @@
 			buildSettings = {
 				GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
 				HEADER_SEARCH_PATHS = (
-					"/usr/local/openssl-1.1.0/include",
+					/usr/local/opt/openssl/include,
 					include,
 				);
-				LIBRARY_SEARCH_PATHS = "/usr/local/openssl-1.1.0/lib";
+				LIBRARY_SEARCH_PATHS = /usr/local/opt/openssl/lib;
 				OTHER_LDFLAGS = "-lcrypto";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
@@ -1273,10 +1273,10 @@
 			buildSettings = {
 				GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
 				HEADER_SEARCH_PATHS = (
-					"/usr/local/openssl-1.1.0/include",
+					/usr/local/opt/openssl/include,
 					include,
 				);
-				LIBRARY_SEARCH_PATHS = "/usr/local/openssl-1.1.0/lib";
+				LIBRARY_SEARCH_PATHS = /usr/local/opt/openssl/lib;
 				OTHER_LDFLAGS = "-lcrypto";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 			};
diff --git a/t/openssl.c b/t/openssl.c
index 121ac3e..5ca7bbf 100644
--- a/t/openssl.c
+++ b/t/openssl.c
@@ -129,47 +129,57 @@
 #endif
 }
 
+static void test_sign_verify(EVP_PKEY *key, const struct st_ptls_openssl_signature_scheme_t *schemes)
+{
+    for (size_t i = 0; schemes[i].scheme_id != UINT16_MAX; ++i) {
+        note("scheme 0x%04x", schemes[i].scheme_id);
+        const void *message = "hello world";
+        ptls_buffer_t sigbuf;
+        uint8_t sigbuf_small[1024];
+
+        ptls_buffer_init(&sigbuf, sigbuf_small, sizeof(sigbuf_small));
+        ok(do_sign(key, &sigbuf, ptls_iovec_init(message, strlen(message)), schemes[i].scheme_md != NULL ? schemes[i].scheme_md() : NULL) == 0);
+        EVP_PKEY_up_ref(key);
+        ok(verify_sign(key, schemes[i].scheme_id, ptls_iovec_init(message, strlen(message)),
+                       ptls_iovec_init(sigbuf.base, sigbuf.off)) == 0);
+
+        ptls_buffer_dispose(&sigbuf);
+    }
+}
+
 static void test_rsa_sign(void)
 {
     ptls_openssl_sign_certificate_t *sc = (ptls_openssl_sign_certificate_t *)ctx->sign_certificate;
-
-    const void *message = "hello world";
-    ptls_buffer_t sigbuf;
-    uint8_t sigbuf_small[1024];
-
-    ptls_buffer_init(&sigbuf, sigbuf_small, sizeof(sigbuf_small));
-    ok(do_sign(sc->key, &sigbuf, ptls_iovec_init(message, strlen(message)), EVP_sha256()) == 0);
-    EVP_PKEY_up_ref(sc->key);
-    ok(verify_sign(sc->key, ptls_iovec_init(message, strlen(message)), ptls_iovec_init(sigbuf.base, sigbuf.off)) == 0);
-
-    ptls_buffer_dispose(&sigbuf);
+    test_sign_verify(sc->key, sc->schemes);
 }
 
-static void test_ecdsa_sign(void)
+static void do_test_ecdsa_sign(int nid, const struct st_ptls_openssl_signature_scheme_t *schemes)
 {
     EVP_PKEY *pkey;
 
     { /* create pkey */
-        EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+        EC_KEY *eckey = EC_KEY_new_by_curve_name(nid);
         EC_KEY_generate_key(eckey);
         pkey = EVP_PKEY_new();
         EVP_PKEY_set1_EC_KEY(pkey, eckey);
         EC_KEY_free(eckey);
     }
 
-    const char *message = "hello world";
-    ptls_buffer_t sigbuf;
-    uint8_t sigbuf_small[1024];
-
-    ptls_buffer_init(&sigbuf, sigbuf_small, sizeof(sigbuf_small));
-    ok(do_sign(pkey, &sigbuf, ptls_iovec_init(message, strlen(message)), EVP_sha256()) == 0);
-    EVP_PKEY_up_ref(pkey);
-    ok(verify_sign(pkey, ptls_iovec_init(message, strlen(message)), ptls_iovec_init(sigbuf.base, sigbuf.off)) == 0);
-
-    ptls_buffer_dispose(&sigbuf);
+    test_sign_verify(pkey, schemes);
     EVP_PKEY_free(pkey);
 }
 
+static void test_ecdsa_sign(void)
+{
+    do_test_ecdsa_sign(NID_X9_62_prime256v1, secp256r1_signature_schemes);
+#if PTLS_OPENSSL_HAVE_SECP384R1
+    do_test_ecdsa_sign(NID_secp384r1, secp384r1_signature_schemes);
+#endif
+#if PTLS_OPENSSL_HAVE_SECP521R1
+    do_test_ecdsa_sign(NID_secp521r1, secp521r1_signature_schemes);
+#endif
+}
+
 static void test_ed25519_sign(void)
 {
 #if defined EVP_PKEY_ED25519
@@ -182,17 +192,7 @@
         EVP_PKEY_CTX_free(pctx);
     }
 
-    const char *message = "hello world";
-    ptls_buffer_t sigbuf;
-  
-    uint8_t sigbuf_small[1024];
-
-    ptls_buffer_init(&sigbuf, sigbuf_small, sizeof(sigbuf_small));
-    ok(do_sign(pkey, &sigbuf, ptls_iovec_init(message, strlen(message)), NULL) == 0);
-    EVP_PKEY_up_ref(pkey);
-    ok(verify_sign(pkey, ptls_iovec_init(message, strlen(message)), ptls_iovec_init(sigbuf.base, sigbuf.off)) == 0);
-
-    ptls_buffer_dispose(&sigbuf);
+    test_sign_verify(pkey, ed25519_signature_schemes);
     EVP_PKEY_free(pkey);
 #endif
 }