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, ext = 0; 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_agel; if (!PACKET_get_length_prefixed_2(&identities, &identity) || !PACKET_get_net_4(&identities, &ticket_agel)) { *al = SSL_AD_DECODE_ERROR; return 0; } 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 (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)) { /* The ciphersuite is not compatible with this session. */ SSL_SESSION_free(sess); sess = NULL; continue; } 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, ext) != 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: SSL_SESSION_free(sess); return 0; }
SSL_SESSION *SSL_SESSION_dup(const SSL_SESSION *src) { return ssl_session_dup(src, 1); }