/* * Construct the pre_shared_key extension */ int tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al) { #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; int ret = 0; s->session->ext.tick_identity = TLSEXT_PSK_BAD_IDENTITY; /* * If this is an incompatible or new session then we have nothing to resume * so don't add this extension. */ if (s->session->ssl_version != TLS1_3_VERSION || s->session->ext.ticklen == 0) return 1; if (s->session->cipher == NULL) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR); goto err; } md = ssl_md(s->session->cipher->algorithm2); if (md == NULL) { /* Don't recognise this cipher so we can't use the session. Ignore it */ return 1; } /* * 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. */ return 1; } /* * 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. */ return 1; } /* * Obfuscate the age. Overflow here is fine, this addition is supposed to * be mod 2^32. */ agems += s->session->ext.tick_age_add; hashsize = EVP_MD_size(md); /* 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_get_total_written(pkt, &binderoffset) || !WPACKET_start_sub_packet_u16(pkt) || !WPACKET_sub_allocate_bytes_u8(pkt, hashsize, &binder) || !WPACKET_close(pkt) || !WPACKET_close(pkt) || !WPACKET_get_total_written(pkt, &msglen) /* * We need to fill in all the sub-packet lengths now so we can * calculate the HMAC of the message up to the binders */ || !WPACKET_fill_lengths(pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR); goto err; } msgstart = WPACKET_get_curr(pkt) - msglen; if (tls_psk_do_binder(s, md, msgstart, binderoffset, NULL, binder, s->session, 1) != 1) { SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_PSK, ERR_R_INTERNAL_ERROR); goto err; } s->session->ext.tick_identity = 0; ret = 1; err: return ret; #else return 1; #endif }
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; }
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; uint32_t ticket_age = 0, now, agesec, agems; /* * 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; int ret; if (!PACKET_get_length_prefixed_2(&identities, &identity) || !PACKET_get_net_4(&identities, &ticket_agel)) { *al = SSL_AD_DECODE_ERROR; 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) { *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; 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; err: SSL_SESSION_free(sess); return 0; }