Beispiel #1
0
int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
				const unsigned char *limit, SSL_SESSION **ret)
	{
	/* Point after session ID in client hello */
	const unsigned char *p = session_id + len;
	unsigned short i;

	/* If tickets disabled behave as if no ticket present
 	 * to permit stateful resumption.
 	 */
	if (SSL_get_options(s) & SSL_OP_NO_TICKET)
		return 1;

	if ((s->version <= SSL3_VERSION) || !limit)
		return 1;
	if (p >= limit)
		return -1;
	/* Skip past cipher list */
	n2s(p, i);
	p+= i;
	if (p >= limit)
		return -1;
	/* Skip past compression algorithm list */
	i = *(p++);
	p += i;
	if (p > limit)
		return -1;
	/* Now at start of extensions */
	if ((p + 2) >= limit)
		return 1;
	n2s(p, i);
	while ((p + 4) <= limit)
		{
		unsigned short type, size;
		n2s(p, type);
		n2s(p, size);
		if (p + size > limit)
			return 1;
		if (type == TLSEXT_TYPE_session_ticket)
			{
			/* If zero length note client will accept a ticket
 			 * and indicate cache miss to trigger full handshake
 			 */
			if (size == 0)
				{
				s->tlsext_ticket_expected = 1;
				return 0;	/* Cache miss */
				}
			return tls_decrypt_ticket(s, p, size, session_id, len,
									ret);
			}
		p += size;
		}
	return 1;
	}
Beispiel #2
0
/* Since the server cache lookup is done early on in the processing of the
 * ClientHello, and other operations depend on the result, we need to handle
 * any TLS session ticket extension at the same time.
 *
 *   session_id: points at the session ID in the ClientHello. This code will
 *       read past the end of this in order to parse out the session ticket
 *       extension, if any.
 *   len: the length of the session ID.
 *   limit: a pointer to the first byte after the ClientHello.
 *   ret: (output) on return, if a ticket was decrypted, then this is set to
 *       point to the resulting session.
 *
 * If s->internal->tls_session_secret_cb is set then we are expecting a pre-shared key
 * ciphersuite, in which case we have no use for session tickets and one will
 * never be decrypted, nor will s->internal->tlsext_ticket_expected be set to 1.
 *
 * Returns:
 *   -1: fatal error, either from parsing or decrypting the ticket.
 *    0: no ticket was found (or was ignored, based on settings).
 *    1: a zero length extension was found, indicating that the client supports
 *       session tickets but doesn't currently have one to offer.
 *    2: either s->internal->tls_session_secret_cb was set, or a ticket was offered but
 *       couldn't be decrypted because of a non-fatal error.
 *    3: a ticket was successfully decrypted and *ret was set.
 *
 * Side effects:
 *   Sets s->internal->tlsext_ticket_expected to 1 if the server will have to issue
 *   a new session ticket to the client because the client indicated support
 *   (and s->internal->tls_session_secret_cb is NULL) but the client either doesn't have
 *   a session ticket or we couldn't use the one it gave us, or if
 *   s->ctx->tlsext_ticket_key_cb asked to renew the client's ticket.
 *   Otherwise, s->internal->tlsext_ticket_expected is set to 0.
 */
int
tls1_process_ticket(SSL *s, const unsigned char *session, int session_len,
    const unsigned char *limit, SSL_SESSION **ret)
{
	/* Point after session ID in client hello */
	CBS session_id, cookie, cipher_list, compress_algo, extensions;

	*ret = NULL;
	s->internal->tlsext_ticket_expected = 0;

	/* If tickets disabled behave as if no ticket present
	 * to permit stateful resumption.
	 */
	if (SSL_get_options(s) & SSL_OP_NO_TICKET)
		return 0;
	if (!limit)
		return 0;

	if (limit < session)
		return -1;

	CBS_init(&session_id, session, limit - session);

	/* Skip past the session id */
	if (!CBS_skip(&session_id, session_len))
		return -1;

	/* Skip past DTLS cookie */
	if (SSL_IS_DTLS(s)) {
		if (!CBS_get_u8_length_prefixed(&session_id, &cookie))
			return -1;
	}

	/* Skip past cipher list */
	if (!CBS_get_u16_length_prefixed(&session_id, &cipher_list))
		return -1;

	/* Skip past compression algorithm list */
	if (!CBS_get_u8_length_prefixed(&session_id, &compress_algo))
		return -1;

	/* Now at start of extensions */
	if (CBS_len(&session_id) == 0)
		return 0;
	if (!CBS_get_u16_length_prefixed(&session_id, &extensions))
		return -1;

	while (CBS_len(&extensions) > 0) {
		CBS ext_data;
		uint16_t ext_type;

		if (!CBS_get_u16(&extensions, &ext_type) ||
		    !CBS_get_u16_length_prefixed(&extensions, &ext_data))
			return -1;

		if (ext_type == TLSEXT_TYPE_session_ticket) {
			int r;
			if (CBS_len(&ext_data) == 0) {
				/* The client will accept a ticket but doesn't
				 * currently have one. */
				s->internal->tlsext_ticket_expected = 1;
				return 1;
			}
			if (s->internal->tls_session_secret_cb) {
				/* Indicate that the ticket couldn't be
				 * decrypted rather than generating the session
				 * from ticket now, trigger abbreviated
				 * handshake based on external mechanism to
				 * calculate the master secret later. */
				return 2;
			}

			r = tls_decrypt_ticket(s, CBS_data(&ext_data),
			    CBS_len(&ext_data), session, session_len, ret);

			switch (r) {
			case 2: /* ticket couldn't be decrypted */
				s->internal->tlsext_ticket_expected = 1;
				return 2;
			case 3: /* ticket was decrypted */
				return r;
			case 4: /* ticket decrypted but need to renew */
				s->internal->tlsext_ticket_expected = 1;
				return 3;
			default: /* fatal error */
				return -1;
			}
		}
	}
	return 0;
}
Beispiel #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, 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;
}
Beispiel #4
0
int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
				const unsigned char *limit, SSL_SESSION **ret)
	{
	/* Point after session ID in client hello */
	const unsigned char *p = session_id + len;
	unsigned short i;

	/* If tickets disabled behave as if no ticket present
 	 * to permit stateful resumption.
 	 */
	if (SSL_get_options(s) & SSL_OP_NO_TICKET)
		return 1;

	if ((s->version <= SSL3_VERSION) || !limit)
		return 1;
	if (p >= limit)
		return -1;
	/* Skip past DTLS cookie */
	if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
		{
		i = *(p++);
		p+= i;
		if (p >= limit)
			return -1;
		}
	/* Skip past cipher list */
	n2s(p, i);
	p+= i;
	if (p >= limit)
		return -1;
	/* Skip past compression algorithm list */
	i = *(p++);
	p += i;
	if (p > limit)
		return -1;
	/* Now at start of extensions */
	if ((p + 2) >= limit)
		return 1;
	n2s(p, i);
	while ((p + 4) <= limit)
		{
		unsigned short type, size;
		n2s(p, type);
		n2s(p, size);
		if (p + size > limit)
			return 1;
		if (type == TLSEXT_TYPE_session_ticket)
			{
			/* If tickets disabled indicate cache miss which will
 			 * trigger a full handshake
 			 */
			if (SSL_get_options(s) & SSL_OP_NO_TICKET)
				return 1;
			/* If zero length note client will accept a ticket
 			 * and indicate cache miss to trigger full handshake
 			 */
			if (size == 0)
				{
				s->tlsext_ticket_expected = 1;
				return 0;	/* Cache miss */
				}
			if (s->tls_session_secret_cb)
				{
				/* Indicate cache miss here and instead of
				 * generating the session from ticket now,
				 * trigger abbreviated handshake based on
				 * external mechanism to calculate the master
				 * secret later. */
				return 0;
				}
			return tls_decrypt_ticket(s, p, size, session_id, len,
									ret);
			}
		p += size;
		}
	return 1;
	}
Beispiel #5
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;
}