Exemplo n.º 1
0
int tls13_process_new_session_ticket(SSL *ssl) {
  SSL_SESSION *session =
      SSL_SESSION_dup(ssl->s3->established_session,
                      SSL_SESSION_INCLUDE_NONAUTH);
  if (session == NULL) {
    return 0;
  }

  CBS cbs, extensions, ticket;
  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
  if (!CBS_get_u32(&cbs, &session->tlsext_tick_lifetime_hint) ||
      !CBS_get_u32(&cbs, &session->ticket_flags) ||
      !CBS_get_u32(&cbs, &session->ticket_age_add) ||
      !CBS_get_u16_length_prefixed(&cbs, &extensions) ||
      !CBS_get_u16_length_prefixed(&cbs, &ticket) ||
      !CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) ||
      CBS_len(&cbs) != 0) {
    SSL_SESSION_free(session);
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    return 0;
  }

  session->ticket_age_add_valid = 1;
  session->not_resumable = 0;

  if (ssl->ctx->new_session_cb != NULL &&
      ssl->ctx->new_session_cb(ssl, session)) {
    /* |new_session_cb|'s return value signals that it took ownership. */
    return 1;
  }

  SSL_SESSION_free(session);
  return 1;
}
Exemplo n.º 2
0
static enum ssl_hs_wait_t do_process_certificate_request(SSL *ssl,
                                                         SSL_HANDSHAKE *hs) {
  ssl->s3->tmp.cert_request = 0;

  /* CertificateRequest may only be sent in certificate-based ciphers. */
  if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
    hs->state = state_process_server_finished;
    return ssl_hs_ok;
  }

  /* CertificateRequest is optional. */
  if (ssl->s3->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) {
    hs->state = state_process_server_certificate;
    return ssl_hs_ok;
  }

  CBS cbs, context, supported_signature_algorithms;
  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
  if (!CBS_get_u8_length_prefixed(&cbs, &context) ||
      !CBS_stow(&context, &ssl->s3->hs->cert_context,
                &ssl->s3->hs->cert_context_len) ||
      !CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) ||
      !tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) {
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    return ssl_hs_error;
  }

  uint8_t alert;
  STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs);
  if (ca_sk == NULL) {
    ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
    return ssl_hs_error;
  }

  /* Ignore extensions. */
  CBS extensions;
  if (!CBS_get_u16_length_prefixed(&cbs, &extensions) ||
      CBS_len(&cbs) != 0) {
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    return ssl_hs_error;
  }

  ssl->s3->tmp.cert_request = 1;
  sk_X509_NAME_pop_free(ssl->s3->tmp.ca_names, X509_NAME_free);
  ssl->s3->tmp.ca_names = ca_sk;

  if (!ssl->method->hash_current_message(ssl)) {
    return ssl_hs_error;
  }

  hs->state = state_process_server_certificate;
  return ssl_hs_read_message;
}
Exemplo n.º 3
0
/* SSL_SESSION_parse_string gets an optional ASN.1 OCTET STRING
 * explicitly tagged with |tag| from |cbs| and stows it in |*out_ptr|
 * and |*out_len|. If |*out_ptr| is not NULL, it frees the existing
 * contents. On entry, if the element was not found, it sets
 * |*out_ptr| to NULL. It returns one on success, whether or not the
 * element was found, and zero on decode error. */
static int SSL_SESSION_parse_octet_string(CBS *cbs, uint8_t **out_ptr,
                                          size_t *out_len, unsigned tag) {
  CBS value;
  if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    return 0;
  }
  if (!CBS_stow(&value, out_ptr, out_len)) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    return 0;
  }
  return 1;
}
Exemplo n.º 4
0
int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) {
  SSL *const ssl = hs->ssl;
  CBS cbs, context, certificate_list;
  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
  if (!CBS_get_u8_length_prefixed(&cbs, &context) ||
      CBS_len(&context) != 0) {
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    return 0;
  }

  const int retain_sha256 =
      ssl->server && ssl->retain_only_sha256_of_client_certs;
  int ret = 0;

  EVP_PKEY *pkey = NULL;
  STACK_OF(CRYPTO_BUFFER) *certs = sk_CRYPTO_BUFFER_new_null();
  if (certs == NULL) {
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list)) {
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    goto err;
  }

  while (CBS_len(&certificate_list) > 0) {
    CBS certificate, extensions;
    if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
        !CBS_get_u16_length_prefixed(&certificate_list, &extensions) ||
        CBS_len(&certificate) == 0) {
      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
      OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
      goto err;
    }

    if (sk_CRYPTO_BUFFER_num(certs) == 0) {
      pkey = ssl_cert_parse_pubkey(&certificate);
      if (pkey == NULL) {
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
        OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
        goto err;
      }
      /* TLS 1.3 always uses certificate keys for signing thus the correct
       * keyUsage is enforced. */
      if (!ssl_cert_check_digital_signature_key_usage(&certificate)) {
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
        goto err;
      }

      if (retain_sha256) {
        /* Retain the hash of the leaf certificate if requested. */
        SHA256(CBS_data(&certificate), CBS_len(&certificate),
               ssl->s3->new_session->peer_sha256);
      }
    }

    CRYPTO_BUFFER *buf =
        CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool);
    if (buf == NULL ||
        !sk_CRYPTO_BUFFER_push(certs, buf)) {
      CRYPTO_BUFFER_free(buf);
      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }

    /* Parse out the extensions. */
    int have_status_request = 0, have_sct = 0;
    CBS status_request, sct;
    const SSL_EXTENSION_TYPE ext_types[] = {
        {TLSEXT_TYPE_status_request, &have_status_request, &status_request},
        {TLSEXT_TYPE_certificate_timestamp, &have_sct, &sct},
    };

    uint8_t alert;
    if (!ssl_parse_extensions(&extensions, &alert, ext_types,
                              OPENSSL_ARRAY_SIZE(ext_types),
                              0 /* reject unknown */)) {
      ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
      goto err;
    }

    /* All Certificate extensions are parsed, but only the leaf extensions are
     * stored. */
    if (have_status_request) {
      if (ssl->server || !ssl->ocsp_stapling_enabled) {
        OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
        goto err;
      }

      uint8_t status_type;
      CBS ocsp_response;
      if (!CBS_get_u8(&status_request, &status_type) ||
          status_type != TLSEXT_STATUSTYPE_ocsp ||
          !CBS_get_u24_length_prefixed(&status_request, &ocsp_response) ||
          CBS_len(&ocsp_response) == 0 ||
          CBS_len(&status_request) != 0) {
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
        goto err;
      }

      if (sk_CRYPTO_BUFFER_num(certs) == 1 &&
          !CBS_stow(&ocsp_response, &ssl->s3->new_session->ocsp_response,
                    &ssl->s3->new_session->ocsp_response_length)) {
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
        goto err;
      }
    }

    if (have_sct) {
      if (ssl->server || !ssl->signed_cert_timestamps_enabled) {
        OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
        goto err;
      }

      if (!ssl_is_sct_list_valid(&sct)) {
        OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
        goto err;
      }

      if (sk_CRYPTO_BUFFER_num(certs) == 1 &&
          !CBS_stow(&sct,
                    &ssl->s3->new_session->tlsext_signed_cert_timestamp_list,
                    &ssl->s3->new_session
                         ->tlsext_signed_cert_timestamp_list_length)) {
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
        goto err;
      }
    }
  }

  if (CBS_len(&cbs) != 0) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    goto err;
  }

  EVP_PKEY_free(hs->peer_pubkey);
  hs->peer_pubkey = pkey;
  pkey = NULL;

  sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free);
  ssl->s3->new_session->certs = certs;
  certs = NULL;

  if (!ssl_session_x509_cache_objects(ssl->s3->new_session)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    goto err;
  }

  if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0) {
    if (!allow_anonymous) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_CERTIFICATE_REQUIRED);
      goto err;
    }

    /* OpenSSL returns X509_V_OK when no certificates are requested. This is
     * classed by them as a bug, but it's assumed by at least NGINX. */
    ssl->s3->new_session->verify_result = X509_V_OK;

    /* No certificate, so nothing more to do. */
    ret = 1;
    goto err;
  }

  ssl->s3->new_session->peer_sha256_valid = retain_sha256;

  if (!ssl_verify_cert_chain(ssl, &ssl->s3->new_session->verify_result,
                             ssl->s3->new_session->x509_chain)) {
    goto err;
  }

  ret = 1;

err:
  sk_CRYPTO_BUFFER_pop_free(certs, CRYPTO_BUFFER_free);
  EVP_PKEY_free(pkey);
  return ret;
}
Exemplo n.º 5
0
SSL_SESSION *
d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length)
{
	CBS cbs, session, cipher_suite, session_id, master_key, peer_cert;
	CBS hostname, ticket;
	uint64_t version, tls_version, stime, timeout, verify_result, lifetime;
	const unsigned char *peer_cert_bytes;
	uint16_t cipher_value;
	SSL_SESSION *s = NULL;
	size_t data_len;
	int present;

	if (a != NULL)
		s = *a;

	if (s == NULL) {
		if ((s = SSL_SESSION_new()) == NULL) {
			SSLerrorx(ERR_R_MALLOC_FAILURE);
			return (NULL);
		}
	}

	CBS_init(&cbs, *pp, length);

	if (!CBS_get_asn1(&cbs, &session, CBS_ASN1_SEQUENCE))
		goto err;

	/* Session ASN1 version. */
	if (!CBS_get_asn1_uint64(&session, &version))
		goto err;
	if (version != SSL_SESSION_ASN1_VERSION)
		goto err;

	/* TLS/SSL Protocol Version. */
	if (!CBS_get_asn1_uint64(&session, &tls_version))
		goto err;
	if (tls_version > INT_MAX)
		goto err;
	s->ssl_version = (int)tls_version;

	/* Cipher suite. */
	if (!CBS_get_asn1(&session, &cipher_suite, CBS_ASN1_OCTETSTRING))
		goto err;
	if (!CBS_get_u16(&cipher_suite, &cipher_value))
		goto err;
	if (CBS_len(&cipher_suite) != 0)
		goto err;

	/* XXX - populate cipher instead? */
	s->cipher = NULL;
	s->cipher_id = SSL3_CK_ID | cipher_value;

	/* Session ID. */
	if (!CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING))
		goto err;
	if (!CBS_write_bytes(&session_id, s->session_id, sizeof(s->session_id),
	    &data_len))
		goto err;
	if (data_len > UINT_MAX)
		goto err;
	s->session_id_length = (unsigned int)data_len;

	/* Master key. */
	if (!CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING))
		goto err;
	if (!CBS_write_bytes(&master_key, s->master_key, sizeof(s->master_key),
	    &data_len))
		goto err;
	if (data_len > INT_MAX)
		goto err;
	s->master_key_length = (int)data_len;

	/* Time [1]. */
	s->time = time(NULL);
	if (!CBS_get_optional_asn1_uint64(&session, &stime, SSLASN1_TIME_TAG,
	    0))
		goto err;
	if (stime > time_max())
		goto err;
	if (stime != 0)
		s->time = (time_t)stime;

	/* Timeout [2]. */
	s->timeout = 3;
	if (!CBS_get_optional_asn1_uint64(&session, &timeout,
	    SSLASN1_TIMEOUT_TAG, 0))
		goto err;
	if (timeout > LONG_MAX)
		goto err;
	if (timeout != 0)
		s->timeout = (long)timeout;
	
	/* Peer certificate [3]. */
	X509_free(s->peer);
	s->peer = NULL;
	if (!CBS_get_optional_asn1(&session, &peer_cert, &present,
	    SSLASN1_PEER_CERT_TAG))
		goto err;
	if (present) {
		data_len = CBS_len(&peer_cert);
		if (data_len > LONG_MAX)
			goto err;
		peer_cert_bytes = CBS_data(&peer_cert);
		if (d2i_X509(&s->peer, &peer_cert_bytes,
		    (long)data_len) == NULL)
			goto err;
	}

	/* Session ID context [4]. */
	s->sid_ctx_length = 0;
	if (!CBS_get_optional_asn1_octet_string(&session, &session_id, &present,
	    SSLASN1_SESSION_ID_CTX_TAG))
		goto err;
	if (present) {
		if (!CBS_write_bytes(&session_id, (uint8_t *)&s->sid_ctx,
		    sizeof(s->sid_ctx), &data_len))
			goto err;
		if (data_len > UINT_MAX)
			goto err;
		s->sid_ctx_length = (unsigned int)data_len;
	}

	/* Verify result [5]. */
	s->verify_result = X509_V_OK;
	if (!CBS_get_optional_asn1_uint64(&session, &verify_result,
	    SSLASN1_VERIFY_RESULT_TAG, X509_V_OK))
		goto err;
	if (verify_result > LONG_MAX)
		goto err;
	s->verify_result = (long)verify_result;

	/* Hostname [6]. */
	free(s->tlsext_hostname);
	s->tlsext_hostname = NULL;
	if (!CBS_get_optional_asn1_octet_string(&session, &hostname, &present,
	    SSLASN1_HOSTNAME_TAG))
		goto err;
	if (present) {
		if (CBS_contains_zero_byte(&hostname))
			goto err;
		if (!CBS_strdup(&hostname, &s->tlsext_hostname))
			goto err;
	}
	
	/* PSK identity hint [7]. */
	/* PSK identity [8]. */

	/* Ticket lifetime [9]. */
	s->tlsext_tick_lifetime_hint = 0;
	/* XXX - tlsext_ticklen is not yet set... */
	if (s->tlsext_ticklen > 0 && s->session_id_length > 0)
		s->tlsext_tick_lifetime_hint = -1;
	if (!CBS_get_optional_asn1_uint64(&session, &lifetime,
	    SSLASN1_LIFETIME_TAG, 0))
		goto err;
	if (lifetime > LONG_MAX)
		goto err;
	if (lifetime > 0)
		s->tlsext_tick_lifetime_hint = (long)lifetime;

	/* Ticket [10]. */
	free(s->tlsext_tick);
	s->tlsext_tick = NULL;
	if (!CBS_get_optional_asn1_octet_string(&session, &ticket, &present,
	    SSLASN1_TICKET_TAG))
		goto err;
	if (present) {
		if (!CBS_stow(&ticket, &s->tlsext_tick, &s->tlsext_ticklen))
			goto err;
	}

	/* Compression method [11]. */
	/* SRP username [12]. */

	*pp = CBS_data(&cbs);

	if (a != NULL)
		*a = s;

	return (s);

err:
	ERR_asprintf_error_data("offset=%d", (int)(CBS_data(&cbs) - *pp));

	if (s != NULL && (a == NULL || *a != s))
		SSL_SESSION_free(s);

	return (NULL);
}