Fix PSK identity hint handling.
[openssl.git] / ssl / s3_srvr.c
index 6bc80d579b7ec720494e5e0e7472a8263f83083b..e864ad158076cfaaef10f9d7c57fdad06629748f 100644 (file)
@@ -281,7 +281,6 @@ int ssl3_accept(SSL *s)
 
             s->init_num = 0;
             s->s3->flags &= ~TLS1_FLAGS_SKIP_CERT_VERIFY;
-            s->s3->flags &= ~SSL3_FLAGS_CCS_OK;
             /*
              * Should have been reset by ssl3_get_finished, too.
              */
@@ -387,19 +386,15 @@ int ssl3_accept(SSL *s)
             ret = ssl3_send_server_hello(s);
             if (ret <= 0)
                 goto end;
-#ifndef OPENSSL_NO_TLSEXT
+
             if (s->hit) {
                 if (s->tlsext_ticket_expected)
                     s->state = SSL3_ST_SW_SESSION_TICKET_A;
                 else
                     s->state = SSL3_ST_SW_CHANGE_A;
-            }
-#else
-            if (s->hit)
-                s->state = SSL3_ST_SW_CHANGE_A;
-#endif
-            else
+            } else {
                 s->state = SSL3_ST_SW_CERT_A;
+            }
             s->init_num = 0;
             break;
 
@@ -407,14 +402,12 @@ int ssl3_accept(SSL *s)
         case SSL3_ST_SW_CERT_B:
             /* Check if it is anon DH or anon ECDH, */
             /* normal PSK or SRP */
-            if (!
-                (s->s3->tmp.
-                 new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP))
-&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
+            if (!(s->s3->tmp.new_cipher->algorithm_auth &
+                 (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
                 ret = ssl3_send_server_certificate(s);
                 if (ret <= 0)
                     goto end;
-#ifndef OPENSSL_NO_TLSEXT
+
                 if (s->tlsext_status_expected)
                     s->state = SSL3_ST_SW_CERT_STATUS_A;
                 else
@@ -423,12 +416,6 @@ int ssl3_accept(SSL *s)
                 skip = 1;
                 s->state = SSL3_ST_SW_KEY_EXCH_A;
             }
-#else
-            } else
-                skip = 1;
-
-            s->state = SSL3_ST_SW_KEY_EXCH_A;
-#endif
             s->init_num = 0;
             break;
 
@@ -456,7 +443,10 @@ int ssl3_accept(SSL *s)
                  * provided
                  */
 #ifndef OPENSSL_NO_PSK
-                || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint)
+                /* Only send SKE if we have identity hint for plain PSK */
+                || ((alg_k & (SSL_kPSK | SSL_kRSAPSK)) && s->cert->psk_identity_hint)
+                /* For other PSK always send SKE */
+                || (alg_k & (SSL_PSK & (SSL_kDHEPSK | SSL_kECDHEPSK)))
 #endif
 #ifndef OPENSSL_NO_SRP
                 /* SRP: send ServerKeyExchange */
@@ -512,16 +502,14 @@ int ssl3_accept(SSL *s)
                     * With normal PSK Certificates and Certificate Requests
                     * are omitted
                     */
-                   || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
+                   || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
                 /* no cert request */
                 skip = 1;
                 s->s3->tmp.cert_request = 0;
                 s->state = SSL3_ST_SW_SRVR_DONE_A;
-                if (s->s3->handshake_buffer) {
-                    if (!ssl3_digest_cached_records(s)) {
-                        s->state = SSL_ST_ERR;
-                        return -1;
-                    }
+                if (!ssl3_digest_cached_records(s, 0)) {
+                    s->state = SSL_ST_ERR;
+                    return -1;
                 }
             } else {
                 s->s3->tmp.cert_request = 1;
@@ -587,14 +575,7 @@ int ssl3_accept(SSL *s)
                  * not sent. Also for GOST ciphersuites when the client uses
                  * its key from the certificate for key exchange.
                  */
-#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
-                s->state = SSL3_ST_SR_FINISHED_A;
-#else
-                if (s->s3->next_proto_neg_seen)
-                    s->state = SSL3_ST_SR_NEXT_PROTO_A;
-                else
-                    s->state = SSL3_ST_SR_FINISHED_A;
-#endif
+                s->state = SSL3_ST_SR_CHANGE_A;
                 s->init_num = 0;
             } else if (SSL_USE_SIGALGS(s)) {
                 s->state = SSL3_ST_SR_CERT_VRFY_A;
@@ -608,14 +589,11 @@ int ssl3_accept(SSL *s)
                 }
                 /*
                  * For sigalgs freeze the handshake buffer. If we support
-                 * extms we've done this already.
+                 * extms we've done this already so this is a no-op
                  */
-                if (!(s->s3->flags & SSL_SESS_FLAG_EXTMS)) {
-                    s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
-                    if (!ssl3_digest_cached_records(s)) {
-                        s->state = SSL_ST_ERR;
-                        return -1;
-                    }
+                if (!ssl3_digest_cached_records(s, 1)) {
+                    s->state = SSL_ST_ERR;
+                    return -1;
                 }
             } else {
                 int offset = 0;
@@ -630,11 +608,9 @@ int ssl3_accept(SSL *s)
                  * CertificateVerify should be generalized. But it is next
                  * step
                  */
-                if (s->s3->handshake_buffer) {
-                    if (!ssl3_digest_cached_records(s)) {
-                        s->state = SSL_ST_ERR;
-                        return -1;
-                    }
+                if (!ssl3_digest_cached_records(s, 0)) {
+                    s->state = SSL_ST_ERR;
+                    return -1;
                 }
                 for (dgst_num = 0; dgst_num < SSL_MAX_DIGEST; dgst_num++)
                     if (s->s3->handshake_dgst[dgst_num]) {
@@ -666,32 +642,13 @@ int ssl3_accept(SSL *s)
             if (ret <= 0)
                 goto end;
 
-#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
-            s->state = SSL3_ST_SR_FINISHED_A;
-#else
-            if (s->s3->next_proto_neg_seen)
-                s->state = SSL3_ST_SR_NEXT_PROTO_A;
-            else
-                s->state = SSL3_ST_SR_FINISHED_A;
-#endif
+            s->state = SSL3_ST_SR_CHANGE_A;
             s->init_num = 0;
             break;
 
-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+#if !defined(OPENSSL_NO_NEXTPROTONEG)
         case SSL3_ST_SR_NEXT_PROTO_A:
         case SSL3_ST_SR_NEXT_PROTO_B:
-            /*
-             * Enable CCS for NPN. Receiving a CCS clears the flag, so make
-             * sure not to re-enable it to ban duplicates. This *should* be the
-             * first time we have received one - but we check anyway to be
-             * cautious.
-             * s->s3->change_cipher_spec is set when a CCS is
-             * processed in s3_pkt.c, and remains set until
-             * the client's Finished message is read.
-             */
-            if (!s->s3->change_cipher_spec)
-                s->s3->flags |= SSL3_FLAGS_CCS_OK;
-
             ret = ssl3_get_next_proto(s);
             if (ret <= 0)
                 goto end;
@@ -700,34 +657,40 @@ int ssl3_accept(SSL *s)
             break;
 #endif
 
+
+        case SSL3_ST_SR_CHANGE_A:
+        case SSL3_ST_SR_CHANGE_B:
+            ret = ssl3_get_change_cipher_spec(s, SSL3_ST_SR_CHANGE_A,
+                                              SSL3_ST_SR_CHANGE_B);
+            if (ret <= 0)
+                goto end;
+
+#if defined(OPENSSL_NO_NEXTPROTONEG)
+            s->state = SSL3_ST_SR_FINISHED_A;
+#else
+            if (s->s3->next_proto_neg_seen)
+                s->state = SSL3_ST_SR_NEXT_PROTO_A;
+            else
+                s->state = SSL3_ST_SR_FINISHED_A;
+#endif
+            s->init_num = 0;
+            break;
+
         case SSL3_ST_SR_FINISHED_A:
         case SSL3_ST_SR_FINISHED_B:
-            /*
-             * Enable CCS for handshakes without NPN. In NPN the CCS flag has
-             * already been set. Receiving a CCS clears the flag, so make
-             * sure not to re-enable it to ban duplicates.
-             * s->s3->change_cipher_spec is set when a CCS is
-             * processed in s3_pkt.c, and remains set until
-             * the client's Finished message is read.
-             */
-            if (!s->s3->change_cipher_spec)
-                s->s3->flags |= SSL3_FLAGS_CCS_OK;
             ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A,
                                     SSL3_ST_SR_FINISHED_B);
             if (ret <= 0)
                 goto end;
             if (s->hit)
                 s->state = SSL_ST_OK;
-#ifndef OPENSSL_NO_TLSEXT
             else if (s->tlsext_ticket_expected)
                 s->state = SSL3_ST_SW_SESSION_TICKET_A;
-#endif
             else
                 s->state = SSL3_ST_SW_CHANGE_A;
             s->init_num = 0;
             break;
 
-#ifndef OPENSSL_NO_TLSEXT
         case SSL3_ST_SW_SESSION_TICKET_A:
         case SSL3_ST_SW_SESSION_TICKET_B:
             ret = ssl3_send_newsession_ticket(s);
@@ -746,8 +709,6 @@ int ssl3_accept(SSL *s)
             s->init_num = 0;
             break;
 
-#endif
-
         case SSL3_ST_SW_CHANGE_A:
         case SSL3_ST_SW_CHANGE_B:
 
@@ -790,14 +751,7 @@ int ssl3_accept(SSL *s)
                 goto end;
             s->state = SSL3_ST_SW_FLUSH;
             if (s->hit) {
-#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
-                s->s3->tmp.next_state = SSL3_ST_SR_FINISHED_A;
-#else
-                if (s->s3->next_proto_neg_seen) {
-                    s->s3->tmp.next_state = SSL3_ST_SR_NEXT_PROTO_A;
-                } else
-                    s->s3->tmp.next_state = SSL3_ST_SR_FINISHED_A;
-#endif
+                s->s3->tmp.next_state = SSL3_ST_SR_CHANGE_A;
             } else
                 s->s3->tmp.next_state = SSL_ST_OK;
             s->init_num = 0;
@@ -883,18 +837,17 @@ int ssl3_send_hello_request(SSL *s)
 
 int ssl3_get_client_hello(SSL *s)
 {
-    int i, complen, j, ok, al = SSL_AD_INTERNAL_ERROR, ret = -1;
-    unsigned int cookie_len;
+    int i, ok, al = SSL_AD_INTERNAL_ERROR, ret = -1;
+    unsigned int j, complen = 0;
     long n;
     unsigned long id;
-    unsigned char *p, *d;
     SSL_CIPHER *c;
 #ifndef OPENSSL_NO_COMP
-    unsigned char *q = NULL;
     SSL_COMP *comp = NULL;
 #endif
     STACK_OF(SSL_CIPHER) *ciphers = NULL;
     int protverr = 1;
+    PACKET pkt, cipher_suite, compression;
 
     if (s->state == SSL3_ST_SR_CLNT_HELLO_C && !s->first_packet)
         goto retry_cert;
@@ -918,10 +871,16 @@ int ssl3_get_client_hello(SSL *s)
     if (!ok)
         return ((int)n);
     s->first_packet = 0;
-    d = p = (unsigned char *)s->init_msg;
+    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
+        SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+        al = SSL_AD_INTERNAL_ERROR;
+        goto f_err;
+    }
 
     /* First lets get s->client_version set correctly */
     if (RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
+        unsigned int version;
+        unsigned int mt;
         /*-
          * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2
          * header is sent directly on the wire, not wrapped as a TLS
@@ -937,7 +896,8 @@ int ssl3_get_client_hello(SSL *s)
          * ...   ...
          */
 
-        if (p[0] != SSL2_MT_CLIENT_HELLO) {
+        if (!PACKET_get_1(&pkt, &mt)
+                || mt != SSL2_MT_CLIENT_HELLO) {
             /*
              * Should never happen. We should have tested this in the record
              * layer in order to have determined that this is a SSLv2 record
@@ -947,13 +907,18 @@ int ssl3_get_client_hello(SSL *s)
             goto err;
         }
 
-        if ((p[1] == 0x00) && (p[2] == 0x02)) {
+        if (!PACKET_get_net_2(&pkt, &version)) {
+            /* No protocol version supplied! */
+            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
+            goto err;
+        }
+        if (version == 0x0002) {
             /* This is real SSLv2. We don't support it. */
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
             goto err;
-        } else if (p[1] == SSL3_VERSION_MAJOR) {
+        } else if ((version & 0xff00) == (SSL3_VERSION_MAJOR << 8)) {
             /* SSLv3/TLS */
-            s->client_version = (((int)p[1]) << 8) | (int)p[2];
+            s->client_version = version;
         } else {
             /* No idea what protocol this is */
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL);
@@ -961,20 +926,14 @@ int ssl3_get_client_hello(SSL *s)
         }
     } else {
         /*
-         * 2 bytes for client version, SSL3_RANDOM_SIZE bytes for random, 1 byte
-         * for session id length
+         * use version from inside client hello, not from record header (may
+         * differ: see RFC 2246, Appendix E, second paragraph)
          */
-        if (n < 2 + SSL3_RANDOM_SIZE + 1) {
+        if(!PACKET_get_net_2(&pkt, (unsigned int *)&s->client_version)) {
             al = SSL_AD_DECODE_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
             goto f_err;
         }
-
-        /*
-         * use version from inside client hello, not from record header (may
-         * differ: see RFC 2246, Appendix E, second paragraph)
-         */
-        s->client_version = (((int)p[0]) << 8) | (int)p[1];
     }
 
     /* Do SSL/TLS version negotiation if applicable */
@@ -1051,27 +1010,31 @@ int ssl3_get_client_hello(SSL *s)
          * Note, this is only for SSLv3+ using the backward compatible format.
          * Real SSLv2 is not supported, and is rejected above.
          */
-        unsigned int csl, sil, cl;
+        unsigned int cipher_len, session_id_len, challenge_len;
 
-        p += 3;
-        n2s(p, csl);
-        n2s(p, sil);
-        n2s(p, cl);
-
-        if (csl + sil + cl + MIN_SSL2_RECORD_LEN != (unsigned int) n) {
+        if (!PACKET_get_net_2(&pkt, &cipher_len)
+                || !PACKET_get_net_2(&pkt, &session_id_len)
+                || !PACKET_get_net_2(&pkt, &challenge_len)) {
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_RECORD_LENGTH_MISMATCH);
             al = SSL_AD_DECODE_ERROR;
             goto f_err;
         }
 
-        if (csl == 0) {
+        if (cipher_len == 0) {
             /* we need at least one cipher */
             al = SSL_AD_ILLEGAL_PARAMETER;
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_CIPHERS_SPECIFIED);
             goto f_err;
         }
 
-        if (ssl_bytes_to_cipher_list(s, p, csl, &(ciphers), 1) == NULL) {
+        if (!PACKET_get_sub_packet(&pkt, &cipher_suite, cipher_len)) {
+            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_RECORD_LENGTH_MISMATCH);
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
+
+        if (ssl_bytes_to_cipher_list(s, PACKET_data(&cipher_suite),
+                                     cipher_len, &(ciphers), 1) == NULL) {
             goto err;
         }
 
@@ -1079,25 +1042,39 @@ int ssl3_get_client_hello(SSL *s)
          * Ignore any session id. We don't allow resumption in a backwards
          * compatible ClientHello
          */
+        if (!PACKET_forward(&pkt, session_id_len)) {
+            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_RECORD_LENGTH_MISMATCH);
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
         s->hit = 0;
 
         if (!ssl_get_new_session(s, 1))
             goto err;
 
         /* Load the client random */
-        i = (cl > SSL3_RANDOM_SIZE) ? SSL3_RANDOM_SIZE : cl;
+        i = challenge_len > SSL3_RANDOM_SIZE ? SSL3_RANDOM_SIZE : challenge_len;
         memset(s->s3->client_random, 0, SSL3_RANDOM_SIZE);
-        memcpy(s->s3->client_random, &(p[csl + sil]), i);
-
-        /* Set p to end of packet to ensure we don't look for extensions */
-        p = d + n;
-
-        /* No compression, so set complen to 0 */
-        complen = 0;
+        if (!PACKET_peek_copy_bytes(&pkt,
+                                    s->s3->client_random + SSL3_RANDOM_SIZE - i,
+                                    i)
+                || !PACKET_forward(&pkt, challenge_len)
+                || PACKET_remaining(&pkt) != 0) {
+            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_RECORD_LENGTH_MISMATCH);
+            al = SSL_AD_DECODE_ERROR;
+            goto f_err;
+        }
     } else {
         /* If we get here we've got SSLv3+ in an SSLv3+ record */
-
-        p += 2;
+        PACKET session_id;
+        unsigned int cookie_len;
+        /* load the client random and get the session-id */
+        if (!PACKET_copy_bytes(&pkt, s->s3->client_random, SSL3_RANDOM_SIZE)
+               || !PACKET_get_length_prefixed_1(&pkt, &session_id)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
+            goto f_err;
+        }
 
         /*
          * If we require cookies and this ClientHello doesn't contain one, just
@@ -1105,34 +1082,17 @@ int ssl3_get_client_hello(SSL *s)
          * cookie length...
          */
         if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) {
-            unsigned int session_length, cookie_length;
 
-            session_length = *(p + SSL3_RANDOM_SIZE);
-
-            if (p + SSL3_RANDOM_SIZE + session_length + 1 >= d + n) {
+            if (!PACKET_peek_1(&pkt, &cookie_len)) {
                 al = SSL_AD_DECODE_ERROR;
                 SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
                 goto f_err;
             }
-            cookie_length = *(p + SSL3_RANDOM_SIZE + session_length + 1);
 
-            if (cookie_length == 0)
+            if (cookie_len == 0)
                 return 1;
         }
 
-        /* load the client random */
-        memcpy(s->s3->client_random, p, SSL3_RANDOM_SIZE);
-        p += SSL3_RANDOM_SIZE;
-
-        /* get the session-id */
-        j = *(p++);
-
-        if (p + j > d + n) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
-            goto f_err;
-        }
-
         s->hit = 0;
         /*
          * Versions before 0.9.7 always allow clients to resume sessions in
@@ -1152,7 +1112,13 @@ int ssl3_get_client_hello(SSL *s)
             if (!ssl_get_new_session(s, 1))
                 goto err;
         } else {
-            i = ssl_get_prev_session(s, p, j, d + n);
+            /*
+             * TODO(openssl-team): ssl_get_prev_session passes a non-const
+             * 'unsigned char*' session id to a user callback. Grab a copy of
+             * the data?
+             */
+           i = ssl_get_prev_session(s, &pkt, PACKET_data(&session_id),
+                                    PACKET_remaining(&session_id));
             /*
              * Only resume if the session's version matches the negotiated
              * version.
@@ -1174,23 +1140,14 @@ int ssl3_get_client_hello(SSL *s)
             }
         }
 
-        p += j;
-
         if (SSL_IS_DTLS(s)) {
-            /* cookie stuff */
-            if (p + 1 > d + n) {
-                al = SSL_AD_DECODE_ERROR;
-                SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
-                goto f_err;
-            }
-            cookie_len = *(p++);
-
-            if (p + cookie_len > d + n) {
+            PACKET cookie;
+            if (!PACKET_get_length_prefixed_1(&pkt, &cookie)) {
                 al = SSL_AD_DECODE_ERROR;
                 SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
                 goto f_err;
             }
-
+           cookie_len = PACKET_remaining(&cookie);
             /*
              * The ClientHello may contain a cookie even if the
              * HelloVerify message has not been sent--make sure that it
@@ -1206,7 +1163,16 @@ int ssl3_get_client_hello(SSL *s)
             /* verify the cookie if appropriate option is set. */
             if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)
                     && cookie_len > 0) {
-                memcpy(s->d1->rcvd_cookie, p, cookie_len);
+                /* Get cookie */
+                /*
+                 * TODO(openssl-team): rcvd_cookie appears unused outside this
+                 * function. Remove the field?
+                 */
+                if (!PACKET_copy_bytes(&cookie, s->d1->rcvd_cookie, cookie_len)) {
+                    al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+                    goto f_err;
+                }
 
                 if (s->ctx->app_verify_cookie_cb != NULL) {
                     if (s->ctx->app_verify_cookie_cb(s, s->d1->rcvd_cookie,
@@ -1228,8 +1194,6 @@ int ssl3_get_client_hello(SSL *s)
                 /* Set to -2 so if successful we return 2 */
                 ret = -2;
             }
-
-            p += cookie_len;
             if (s->method->version == DTLS_ANY_VERSION) {
                 /* Select version to use */
                 if (s->client_version <= DTLS1_2_VERSION &&
@@ -1257,30 +1221,23 @@ int ssl3_get_client_hello(SSL *s)
             }
         }
 
-        if (p + 2 > d + n) {
+        if (!PACKET_get_length_prefixed_2(&pkt, &cipher_suite)) {
             al = SSL_AD_DECODE_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT);
             goto f_err;
         }
-        n2s(p, i);
 
-        if (i == 0) {
+        if (PACKET_remaining(&cipher_suite) == 0) {
             al = SSL_AD_ILLEGAL_PARAMETER;
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_CIPHERS_SPECIFIED);
             goto f_err;
         }
 
-        /* i bytes of cipher data + 1 byte for compression length later */
-        if ((p + i + 1) > (d + n)) {
-            /* not enough data */
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
-            goto f_err;
-        }
-        if (ssl_bytes_to_cipher_list(s, p, i, &(ciphers), 0) == NULL) {
+        if (ssl_bytes_to_cipher_list(s, PACKET_data(&cipher_suite),
+                                     PACKET_remaining(&cipher_suite),
+                                     &(ciphers), 0) == NULL) {
             goto err;
         }
-        p += i;
 
         /* If it is a hit, check that the cipher is in the list */
         if (s->hit) {
@@ -1337,22 +1294,24 @@ int ssl3_get_client_hello(SSL *s)
         }
 
         /* compression */
-        complen = *(p++);
-        if ((p + complen) > (d + n)) {
+        if (!PACKET_get_length_prefixed_1(&pkt, &compression)) {
             /* not enough data */
             al = SSL_AD_DECODE_ERROR;
+            /*
+             * TODO(openssl-team):
+             * SSL_R_LENGTH_TOO_SHORT and SSL_R_LENGTH_MISMATCH are used
+             * interchangeably. Pick one.
+             */
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH);
             goto f_err;
         }
-#ifndef OPENSSL_NO_COMP
-        q = p;
-#endif
+
+        complen = PACKET_remaining(&compression);
         for (j = 0; j < complen; j++) {
-            if (p[j] == 0)
+            if (PACKET_data(&compression)[j] == 0)
                 break;
         }
 
-        p += complen;
         if (j >= complen) {
             /* no compress */
             al = SSL_AD_DECODE_ERROR;
@@ -1361,10 +1320,9 @@ int ssl3_get_client_hello(SSL *s)
         }
     }
 
-#ifndef OPENSSL_NO_TLSEXT
     /* TLS extensions */
     if (s->version >= SSL3_VERSION) {
-        if (!ssl_parse_clienthello_tlsext(s, &p, d, n)) {
+        if (!ssl_parse_clienthello_tlsext(s, &pkt)) {
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_PARSE_TLSEXT);
             goto err;
         }
@@ -1418,7 +1376,6 @@ int ssl3_get_client_hello(SSL *s)
             s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
         }
     }
-#endif
 
     /*
      * Worst case, we will use the NULL compression, but if we have other
@@ -1430,6 +1387,7 @@ int ssl3_get_client_hello(SSL *s)
     /* This only happens if we have a cache hit */
     if (s->session->compress_meth != 0) {
         int m, comp_id = s->session->compress_meth;
+        unsigned int k;
         /* Perform sanity checks on resumed compression algorithm */
         /* Can't disable compression */
         if (!ssl_allow_compression(s)) {
@@ -1451,11 +1409,11 @@ int ssl3_get_client_hello(SSL *s)
             goto f_err;
         }
         /* Look for resumed method in compression list */
-        for (m = 0; m < complen; m++) {
-            if (q[m] == comp_id)
+        for (k = 0; k < complen; k++) {
+            if (PACKET_data(&compression)[k] == comp_id)
                 break;
         }
-        if (m >= complen) {
+        if (k >= complen) {
             al = SSL_AD_ILLEGAL_PARAMETER;
             SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,
                    SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING);
@@ -1465,14 +1423,15 @@ int ssl3_get_client_hello(SSL *s)
         comp = NULL;
     else if (ssl_allow_compression(s) && s->ctx->comp_methods) {
         /* See if we have a match */
-        int m, nn, o, v, done = 0;
+        int m, nn, v, done = 0;
+        unsigned int o;
 
         nn = sk_SSL_COMP_num(s->ctx->comp_methods);
         for (m = 0; m < nn; m++) {
             comp = sk_SSL_COMP_value(s->ctx->comp_methods, m);
             v = comp->id;
             for (o = 0; o < complen; o++) {
-                if (v == q[o]) {
+                if (v == PACKET_data(&compression)[o]) {
                     done = 1;
                     break;
                 }
@@ -1555,7 +1514,7 @@ int ssl3_get_client_hello(SSL *s)
     }
 
     if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) {
-        if (!ssl3_digest_cached_records(s))
+        if (!ssl3_digest_cached_records(s, 0))
             goto f_err;
     }
 
@@ -1602,20 +1561,17 @@ int ssl3_send_server_hello(SSL *s)
 
     if (s->state == SSL3_ST_SW_SRVR_HELLO_A) {
         buf = (unsigned char *)s->init_buf->data;
-#ifdef OPENSSL_NO_TLSEXT
-        p = s->s3->server_random;
-        if (ssl_fill_hello_random(s, 1, p, SSL3_RANDOM_SIZE) <= 0) {
-            s->state = SSL_ST_ERR;
-            return -1;
-        }
-#endif
+
         /* Do the message type and length last */
         d = p = ssl_handshake_start(s);
 
         *(p++) = s->version >> 8;
         *(p++) = s->version & 0xff;
 
-        /* Random stuff */
+        /*
+         * Random stuff. Filling of the server_random takes place in
+         * ssl3_get_client_hello()
+         */
         memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
         p += SSL3_RANDOM_SIZE;
 
@@ -1663,7 +1619,7 @@ int ssl3_send_server_hello(SSL *s)
         else
             *(p++) = s->s3->tmp.new_compression->id;
 #endif
-#ifndef OPENSSL_NO_TLSEXT
+
         if (ssl_prepare_serverhello_tlsext(s) <= 0) {
             SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT);
             s->state = SSL_ST_ERR;
@@ -1677,7 +1633,7 @@ int ssl3_send_server_hello(SSL *s)
             s->state = SSL_ST_ERR;
             return -1;
         }
-#endif
+
         /* do the header */
         l = (p - d);
         if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l)) {
@@ -1746,6 +1702,19 @@ int ssl3_send_server_key_exchange(SSL *s)
 
         r[0] = r[1] = r[2] = r[3] = NULL;
         n = 0;
+#ifndef OPENSSL_NO_PSK
+        if (type & SSL_PSK) {
+            /*
+             * reserve size for record length and PSK identity hint
+             */
+            n += 2;
+            if (s->cert->psk_identity_hint)
+                n += strlen(s->cert->psk_identity_hint);
+        }
+        /* Plain PSK or RSAPSK nothing to do */
+        if (type & (SSL_kPSK | SSL_kRSAPSK)) {
+        } else
+#endif                          /* !OPENSSL_NO_PSK */
 #ifndef OPENSSL_NO_RSA
         if (type & SSL_kRSA) {
             rsa = cert->rsa_tmp;
@@ -1776,7 +1745,7 @@ int ssl3_send_server_key_exchange(SSL *s)
         } else
 #endif
 #ifndef OPENSSL_NO_DH
-        if (type & SSL_kDHE) {
+        if (type & (SSL_kDHE | SSL_kDHEPSK)) {
             if (s->cert->dh_tmp_auto) {
                 dhp = ssl_get_auto_dh(s);
                 if (dhp == NULL) {
@@ -1841,7 +1810,7 @@ int ssl3_send_server_key_exchange(SSL *s)
         } else
 #endif
 #ifndef OPENSSL_NO_EC
-        if (type & SSL_kECDHE) {
+        if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
             const EC_GROUP *group;
 
             ecdhp = cert->ecdh_tmp;
@@ -1957,7 +1926,7 @@ int ssl3_send_server_key_exchange(SSL *s)
              * additional bytes to encode the entire ServerECDHParams
              * structure.
              */
-            n = 4 + encodedlen;
+            n += 4 + encodedlen;
 
             /*
              * We'll generate the serverKeyExchange message explicitly so we
@@ -1969,14 +1938,6 @@ int ssl3_send_server_key_exchange(SSL *s)
             r[3] = NULL;
         } else
 #endif                          /* !OPENSSL_NO_EC */
-#ifndef OPENSSL_NO_PSK
-        if (type & SSL_kPSK) {
-            /*
-             * reserve size for record length and PSK identity hint
-             */
-            n += 2 + strlen(s->ctx->psk_identity_hint);
-        } else
-#endif                          /* !OPENSSL_NO_PSK */
 #ifndef OPENSSL_NO_SRP
         if (type & SSL_kSRP) {
             if ((s->srp_ctx.N == NULL) ||
@@ -2008,8 +1969,8 @@ int ssl3_send_server_key_exchange(SSL *s)
                 n += 2 + nr[i];
         }
 
-        if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP))
-            && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
+        if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL|SSL_aSRP))
+            && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
             if ((pkey = ssl_get_sign_pkey(s, s->s3->tmp.new_cipher, &md))
                 == NULL) {
                 al = SSL_AD_DECODE_ERROR;
@@ -2027,6 +1988,20 @@ int ssl3_send_server_key_exchange(SSL *s)
         }
         d = p = ssl_handshake_start(s);
 
+#ifndef OPENSSL_NO_PSK
+        if (type & SSL_PSK) {
+            /* copy PSK identity hint */
+            if (s->cert->psk_identity_hint) {
+                s2n(strlen(s->cert->psk_identity_hint), p);
+                strncpy((char *)p, s->cert->psk_identity_hint,
+                        strlen(s->cert->psk_identity_hint));
+                p += strlen(s->cert->psk_identity_hint);
+            } else {
+                s2n(0, p);
+            }
+        }
+#endif
+
         for (i = 0; i < 4 && r[i] != NULL; i++) {
 #ifndef OPENSSL_NO_SRP
             if ((i == 2) && (type & SSL_kSRP)) {
@@ -2040,7 +2015,7 @@ int ssl3_send_server_key_exchange(SSL *s)
         }
 
 #ifndef OPENSSL_NO_EC
-        if (type & SSL_kECDHE) {
+        if (type & (SSL_kECDHE | SSL_kECDHEPSK)) {
             /*
              * XXX: For now, we only support named (not generic) curves. In
              * this situation, the serverKeyExchange message has: [1 byte
@@ -2062,16 +2037,6 @@ int ssl3_send_server_key_exchange(SSL *s)
         }
 #endif
 
-#ifndef OPENSSL_NO_PSK
-        if (type & SSL_kPSK) {
-            /* copy PSK identity hint */
-            s2n(strlen(s->ctx->psk_identity_hint), p);
-            strncpy((char *)p, s->ctx->psk_identity_hint,
-                    strlen(s->ctx->psk_identity_hint));
-            p += strlen(s->ctx->psk_identity_hint);
-        }
-#endif
-
         /* not anonymous */
         if (pkey != NULL) {
             /*
@@ -2243,10 +2208,10 @@ int ssl3_send_certificate_request(SSL *s)
 
 int ssl3_get_client_key_exchange(SSL *s)
 {
-    int i, al, ok;
+    unsigned int i;
+    int al, ok;
     long n;
     unsigned long alg_k;
-    unsigned char *p;
 #ifndef OPENSSL_NO_RSA
     RSA *rsa = NULL;
     EVP_PKEY *pkey = NULL;
@@ -2255,13 +2220,15 @@ int ssl3_get_client_key_exchange(SSL *s)
     BIGNUM *pub = NULL;
     DH *dh_srvr, *dh_clnt = NULL;
 #endif
-
 #ifndef OPENSSL_NO_EC
     EC_KEY *srvr_ecdh = NULL;
     EVP_PKEY *clnt_pub_pkey = NULL;
     EC_POINT *clnt_ecpoint = NULL;
     BN_CTX *bn_ctx = NULL;
 #endif
+    PACKET pkt;
+    unsigned char *data;
+    size_t remain;
 
     n = s->method->ssl_get_message(s,
                                    SSL3_ST_SR_KEY_EXCH_A,
@@ -2270,12 +2237,91 @@ int ssl3_get_client_key_exchange(SSL *s)
 
     if (!ok)
         return ((int)n);
-    p = (unsigned char *)s->init_msg;
+    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
+        al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        goto f_err;
+    }
 
     alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
 
+#ifndef OPENSSL_NO_PSK
+    /* For PSK parse and retrieve identity, obtain PSK key */
+    if (alg_k & SSL_PSK) {
+        unsigned char psk[PSK_MAX_PSK_LEN];
+        size_t psklen;
+       PACKET psk_identity;
+
+        if (!PACKET_get_length_prefixed_2(&pkt, &psk_identity)) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        if (PACKET_remaining(&psk_identity) > PSK_MAX_IDENTITY_LEN) {
+            al = SSL_AD_DECODE_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+                   SSL_R_DATA_LENGTH_TOO_LONG);
+            goto f_err;
+        }
+        if (s->psk_server_callback == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+                   SSL_R_PSK_NO_SERVER_CB);
+            goto f_err;
+        }
+
+        if (!PACKET_strndup(&psk_identity, &s->session->psk_identity)) {
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            al = SSL_AD_INTERNAL_ERROR;
+            goto f_err;
+        }
+
+        psklen = s->psk_server_callback(s, s->session->psk_identity,
+                                         psk, sizeof(psk));
+
+        if (psklen > PSK_MAX_PSK_LEN) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        } else if (psklen == 0) {
+            /*
+             * PSK related to the given identity not found
+             */
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+                   SSL_R_PSK_IDENTITY_NOT_FOUND);
+            al = SSL_AD_UNKNOWN_PSK_IDENTITY;
+            goto f_err;
+        }
+
+        OPENSSL_free(s->s3->tmp.psk);
+        s->s3->tmp.psk = BUF_memdup(psk, psklen);
+        OPENSSL_cleanse(psk, psklen);
+
+        if (s->s3->tmp.psk == NULL) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto f_err;
+        }
+
+        s->s3->tmp.psklen = psklen;
+    }
+    if (alg_k & SSL_kPSK) {
+        /* Identity extracted earlier: should be nothing left */
+        if (PACKET_remaining(&pkt) != 0) {
+            al = SSL_AD_HANDSHAKE_FAILURE;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+            goto f_err;
+        }
+        /* PSK handled by ssl_generate_master_secret */
+        if (!ssl_generate_master_secret(s, NULL, 0, 0)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+    } else
+#endif
 #ifndef OPENSSL_NO_RSA
-    if (alg_k & SSL_kRSA) {
+    if (alg_k & (SSL_kRSA | SSL_kRSAPSK)) {
         unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
         int decrypt_len;
         unsigned char decrypt_good, version_good;
@@ -2309,17 +2355,34 @@ int ssl3_get_client_key_exchange(SSL *s)
 
         /* TLS and [incidentally] DTLS{0xFEFF} */
         if (s->version > SSL3_VERSION && s->version != DTLS1_BAD_VER) {
-            n2s(p, i);
-            if (n != i + 2) {
+            if (!PACKET_get_net_2(&pkt, &i)) {
+                al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
+                goto f_err;
+            }
+            remain = PACKET_remaining(&pkt);
+            if (remain != i) {
                 if (!(s->options & SSL_OP_TLS_D5_BUG)) {
                     al = SSL_AD_DECODE_ERROR;
                     SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
                            SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
                     goto f_err;
-                } else
-                    p -= 2;
-            } else
-                n = i;
+                } else {
+                    remain += 2;
+                    if (!PACKET_back(&pkt, 2)) {
+                        /*
+                         * We already read these 2 bytes so this should never
+                         * fail
+                         */
+                        al = SSL_AD_INTERNAL_ERROR;
+                        SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+                               ERR_R_INTERNAL_ERROR);
+                        goto f_err;
+                    }
+                }
+            }
+        } else {
+            remain = PACKET_remaining(&pkt);
         }
 
         /*
@@ -2329,13 +2392,20 @@ int ssl3_get_client_key_exchange(SSL *s)
          * actual expected size is larger due to RSA padding, but the
          * bound is sufficient to be safe.
          */
-        if (n < SSL_MAX_MASTER_KEY_LENGTH) {
+
+        if (remain < SSL_MAX_MASTER_KEY_LENGTH) {
             al = SSL_AD_DECRYPT_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
                    SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG);
             goto f_err;
         }
 
+        if (!PACKET_get_bytes(&pkt, &data, remain)) {
+            /* We already checked we had enough data so this shouldn't happen */
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
         /*
          * We must not leak whether a decryption failure occurs because of
          * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246,
@@ -2348,7 +2418,7 @@ int ssl3_get_client_key_exchange(SSL *s)
                               sizeof(rand_premaster_secret)) <= 0)
             goto err;
         decrypt_len =
-            RSA_private_decrypt((int)n, p, p, rsa, RSA_PKCS1_PADDING);
+            RSA_private_decrypt(remain, data, data, rsa, RSA_PKCS1_PADDING);
         ERR_clear_error();
 
         /*
@@ -2367,9 +2437,9 @@ int ssl3_get_client_key_exchange(SSL *s)
          * constant time and are treated like any other decryption error.
          */
         version_good =
-            constant_time_eq_8(p[0], (unsigned)(s->client_version >> 8));
+            constant_time_eq_8(data[0], (unsigned)(s->client_version >> 8));
         version_good &=
-            constant_time_eq_8(p[1], (unsigned)(s->client_version & 0xff));
+            constant_time_eq_8(data[1], (unsigned)(s->client_version & 0xff));
 
         /*
          * The premaster secret must contain the same version number as the
@@ -2383,9 +2453,9 @@ int ssl3_get_client_key_exchange(SSL *s)
         if (s->options & SSL_OP_TLS_ROLLBACK_BUG) {
             unsigned char workaround_good;
             workaround_good =
-                constant_time_eq_8(p[0], (unsigned)(s->version >> 8));
+                constant_time_eq_8(data[0], (unsigned)(s->version >> 8));
             workaround_good &=
-                constant_time_eq_8(p[1], (unsigned)(s->version & 0xff));
+                constant_time_eq_8(data[1], (unsigned)(s->version & 0xff));
             version_good |= workaround_good;
         }
 
@@ -2402,19 +2472,12 @@ int ssl3_get_client_key_exchange(SSL *s)
          * it is still sufficiently large to read from.
          */
         for (j = 0; j < sizeof(rand_premaster_secret); j++) {
-            p[j] = constant_time_select_8(decrypt_good, p[j],
+            data[j] = constant_time_select_8(decrypt_good, data[j],
                                           rand_premaster_secret[j]);
         }
 
-        s->session->master_key_length =
-            s->method->ssl3_enc->generate_master_secret(s,
-                                                        s->
-                                                        session->master_key,
-                                                        p,
-                                                        sizeof
-                                                        (rand_premaster_secret));
-        OPENSSL_cleanse(p, sizeof(rand_premaster_secret));
-        if (s->session->master_key_length < 0) {
+        if (!ssl_generate_master_secret(s, data, sizeof(rand_premaster_secret),
+                                        0)) {
             al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto f_err;
@@ -2422,13 +2485,19 @@ int ssl3_get_client_key_exchange(SSL *s)
     } else
 #endif
 #ifndef OPENSSL_NO_DH
-    if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd)) {
+    if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd | SSL_kDHEPSK)) {
         int idx = -1;
         EVP_PKEY *skey = NULL;
-        if (n > 1) {
-            n2s(p, i);
-        } else {
-            if (alg_k & SSL_kDHE) {
+        size_t bookm;
+        unsigned char shared[(OPENSSL_DH_MAX_MODULUS_BITS + 7) / 8];
+
+        if (!PACKET_get_bookmark(&pkt, &bookm)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
+        if (!PACKET_get_net_2(&pkt, &i)) {
+            if (alg_k & (SSL_kDHE | SSL_kDHEPSK)) {
                 al = SSL_AD_HANDSHAKE_FAILURE;
                 SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
                        SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
@@ -2436,14 +2505,19 @@ int ssl3_get_client_key_exchange(SSL *s)
             }
             i = 0;
         }
-        if (n && n != i + 2) {
+        if (PACKET_remaining(&pkt) != i) {
             if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG)) {
                 SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
                        SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG);
                 goto err;
             } else {
-                p -= 2;
-                i = (int)n;
+                if (!PACKET_goto_bookmark(&pkt, bookm)) {
+                    al = SSL_AD_INTERNAL_ERROR;
+                    SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+                           ERR_R_INTERNAL_ERROR);
+                    goto f_err;
+                }
+                i = PACKET_remaining(&pkt);
             }
         }
         if (alg_k & SSL_kDHr)
@@ -2483,14 +2557,22 @@ int ssl3_get_client_key_exchange(SSL *s)
             }
             EVP_PKEY_free(clkey);
             pub = dh_clnt->pub_key;
-        } else
-            pub = BN_bin2bn(p, i, NULL);
+        } else {
+            if (!PACKET_get_bytes(&pkt, &data, i)) {
+                /* We already checked we have enough data */
+                al = SSL_AD_INTERNAL_ERROR;
+                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+                       ERR_R_INTERNAL_ERROR);
+                goto f_err;
+            }
+            pub = BN_bin2bn(data, i, NULL);
+        }
         if (pub == NULL) {
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BN_LIB);
             goto err;
         }
 
-        i = DH_compute_key(p, pub, dh_srvr);
+        i = DH_compute_key(shared, pub, dh_srvr);
 
         if (i <= 0) {
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB);
@@ -2505,13 +2587,7 @@ int ssl3_get_client_key_exchange(SSL *s)
         else
             BN_clear_free(pub);
         pub = NULL;
-        s->session->master_key_length =
-            s->method->ssl3_enc->generate_master_secret(s,
-                                                        s->
-                                                        session->master_key,
-                                                        p, i);
-        OPENSSL_cleanse(p, i);
-        if (s->session->master_key_length < 0) {
+        if (!ssl_generate_master_secret(s, shared, i, 0)) {
             al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto f_err;
@@ -2522,12 +2598,13 @@ int ssl3_get_client_key_exchange(SSL *s)
 #endif
 
 #ifndef OPENSSL_NO_EC
-    if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe)) {
+    if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe | SSL_kECDHEPSK)) {
         int ret = 1;
         int field_size = 0;
         const EC_KEY *tkey;
         const EC_GROUP *group;
         const BIGNUM *priv_key;
+        unsigned char *shared;
 
         /* initialize structures for server's ECDH key pair */
         if ((srvr_ecdh = EC_KEY_new()) == NULL) {
@@ -2565,7 +2642,7 @@ int ssl3_get_client_key_exchange(SSL *s)
         if (n == 0L) {
             /* Client Publickey was in Client Certificate */
 
-            if (alg_k & SSL_kECDHE) {
+            if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
                 al = SSL_AD_HANDSHAKE_FAILURE;
                 SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
                        SSL_R_MISSING_TMP_ECDH_KEY);
@@ -2606,21 +2683,21 @@ int ssl3_get_client_key_exchange(SSL *s)
             }
 
             /* Get encoded point length */
-            i = *p;
-            p += 1;
-            if (n != 1 + i) {
+            if (!PACKET_get_1(&pkt, &i)) {
+                al = SSL_AD_DECODE_ERROR;
+                SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+                       SSL_R_LENGTH_MISMATCH);
+                goto f_err;
+            }
+            if (!PACKET_get_bytes(&pkt, &data, i)
+                    || PACKET_remaining(&pkt) != 0) {
                 SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
                 goto err;
             }
-            if (EC_POINT_oct2point(group, clnt_ecpoint, p, i, bn_ctx) == 0) {
+            if (EC_POINT_oct2point(group, clnt_ecpoint, data, i, bn_ctx) == 0) {
                 SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB);
                 goto err;
             }
-            /*
-             * p is pointing to somewhere in the buffer currently, so set it
-             * to the start
-             */
-            p = (unsigned char *)s->init_buf->data;
         }
 
         /* Compute the shared pre-master secret */
@@ -2629,10 +2706,16 @@ int ssl3_get_client_key_exchange(SSL *s)
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
             goto err;
         }
-        i = ECDH_compute_key(p, (field_size + 7) / 8, clnt_ecpoint, srvr_ecdh,
-                             NULL);
+        shared = OPENSSL_malloc((field_size + 7) / 8);
+        if (shared == NULL) {
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        i = ECDH_compute_key(shared, (field_size + 7) / 8, clnt_ecpoint,
+                             srvr_ecdh, NULL);
         if (i <= 0) {
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
+            OPENSSL_free(shared);
             goto err;
         }
 
@@ -2643,15 +2726,7 @@ int ssl3_get_client_key_exchange(SSL *s)
         EC_KEY_free(s->s3->tmp.ecdh);
         s->s3->tmp.ecdh = NULL;
 
-        /* Compute the master secret */
-        s->session->master_key_length =
-            s->method->ssl3_enc->generate_master_secret(s,
-                                                        s->
-                                                        session->master_key,
-                                                        p, i);
-
-        OPENSSL_cleanse(p, i);
-        if (s->session->master_key_length < 0) {
+        if (!ssl_generate_master_secret(s, shared, i, 1)) {
             al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto f_err;
@@ -2659,110 +2734,15 @@ int ssl3_get_client_key_exchange(SSL *s)
         return (ret);
     } else
 #endif
-#ifndef OPENSSL_NO_PSK
-    if (alg_k & SSL_kPSK) {
-        unsigned char *t = NULL;
-        unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN * 2 + 4];
-        unsigned int pre_ms_len = 0, psk_len = 0;
-        int psk_err = 1;
-        char tmp_id[PSK_MAX_IDENTITY_LEN + 1];
-
-        al = SSL_AD_HANDSHAKE_FAILURE;
-
-        n2s(p, i);
-        if (n != i + 2) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH);
-            goto psk_err;
-        }
-        if (i > PSK_MAX_IDENTITY_LEN) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_DATA_LENGTH_TOO_LONG);
-            goto psk_err;
-        }
-        if (s->psk_server_callback == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_PSK_NO_SERVER_CB);
-            goto psk_err;
-        }
-
-        /*
-         * Create guaranteed NULL-terminated identity string for the callback
-         */
-        memcpy(tmp_id, p, i);
-        memset(tmp_id + i, 0, PSK_MAX_IDENTITY_LEN + 1 - i);
-        psk_len = s->psk_server_callback(s, tmp_id,
-                                         psk_or_pre_ms,
-                                         sizeof(psk_or_pre_ms));
-        OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN + 1);
-
-        if (psk_len > PSK_MAX_PSK_LEN) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto psk_err;
-        } else if (psk_len == 0) {
-            /*
-             * PSK related to the given identity not found
-             */
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_PSK_IDENTITY_NOT_FOUND);
-            al = SSL_AD_UNKNOWN_PSK_IDENTITY;
-            goto psk_err;
-        }
-
-        /* create PSK pre_master_secret */
-        pre_ms_len = 2 + psk_len + 2 + psk_len;
-        t = psk_or_pre_ms;
-        memmove(psk_or_pre_ms + psk_len + 4, psk_or_pre_ms, psk_len);
-        s2n(psk_len, t);
-        memset(t, 0, psk_len);
-        t += psk_len;
-        s2n(psk_len, t);
-
-        OPENSSL_free(s->session->psk_identity);
-        s->session->psk_identity = BUF_strdup((char *)p);
-        if (s->session->psk_identity == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto psk_err;
-        }
-
-        OPENSSL_free(s->session->psk_identity_hint);
-        s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint);
-        if (s->ctx->psk_identity_hint != NULL &&
-            s->session->psk_identity_hint == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
-            goto psk_err;
-        }
-
-        s->session->master_key_length =
-            s->method->ssl3_enc->generate_master_secret(s,
-                                                        s->
-                                                        session->master_key,
-                                                        psk_or_pre_ms,
-                                                        pre_ms_len);
-        if (s->session->master_key_length < 0) {
-            al = SSL_AD_INTERNAL_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
-            goto psk_err;
-        }
-        psk_err = 0;
- psk_err:
-        OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
-        if (psk_err != 0)
-            goto f_err;
-    } else
-#endif
 #ifndef OPENSSL_NO_SRP
     if (alg_k & SSL_kSRP) {
-        int param_len;
-
-        n2s(p, i);
-        param_len = i + 2;
-        if (param_len > n) {
+        if (!PACKET_get_net_2(&pkt, &i)
+                || !PACKET_get_bytes(&pkt, &data, i)) {
             al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
-                   SSL_R_BAD_SRP_A_LENGTH);
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_SRP_A_LENGTH);
             goto f_err;
         }
-        if ((s->srp_ctx.A = BN_bin2bn(p, i, NULL)) == NULL) {
+        if ((s->srp_ctx.A = BN_bin2bn(data, i, NULL)) == NULL) {
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_BN_LIB);
             goto err;
         }
@@ -2780,14 +2760,10 @@ int ssl3_get_client_key_exchange(SSL *s)
             goto err;
         }
 
-        if ((s->session->master_key_length =
-             SRP_generate_server_master_secret(s,
-                                               s->session->master_key)) < 0) {
+        if (!srp_generate_server_master_secret(s)) {
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto err;
         }
-
-        p += i;
     } else
 #endif                          /* OPENSSL_NO_SRP */
     if (alg_k & SSL_kGOST) {
@@ -2802,9 +2778,7 @@ int ssl3_get_client_key_exchange(SSL *s)
 
         /* Get our certificate private key */
         alg_a = s->s3->tmp.new_cipher->algorithm_auth;
-        if (alg_a & SSL_aGOST94)
-            pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey;
-        else if (alg_a & SSL_aGOST01)
+        if (alg_a & SSL_aGOST01)
             pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey;
 
         pkey_ctx = EVP_PKEY_CTX_new(pk, NULL);
@@ -2821,15 +2795,20 @@ int ssl3_get_client_key_exchange(SSL *s)
                 ERR_clear_error();
         }
         /* Decrypt session key */
+        if (!PACKET_get_bytes(&pkt, &data, n)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+            goto f_err;
+        }
         if (ASN1_get_object
-            ((const unsigned char **)&p, &Tlen, &Ttag, &Tclass,
+            ((const unsigned char **)&data, &Tlen, &Ttag, &Tclass,
              n) != V_ASN1_CONSTRUCTED || Ttag != V_ASN1_SEQUENCE
             || Tclass != V_ASN1_UNIVERSAL) {
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
                    SSL_R_DECRYPTION_FAILED);
             goto gerr;
         }
-        start = p;
+        start = data;
         inlen = Tlen;
         if (EVP_PKEY_decrypt
             (pkey_ctx, premaster_secret, &outlen, start, inlen) <= 0) {
@@ -2838,12 +2817,8 @@ int ssl3_get_client_key_exchange(SSL *s)
             goto gerr;
         }
         /* Generate master secret */
-        s->session->master_key_length =
-            s->method->ssl3_enc->generate_master_secret(s,
-                                                        s->
-                                                        session->master_key,
-                                                        premaster_secret, 32);
-        if (s->session->master_key_length < 0) {
+        if (!ssl_generate_master_secret(s, premaster_secret,
+                                        sizeof(premaster_secret), 0)) {
             al = SSL_AD_INTERNAL_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
             goto f_err;
@@ -2877,6 +2852,10 @@ int ssl3_get_client_key_exchange(SSL *s)
     EC_POINT_free(clnt_ecpoint);
     EC_KEY_free(srvr_ecdh);
     BN_CTX_free(bn_ctx);
+#endif
+#ifndef OPENSSL_NO_PSK
+    OPENSSL_clear_free(s->s3->tmp.psk, s->s3->tmp.psklen);
+    s->s3->tmp.psk = NULL;
 #endif
     s->state = SSL_ST_ERR;
     return (-1);
@@ -2885,13 +2864,15 @@ int ssl3_get_client_key_exchange(SSL *s)
 int ssl3_get_cert_verify(SSL *s)
 {
     EVP_PKEY *pkey = NULL;
-    unsigned char *p;
+    unsigned char *sig, *data;
     int al, ok, ret = 0;
     long n;
     int type = 0, i, j;
+    unsigned int len;
     X509 *peer;
     const EVP_MD *md = NULL;
     EVP_MD_CTX mctx;
+    PACKET pkt;
     EVP_MD_CTX_init(&mctx);
 
     /*
@@ -2928,18 +2909,27 @@ int ssl3_get_cert_verify(SSL *s)
     }
 
     /* we now have a signature that we need to verify */
-    p = (unsigned char *)s->init_msg;
+    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
+        SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+        al = SSL_AD_INTERNAL_ERROR;
+        goto f_err;
+    }
     /* Check for broken implementations of GOST ciphersuites */
     /*
      * If key is GOST and n is exactly 64, it is bare signature without
      * length field
      */
-    if (n == 64 && (pkey->type == NID_id_GostR3410_94 ||
-                    pkey->type == NID_id_GostR3410_2001)) {
-        i = 64;
+    if (n == 64 && pkey->type == NID_id_GostR3410_2001) {
+        len = 64;
     } else {
         if (SSL_USE_SIGALGS(s)) {
-            int rv = tls12_check_peer_sigalg(&md, s, p, pkey);
+            int rv;
+
+            if (!PACKET_get_bytes(&pkt, &sig, 2)) {
+                al = SSL_AD_DECODE_ERROR;
+                goto f_err;
+            }
+            rv = tls12_check_peer_sigalg(&md, s, sig, pkey);
             if (rv == -1) {
                 al = SSL_AD_INTERNAL_ERROR;
                 goto f_err;
@@ -2950,23 +2940,24 @@ int ssl3_get_cert_verify(SSL *s)
 #ifdef SSL_DEBUG
             fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
 #endif
-            p += 2;
-            n -= 2;
         }
-        n2s(p, i);
-        n -= 2;
-        if (i > n) {
+        if (!PACKET_get_net_2(&pkt, &len)) {
             SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
             al = SSL_AD_DECODE_ERROR;
             goto f_err;
         }
     }
     j = EVP_PKEY_size(pkey);
-    if ((i > j) || (n > j) || (n <= 0)) {
+    if (((int)len > j) || ((int)PACKET_remaining(&pkt) > j) || (n <= 0)) {
         SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_WRONG_SIGNATURE_SIZE);
         al = SSL_AD_DECODE_ERROR;
         goto f_err;
     }
+    if (!PACKET_get_bytes(&pkt, &data, len)) {
+        SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_LENGTH_MISMATCH);
+        al = SSL_AD_DECODE_ERROR;
+        goto f_err;
+    }
 
     if (SSL_USE_SIGALGS(s)) {
         long hdatalen = 0;
@@ -2988,7 +2979,7 @@ int ssl3_get_cert_verify(SSL *s)
             goto f_err;
         }
 
-        if (EVP_VerifyFinal(&mctx, p, i, pkey) <= 0) {
+        if (EVP_VerifyFinal(&mctx, data, len, pkey) <= 0) {
             al = SSL_AD_DECRYPT_ERROR;
             SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_BAD_SIGNATURE);
             goto f_err;
@@ -2997,7 +2988,7 @@ int ssl3_get_cert_verify(SSL *s)
 #ifndef OPENSSL_NO_RSA
     if (pkey->type == EVP_PKEY_RSA) {
         i = RSA_verify(NID_md5_sha1, s->s3->tmp.cert_verify_md,
-                       MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, p, i,
+                       MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, data, len,
                        pkey->pkey.rsa);
         if (i < 0) {
             al = SSL_AD_DECRYPT_ERROR;
@@ -3015,7 +3006,7 @@ int ssl3_get_cert_verify(SSL *s)
     if (pkey->type == EVP_PKEY_DSA) {
         j = DSA_verify(pkey->save_type,
                        &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
-                       SHA_DIGEST_LENGTH, p, i, pkey->pkey.dsa);
+                       SHA_DIGEST_LENGTH, data, len, pkey->pkey.dsa);
         if (j <= 0) {
             /* bad signature */
             al = SSL_AD_DECRYPT_ERROR;
@@ -3028,7 +3019,7 @@ int ssl3_get_cert_verify(SSL *s)
     if (pkey->type == EVP_PKEY_EC) {
         j = ECDSA_verify(pkey->save_type,
                          &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]),
-                         SHA_DIGEST_LENGTH, p, i, pkey->pkey.ec);
+                         SHA_DIGEST_LENGTH, data, len, pkey->pkey.ec);
         if (j <= 0) {
             /* bad signature */
             al = SSL_AD_DECRYPT_ERROR;
@@ -3037,17 +3028,16 @@ int ssl3_get_cert_verify(SSL *s)
         }
     } else
 #endif
-    if (pkey->type == NID_id_GostR3410_94
-            || pkey->type == NID_id_GostR3410_2001) {
+    if (pkey->type == NID_id_GostR3410_2001) {
         unsigned char signature[64];
         int idx;
         EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL);
         EVP_PKEY_verify_init(pctx);
-        if (i != 64) {
-            fprintf(stderr, "GOST signature length is %d", i);
+        if (len != 64) {
+            fprintf(stderr, "GOST signature length is %d", len);
         }
         for (idx = 0; idx < 64; idx++) {
-            signature[63 - idx] = p[idx];
+            signature[63 - idx] = data[idx];
         }
         j = EVP_PKEY_verify(pctx, signature, 64, s->s3->tmp.cert_verify_md,
                             32);
@@ -3072,7 +3062,6 @@ int ssl3_get_cert_verify(SSL *s)
  end:
     BIO_free(s->s3->handshake_buffer);
     s->s3->handshake_buffer = NULL;
-    s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
     EVP_MD_CTX_cleanup(&mctx);
     EVP_PKEY_free(pkey);
     return (ret);
@@ -3082,10 +3071,11 @@ int ssl3_get_client_certificate(SSL *s)
 {
     int i, ok, al, ret = -1;
     X509 *x = NULL;
-    unsigned long l, nc, llen, n;
-    const unsigned char *p, *q;
-    unsigned char *d;
+    unsigned long l, llen, n;
+    const unsigned char *certstart;
+    unsigned char *certbytes;
     STACK_OF(X509) *sk = NULL;
+    PACKET pkt, spkt;
 
     n = s->method->ssl_get_message(s,
                                    SSL3_ST_SR_CERT_A,
@@ -3121,35 +3111,42 @@ int ssl3_get_client_certificate(SSL *s)
         SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, SSL_R_WRONG_MESSAGE_TYPE);
         goto f_err;
     }
-    p = d = (unsigned char *)s->init_msg;
+
+    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
+        al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+        goto f_err;
+    }
 
     if ((sk = sk_X509_new_null()) == NULL) {
         SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
         goto done;
     }
 
-    n2l3(p, llen);
-    if (llen + 3 != n) {
+    if (!PACKET_get_net_3(&pkt, &llen)
+            || !PACKET_get_sub_packet(&pkt, &spkt, llen)
+            || PACKET_remaining(&pkt) != 0) {
         al = SSL_AD_DECODE_ERROR;
         SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, SSL_R_LENGTH_MISMATCH);
         goto f_err;
     }
-    for (nc = 0; nc < llen;) {
-        n2l3(p, l);
-        if ((l + nc + 3) > llen) {
+
+    while (PACKET_remaining(&spkt) > 0) {
+        if (!PACKET_get_net_3(&spkt, &l)
+                || !PACKET_get_bytes(&spkt, &certbytes, l)) {
             al = SSL_AD_DECODE_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
                    SSL_R_CERT_LENGTH_MISMATCH);
             goto f_err;
         }
 
-        q = p;
-        x = d2i_X509(NULL, &p, l);
+        certstart = certbytes;
+        x = d2i_X509(NULL, (const unsigned char **)&certbytes, l);
         if (x == NULL) {
             SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_ASN1_LIB);
             goto done;
         }
-        if (p != (q + l)) {
+        if (certbytes != (certstart + l)) {
             al = SSL_AD_DECODE_ERROR;
             SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,
                    SSL_R_CERT_LENGTH_MISMATCH);
@@ -3160,7 +3157,6 @@ int ssl3_get_client_certificate(SSL *s)
             goto done;
         }
         x = NULL;
-        nc += l + 3;
     }
 
     if (sk_X509_num(sk) <= 0) {
@@ -3180,7 +3176,7 @@ int ssl3_get_client_certificate(SSL *s)
             goto f_err;
         }
         /* No client certificate so digest cached records */
-        if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s)) {
+        if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, 0)) {
             al = SSL_AD_INTERNAL_ERROR;
             goto f_err;
         }
@@ -3212,19 +3208,8 @@ int ssl3_get_client_certificate(SSL *s)
     s->session->peer = sk_X509_shift(sk);
     s->session->verify_result = s->verify_result;
 
-    /*
-     * With the current implementation, sess_cert will always be NULL when we
-     * arrive here.
-     */
-    if (s->session->sess_cert == NULL) {
-        s->session->sess_cert = ssl_sess_cert_new();
-        if (s->session->sess_cert == NULL) {
-            SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE);
-            goto done;
-        }
-    }
-    sk_X509_pop_free(s->session->sess_cert->cert_chain, X509_free);
-    s->session->sess_cert->cert_chain = sk;
+    sk_X509_pop_free(s->session->peer_chain, X509_free);
+    s->session->peer_chain = sk;
     /*
      * Inconsistency alert: cert_chain does *not* include the peer's own
      * certificate, while we do include it in s3_clnt.c
@@ -3266,7 +3251,6 @@ int ssl3_send_server_certificate(SSL *s)
     return ssl_do_write(s);
 }
 
-#ifndef OPENSSL_NO_TLSEXT
 /* send a new session ticket (not necessarily for a new session) */
 int ssl3_send_newsession_ticket(SSL *s)
 {
@@ -3454,7 +3438,7 @@ int ssl3_send_cert_status(SSL *s)
     return (ssl3_do_write(s, SSL3_RT_HANDSHAKE));
 }
 
-# ifndef OPENSSL_NO_NEXTPROTONEG
+#ifndef OPENSSL_NO_NEXTPROTONEG
 /*
  * ssl3_get_next_proto reads a Next Protocol Negotiation handshake message.
  * It sets the next_proto member in s if found
@@ -3462,9 +3446,9 @@ int ssl3_send_cert_status(SSL *s)
 int ssl3_get_next_proto(SSL *s)
 {
     int ok;
-    int proto_len, padding_len;
     long n;
-    const unsigned char *p;
+    PACKET pkt, next_proto, padding;
+    size_t next_proto_len;
 
     /*
      * Clients cannot send a NextProtocol message if we didn't see the
@@ -3498,11 +3482,13 @@ int ssl3_get_next_proto(SSL *s)
     }
 
     if (n < 2) {
-        s->state = SSL_ST_ERR;
-        return 0;               /* The body must be > 1 bytes long */
+        goto err;               /* The body must be > 1 bytes long */
     }
 
-    p = (unsigned char *)s->init_msg;
+    if (!PACKET_buf_init(&pkt, s->init_msg, n)) {
+        SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, ERR_R_INTERNAL_ERROR);
+        goto err;
+    }
 
     /*-
      * The payload looks like:
@@ -3511,30 +3497,26 @@ int ssl3_get_next_proto(SSL *s)
      *   uint8 padding_len;
      *   uint8 padding[padding_len];
      */
-    proto_len = p[0];
-    if (proto_len + 2 > s->init_num) {
-        s->state = SSL_ST_ERR;
-        return 0;
-    }
-    padding_len = p[proto_len + 1];
-    if (proto_len + padding_len + 2 != s->init_num) {
-        s->state = SSL_ST_ERR;
-        return 0;
+    if (!PACKET_get_length_prefixed_1(&pkt, &next_proto)
+        || !PACKET_get_length_prefixed_1(&pkt, &padding)
+        || PACKET_remaining(&pkt) > 0) {
+        SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, SSL_R_LENGTH_MISMATCH);
+        goto err;
     }
 
-    s->next_proto_negotiated = OPENSSL_malloc(proto_len);
-    if (!s->next_proto_negotiated) {
-        SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, ERR_R_MALLOC_FAILURE);
-        s->state = SSL_ST_ERR;
-        return 0;
+    if (!PACKET_memdup(&next_proto, &s->next_proto_negotiated,
+                       &next_proto_len)) {
+        s->next_proto_negotiated_len = 0;
+        goto err;
     }
-    memcpy(s->next_proto_negotiated, p + 1, proto_len);
-    s->next_proto_negotiated_len = proto_len;
+
+    s->next_proto_negotiated_len = (unsigned char)next_proto_len;
 
     return 1;
+err:
+    s->state = SSL_ST_ERR;
+    return 0;
 }
-# endif
-
 #endif
 
 #define SSLV2_CIPHER_LEN    3