+int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
+ size_t chainidx, int *al)
+{
+ PACKET identities, binders, binder;
+ size_t binderoffset, hashsize;
+ SSL_SESSION *sess = NULL;
+ unsigned int id, i;
+ const EVP_MD *md = NULL;
+
+ /*
+ * If we have no PSK kex mode that we recognise then we can't resume so
+ * ignore this extension
+ */
+ if ((s->ext.psk_kex_mode
+ & (TLSEXT_KEX_MODE_FLAG_KE | TLSEXT_KEX_MODE_FLAG_KE_DHE)) == 0)
+ return 1;
+
+ if (!PACKET_get_length_prefixed_2(pkt, &identities)) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ for (id = 0; PACKET_remaining(&identities) != 0; id++) {
+ PACKET identity;
+ unsigned long ticket_age;
+ int ret;
+
+ if (!PACKET_get_length_prefixed_2(&identities, &identity)
+ || !PACKET_get_net_4(&identities, &ticket_age)) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* TODO(TLS1.3): Should we validate the ticket age? */
+
+ 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;
+
+ md = ssl_md(sess->cipher->algorithm2);
+ if (md == NULL) {
+ /*
+ * Don't recognise this cipher so we can't use the session.
+ * Ignore it
+ */
+ SSL_SESSION_free(sess);
+ sess = NULL;
+ continue;
+ }
+
+ /*
+ * TODO(TLS1.3): Somehow we need to handle the case of a ticket renewal.
+ * Ignored for now
+ */
+
+ break;
+ }
+
+ if (sess == NULL)
+ return 1;
+
+ binderoffset = PACKET_data(pkt) - (const unsigned char *)s->init_buf->data;
+ hashsize = EVP_MD_size(md);
+
+ if (!PACKET_get_length_prefixed_2(pkt, &binders)) {
+ *al = SSL_AD_DECODE_ERROR;
+ goto err;
+ }
+
+ for (i = 0; i <= id; i++) {
+ if (!PACKET_get_length_prefixed_1(&binders, &binder)) {
+ *al = SSL_AD_DECODE_ERROR;
+ goto err;
+ }
+ }
+
+ if (PACKET_remaining(&binder) != hashsize
+ || tls_psk_do_binder(s, md,
+ (const unsigned char *)s->init_buf->data,
+ binderoffset, PACKET_data(&binder), NULL,
+ sess, 0) != 1) {
+ *al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS_PARSE_CTOS_PSK, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ sess->ext.tick_identity = id;
+ SSL_SESSION_free(s->session);
+ s->session = sess;
+ return 1;
+err:
+ return 0;
+}
+