Exemple #1
0
EXT_RETURN tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt,
                                             unsigned int context, X509 *x,
                                             size_t chainidx, int *al)
{
    const unsigned char *npa;
    unsigned int npalen;
    int ret;
    int npn_seen = s->s3->npn_seen;

    s->s3->npn_seen = 0;
    if (!npn_seen || s->ctx->ext.npn_advertised_cb == NULL)
        return EXT_RETURN_NOT_SENT;

    ret = s->ctx->ext.npn_advertised_cb(s, &npa, &npalen,
                                        s->ctx->ext.npn_advertised_cb_arg);
    if (ret == SSL_TLSEXT_ERR_OK) {
        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
                || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) {
            SSLerr(SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG,
                   ERR_R_INTERNAL_ERROR);
            return EXT_RETURN_FAIL;
        }
        s->s3->npn_seen = 1;
    }

    return EXT_RETURN_SENT;
}
Exemple #2
0
int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, int *al)
{
    s->s3->alpn_sent = 0;

    /*
     * finish_md_len is non-zero during a renegotiation, so
     * this avoids sending ALPN during the renegotiation
     */
    if (s->alpn_client_proto_list == NULL || s->s3->tmp.finish_md_len != 0)
        return 1;

    if (!WPACKET_put_bytes_u16(pkt,
                TLSEXT_TYPE_application_layer_protocol_negotiation)
               /* Sub-packet ALPN extension */
            || !WPACKET_start_sub_packet_u16(pkt)
            || !WPACKET_sub_memcpy_u16(pkt, s->alpn_client_proto_list,
                                       s->alpn_client_proto_list_len)
            || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_ALPN, ERR_R_INTERNAL_ERROR);
        return 0;
    }
    s->s3->alpn_sent = 1;

    return 1;
}
Exemple #3
0
int tls_construct_stoc_next_proto_neg(SSL *s, WPACKET *pkt, int *al)
{
    const unsigned char *npa;
    unsigned int npalen;
    int ret;
    int next_proto_neg_seen = s->s3->next_proto_neg_seen;

    s->s3->next_proto_neg_seen = 0;
    if (!next_proto_neg_seen || s->ctx->next_protos_advertised_cb == NULL)
        return 1;

    ret = s->ctx->next_protos_advertised_cb(s, &npa, &npalen,
                                      s->ctx->next_protos_advertised_cb_arg);
    if (ret == SSL_TLSEXT_ERR_OK) {
        if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
                || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) {
            SSLerr(SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG,
                   ERR_R_INTERNAL_ERROR);
            return 0;
        }
        s->s3->next_proto_neg_seen = 1;
    }

    return 1;
}
Exemple #4
0
int tls_construct_stoc_key_share(SSL *s, WPACKET *pkt, int *al)
{
    unsigned char *encodedPoint;
    size_t encoded_pt_len = 0;
    EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;

    if (s->hit)
        return 1;

    if (ckey == NULL) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
            || !WPACKET_start_sub_packet_u16(pkt)
            || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    skey = ssl_generate_pkey(ckey);
    if (skey == NULL) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_MALLOC_FAILURE);
        return 0;
    }

    /* Generate encoding of server key */
    encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
    if (encoded_pt_len == 0) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_EC_LIB);
        EVP_PKEY_free(skey);
        return 0;
    }

    if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
            || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        EVP_PKEY_free(skey);
        OPENSSL_free(encodedPoint);
        return 0;
    }
    OPENSSL_free(encodedPoint);

    /* This causes the crypto state to be updated based on the derived keys */
    s->s3->tmp.pkey = skey;
    if (ssl_derive(s, skey, ckey, 1) == 0) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    return 1;
}
Exemple #5
0
static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
{
    unsigned char *encoded_point;
    EVP_PKEY *key_share_key;
    size_t encodedlen;

    key_share_key = ssl_generate_pkey_curve(curve_id);
    if (key_share_key == NULL) {
        SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_EVP_LIB);
        return 0;
    }

    /* Encode the public key. */
    encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
                                                &encoded_point);
    if (encodedlen == 0) {
        SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_EC_LIB);
        EVP_PKEY_free(key_share_key);
        return 0;
    }

    /* Create KeyShareEntry */
    if (!WPACKET_put_bytes_u16(pkt, curve_id)
            || !WPACKET_sub_memcpy_u16(pkt, encoded_point, encodedlen)) {
        SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        EVP_PKEY_free(key_share_key);
        OPENSSL_free(encoded_point);
        return 0;
    }

    /*
     * TODO(TLS1.3): When changing to send more than one key_share we're
     * going to need to be able to save more than one EVP_PKEY. For now
     * we reuse the existing tmp.pkey
     */
    s->s3->tmp.pkey = key_share_key;
    s->s3->group_id = curve_id;
    OPENSSL_free(encoded_point);

    return 1;
}
Exemple #6
0
int tls_construct_ctos_session_ticket(SSL *s, WPACKET *pkt,
                                      unsigned int context, X509 *x,
                                      size_t chainidx, int *al)
{
    size_t ticklen;

    if (!tls_use_ticket(s))
        return 1;

    if (!s->new_session && s->session != NULL
            && s->session->ext.tick != NULL
            && s->session->ssl_version != TLS1_3_VERSION) {
        ticklen = s->session->ext.ticklen;
    } else if (s->session && s->ext.session_ticket != NULL
               && s->ext.session_ticket->data != NULL) {
        ticklen = s->ext.session_ticket->length;
        s->session->ext.tick = OPENSSL_malloc(ticklen);
        if (s->session->ext.tick == NULL) {
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET,
                   ERR_R_INTERNAL_ERROR);
            return 0;
        }
        memcpy(s->session->ext.tick,
               s->ext.session_ticket->data, ticklen);
        s->session->ext.ticklen = ticklen;
    } else {
        ticklen = 0;
    }

    if (ticklen == 0 && s->ext.session_ticket != NULL &&
            s->ext.session_ticket->data == NULL)
        return 1;

    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
            || !WPACKET_sub_memcpy_u16(pkt, s->session->ext.tick, ticklen)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SESSION_TICKET, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    return 1;
}
Exemple #7
0
int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context, X509 *x,
                            size_t chainidx, int *al)
{
    s->s3->alpn_sent = 0;

    if (s->ext.alpn == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
        return 1;

    if (!WPACKET_put_bytes_u16(pkt,
                TLSEXT_TYPE_application_layer_protocol_negotiation)
               /* Sub-packet ALPN extension */
            || !WPACKET_start_sub_packet_u16(pkt)
            || !WPACKET_sub_memcpy_u16(pkt, s->ext.alpn, s->ext.alpn_len)
            || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_ALPN, ERR_R_INTERNAL_ERROR);
        return 0;
    }
    s->s3->alpn_sent = 1;

    return 1;
}
Exemple #8
0
int tls_construct_ctos_server_name(SSL *s, WPACKET *pkt, int *al)
{
    if (s->tlsext_hostname == NULL)
        return 1;

    /* Add TLS extension servername to the Client Hello message */
    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
               /* Sub-packet for server_name extension */
            || !WPACKET_start_sub_packet_u16(pkt)
               /* Sub-packet for servername list (always 1 hostname)*/
            || !WPACKET_start_sub_packet_u16(pkt)
            || !WPACKET_put_bytes_u8(pkt, TLSEXT_NAMETYPE_host_name)
            || !WPACKET_sub_memcpy_u16(pkt, s->tlsext_hostname,
                                       strlen(s->tlsext_hostname))
            || !WPACKET_close(pkt)
            || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    return 1;
}
Exemple #9
0
EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
                                        unsigned int context, X509 *x,
                                        size_t chainidx, int *al)
{
#ifndef OPENSSL_NO_TLS1_3
    unsigned char *encodedPoint;
    size_t encoded_pt_len = 0;
    EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;

    if (ckey == NULL) {
        /* No key_share received from client */
        if (s->hello_retry_request) {
            if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
                    || !WPACKET_start_sub_packet_u16(pkt)
                    || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)
                    || !WPACKET_close(pkt)) {
                SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
                       ERR_R_INTERNAL_ERROR);
                return EXT_RETURN_FAIL;
            }

            return EXT_RETURN_SENT;
        }

        /* Must be resuming. */
        if (!s->hit || !tls13_generate_handshake_secret(s, NULL, 0)) {
            *al = SSL_AD_INTERNAL_ERROR;
            SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
            return EXT_RETURN_FAIL;
        }
        return EXT_RETURN_NOT_SENT;
    }

    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
            || !WPACKET_start_sub_packet_u16(pkt)
            || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return EXT_RETURN_FAIL;
    }

    skey = ssl_generate_pkey(ckey);
    if (skey == NULL) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_MALLOC_FAILURE);
        return EXT_RETURN_FAIL;
    }

    /* Generate encoding of server key */
    encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
    if (encoded_pt_len == 0) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_EC_LIB);
        EVP_PKEY_free(skey);
        return EXT_RETURN_FAIL;
    }

    if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
            || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        EVP_PKEY_free(skey);
        OPENSSL_free(encodedPoint);
        return EXT_RETURN_FAIL;
    }
    OPENSSL_free(encodedPoint);

    /* This causes the crypto state to be updated based on the derived keys */
    s->s3->tmp.pkey = skey;
    if (ssl_derive(s, skey, ckey, 1) == 0) {
        SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return EXT_RETURN_FAIL;
    }
#endif

    return EXT_RETURN_SENT;
}
Exemple #10
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
}
Exemple #11
0
int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, int *al)
{
    size_t i, sharessent = 0, num_curves = 0;
    const unsigned char *pcurves = NULL;

    /* key_share extension */
    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
               /* Extension data sub-packet */
            || !WPACKET_start_sub_packet_u16(pkt)
               /* KeyShare list sub-packet */
            || !WPACKET_start_sub_packet_u16(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    pcurves = s->tlsext_supportedgroupslist;
    if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    /*
     * TODO(TLS1.3): Make the number of key_shares sent configurable. For
     * now, just send one
     */
    for (i = 0; i < num_curves && sharessent < 1; i++, pcurves += 2) {
        unsigned char *encodedPoint = NULL;
        unsigned int curve_id = 0;
        EVP_PKEY *key_share_key = NULL;
        size_t encodedlen;

        if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED))
            continue;

        if (s->s3->tmp.pkey != NULL) {
            /* Shouldn't happen! */
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
            return 0;
        }

        /* Generate a key for this key_share */
        curve_id = (pcurves[0] << 8) | pcurves[1];
        key_share_key = ssl_generate_pkey_curve(curve_id);
        if (key_share_key == NULL) {
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EVP_LIB);
            return 0;
        }

        /* Encode the public key. */
        encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
                                                    &encodedPoint);
        if (encodedlen == 0) {
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EC_LIB);
            EVP_PKEY_free(key_share_key);
            return 0;
        }

        /* Create KeyShareEntry */
        if (!WPACKET_put_bytes_u16(pkt, curve_id)
                || !WPACKET_sub_memcpy_u16(pkt, encodedPoint, encodedlen)) {
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
            EVP_PKEY_free(key_share_key);
            OPENSSL_free(encodedPoint);
            return 0;
        }

        /*
         * TODO(TLS1.3): When changing to send more than one key_share we're
         * going to need to be able to save more than one EVP_PKEY. For now
         * we reuse the existing tmp.pkey
         */
        s->s3->group_id = curve_id;
        s->s3->tmp.pkey = key_share_key;
        sharessent++;
        OPENSSL_free(encodedPoint);
    }

    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    return 1;
}