Ejemplo n.º 1
0
/*
 * 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
}
Ejemplo n.º 2
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, 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;
}
Ejemplo n.º 3
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;
}