[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Wed Jun 21 13:50:28 UTC 2017


The branch master has been updated
       via  72257204bd2a88773461150765dfd0e0a428ee86 (commit)
       via  adfc37868e2dc406b80ab3111163eb475ef06975 (commit)
       via  ca8c71ba3586fd0fcf6c011cbf39f5076d18c126 (commit)
       via  011d768aba675ed3efa4b8484eb6a14d78c27f12 (commit)
       via  725b0f1e133495acc35378bd6304ec1d401a761c (commit)
       via  8ead6158a961c9b86bc086fbe96c9fbbe715a8c5 (commit)
       via  93a048a1d8f1f6307aea0c1e7854a40b2daf236f (commit)
       via  dc87d5a92288df394f5a887be5c788a530992185 (commit)
       via  801d9fbd97e5f29b19851562a72b8be4c5fd0783 (commit)
       via  9c39fa1e38d0973787e32799a28a46a2812aba2b (commit)
       via  267869d3f307e1160f79e1b09246bb091ed00bbf (commit)
       via  5eb7273669e5dc05c9b744cbba5a2a2915827746 (commit)
       via  7721978ca8033fe4fe89a2fe673fea04436da15b (commit)
       via  14e353506a8a255c31b5b6b7520e00ed323d5a13 (commit)
       via  5ffff5990caa42b8a2d55fc70e23edbe9397e4cb (commit)
       via  5a43d5119eca14838759913d7235d450a5c1a2ed (commit)
       via  1a993d1d56835fdf981988367b4bbc3078101d28 (commit)
       via  911d63f2611490590e0527ffcd4c95a67cd13a28 (commit)
       via  df894947c4f04dedb0bded25195bc2fc7b2b6915 (commit)
       via  e261bdd185e074228c3ee6359a4eeb9781e3ef3d (commit)
       via  ba4df6828620acddab3c2bf3b99a2b4a838c61de (commit)
       via  f46184bd90aea1d71e46a598038215a7fcb359c6 (commit)
       via  9368f86526d9feb1f511fab9c0eee8e8dc869b87 (commit)
       via  3a7c56b2c0e6680e4ad3d83387a970110efdf1ba (commit)
      from  2556aec5d07546963eddc2df6824729fc218f41b (commit)


- Log -----------------------------------------------------------------
commit 72257204bd2a88773461150765dfd0e0a428ee86
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jun 21 12:17:30 2017 +0100

    PSK related tweaks based on review feedback
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit adfc37868e2dc406b80ab3111163eb475ef06975
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jun 21 11:58:10 2017 +0100

    Use constants rather than macros for the cipher bytes in the apps
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit ca8c71ba3586fd0fcf6c011cbf39f5076d18c126
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jun 20 14:26:00 2017 +0100

    Add some tests for the new TLSv1.3 PSK code
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 011d768aba675ed3efa4b8484eb6a14d78c27f12
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jun 20 14:25:38 2017 +0100

    Fix some bugs in the TLSv1.3 PSK code
    
    Found while developing the PSK tests
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 725b0f1e133495acc35378bd6304ec1d401a761c
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jun 20 14:24:39 2017 +0100

    Make the input parameters for SSL_SESSION_set1_master_key const
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 8ead6158a961c9b86bc086fbe96c9fbbe715a8c5
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 19 15:03:43 2017 +0100

    Document SSL_set_psk_find_session_callback() and SSL_CTX equivalent
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 93a048a1d8f1f6307aea0c1e7854a40b2daf236f
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jun 16 16:27:33 2017 +0100

    Document SSL_set_psk_use_session_callback() and SSL_CTX equivalent
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit dc87d5a92288df394f5a887be5c788a530992185
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jun 16 16:26:25 2017 +0100

    Tweak the client side PSK callback
    
    Ensure that we properly distinguish between successful return (PSK
    provided), successful return (no PSK provided) and failure.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 801d9fbd97e5f29b19851562a72b8be4c5fd0783
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Jun 16 14:30:10 2017 +0100

    Add documentation for SSL_CTX_set_psk_use_session_callback()
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 9c39fa1e38d0973787e32799a28a46a2812aba2b
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jun 14 14:27:53 2017 +0100

    Document SSL_CIPHER_get_handshake_digest()
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 267869d3f307e1160f79e1b09246bb091ed00bbf
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jun 14 13:58:29 2017 +0100

    Document SSL_SESSION_set_protocol_version()
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 5eb7273669e5dc05c9b744cbba5a2a2915827746
Author: Matt Caswell <matt at openssl.org>
Date:   Wed Jun 14 10:37:25 2017 +0100

    Document SSL_SESSION_set1_master_key()
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 7721978ca8033fe4fe89a2fe673fea04436da15b
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jun 13 15:27:50 2017 +0100

    Add documentation for SSL_SESSION_set_cipher()
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 14e353506a8a255c31b5b6b7520e00ed323d5a13
Author: Matt Caswell <matt at openssl.org>
Date:   Tue Jun 13 14:28:45 2017 +0100

    Fix no-psk
    
    Broken through previous PSK related commits
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 5ffff5990caa42b8a2d55fc70e23edbe9397e4cb
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 19:12:13 2017 +0100

    Add the ability to set a TLSv1.3 PSK via just the key bytes
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 5a43d5119eca14838759913d7235d450a5c1a2ed
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 19:40:11 2017 +0100

    Add SSL_SESSION_set_protocol_version()
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 1a993d1d56835fdf981988367b4bbc3078101d28
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 19:12:04 2017 +0100

    Add SSL_SESSION_set_cipher()
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 911d63f2611490590e0527ffcd4c95a67cd13a28
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 18:38:30 2017 +0100

    Add SSL_SESSION_set1_master_key()
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit df894947c4f04dedb0bded25195bc2fc7b2b6915
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 18:26:09 2017 +0100

    Add the ability to use a server side TLSv1.3 external PSK in s_server
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit e261bdd185e074228c3ee6359a4eeb9781e3ef3d
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 16:57:06 2017 +0100

    Add the ability to use a client side TLSv1.3 external PSK in s_client
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit ba4df6828620acddab3c2bf3b99a2b4a838c61de
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 16:56:15 2017 +0100

    Add a function to get the handshake digest for an SSL_CIPHER
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit f46184bd90aea1d71e46a598038215a7fcb359c6
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 15:59:00 2017 +0100

    Add public API functions for setting TLSv1.3 PSK callbacks
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 9368f86526d9feb1f511fab9c0eee8e8dc869b87
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 13:30:21 2017 +0100

    Add TLSv1.3 client side external PSK support
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

commit 3a7c56b2c0e6680e4ad3d83387a970110efdf1ba
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Jun 12 09:18:24 2017 +0100

    Add TLSv1.3 server side external PSK support
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3670)

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

Summary of changes:
 apps/apps.h                                   |   6 +-
 apps/s_client.c                               | 105 ++++++++++++-
 apps/s_server.c                               |  97 +++++++++++--
 crypto/err/openssl.txt                        |   1 +
 doc/man3/SSL_CIPHER_get_name.pod              |  31 ++--
 doc/man3/SSL_CTX_set_psk_client_callback.pod  | 109 ++++++++++++--
 doc/man3/SSL_CTX_use_psk_identity_hint.pod    | 100 +++++++++----
 doc/man3/SSL_SESSION_get0_cipher.pod          |  24 ++-
 doc/man3/SSL_SESSION_get_protocol_version.pod |  20 ++-
 doc/man3/SSL_get_client_random.pod            |  29 +++-
 include/openssl/ssl.h                         |  22 +++
 include/openssl/sslerr.h                      |   1 +
 ssl/ssl_ciph.c                                |   9 ++
 ssl/ssl_err.c                                 |   1 +
 ssl/ssl_lib.c                                 |  39 +++++
 ssl/ssl_locl.h                                |   8 +
 ssl/ssl_sess.c                                |  12 ++
 ssl/statem/extensions.c                       |  38 +++--
 ssl/statem/extensions_clnt.c                  | 202 +++++++++++++++++++-------
 ssl/statem/extensions_srvr.c                  | 106 ++++++++------
 ssl/statem/statem_locl.h                      |   2 +-
 test/sslapitest.c                             | 182 +++++++++++++++++++++++
 test/ssltestlib.c                             |   8 +
 test/ssltestlib.h                             |   1 +
 util/libssl.num                               |   8 +
 util/private.num                              |   4 +
 26 files changed, 968 insertions(+), 197 deletions(-)

diff --git a/apps/apps.h b/apps/apps.h
index 31cf7b0..4ec0693 100644
--- a/apps/apps.h
+++ b/apps/apps.h
@@ -55,6 +55,8 @@ extern char *default_config_file;
 extern BIO *bio_in;
 extern BIO *bio_out;
 extern BIO *bio_err;
+extern const unsigned char tls13_aes128gcmsha256_id[];
+extern const unsigned char tls13_aes256gcmsha384_id[];
 BIO *dup_bio_in(int format);
 BIO *dup_bio_out(int format);
 BIO *dup_bio_err(int format);
@@ -515,9 +517,9 @@ int do_X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md,
                      STACK_OF(OPENSSL_STRING) *sigopts);
 int do_X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md,
                      STACK_OF(OPENSSL_STRING) *sigopts);
-# ifndef OPENSSL_NO_PSK
+
 extern char *psk_key;
-# endif
+
 
 unsigned char *next_protos_parse(size_t *outlen, const char *in);
 
diff --git a/apps/s_client.c b/apps/s_client.c
index 0a45636..393b311 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -65,6 +65,7 @@ static int keymatexportlen = 20;
 static BIO *bio_c_out = NULL;
 static int c_quiet = 0;
 static char *sess_out = NULL;
+static SSL_SESSION *psksess = NULL;
 
 static void print_stuff(BIO *berr, SSL *con, int full);
 #ifndef OPENSSL_NO_OCSP
@@ -108,10 +109,10 @@ static void do_ssl_shutdown(SSL *ssl)
     } while (ret < 0);
 }
 
-#ifndef OPENSSL_NO_PSK
 /* Default PSK identity and key */
 static char *psk_identity = "Client_identity";
 
+#ifndef OPENSSL_NO_PSK
 static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity,
                                   unsigned int max_identity_len,
                                   unsigned char *psk,
@@ -171,6 +172,76 @@ static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity,
 }
 #endif
 
+const unsigned char tls13_aes128gcmsha256_id[] = { 0x13, 0x01 };
+const unsigned char tls13_aes256gcmsha384_id[] = { 0x13, 0x02 };
+
+static int psk_use_session_cb(SSL *s, const EVP_MD *md,
+                              const unsigned char **id, size_t *idlen,
+                              SSL_SESSION **sess)
+{
+    SSL_SESSION *usesess = NULL;
+    const SSL_CIPHER *cipher = NULL;
+
+    if (psksess != NULL) {
+        SSL_SESSION_up_ref(psksess);
+        usesess = psksess;
+    } else {
+        long key_len;
+        unsigned char *key = OPENSSL_hexstr2buf(psk_key, &key_len);
+
+        if (key == NULL) {
+            BIO_printf(bio_err, "Could not convert PSK key '%s' to buffer\n",
+                       psk_key);
+            return 0;
+        }
+
+        if (key_len == EVP_MD_size(EVP_sha256()))
+            cipher = SSL_CIPHER_find(s, tls13_aes128gcmsha256_id);
+        else if(key_len == EVP_MD_size(EVP_sha384()))
+            cipher = SSL_CIPHER_find(s, tls13_aes256gcmsha384_id);
+
+        if (cipher == NULL) {
+            /* Doesn't look like a suitable TLSv1.3 key. Ignore it */
+            OPENSSL_free(key);
+            *id = NULL;
+            *idlen = 0;
+            *sess = NULL;
+            return 0;
+        }
+        usesess = SSL_SESSION_new();
+        if (usesess == NULL
+                || !SSL_SESSION_set1_master_key(usesess, key, key_len)
+                || !SSL_SESSION_set_cipher(usesess, cipher)
+                || !SSL_SESSION_set_protocol_version(usesess, TLS1_3_VERSION)) {
+            OPENSSL_free(key);
+            goto err;
+        }
+        OPENSSL_free(key);
+    }
+
+    cipher = SSL_SESSION_get0_cipher(usesess);
+    if (cipher == NULL)
+        goto err;
+
+    if (md != NULL && SSL_CIPHER_get_handshake_digest(cipher) != md) {
+        /* PSK not usable, ignore it */
+        *id = NULL;
+        *idlen = 0;
+        *sess = NULL;
+        SSL_SESSION_free(usesess);
+    } else {
+        *sess = usesess;
+        *id = (unsigned char *)psk_identity;
+        *idlen = strlen(psk_identity);
+    }
+
+    return 1;
+
+ err:
+    SSL_SESSION_free(usesess);
+    return 0;
+}
+
 /* This is a context that we pass to callbacks */
 typedef struct tlsextctx_st {
     BIO *biodebug;
@@ -505,9 +576,7 @@ typedef enum OPTION_choice {
     OPT_DEBUG, OPT_TLSEXTDEBUG, OPT_STATUS, OPT_WDEBUG,
     OPT_MSG, OPT_MSGFILE, OPT_ENGINE, OPT_TRACE, OPT_SECURITY_DEBUG,
     OPT_SECURITY_DEBUG_VERBOSE, OPT_SHOWCERTS, OPT_NBIO_TEST, OPT_STATE,
-#ifndef OPENSSL_NO_PSK
-    OPT_PSK_IDENTITY, OPT_PSK,
-#endif
+    OPT_PSK_IDENTITY, OPT_PSK, OPT_PSK_SESS,
 #ifndef OPENSSL_NO_SRP
     OPT_SRPUSER, OPT_SRPPASS, OPT_SRP_STRENGTH, OPT_SRP_LATEUSER,
     OPT_SRP_MOREGROUPS,
@@ -686,10 +755,9 @@ const OPTIONS s_client_options[] = {
     {"wdebug", OPT_WDEBUG, '-', "WATT-32 tcp debugging"},
 #endif
     {"nbio", OPT_NBIO, '-', "Use non-blocking IO"},
-#ifndef OPENSSL_NO_PSK
     {"psk_identity", OPT_PSK_IDENTITY, 's', "PSK identity"},
     {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"},
-#endif
+    {"psk_session", OPT_PSK_SESS, '<', "File to read PSK SSL session from"},
 #ifndef OPENSSL_NO_SRP
     {"srpuser", OPT_SRPUSER, 's', "SRP authentication for 'user'"},
     {"srppass", OPT_SRPPASS, 's', "Password for 'user'"},
@@ -886,6 +954,7 @@ int s_client_main(int argc, char **argv)
 #ifndef OPENSSL_NO_DTLS
     int isdtls = 0;
 #endif
+    char *psksessf = NULL;
 
     FD_ZERO(&readfds);
     FD_ZERO(&writefds);
@@ -1134,7 +1203,6 @@ int s_client_main(int argc, char **argv)
         case OPT_STATE:
             state = 1;
             break;
-#ifndef OPENSSL_NO_PSK
         case OPT_PSK_IDENTITY:
             psk_identity = opt_arg();
             break;
@@ -1146,7 +1214,9 @@ int s_client_main(int argc, char **argv)
                 goto end;
             }
             break;
-#endif
+        case OPT_PSK_SESS:
+            psksessf = opt_arg();
+            break;
 #ifndef OPENSSL_NO_SRP
         case OPT_SRPUSER:
             srp_arg.srplogin = opt_arg();
@@ -1656,6 +1726,25 @@ int s_client_main(int argc, char **argv)
         SSL_CTX_set_psk_client_callback(ctx, psk_client_cb);
     }
 #endif
+    if (psksessf != NULL) {
+        BIO *stmp = BIO_new_file(psksessf, "r");
+
+        if (stmp == NULL) {
+            BIO_printf(bio_err, "Can't open PSK session file %s\n", psksessf);
+            ERR_print_errors(bio_err);
+            goto end;
+        }
+        psksess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL);
+        BIO_free(stmp);
+        if (psksess == NULL) {
+            BIO_printf(bio_err, "Can't read PSK session file %s\n", psksessf);
+            ERR_print_errors(bio_err);
+            goto end;
+        }
+    }
+    if (psk_key != NULL || psksess != NULL)
+        SSL_CTX_set_psk_use_session_callback(ctx, psk_use_session_cb);
+
 #ifndef OPENSSL_NO_SRTP
     if (srtp_profiles != NULL) {
         /* Returns 0 on success! */
diff --git a/apps/s_server.c b/apps/s_server.c
index a9020b2..13cc7a1 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -117,11 +117,12 @@ static long socket_mtu;
 static int dtlslisten = 0;
 
 static int early_data = 0;
+static SSL_SESSION *psksess = NULL;
 
-#ifndef OPENSSL_NO_PSK
 static char *psk_identity = "Client_identity";
 char *psk_key = NULL;           /* by default PSK is not used */
 
+#ifndef OPENSSL_NO_PSK
 static unsigned int psk_server_cb(SSL *ssl, const char *identity,
                                   unsigned char *psk,
                                   unsigned int max_psk_len)
@@ -178,6 +179,59 @@ static unsigned int psk_server_cb(SSL *ssl, const char *identity,
 }
 #endif
 
+#define TLS13_AES_128_GCM_SHA256_BYTES  ((const unsigned char *)"\x13\x01")
+#define TLS13_AES_256_GCM_SHA384_BYTES  ((const unsigned char *)"\x13\x02")
+
+static int psk_find_session_cb(SSL *ssl, const unsigned char *identity,
+                               size_t identity_len, SSL_SESSION **sess)
+{
+    SSL_SESSION *tmpsess = NULL;
+    unsigned char *key;
+    long key_len;
+    const SSL_CIPHER *cipher = NULL;
+
+    if (strlen(psk_identity) != identity_len
+            || memcmp(psk_identity, identity, identity_len) != 0)
+        return 0;
+
+    if (psksess != NULL) {
+        SSL_SESSION_up_ref(psksess);
+        *sess = psksess;
+        return 1;
+    }
+
+    key = OPENSSL_hexstr2buf(psk_key, &key_len);
+    if (key == NULL) {
+        BIO_printf(bio_err, "Could not convert PSK key '%s' to buffer\n",
+                   psk_key);
+        return 0;
+    }
+
+    if (key_len == EVP_MD_size(EVP_sha256()))
+        cipher = SSL_CIPHER_find(ssl, tls13_aes128gcmsha256_id);
+    else if(key_len == EVP_MD_size(EVP_sha384()))
+        cipher = SSL_CIPHER_find(ssl, tls13_aes256gcmsha384_id);
+
+    if (cipher == NULL) {
+        /* Doesn't look like a suitable TLSv1.3 key. Ignore it */
+        OPENSSL_free(key);
+        return 0;
+    }
+
+    tmpsess = SSL_SESSION_new();
+    if (tmpsess == NULL
+            || !SSL_SESSION_set1_master_key(tmpsess, key, key_len)
+            || !SSL_SESSION_set_cipher(tmpsess, cipher)
+            || !SSL_SESSION_set_protocol_version(tmpsess, SSL_version(ssl))) {
+        OPENSSL_free(key);
+        return 0;
+    }
+    OPENSSL_free(key);
+    *sess = tmpsess;
+
+    return 1;
+}
+
 #ifndef OPENSSL_NO_SRP
 /* This is a context that we pass to callbacks */
 typedef struct srpsrvparm_st {
@@ -685,9 +739,9 @@ typedef enum OPTION_choice {
     OPT_STATUS_TIMEOUT, OPT_STATUS_URL, OPT_STATUS_FILE, OPT_MSG, OPT_MSGFILE,
     OPT_TRACE, OPT_SECURITY_DEBUG, OPT_SECURITY_DEBUG_VERBOSE, OPT_STATE,
     OPT_CRLF, OPT_QUIET, OPT_BRIEF, OPT_NO_DHE,
-    OPT_NO_RESUME_EPHEMERAL, OPT_PSK_IDENTITY, OPT_PSK_HINT, OPT_PSK, OPT_SRPVFILE,
-    OPT_SRPUSERSEED, OPT_REV, OPT_WWW, OPT_UPPER_WWW, OPT_HTTP, OPT_ASYNC,
-    OPT_SSL_CONFIG,
+    OPT_NO_RESUME_EPHEMERAL, OPT_PSK_IDENTITY, OPT_PSK_HINT, OPT_PSK,
+    OPT_PSK_SESS, OPT_SRPVFILE, OPT_SRPUSERSEED, OPT_REV, OPT_WWW,
+    OPT_UPPER_WWW, OPT_HTTP, OPT_ASYNC, OPT_SSL_CONFIG,
     OPT_MAX_SEND_FRAG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF,
     OPT_SSL3, OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1,
     OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_LISTEN,
@@ -838,11 +892,12 @@ const OPTIONS s_server_options[] = {
     OPT_V_OPTIONS,
     OPT_X_OPTIONS,
     {"nbio", OPT_NBIO, '-', "Use non-blocking IO"},
-#ifndef OPENSSL_NO_PSK
     {"psk_identity", OPT_PSK_IDENTITY, 's', "PSK identity to expect"},
+#ifndef OPENSSL_NO_PSK
     {"psk_hint", OPT_PSK_HINT, 's', "PSK identity hint to use"},
-    {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"},
 #endif
+    {"psk", OPT_PSK, 's', "PSK in hex (without 0x)"},
+    {"psk_session", OPT_PSK_SESS, '<', "File to read PSK SSL session from"},
 #ifndef OPENSSL_NO_SRP
     {"srpvfile", OPT_SRPVFILE, '<', "The verifier file for SRP"},
     {"srpuserseed", OPT_SRPUSERSEED, 's',
@@ -956,8 +1011,8 @@ int s_server_main(int argc, char *argv[])
 #ifndef OPENSSL_NO_PSK
     /* by default do not send a PSK identity hint */
     char *psk_identity_hint = NULL;
-    char *p;
 #endif
+    char *p;
 #ifndef OPENSSL_NO_SRP
     char *srpuserseed = NULL;
     char *srp_verifier_file = NULL;
@@ -977,6 +1032,7 @@ int s_server_main(int argc, char *argv[])
     const char *s_serverinfo_file = NULL;
     const char *keylog_file = NULL;
     int max_early_data = -1;
+    char *psksessf = NULL;
 
     /* Init of few remaining global variables */
     local_argc = argc;
@@ -1323,9 +1379,7 @@ int s_server_main(int argc, char *argv[])
             no_resume_ephemeral = 1;
             break;
         case OPT_PSK_IDENTITY:
-#ifndef OPENSSL_NO_PSK
             psk_identity = opt_arg();
-#endif
             break;
         case OPT_PSK_HINT:
 #ifndef OPENSSL_NO_PSK
@@ -1333,14 +1387,15 @@ int s_server_main(int argc, char *argv[])
 #endif
             break;
         case OPT_PSK:
-#ifndef OPENSSL_NO_PSK
             for (p = psk_key = opt_arg(); *p; p++) {
                 if (isxdigit(_UC(*p)))
                     continue;
                 BIO_printf(bio_err, "Not a hex number '%s'\n", *argv);
                 goto end;
             }
-#endif
+            break;
+        case OPT_PSK_SESS:
+            psksessf = opt_arg();
             break;
         case OPT_SRPVFILE:
 #ifndef OPENSSL_NO_SRP
@@ -1940,6 +1995,26 @@ int s_server_main(int argc, char *argv[])
         goto end;
     }
 #endif
+    if (psksessf != NULL) {
+        BIO *stmp = BIO_new_file(psksessf, "r");
+
+        if (stmp == NULL) {
+            BIO_printf(bio_err, "Can't open PSK session file %s\n", psksessf);
+            ERR_print_errors(bio_err);
+            goto end;
+        }
+        psksess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL);
+        BIO_free(stmp);
+        if (psksess == NULL) {
+            BIO_printf(bio_err, "Can't read PSK session file %s\n", psksessf);
+            ERR_print_errors(bio_err);
+            goto end;
+        }
+
+    }
+
+    if (psk_key != NULL || psksess != NULL)
+        SSL_CTX_set_psk_find_session_callback(ctx, psk_find_session_cb);
 
     SSL_CTX_set_verify(ctx, s_server_verify, verify_callback);
     if (!SSL_CTX_set_session_id_context(ctx,
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index e2cf2c5..813ca74 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2137,6 +2137,7 @@ SSL_R_BAD_KEY_UPDATE:122:bad key update
 SSL_R_BAD_LENGTH:271:bad length
 SSL_R_BAD_PACKET_LENGTH:115:bad packet length
 SSL_R_BAD_PROTOCOL_VERSION_NUMBER:116:bad protocol version number
+SSL_R_BAD_PSK:219:bad psk
 SSL_R_BAD_PSK_IDENTITY:114:bad psk identity
 SSL_R_BAD_RECORD_TYPE:443:bad record type
 SSL_R_BAD_RSA_ENCRYPT:119:bad rsa encrypt
diff --git a/doc/man3/SSL_CIPHER_get_name.pod b/doc/man3/SSL_CIPHER_get_name.pod
index e19bf21..157c162 100644
--- a/doc/man3/SSL_CIPHER_get_name.pod
+++ b/doc/man3/SSL_CIPHER_get_name.pod
@@ -2,10 +2,16 @@
 
 =head1 NAME
 
-SSL_CIPHER_get_cipher_nid, SSL_CIPHER_get_digest_nid, SSL_CIPHER_get_kx_nid,
-SSL_CIPHER_get_auth_nid, SSL_CIPHER_is_aead,
-SSL_CIPHER_get_name, SSL_CIPHER_get_bits,
-SSL_CIPHER_get_version, SSL_CIPHER_description
+SSL_CIPHER_get_name,
+SSL_CIPHER_get_bits,
+SSL_CIPHER_get_version,
+SSL_CIPHER_description,
+SSL_CIPHER_get_cipher_nid,
+SSL_CIPHER_get_digest_nid,
+SSL_CIPHER_get_handshake_digest,
+SSL_CIPHER_get_kx_nid,
+SSL_CIPHER_get_auth_nid,
+SSL_CIPHER_is_aead
 - get SSL_CIPHER properties
 
 =head1 SYNOPSIS
@@ -18,6 +24,7 @@ SSL_CIPHER_get_version, SSL_CIPHER_description
  char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int size);
  int SSL_CIPHER_get_cipher_nid(const SSL_CIPHER *c);
  int SSL_CIPHER_get_digest_nid(const SSL_CIPHER *c);
+ const EVP_MD *SSL_CIPHER_get_handshake_digest(const SSL_CIPHER *c);
  int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *c);
  int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *c);
  int SSL_CIPHER_is_aead(const SSL_CIPHER *c);
@@ -38,8 +45,12 @@ If there is no cipher (e.g. for cipher suites with no encryption) then
 B<NID_undef> is returned.
 
 SSL_CIPHER_get_digest_nid() returns the digest NID corresponding to the MAC
-used by B<c>. If there is no digest (e.g. for AEAD cipher suites) then
-B<NID_undef> is returned.
+used by B<c> during record encryption/decryption. If there is no digest (e.g.
+for AEAD cipher suites) then B<NID_undef> is returned.
+
+SSL_CIPHER_get_handshake_digest() returns an EVP_MD for the digest used during
+the SSL/TLS handshake when using the SSL_CIPHER B<c>. Note that this may be
+different to the digest used to calculate the MAC for encrypted records.
 
 SSL_CIPHER_get_kx_nid() returns the key exchange NID corresponding to the method
 used by B<c>. If there is no key exchange, then B<NID_undef> is returned.
@@ -109,10 +120,12 @@ Some examples for the output of SSL_CIPHER_description():
 =head1 HISTORY
 
 SSL_CIPHER_get_version() was updated to always return the correct protocol
-string in OpenSSL 1.1.
+string in OpenSSL 1.1.0.
 
 SSL_CIPHER_description() was changed to return B<NULL> on error,
-rather than a fixed string, in OpenSSL 1.1
+rather than a fixed string, in OpenSSL 1.1.0.
+
+SSL_CIPHER_get_handshake_digest() was added in OpenSSL 1.1.1.
 
 =head1 SEE ALSO
 
@@ -121,7 +134,7 @@ L<SSL_get_ciphers(3)>, L<ciphers(1)>
 
 =head1 COPYRIGHT
 
-Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2000-2017 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
diff --git a/doc/man3/SSL_CTX_set_psk_client_callback.pod b/doc/man3/SSL_CTX_set_psk_client_callback.pod
index 6aa60bb..919b6af 100644
--- a/doc/man3/SSL_CTX_set_psk_client_callback.pod
+++ b/doc/man3/SSL_CTX_set_psk_client_callback.pod
@@ -2,26 +2,44 @@
 
 =head1 NAME
 
-SSL_CTX_set_psk_client_callback, SSL_set_psk_client_callback - set PSK client callback
+SSL_psk_client_cb_func,
+SSL_psk_use_session_cb_func,
+SSL_CTX_set_psk_client_callback,
+SSL_set_psk_client_callback,
+SSL_CTX_set_psk_use_session_callback,
+SSL_set_psk_use_session_callback
+- set PSK client callback
 
 =head1 SYNOPSIS
 
  #include <openssl/ssl.h>
 
- void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx,
-     unsigned int (*callback)(SSL *ssl, const char *hint,
-                              char *identity, unsigned int max_identity_len,
-                              unsigned char *psk, unsigned int max_psk_len));
- void SSL_set_psk_client_callback(SSL *ssl,
-     unsigned int (*callback)(SSL *ssl, const char *hint,
-                              char *identity, unsigned int max_identity_len,
-                              unsigned char *psk, unsigned int max_psk_len));
+ typedef unsigned int (*SSL_psk_client_cb_func)(SSL *ssl,
+                                                const char *hint,
+                                                char *identity,
+                                                unsigned int max_identity_len,
+                                                unsigned char *psk,
+                                                unsigned int max_psk_len);
+ typedef int (*SSL_psk_use_session_cb_func)(SSL *ssl, const EVP_MD *md,
+                                            const unsigned char **id,
+                                            size_t *idlen,
+                                            SSL_SESSION **sess);
 
+ void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx, SSL_psk_client_cb_func cb);
+ void SSL_set_psk_client_callback(SSL *ssl, SSL_psk_client_cb_func cb);
+
+ void SSL_CTX_set_psk_use_session_callback(SSL_CTX *ctx,
+                                           SSL_psk_use_session_cb_func cb);
+ void SSL_set_psk_use_session_callback(SSL *s, SSL_psk_use_session_cb_func cb);
 
 =head1 DESCRIPTION
 
-A client application must provide a callback function which is called
-when the client is sending the ClientKeyExchange message to the server.
+TLSv1.3 Pre-Shared Keys (PSKs) and PSKs for TLSv1.2 and below are not
+compatible.
+
+A client application wishing to use PSK ciphersuites for TLSv1.2 and below must
+provide a callback function. This function will be called when the client is
+sending the ClientKeyExchange message to the server.
 
 The purpose of the callback function is to select the PSK identity and
 the pre-shared key to use during the connection setup phase.
@@ -35,23 +53,86 @@ B<NULL>-terminated identity is to be stored, and a buffer B<psk> of
 length B<max_psk_len> bytes where the resulting pre-shared key is to
 be stored.
 
+A client application wishing to use TLSv1.3 PSKs must set a different callback
+using either SSL_CTX_set_psk_use_session_callback() or
+SSL_set_psk_use_session_callback() as appropriate.
+
+The callback function is given a pointer to the SSL connection in B<ssl>.
+
+The first time the callback is called for a connection the B<md> parameter is
+NULL. In some circumstances the callback will be called a second time. In that
+case the server will have specified a ciphersuite to use already and the PSK
+must be compatible with the digest for that ciphersuite. The digest will be
+given in B<md>. The PSK returned by the callback is allowed to be different
+between the first and second time it is called.
+
+On successful completion the callback must store a pointer to an identifier for
+the PSK in B<*id>. The identifier length in bytes should be stored in B<*idlen>.
+The memory pointed to by B<*id> remains owned by the application and should
+be freed by it as required at any point after the handshake is complete.
+
+Additionally the callback should store a pointer to an SSL_SESSION object in
+B<*sess>. This is used as the basis for the PSK, and should, at a minimum, have
+the following fields set:
+
+=over 4
+
+=item The master key
+
+This can be set via a call to L<SSL_SESSION_set1_master_key(3)>.
+
+=item A ciphersuite
+
+Only the handshake digest associated with the ciphersuite is relevant for the
+PSK (the server may go on to negotiate any ciphersuite which is compatible with
+the digest). The application can use any TLSv1.3 ciphersuite. If B<md> is
+not NULL the handshake digest for the ciphersuite should be the same.
+The ciphersuite can be set via a call to <SSL_SESSION_set_cipher(3)>. The
+handshake digest of an SSL_CIPHER object can be checked using
+<SSL_CIPHER_get_handshake_digest(3)>.
+
+=item The protocol version
+
+This can be set via a call to L<SSL_SESSION_set_protocol_version(3)> and should
+be TLS1_3_VERSION.
+
+=back
+
+Alternatively an SSL_SESSION created from a previous non-PSK handshake may also
+be used as the basis for a PSK.
+
+Ownership of the SSL_SESSION object is passed to the OpenSSL library and so it
+should not be freed by the application.
+
+It is also possible for the callback to succeed but not supply a PSK. In this
+case no PSK will be sent to the server but the handshake will continue. To do
+this the callback should return successfully and ensure that B<*sess> is
+NULL. The contents of B<*id> and B<*idlen> will be ignored.
+
 =head1 NOTES
 
 Note that parameter B<hint> given to the callback may be B<NULL>.
 
+A connection established via a TLSv1.3 PSK will appear as if session resumption
+has occurred so that L<SSL_session_reused(3)> will return true.
+
 =head1 RETURN VALUES
 
-Return values from the client callback are interpreted as follows:
+Return values from the B<SSL_psk_client_cb_func> callback are interpreted as
+follows:
 
 On success (callback found a PSK identity and a pre-shared key to use)
 the length (> 0) of B<psk> in bytes is returned.
 
-Otherwise or on errors callback should return 0. In this case
+Otherwise or on errors the callback should return 0. In this case
 the connection setup fails.
 
+The SSL_psk_use_session_cb_func callback should return 1 on success or 0 on
+failure. In the event of failure the connection setup fails.
+
 =head1 COPYRIGHT
 
-Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2006-2017 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
diff --git a/doc/man3/SSL_CTX_use_psk_identity_hint.pod b/doc/man3/SSL_CTX_use_psk_identity_hint.pod
index 41384ac..4ded544 100644
--- a/doc/man3/SSL_CTX_use_psk_identity_hint.pod
+++ b/doc/man3/SSL_CTX_use_psk_identity_hint.pod
@@ -2,58 +2,93 @@
 
 =head1 NAME
 
-SSL_CTX_use_psk_identity_hint, SSL_use_psk_identity_hint,
-SSL_CTX_set_psk_server_callback, SSL_set_psk_server_callback - set PSK
-identity hint to use
+SSL_psk_server_cb_func,
+SSL_psk_find_session_cb_func,
+SSL_CTX_use_psk_identity_hint,
+SSL_use_psk_identity_hint,
+SSL_CTX_set_psk_server_callback,
+SSL_set_psk_server_callback,
+SSL_CTX_set_psk_find_session_callback,
+SSL_set_psk_find_session_callback
+- set PSK identity hint to use
 
 =head1 SYNOPSIS
 
  #include <openssl/ssl.h>
 
+ typedef unsigned int (*SSL_psk_server_cb_func)(SSL *ssl,
+                                                const char *identity,
+                                                unsigned char *psk,
+                                                unsigned int max_psk_len);
+
+ typedef int (*SSL_psk_find_session_cb_func)(SSL *ssl,
+                                             const unsigned char *identity,
+                                             size_t identity_len,
+                                             SSL_SESSION **sess);
+
  int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint);
  int SSL_use_psk_identity_hint(SSL *ssl, const char *hint);
 
- void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx,
-                                      unsigned int (*callback)(SSL *ssl,
-                                                               const char *identity,
-                                                               unsigned char *psk,
-                                                               int max_psk_len));
- void SSL_set_psk_server_callback(SSL *ssl,
-                                  unsigned int (*callback)(SSL *ssl,
-                                                           const char *identity,
-                                                           unsigned char *psk,
-                                                           int max_psk_len));
+ void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, SSL_psk_server_cb_func cb);
+ void SSL_set_psk_server_callback(SSL *ssl, SSL_psk_server_cb_func cb);
 
+ void SSL_CTX_set_psk_find_session_callback(SSL_CTX *ctx,
+                                            SSL_psk_find_session_cb_func cb);
+ void SSL_set_psk_find_session_callback(SSL *s, SSL_psk_find_session_cb_func cb);
 
 =head1 DESCRIPTION
 
-SSL_CTX_use_psk_identity_hint() sets the given B<NULL>-terminated PSK
-identity hint B<hint> to SSL context object
-B<ctx>. SSL_use_psk_identity_hint() sets the given B<NULL>-terminated
-PSK identity hint B<hint> to SSL connection object B<ssl>. If B<hint>
-is B<NULL> the current hint from B<ctx> or B<ssl> is deleted.
+TLSv1.3 Pre-Shared Keys (PSKs) and PSKs for TLSv1.2 and below are not
+compatible.
 
-In the case where PSK identity hint is B<NULL>, the server
-does not send the ServerKeyExchange message to the client.
+Identity hints are not relevant for TLSv1.3. A server application wishing to use
+PSK ciphersuites for TLSv1.2 and below may call SSL_CTX_use_psk_identity_hint()
+to set the given B<NUL>-terminated PSK identity hint B<hint> for SSL context
+object B<ctx>. SSL_use_psk_identity_hint() sets the given B<NUL>-terminated PSK
+identity hint B<hint> for the SSL connection object B<ssl>. If B<hint> is
+B<NULL> the current hint from B<ctx> or B<ssl> is deleted.
 
-A server application must provide a callback function which is called
-when the server receives the ClientKeyExchange message from the
+In the case where PSK identity hint is B<NULL>, the server does not send the
+ServerKeyExchange message to the client.
+
+A server application for TLSv1.2 and below must provide a callback function
+which is called when the server receives the ClientKeyExchange message from the
 client. The purpose of the callback function is to validate the
 received PSK identity and to fetch the pre-shared key used during the
-connection setup phase. The callback is set using functions
-SSL_CTX_set_psk_server_callback() or
-SSL_set_psk_server_callback(). The callback function is given the
-connection in parameter B<ssl>, B<NULL>-terminated PSK identity sent
-by the client in parameter B<identity>, and a buffer B<psk> of length
-B<max_psk_len> bytes where the pre-shared key is to be stored.
+connection setup phase. The callback is set using the functions
+SSL_CTX_set_psk_server_callback() or SSL_set_psk_server_callback(). The callback
+function is given the connection in parameter B<ssl>, B<NUL>-terminated PSK
+identity sent by the client in parameter B<identity>, and a buffer B<psk> of
+length B<max_psk_len> bytes where the pre-shared key is to be stored.
+
+A client application wishing to use TLSv1.3 PSKs must set a different callback
+using either SSL_CTX_set_psk_use_session_callback() or
+SSL_set_psk_use_session_callback() as appropriate.
 
+The callback function is given a pointer to the SSL connection in B<ssl> and
+an identity in B<identity> of length B<identity_len>. The callback function
+should identify an SSL_SESSION object that provides the PSK details and store it
+in B<*sess>. The SSL_SESSION object should, as a minimum, set the master key,
+the ciphersuite and the protocol version. See
+L<SSL_CTX_set_psk_use_session_callback(3)> for details.
+
+It is also possible for the callback to succeed but not supply a PSK. In this
+case no PSK will be used but the handshake will continue. To do this the
+callback should return successfully and ensure that B<*sess> is
+NULL.
+
+=head1 NOTES
+
+A connection established via a TLSv1.3 PSK will appear as if session resumption
+has occurred so that L<SSL_session_reused(3)> will return true.
 
 =head1 RETURN VALUES
 
-SSL_CTX_use_psk_identity_hint() and SSL_use_psk_identity_hint() return
+B<SSL_CTX_use_psk_identity_hint()> and B<SSL_use_psk_identity_hint()> return
 1 on success, 0 otherwise.
 
-Return values from the server callback are interpreted as follows:
+Return values from the TLSv1.2 and below server callback are interpreted as
+follows:
 
 =over 4
 
@@ -77,9 +112,12 @@ completely.
 
 =back
 
+The B<SSL_psk_find_session_cb_func> callback should return 1 on success or 0 on
+failure. In the event of failure the connection setup fails.
+
 =head1 COPYRIGHT
 
-Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2006-2017 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
diff --git a/doc/man3/SSL_SESSION_get0_cipher.pod b/doc/man3/SSL_SESSION_get0_cipher.pod
index 3732c57..60f66a2 100644
--- a/doc/man3/SSL_SESSION_get0_cipher.pod
+++ b/doc/man3/SSL_SESSION_get0_cipher.pod
@@ -2,13 +2,16 @@
 
 =head1 NAME
 
-SSL_SESSION_get0_cipher - retrieve the SSL cipher associated with a session
+SSL_SESSION_get0_cipher,
+SSL_SESSION_set_cipher
+- set and retrieve the SSL cipher associated with a session
 
 =head1 SYNOPSIS
 
  #include <openssl/ssl.h>
 
  const SSL_CIPHER *SSL_SESSION_get0_cipher(const SSL_SESSION *s);
+ int SSL_SESSION_set_cipher(SSL_SESSION *s, const SSL_CIPHER *cipher);
 
 =head1 DESCRIPTION
 
@@ -18,21 +21,34 @@ connection when the session was created, or NULL if it cannot be determined.
 The value returned is a pointer to an object maintained within B<s> and
 should not be released.
 
+SSL_SESSION_set_cipher() can be used to set the ciphersuite associated with the
+SSL_SESSION B<s> to B<cipher>. For example, this could be used to set up a
+session based PSK (see L<SSL_CTX_set_psk_use_session_callback(3)>).
+
+=head1 RETURN VALUES
+
+SSL_SESSION_get0_cipher() returns the SSL_CIPHER associated with the SSL_SESSION
+or NULL if it cannot be determined.
+
+SSL_SESSION_set_cipher() returns 1 on success or 0 on failure.
+
 =head1 SEE ALSO
 
 L<ssl(7)>,
 L<d2i_SSL_SESSION(3)>,
 L<SSL_SESSION_get_time(3)>,
 L<SSL_SESSION_get0_hostname(3)>,
-L<SSL_SESSION_free(3)>
+L<SSL_SESSION_free(3)>,
+L<SSL_CTX_set_psk_use_session_callback(3)>
 
 =head1 HISTORY
 
-SSL_SESSION_get0_cipher() was first added to OpenSSL 1.1.0
+SSL_SESSION_get0_cipher() was first added to OpenSSL 1.1.0.
+SSL_SESSION_set_cipher() was first added to OpenSSL 1.1.1.
 
 =head1 COPYRIGHT
 
-Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
diff --git a/doc/man3/SSL_SESSION_get_protocol_version.pod b/doc/man3/SSL_SESSION_get_protocol_version.pod
index ea36012..22e40bd 100644
--- a/doc/man3/SSL_SESSION_get_protocol_version.pod
+++ b/doc/man3/SSL_SESSION_get_protocol_version.pod
@@ -2,19 +2,27 @@
 
 =head1 NAME
 
-SSL_SESSION_get_protocol_version - retrieve session protocol version
+SSL_SESSION_get_protocol_version,
+SSL_SESSION_set_protocol_version
+- get and set the session protocol version
 
 =head1 SYNOPSIS
 
  #include <openssl/ssl.h>
 
  int SSL_SESSION_get_protocol_version(const SSL_SESSION *s);
+ int SSL_SESSION_set_protocol_version(SSL_SESSION *s, int version);
 
 =head1 DESCRIPTION
 
 SSL_SESSION_get_protocol_version() returns the protocol version number used
 by session B<s>.
 
+SSL_SESSION_set_protocol_version() sets the protocol version associated with the
+SSL_SESSION object B<s> to the value B<version>. This value should be a version
+constant such as B<TLS1_3_VERSION> etc. For example, this could be used to set
+up a session based PSK (see L<SSL_CTX_set_psk_use_session_callback(3)>).
+
 =head1 RETURN VALUES
 
 SSL_SESSION_get_protocol_version() returns a number indicating the protocol
@@ -24,17 +32,21 @@ B<TLS1_VERSION> or B<TLS1_2_VERSION>.
 Note that the SSL_SESSION_get_protocol_version() function
 does B<not> perform a null check on the provided session B<s> pointer.
 
+SSL_SESSION_set_protocol_version() returns 1 on success or 0 on failure.
+
 =head1 SEE ALSO
 
-L<ssl(7)>
+L<ssl(7)>,
+L<SSL_CTX_set_psk_use_session_callback(3)>
 
 =head1 HISTORY
 
-SSL_SESSION_get_protocol_version() was first added to OpenSSL 1.1.0
+SSL_SESSION_get_protocol_version() was first added to OpenSSL 1.1.0.
+SSL_SESSION_set_protocol_version() was first added to OpenSSL 1.1.1.
 
 =head1 COPYRIGHT
 
-Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2001-2017 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
diff --git a/doc/man3/SSL_get_client_random.pod b/doc/man3/SSL_get_client_random.pod
index 7f4e753..1e4c666 100644
--- a/doc/man3/SSL_get_client_random.pod
+++ b/doc/man3/SSL_get_client_random.pod
@@ -2,7 +2,11 @@
 
 =head1 NAME
 
-SSL_get_client_random, SSL_get_server_random, SSL_SESSION_get_master_key - retrieve internal TLS/SSL random values and master key
+SSL_get_client_random,
+SSL_get_server_random,
+SSL_SESSION_get_master_key,
+SSL_SESSION_set1_master_key
+- get internal TLS/SSL random values and get/set master key
 
 =head1 SYNOPSIS
 
@@ -12,6 +16,8 @@ SSL_get_client_random, SSL_get_server_random, SSL_SESSION_get_master_key - retri
  size_t SSL_get_server_random(const SSL *ssl, unsigned char *out, size_t outlen);
  size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
                                    unsigned char *out, size_t outlen);
+ int SSL_SESSION_set1_master_key(SSL_SESSION *sess, const unsigned char *in,
+                                 size_t len);
 
 =head1 DESCRIPTION
 
@@ -30,6 +36,13 @@ SSL_SESSION_get_master_key() behaves the same, but extracts the master
 secret used to guarantee the security of the SSL/TLS session.  This one
 can be dangerous if misused; see NOTES below.
 
+SSL_SESSION_set1_master_key() sets the master key value associated with the
+SSL_SESSION B<sess>. For example, this could be used to set up a session based
+PSK (see L<SSL_CTX_set_psk_use_session_callback(3)>). The master key of length
+B<len> should be provided at B<in>. The supplied master key is copied by the
+function, so the caller is responsible for freeing and cleaning any memory
+associated with B<in>. The caller must ensure that the length of the key is
+suitable for the ciphersuite associated with the SSL_SESSION.
 
 =head1 NOTES
 
@@ -64,22 +77,24 @@ values based on their view of the current time.
 
 =head1 RETURN VALUES
 
-If B<outlen> is greater than 0, these functions return the number of bytes
-actually copied, which will be less than or equal to B<outlen>.
+SSL_SESSION_set1_master_key() returns 1 on success or 0 on failure.
 
-If B<outlen> is 0, these functions return the maximum number
-of bytes they would copy--that is, the length of the underlying field.
+For the other functions, if B<outlen> is greater than 0 then these functions
+return the number of bytes actually copied, which will be less than or equal to
+B<outlen>. If B<outlen> is 0 then these functions return the maximum number
+of bytes they would copy -- that is, the length of the underlying field.
 
 =head1 SEE ALSO
 
 L<ssl(7)>,
 L<RAND_bytes(3)>,
-L<SSL_export_keying_material(3)>
+L<SSL_export_keying_material(3)>,
+L<SSL_CTX_set_psk_use_session_callback(3)>
 
 
 =head1 COPYRIGHT
 
-Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2015-2017 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index cd1fc2e..75fb1fc 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -772,6 +772,22 @@ const char *SSL_get_psk_identity_hint(const SSL *s);
 const char *SSL_get_psk_identity(const SSL *s);
 # endif
 
+typedef int (*SSL_psk_find_session_cb_func)(SSL *ssl,
+                                            const unsigned char *identity,
+                                            size_t identity_len,
+                                            SSL_SESSION **sess);
+typedef int (*SSL_psk_use_session_cb_func)(SSL *ssl, const EVP_MD *md,
+                                           const unsigned char **id,
+                                           size_t *idlen,
+                                           SSL_SESSION **sess);
+
+void SSL_set_psk_find_session_callback(SSL *s, SSL_psk_find_session_cb_func cb);
+void SSL_CTX_set_psk_find_session_callback(SSL_CTX *ctx,
+                                           SSL_psk_find_session_cb_func cb);
+void SSL_set_psk_use_session_callback(SSL *s, SSL_psk_use_session_cb_func cb);
+void SSL_CTX_set_psk_use_session_callback(SSL_CTX *ctx,
+                                          SSL_psk_use_session_cb_func cb);
+
 /* Register callbacks to handle custom TLS Extensions for client or server. */
 
 __owur int SSL_CTX_has_client_custom_ext(const SSL_CTX *ctx,
@@ -1403,6 +1419,7 @@ __owur const char *SSL_CIPHER_get_name(const SSL_CIPHER *c);
 __owur uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *c);
 __owur int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *c);
 __owur int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *c);
+__owur const EVP_MD *SSL_CIPHER_get_handshake_digest(const SSL_CIPHER *c);
 __owur int SSL_CIPHER_is_aead(const SSL_CIPHER *c);
 
 __owur int SSL_get_fd(const SSL *s);
@@ -1490,8 +1507,11 @@ __owur long SSL_SESSION_set_time(SSL_SESSION *s, long t);
 __owur long SSL_SESSION_get_timeout(const SSL_SESSION *s);
 __owur long SSL_SESSION_set_timeout(SSL_SESSION *s, long t);
 __owur int SSL_SESSION_get_protocol_version(const SSL_SESSION *s);
+__owur int SSL_SESSION_set_protocol_version(SSL_SESSION *s, int version);
+
 __owur const char *SSL_SESSION_get0_hostname(const SSL_SESSION *s);
 __owur const SSL_CIPHER *SSL_SESSION_get0_cipher(const SSL_SESSION *s);
+__owur int SSL_SESSION_set_cipher(SSL_SESSION *s, const SSL_CIPHER *cipher);
 __owur int SSL_SESSION_has_ticket(const SSL_SESSION *s);
 __owur unsigned long SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *s);
 void SSL_SESSION_get0_ticket(const SSL_SESSION *s, const unsigned char **tick,
@@ -1845,6 +1865,8 @@ __owur size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
                                     size_t outlen);
 __owur size_t SSL_SESSION_get_master_key(const SSL_SESSION *ssl,
                                          unsigned char *out, size_t outlen);
+__owur int SSL_SESSION_set1_master_key(SSL_SESSION *sess,
+                                       const unsigned char *in, size_t len);
 
 #define SSL_get_ex_new_index(l, p, newf, dupf, freef) \
     CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, l, p, newf, dupf, freef)
diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h
index 8dfc974..540baff 100644
--- a/include/openssl/sslerr.h
+++ b/include/openssl/sslerr.h
@@ -381,6 +381,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_BAD_LENGTH                                 271
 # define SSL_R_BAD_PACKET_LENGTH                          115
 # define SSL_R_BAD_PROTOCOL_VERSION_NUMBER                116
+# define SSL_R_BAD_PSK                                    219
 # define SSL_R_BAD_PSK_IDENTITY                           114
 # define SSL_R_BAD_RECORD_TYPE                            443
 # define SSL_R_BAD_RSA_ENCRYPT                            119
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index f048b34..64bb264 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -1931,6 +1931,15 @@ int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *c)
     return ssl_cipher_table_auth[i].nid;
 }
 
+const EVP_MD *SSL_CIPHER_get_handshake_digest(const SSL_CIPHER *c)
+{
+    int idx = c->algorithm2 & SSL_HANDSHAKE_MAC_MASK;
+
+    if (idx < 0 || idx >= SSL_MD_NUM_IDX)
+        return NULL;
+    return ssl_digest_methods[idx];
+}
+
 int SSL_CIPHER_is_aead(const SSL_CIPHER *c)
 {
     return (c->algorithm_mac & SSL_AEAD) ? 1 : 0;
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index eccc5af..0b82c0e 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -594,6 +594,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PACKET_LENGTH), "bad packet length"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PROTOCOL_VERSION_NUMBER),
     "bad protocol version number"},
+    {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PSK), "bad psk"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PSK_IDENTITY), "bad psk identity"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RECORD_TYPE), "bad record type"},
     {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RSA_ENCRYPT), "bad rsa encrypt"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index a46ede1..d8dd45e 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -419,6 +419,8 @@ int SSL_clear(SSL *s)
         SSL_SESSION_free(s->session);
         s->session = NULL;
     }
+    SSL_SESSION_free(s->psksession);
+    s->psksession = NULL;
 
     s->error = 0;
     s->hit = 0;
@@ -634,6 +636,8 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->psk_client_callback = ctx->psk_client_callback;
     s->psk_server_callback = ctx->psk_server_callback;
 #endif
+    s->psk_find_session_cb = ctx->psk_find_session_cb;
+    s->psk_use_session_cb = ctx->psk_use_session_cb;
 
     s->job = NULL;
 
@@ -969,6 +973,7 @@ void SSL_free(SSL *s)
         ssl_clear_bad_session(s);
         SSL_SESSION_free(s->session);
     }
+    SSL_SESSION_free(s->psksession);
 
     clear_ciphers(s);
 
@@ -3720,6 +3725,18 @@ size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
     return outlen;
 }
 
+int SSL_SESSION_set1_master_key(SSL_SESSION *sess, const unsigned char *in,
+                                size_t len)
+{
+    if (len > sizeof(sess->master_key))
+        return 0;
+
+    memcpy(sess->master_key, in, len);
+    sess->master_key_length = len;
+    return 1;
+}
+
+
 int SSL_set_ex_data(SSL *s, int idx, void *arg)
 {
     return (CRYPTO_set_ex_data(&s->ex_data, idx, arg));
@@ -3855,6 +3872,28 @@ void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, SSL_psk_server_cb_func cb)
 }
 #endif
 
+void SSL_set_psk_find_session_callback(SSL *s, SSL_psk_find_session_cb_func cb)
+{
+    s->psk_find_session_cb = cb;
+}
+
+void SSL_CTX_set_psk_find_session_callback(SSL_CTX *ctx,
+                                           SSL_psk_find_session_cb_func cb)
+{
+    ctx->psk_find_session_cb = cb;
+}
+
+void SSL_set_psk_use_session_callback(SSL *s, SSL_psk_use_session_cb_func cb)
+{
+    s->psk_use_session_cb = cb;
+}
+
+void SSL_CTX_set_psk_use_session_callback(SSL_CTX *ctx,
+                                           SSL_psk_use_session_cb_func cb)
+{
+    ctx->psk_use_session_cb = cb;
+}
+
 void SSL_CTX_set_msg_callback(SSL_CTX *ctx,
                               void (*cb) (int write_p, int version,
                                           int content_type, const void *buf,
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 7dc6cd6..7889ab5 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -485,6 +485,8 @@ struct ssl_session_st {
                                  * in here? */
     size_t master_key_length;
 
+    /* TLSv1.3 early_secret used for external PSKs */
+    unsigned char early_secret[EVP_MAX_MD_SIZE];
     /*
      * For <=TLS1.2 this is the master_key. For TLS1.3 this is the resumption
      * master secret
@@ -952,6 +954,8 @@ struct ssl_ctx_st {
     SSL_psk_client_cb_func psk_client_callback;
     SSL_psk_server_cb_func psk_server_callback;
 # endif
+    SSL_psk_find_session_cb_func psk_find_session_cb;
+    SSL_psk_use_session_cb_func psk_use_session_cb;
 
 # ifndef OPENSSL_NO_SRP
     SRP_CTX srp_ctx;            /* ctx for SRP authentication */
@@ -1102,6 +1106,8 @@ struct ssl_st {
     unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
     /* This can also be in the session once a session is established */
     SSL_SESSION *session;
+    /* TLSv1.3 PSK session */
+    SSL_SESSION *psksession;
     /* Default generate session ID callback. */
     GEN_SESSION_CB generate_session_id;
     /* Used in SSL3 */
@@ -1122,6 +1128,8 @@ struct ssl_st {
     SSL_psk_client_cb_func psk_client_callback;
     SSL_psk_server_cb_func psk_server_callback;
 # endif
+    SSL_psk_find_session_cb_func psk_find_session_cb;
+    SSL_psk_use_session_cb_func psk_use_session_cb;
     SSL_CTX *ctx;
     /* Verified chain of peer */
     STACK_OF(X509) *verified_chain;
diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c
index c7bbc96..df992bd 100644
--- a/ssl/ssl_sess.c
+++ b/ssl/ssl_sess.c
@@ -858,11 +858,23 @@ int SSL_SESSION_get_protocol_version(const SSL_SESSION *s)
     return s->ssl_version;
 }
 
+int SSL_SESSION_set_protocol_version(SSL_SESSION *s, int version)
+{
+    s->ssl_version = version;
+    return 1;
+}
+
 const SSL_CIPHER *SSL_SESSION_get0_cipher(const SSL_SESSION *s)
 {
     return s->cipher;
 }
 
+int SSL_SESSION_set_cipher(SSL_SESSION *s, const SSL_CIPHER *cipher)
+{
+    s->cipher = cipher;
+    return 1;
+}
+
 const char *SSL_SESSION_get0_hostname(const SSL_SESSION *s)
 {
     return s->ext.hostname;
diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c
index d40c34c..4965231 100644
--- a/ssl/statem/extensions.c
+++ b/ssl/statem/extensions.c
@@ -1227,21 +1227,41 @@ static int init_psk_kex_modes(SSL *s, unsigned int context)
 
 int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
                       size_t binderoffset, const unsigned char *binderin,
-                      unsigned char *binderout,
-                      SSL_SESSION *sess, int sign)
+                      unsigned char *binderout, SSL_SESSION *sess, int sign,
+                      int external)
 {
     EVP_PKEY *mackey = NULL;
     EVP_MD_CTX *mctx = NULL;
     unsigned char hash[EVP_MAX_MD_SIZE], binderkey[EVP_MAX_MD_SIZE];
     unsigned char finishedkey[EVP_MAX_MD_SIZE], tmpbinder[EVP_MAX_MD_SIZE];
+    unsigned char *early_secret;
     const char resumption_label[] = "res binder";
-    size_t bindersize, hashsize = EVP_MD_size(md);
+    const char external_label[] = "ext binder";
+    const char *label;
+    size_t bindersize, labelsize, hashsize = EVP_MD_size(md);
     int ret = -1;
 
-    /* Generate the early_secret */
+    if (external) {
+        label = external_label;
+        labelsize = sizeof(external_label) - 1;
+    } else {
+        label = resumption_label;
+        labelsize = sizeof(resumption_label) - 1;
+    }
+
+    /*
+     * Generate the early_secret. On the server side we've selected a PSK to
+     * resume with (internal or external) so we always do this. On the client
+     * side we do this for a non-external (i.e. resumption) PSK so that it
+     * is in place for sending early data. For client side external PSK we
+     * generate it but store it away for later use.
+     */
+    if (s->server || !external)
+        early_secret = (unsigned char *)s->early_secret;
+    else
+        early_secret = (unsigned char *)sess->early_secret;
     if (!tls13_generate_secret(s, md, NULL, sess->master_key,
-                               sess->master_key_length,
-                               (unsigned char *)&s->early_secret)) {
+                               sess->master_key_length, early_secret)) {
         SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
         goto err;
     }
@@ -1259,10 +1279,8 @@ int tls_psk_do_binder(SSL *s, const EVP_MD *md, const unsigned char *msgstart,
     }
 
     /* Generate the binder key */
-    if (!tls13_hkdf_expand(s, md, s->early_secret,
-                           (unsigned char *)resumption_label,
-                           sizeof(resumption_label) - 1, hash, binderkey,
-                           hashsize)) {
+    if (!tls13_hkdf_expand(s, md, early_secret, (unsigned char *)label,
+                           labelsize, hash, binderkey, hashsize)) {
         SSLerr(SSL_F_TLS_PSK_DO_BINDER, ERR_R_INTERNAL_ERROR);
         goto err;
     }
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index 8aa795e..846ee30 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -791,10 +791,13 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
 {
 #ifndef OPENSSL_NO_TLS1_3
     uint32_t now, agesec, agems;
-    size_t hashsize, binderoffset, msglen;
-    unsigned char *binder = NULL, *msgstart = NULL;
-    const EVP_MD *md;
+    size_t reshashsize, pskhashsize, binderoffset, msglen, idlen;
+    unsigned char *resbinder = NULL, *pskbinder = NULL, *msgstart = NULL;
+    const unsigned char *id;
+    const EVP_MD *handmd = NULL, *mdres, *mdpsk;
     EXT_RETURN ret = EXT_RETURN_FAIL;
+    SSL_SESSION *psksess = NULL;
+    int dores = 0;
 
     s->session->ext.tick_identity = TLSEXT_PSK_BAD_IDENTITY;
 
@@ -809,76 +812,140 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
      * so don't add this extension.
      */
     if (s->session->ssl_version != TLS1_3_VERSION
-            || s->session->ext.ticklen == 0)
+            || (s->session->ext.ticklen == 0 && s->psk_use_session_cb == NULL))
         return EXT_RETURN_NOT_SENT;
 
-    if (s->session->cipher == NULL) {
-        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+    if (s->hello_retry_request)
+        handmd = ssl_handshake_md(s);
+
+    if (s->psk_use_session_cb != NULL
+            && !s->psk_use_session_cb(s, handmd, &id, &idlen, &psksess)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, SSL_R_BAD_PSK);
         goto err;
     }
 
-    md = ssl_md(s->session->cipher->algorithm2);
-    if (md == NULL) {
-        /* Don't recognize this cipher so we can't use the session. Ignore it */
-        return EXT_RETURN_NOT_SENT;
-    }
+    if (s->session->ext.ticklen != 0) {
+        /* Get the digest associated with the ciphersuite in the session */
+        if (s->session->cipher == NULL) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+        mdres = ssl_md(s->session->cipher->algorithm2);
+        if (mdres == NULL) {
+            /*
+             * Don't recognize this cipher so we can't use the session.
+             * Ignore it
+             */
+            goto dopsksess;
+        }
+
+        if (s->hello_retry_request && mdres != handmd) {
+            /*
+             * Selected ciphersuite hash does not match the hash for the session
+             * so we can't use it.
+             */
+            goto dopsksess;
+        }
 
-    if (s->hello_retry_request && md != ssl_handshake_md(s)) {
         /*
-         * Selected ciphersuite hash does not match the hash for the session so
-         * we can't use it.
+         * Technically the C standard just says time() returns a time_t and says
+         * nothing about the encoding of that type. In practice most
+         * implementations follow POSIX which holds it as an integral type in
+         * seconds since epoch. We've already made the assumption that we can do
+         * this in multiple places in the code, so portability shouldn't be an
+         * issue.
          */
-        return EXT_RETURN_NOT_SENT;
-    }
+        now = (uint32_t)time(NULL);
+        agesec = now - (uint32_t)s->session->time;
 
-    /*
-     * Technically the C standard just says time() returns a time_t and says
-     * nothing about the encoding of that type. In practice most implementations
-     * follow POSIX which holds it as an integral type in seconds since epoch.
-     * We've already made the assumption that we can do this in multiple places
-     * in the code, so portability shouldn't be an issue.
-     */
-    now = (uint32_t)time(NULL);
-    agesec = now - (uint32_t)s->session->time;
+        if (s->session->ext.tick_lifetime_hint < agesec) {
+            /* Ticket is too old. Ignore it. */
+            goto dopsksess;
+        }
 
-    if (s->session->ext.tick_lifetime_hint < agesec) {
-        /* Ticket is too old. Ignore it. */
-        return EXT_RETURN_NOT_SENT;
-    }
+        /*
+         * Calculate age in ms. We're just doing it to nearest second. Should be
+         * good enough.
+         */
+        agems = agesec * (uint32_t)1000;
 
-    /*
-     * Calculate age in ms. We're just doing it to nearest second. Should be
-     * good enough.
-     */
-    agems = agesec * (uint32_t)1000;
+        if (agesec != 0 && agems / (uint32_t)1000 != agesec) {
+            /*
+             * Overflow. Shouldn't happen unless this is a *really* old session.
+             * If so we just ignore it.
+             */
+            goto dopsksess;
+        }
 
-    if (agesec != 0 && agems / (uint32_t)1000 != agesec) {
         /*
-         * Overflow. Shouldn't happen unless this is a *really* old session. If
-         * so we just ignore it.
+         * Obfuscate the age. Overflow here is fine, this addition is supposed
+         * to be mod 2^32.
          */
-        return EXT_RETURN_NOT_SENT;
+        agems += s->session->ext.tick_age_add;
+
+        reshashsize = EVP_MD_size(mdres);
+        dores = 1;
     }
 
-    /*
-     * Obfuscate the age. Overflow here is fine, this addition is supposed to
-     * be mod 2^32.
-     */
-    agems += s->session->ext.tick_age_add;
+ dopsksess:
+    if (!dores && psksess == NULL)
+        return EXT_RETURN_NOT_SENT;
 
-    hashsize = EVP_MD_size(md);
+    if (psksess != NULL) {
+        mdpsk = ssl_md(psksess->cipher->algorithm2);
+        if (mdpsk == NULL) {
+            /*
+             * Don't recognize this cipher so we can't use the session.
+             * If this happens it's an application bug.
+             */
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, SSL_R_BAD_PSK);
+            goto err;
+        }
+
+        if (s->hello_retry_request && mdpsk != handmd) {
+            /*
+             * Selected ciphersuite hash does not match the hash for the PSK
+             * session. This is an application bug.
+             */
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, SSL_R_BAD_PSK);
+            goto err;
+        }
+
+        pskhashsize = EVP_MD_size(mdpsk);
+    }
 
     /* Create the extension, but skip over the binder for now */
     if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_psk)
             || !WPACKET_start_sub_packet_u16(pkt)
-            || !WPACKET_start_sub_packet_u16(pkt)
-            || !WPACKET_sub_memcpy_u16(pkt, s->session->ext.tick,
-                                       s->session->ext.ticklen)
-            || !WPACKET_put_bytes_u32(pkt, agems)
-            || !WPACKET_close(pkt)
+            || !WPACKET_start_sub_packet_u16(pkt)) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (dores) {
+        if (!WPACKET_sub_memcpy_u16(pkt, s->session->ext.tick,
+                                           s->session->ext.ticklen)
+                || !WPACKET_put_bytes_u32(pkt, agems)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    if (psksess != NULL) {
+        if (!WPACKET_sub_memcpy_u16(pkt, id, idlen)
+                || !WPACKET_put_bytes_u32(pkt, 0)) {
+            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+            goto err;
+        }
+    }
+
+    if (!WPACKET_close(pkt)
             || !WPACKET_get_total_written(pkt, &binderoffset)
             || !WPACKET_start_sub_packet_u16(pkt)
-            || !WPACKET_sub_allocate_bytes_u8(pkt, hashsize, &binder)
+            || (dores
+                && !WPACKET_sub_allocate_bytes_u8(pkt, reshashsize, &resbinder))
+            || (psksess != NULL
+                && !WPACKET_sub_allocate_bytes_u8(pkt, pskhashsize, &pskbinder))
             || !WPACKET_close(pkt)
             || !WPACKET_close(pkt)
             || !WPACKET_get_total_written(pkt, &msglen)
@@ -893,16 +960,31 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
 
     msgstart = WPACKET_get_curr(pkt) - msglen;
 
-    if (tls_psk_do_binder(s, md, msgstart, binderoffset, NULL, binder,
-                          s->session, 1) != 1) {
+    if (dores
+            && tls_psk_do_binder(s, mdres, msgstart, binderoffset, NULL,
+                                 resbinder, s->session, 1, 0) != 1) {
         SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
         goto err;
     }
 
-    s->session->ext.tick_identity = 0;
+    if (psksess != NULL
+            && tls_psk_do_binder(s, mdpsk, msgstart, binderoffset, NULL,
+                                 pskbinder, psksess, 1, 1) != 1) {
+        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
+
+    if (dores)
+        s->session->ext.tick_identity = 0;
+    SSL_SESSION_free(s->psksession);
+    s->psksession = psksess;
+    if (psksess != NULL)
+        s->psksession->ext.tick_identity = (dores ? 1 : 0);
+    psksess = NULL;
 
     ret = EXT_RETURN_SENT;
  err:
+    SSL_SESSION_free(psksess);
     return ret;
 #else
     return 1;
@@ -1508,12 +1590,24 @@ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
         return 0;
     }
 
-    if (s->session->ext.tick_identity != (int)identity) {
+    if (s->session->ext.tick_identity == (int)identity) {
+        s->hit = 1;
+        SSL_SESSION_free(s->psksession);
+        s->psksession = NULL;
+        return 1;
+    }
+
+    if (s->psksession == NULL
+            || s->psksession->ext.tick_identity != (int)identity) {
         *al = SSL_AD_ILLEGAL_PARAMETER;
         SSLerr(SSL_F_TLS_PARSE_STOC_PSK, SSL_R_BAD_PSK_IDENTITY);
         return 0;
     }
 
+    SSL_SESSION_free(s->session);
+    s->session = s->psksession;
+    s->psksession = NULL;
+    memcpy(s->early_secret, s->session->early_secret, EVP_MAX_MD_SIZE);
     s->hit = 1;
 #endif
 
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index 39e6c07..3da9f55 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -686,9 +686,8 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
     PACKET identities, binders, binder;
     size_t binderoffset, hashsize;
     SSL_SESSION *sess = NULL;
-    unsigned int id, i;
+    unsigned int id, i, ext = 0;
     const EVP_MD *md = NULL;
-    uint32_t ticket_age = 0, now, agesec, agems;
 
     /*
      * If we have no PSK kex mode that we recognise then we can't resume so
@@ -706,7 +705,6 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
     for (id = 0; PACKET_remaining(&identities) != 0; id++) {
         PACKET identity;
         unsigned long ticket_agel;
-        int ret;
 
         if (!PACKET_get_length_prefixed_2(&identities, &identity)
                 || !PACKET_get_net_4(&identities, &ticket_agel)) {
@@ -714,16 +712,71 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             return 0;
         }
 
-        ticket_age = (uint32_t)ticket_agel;
-
-        ret = tls_decrypt_ticket(s, PACKET_data(&identity),
-                                 PACKET_remaining(&identity), NULL, 0, &sess);
-        if (ret == TICKET_FATAL_ERR_MALLOC || ret == TICKET_FATAL_ERR_OTHER) {
+        if (s->psk_find_session_cb != NULL
+                && !s->psk_find_session_cb(s, PACKET_data(&identity),
+                                           PACKET_remaining(&identity),
+                                           &sess)) {
             *al = SSL_AD_INTERNAL_ERROR;
             return 0;
         }
-        if (ret == TICKET_NO_DECRYPT)
-            continue;
+
+        if (sess != NULL) {
+            /* We found a PSK */
+            SSL_SESSION *sesstmp = ssl_session_dup(sess, 0);
+
+            if (sesstmp == NULL) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                return 0;
+            }
+            SSL_SESSION_free(sess);
+            sess = sesstmp;
+
+            /*
+             * We've just been told to use this session for this context so
+             * make sure the sid_ctx matches up.
+             */
+            memcpy(sess->sid_ctx, s->sid_ctx, s->sid_ctx_length);
+            sess->sid_ctx_length = s->sid_ctx_length;
+            ext = 1;
+        } else {
+            uint32_t ticket_age = 0, now, agesec, agems;
+            int ret = tls_decrypt_ticket(s, PACKET_data(&identity),
+                                         PACKET_remaining(&identity), NULL, 0,
+                                         &sess);
+
+            if (ret == TICKET_FATAL_ERR_MALLOC
+                    || ret == TICKET_FATAL_ERR_OTHER) {
+                *al = SSL_AD_INTERNAL_ERROR;
+                return 0;
+            }
+            if (ret == TICKET_NO_DECRYPT)
+                continue;
+
+            ticket_age = (uint32_t)ticket_agel;
+            now = (uint32_t)time(NULL);
+            agesec = now - (uint32_t)sess->time;
+            agems = agesec * (uint32_t)1000;
+            ticket_age -= sess->ext.tick_age_add;
+
+            /*
+             * For simplicity we do our age calculations in seconds. If the
+             * client does it in ms then it could appear that their ticket age
+             * is longer than ours (our ticket age calculation should always be
+             * slightly longer than the client's due to the network latency).
+             * Therefore we add 1000ms to our age calculation to adjust for
+             * rounding errors.
+             */
+            if (sess->timeout >= (long)agesec
+                    && agems / (uint32_t)1000 == agesec
+                    && ticket_age <= agems + 1000
+                    && ticket_age + TICKET_AGE_ALLOWANCE >= agems + 1000) {
+                /*
+                 * Ticket age is within tolerance and not expired. We allow it
+                 * for early data
+                 */
+                s->ext.early_data_ok = 1;
+            }
+        }
 
         md = ssl_md(sess->cipher->algorithm2);
         if (md != ssl_md(s->s3->tmp.new_cipher->algorithm2)) {
@@ -732,12 +785,6 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             sess = NULL;
             continue;
         }
-
-        /*
-         * TODO(TLS1.3): Somehow we need to handle the case of a ticket renewal.
-         * Ignored for now
-         */
-
         break;
     }
 
@@ -763,7 +810,7 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
             || tls_psk_do_binder(s, md,
                                  (const unsigned char *)s->init_buf->data,
                                  binderoffset, PACKET_data(&binder), NULL,
-                                 sess, 0) != 1) {
+                                 sess, 0, ext) != 1) {
         *al = SSL_AD_DECODE_ERROR;
         SSLerr(SSL_F_TLS_PARSE_CTOS_PSK, ERR_R_INTERNAL_ERROR);
         goto err;
@@ -771,31 +818,6 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
 
     sess->ext.tick_identity = id;
 
-    now = (uint32_t)time(NULL);
-    agesec = now - (uint32_t)sess->time;
-    agems = agesec * (uint32_t)1000;
-    ticket_age -= sess->ext.tick_age_add;
-
-
-    /*
-     * For simplicity we do our age calculations in seconds. If the client does
-     * it in ms then it could appear that their ticket age is longer than ours
-     * (our ticket age calculation should always be slightly longer than the
-     * client's due to the network latency). Therefore we add 1000ms to our age
-     * calculation to adjust for rounding errors.
-     */
-    if (sess->timeout >= (long)agesec
-            && agems / (uint32_t)1000 == agesec
-            && ticket_age <= agems + 1000
-            && ticket_age + TICKET_AGE_ALLOWANCE >= agems + 1000) {
-        /*
-         * Ticket age is within tolerance and not expired. We allow it for early
-         * data
-         */
-        s->ext.early_data_ok = 1;
-    }
-
-
     SSL_SESSION_free(s->session);
     s->session = sess;
     return 1;
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index b6ce4cc..1f8c22d 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -183,7 +183,7 @@ __owur int tls_psk_do_binder(SSL *s, const EVP_MD *md,
                              const unsigned char *msgstart,
                              size_t binderoffset, const unsigned char *binderin,
                              unsigned char *binderout,
-                             SSL_SESSION *sess, int sign);
+                             SSL_SESSION *sess, int sign, int external);
 
 /* Server Extension processing */
 int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
diff --git a/test/sslapitest.c b/test/sslapitest.c
index a161989..215035a 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -1927,6 +1927,187 @@ static int test_ciphersuite_change(void)
     return testresult;
 }
 
+
+static SSL_SESSION *psk = NULL;
+static const char *pskid = "Identity";
+static const char *srvid;
+
+static int use_session_cb_cnt = 0;
+static int find_session_cb_cnt = 0;
+
+static int use_session_cb(SSL *ssl, const EVP_MD *md, const unsigned char **id,
+                          size_t *idlen, SSL_SESSION **sess)
+{
+    switch (++use_session_cb_cnt) {
+    case 1:
+        /* The first call should always have a NULL md */
+        if (md != NULL)
+            return 0;
+        break;
+
+    case 2:
+        /* The second call should always have an md */
+        if (md == NULL)
+            return 0;
+        break;
+
+    default:
+        /* We should only be called a maximum of twice */
+        return 0;
+    }
+
+    if (psk != NULL)
+        SSL_SESSION_up_ref(psk);
+
+    *sess = psk;
+    *id = (const unsigned char *)pskid;
+    *idlen = strlen(pskid);
+
+    return 1;
+}
+
+static int find_session_cb(SSL *ssl, const unsigned char *identity,
+                           size_t identity_len, SSL_SESSION **sess)
+{
+    find_session_cb_cnt++;
+
+    /* We should only ever be called a maximum of twice per connection */
+    if (find_session_cb_cnt > 2)
+        return 0;
+
+    if (psk == NULL)
+        return 0;
+
+    /* Identity should match that set by the client */
+    if (strlen(srvid) != identity_len
+            || strncmp(srvid, (const char *)identity, identity_len) != 0) {
+        /* No PSK found, continue but without a PSK */
+        *sess = NULL;
+        return 1;
+    }
+
+    SSL_SESSION_up_ref(psk);
+    *sess = psk;
+
+    return 1;
+}
+
+#define TLS13_AES_256_GCM_SHA384_BYTES  ((const unsigned char *)"\x13\x02")
+
+static int test_tls13_psk(void)
+{
+    SSL_CTX *sctx = NULL, *cctx = NULL;
+    SSL *serverssl = NULL, *clientssl = NULL;
+    const SSL_CIPHER *cipher = NULL;
+    const unsigned char key[] = {
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+        0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
+    };
+    int testresult = 0;
+
+    if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
+                                       TLS_client_method(), &sctx,
+                                       &cctx, cert, privkey)))
+        goto end;
+
+    SSL_CTX_set_psk_use_session_callback(cctx, use_session_cb);
+    SSL_CTX_set_psk_find_session_callback(sctx, find_session_cb);
+    srvid = pskid;
+
+    /* Check we can create a connection if callback decides not to send a PSK */
+    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_NONE))
+            || !TEST_false(SSL_session_reused(clientssl))
+            || !TEST_false(SSL_session_reused(serverssl))
+            || !TEST_true(use_session_cb_cnt == 1)
+            || !TEST_true(find_session_cb_cnt == 0))
+        goto end;
+
+    shutdown_ssl_connection(serverssl, clientssl);
+    serverssl = clientssl = NULL;
+    use_session_cb_cnt = 0;
+
+    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL)))
+        goto end;
+
+    /* Create the PSK */
+    cipher = SSL_CIPHER_find(clientssl, TLS13_AES_256_GCM_SHA384_BYTES);
+    psk = SSL_SESSION_new();
+    if (!TEST_ptr(psk)
+            || !TEST_ptr(cipher)
+            || !TEST_true(SSL_SESSION_set1_master_key(psk, key, sizeof(key)))
+            || !TEST_true(SSL_SESSION_set_cipher(psk, cipher))
+            || !TEST_true(SSL_SESSION_set_protocol_version(psk,
+                                                           TLS1_3_VERSION)))
+        goto end;
+
+    /* Check we can create a connection and the PSK is used */
+    if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))
+            || !TEST_true(SSL_session_reused(clientssl))
+            || !TEST_true(SSL_session_reused(serverssl))
+            || !TEST_true(use_session_cb_cnt == 1)
+            || !TEST_true(find_session_cb_cnt == 1))
+        goto end;
+
+    shutdown_ssl_connection(serverssl, clientssl);
+    serverssl = clientssl = NULL;
+    use_session_cb_cnt = find_session_cb_cnt = 0;
+
+    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL)))
+        goto end;
+
+    /* Force an HRR */
+    if (!TEST_true(SSL_set1_groups_list(serverssl, "P-256")))
+        goto end;
+
+    /*
+     * Check we can create a connection, the PSK is used and the callbacks are
+     * called twice.
+     */
+    if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))
+            || !TEST_true(SSL_session_reused(clientssl))
+            || !TEST_true(SSL_session_reused(serverssl))
+            || !TEST_true(use_session_cb_cnt == 2)
+            || !TEST_true(find_session_cb_cnt == 2))
+        goto end;
+
+    shutdown_ssl_connection(serverssl, clientssl);
+    serverssl = clientssl = NULL;
+    use_session_cb_cnt = find_session_cb_cnt = 0;
+
+    /*
+     * Check that if the server rejects the PSK we can still connect, but with
+     * a full handshake
+     */
+    srvid = "Dummy Identity";
+    if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+                                             NULL, NULL))
+            || !TEST_true(create_ssl_connection(serverssl, clientssl,
+                                                SSL_ERROR_NONE))
+            || !TEST_false(SSL_session_reused(clientssl))
+            || !TEST_false(SSL_session_reused(serverssl))
+            || !TEST_true(use_session_cb_cnt == 1)
+            || !TEST_true(find_session_cb_cnt == 1))
+        goto end;
+
+    shutdown_ssl_connection(serverssl, clientssl);
+    serverssl = clientssl = NULL;
+    testresult = 1;
+
+ end:
+    SSL_SESSION_free(psk);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+    return testresult;
+}
+
 #endif /* OPENSSL_NO_TLS1_3 */
 
 static int clntaddoldcb = 0;
@@ -2352,6 +2533,7 @@ int test_main(int argc, char *argv[])
 #endif
 #ifndef OPENSSL_NO_TLS1_3
     ADD_TEST(test_ciphersuite_change);
+    ADD_TEST(test_tls13_psk);
     ADD_ALL_TESTS(test_custom_exts, 5);
 #else
     ADD_ALL_TESTS(test_custom_exts, 3);
diff --git a/test/ssltestlib.c b/test/ssltestlib.c
index 4ee0bae..64acea3 100644
--- a/test/ssltestlib.c
+++ b/test/ssltestlib.c
@@ -661,3 +661,11 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want)
 
     return 1;
 }
+
+void shutdown_ssl_connection(SSL *serverssl, SSL *clientssl)
+{
+    SSL_shutdown(clientssl);
+    SSL_shutdown(serverssl);
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+}
diff --git a/test/ssltestlib.h b/test/ssltestlib.h
index e74a5cc..385833b 100644
--- a/test/ssltestlib.h
+++ b/test/ssltestlib.h
@@ -18,6 +18,7 @@ int create_ssl_ctx_pair(const SSL_METHOD *sm, const SSL_METHOD *cm,
 int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
                        SSL **cssl, BIO *s_to_c_fbio, BIO *c_to_s_fbio);
 int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want);
+void shutdown_ssl_connection(SSL *serverssl, SSL *clientssl);
 
 /* Note: Not thread safe! */
 const BIO_METHOD *bio_f_tls_dump_filter(void);
diff --git a/util/libssl.num b/util/libssl.num
index 4cf8227..ae16d13 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -451,3 +451,11 @@ SSL_set_record_padding_callback_arg     451	1_1_1	EXIST::FUNCTION:
 SSL_CTX_set_record_padding_callback_arg 452	1_1_1	EXIST::FUNCTION:
 SSL_CTX_use_serverinfo_ex               453	1_1_1	EXIST::FUNCTION:
 SSL_early_get1_extensions_present       454	1_1_1	EXIST::FUNCTION:
+SSL_set_psk_find_session_callback       455	1_1_1	EXIST::FUNCTION:
+SSL_set_psk_use_session_callback        456	1_1_1	EXIST::FUNCTION:
+SSL_CTX_set_psk_use_session_callback    457	1_1_1	EXIST::FUNCTION:
+SSL_CTX_set_psk_find_session_callback   458	1_1_1	EXIST::FUNCTION:
+SSL_CIPHER_get_handshake_digest         459	1_1_1	EXIST::FUNCTION:
+SSL_SESSION_set1_master_key             460	1_1_1	EXIST::FUNCTION:
+SSL_SESSION_set_cipher                  461	1_1_1	EXIST::FUNCTION:
+SSL_SESSION_set_protocol_version        462	1_1_1	EXIST::FUNCTION:
diff --git a/util/private.num b/util/private.num
index 9488f00..2ad754f 100644
--- a/util/private.num
+++ b/util/private.num
@@ -22,6 +22,10 @@ GEN_SESSION_CB                          datatype
 OPENSSL_Applink                         external
 SSL_CTX_keylog_cb_func                  datatype
 SSL_early_cb_fn                         datatype
+SSL_psk_client_cb_func                  datatype
+SSL_psk_find_session_cb_func            datatype
+SSL_psk_server_cb_func                  datatype
+SSL_psk_use_session_cb_func             datatype
 SSL_verify_cb                           datatype
 UI                                      datatype
 UI_METHOD                               datatype


More information about the openssl-commits mailing list