int ssl3_read_change_cipher_spec(SSL *ssl) { SSL3_RECORD *rr = &ssl->s3->rrec; if (rr->length == 0) { int ret = ssl3_get_record(ssl); if (ret <= 0) { return ret; } } if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); return -1; } if (rr->length != 1 || rr->data[0] != SSL3_MT_CCS) { OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_CHANGE_CIPHER_SPEC); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); return -1; } ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, rr->length); rr->length = 0; ssl_read_buffer_discard(ssl); return 1; }
static int resolve_ecdhe_secret(SSL_HANDSHAKE *hs, int *out_need_retry, SSL_CLIENT_HELLO *client_hello) { SSL *const ssl = hs->ssl; *out_need_retry = 0; /* We only support connections that include an ECDHE key exchange. */ CBS key_share; if (!ssl_client_hello_get_extension(client_hello, &key_share, TLSEXT_TYPE_key_share)) { OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION); return 0; } int found_key_share; uint8_t *dhe_secret; size_t dhe_secret_len; uint8_t alert = SSL_AD_DECODE_ERROR; if (!ssl_ext_key_share_parse_clienthello(hs, &found_key_share, &dhe_secret, &dhe_secret_len, &alert, &key_share)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return 0; } if (!found_key_share) { *out_need_retry = 1; return 0; } int ok = tls13_advance_key_schedule(hs, dhe_secret, dhe_secret_len); OPENSSL_free(dhe_secret); return ok; }
int tls13_post_handshake(SSL *ssl) { if (ssl->s3->tmp.message_type == SSL3_MT_KEY_UPDATE) { ssl->s3->key_update_count++; if (ssl->s3->key_update_count > kMaxKeyUpdates) { OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MANY_KEY_UPDATES); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); return 0; } return tls13_receive_key_update(ssl); } ssl->s3->key_update_count = 0; if (ssl->s3->tmp.message_type == SSL3_MT_NEW_SESSION_TICKET && !ssl->server) { return tls13_process_new_session_ticket(ssl); } // TODO(svaldez): Handle post-handshake authentication. ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); return 0; }
static enum ssl_hs_wait_t do_process_second_client_hello(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) { return ssl_hs_error; } SSL_CLIENT_HELLO client_hello; if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, ssl->init_num)) { OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return ssl_hs_error; } int need_retry; if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) { if (need_retry) { /* Only send one HelloRetryRequest. */ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); } return ssl_hs_error; } if (!ssl_hash_current_message(ssl)) { return ssl_hs_error; } ssl->method->received_flight(ssl); hs->tls13_state = state_send_server_hello; return ssl_hs_ok; }
static enum ssl_hs_wait_t do_process_hello_retry_request(SSL *ssl, SSL_HANDSHAKE *hs) { if (ssl->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST) { hs->state = state_process_server_hello; return ssl_hs_ok; } CBS cbs, extensions; uint16_t server_wire_version, cipher_suite, group_id; CBS_init(&cbs, ssl->init_msg, ssl->init_num); if (!CBS_get_u16(&cbs, &server_wire_version) || !CBS_get_u16(&cbs, &cipher_suite) || !CBS_get_u16(&cbs, &group_id) || /* We do not currently parse any HelloRetryRequest extensions. */ !CBS_get_u16_length_prefixed(&cbs, &extensions) || CBS_len(&cbs) != 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return ssl_hs_error; } /* TODO(svaldez): Don't do early_data on HelloRetryRequest. */ const uint16_t *groups; size_t groups_len; tls1_get_grouplist(ssl, 0 /* local groups */, &groups, &groups_len); int found = 0; for (size_t i = 0; i < groups_len; i++) { if (groups[i] == group_id) { found = 1; break; } } if (!found) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); return ssl_hs_error; } for (size_t i = 0; i < ssl->s3->hs->groups_len; i++) { /* Check that the HelloRetryRequest does not request a key share that was * provided in the initial ClientHello. * * TODO(svaldez): Don't enforce this check when the HelloRetryRequest is due * to a cookie. */ if (SSL_ECDH_CTX_get_id(&ssl->s3->hs->groups[i]) == group_id) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); return ssl_hs_error; } } ssl_handshake_clear_groups(ssl->s3->hs); ssl->s3->hs->retry_group = group_id; hs->state = state_send_second_client_hello; return ssl_hs_ok; }
int tls13_process_certificate_verify(SSL *ssl) { int ret = 0; X509 *peer = ssl->s3->new_session->peer; EVP_PKEY *pkey = NULL; uint8_t *msg = NULL; size_t msg_len; /* Filter out unsupported certificate types. */ pkey = X509_get_pubkey(peer); if (pkey == NULL) { goto err; } CBS cbs, signature; uint16_t signature_algorithm; CBS_init(&cbs, ssl->init_msg, ssl->init_num); if (!CBS_get_u16(&cbs, &signature_algorithm) || !CBS_get_u16_length_prefixed(&cbs, &signature) || 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; } int al; if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, al); goto err; } ssl->s3->tmp.peer_signature_algorithm = signature_algorithm; if (!tls13_get_cert_verify_signature_input( ssl, &msg, &msg_len, ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); goto err; } int sig_ok = ssl_public_key_verify(ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm, pkey, msg, msg_len); #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) sig_ok = 1; ERR_clear_error(); #endif if (!sig_ok) { OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); goto err; } ret = 1; err: EVP_PKEY_free(pkey); OPENSSL_free(msg); return ret; }
int ssl_check_clienthello_tlsext(SSL *s) { int ret=SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg); else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg); /* If status request then ask callback what to do. * Note: this must be called after servername callbacks in case * the certificate has changed. */ if ((s->tlsext_status_type != -1) && s->ctx->tlsext_status_cb) { int r; r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); switch (r) { /* We don't want to send a status request response */ case SSL_TLSEXT_ERR_NOACK: s->tlsext_status_expected = 0; break; /* status request response should be sent */ case SSL_TLSEXT_ERR_OK: if (s->tlsext_ocsp_resp) s->tlsext_status_expected = 1; else s->tlsext_status_expected = 0; break; /* something bad happened */ case SSL_TLSEXT_ERR_ALERT_FATAL: ret = SSL_TLSEXT_ERR_ALERT_FATAL; al = SSL_AD_INTERNAL_ERROR; goto err; } } else s->tlsext_status_expected = 0; err: switch (ret) { case SSL_TLSEXT_ERR_ALERT_FATAL: ssl3_send_alert(s,SSL3_AL_FATAL,al); return -1; case SSL_TLSEXT_ERR_ALERT_WARNING: ssl3_send_alert(s,SSL3_AL_WARNING,al); return 1; case SSL_TLSEXT_ERR_NOACK: s->servername_done=0; default: return 1; } }
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) || /* The request context is always empty during the handshake. */ CBS_len(&context) != 0 || !CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) || CBS_len(&supported_signature_algorithms) == 0 || !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; }
int ssl_check_serverhello_tlsext(SSL *s) { int ret=SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg); else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg); /* If we've requested certificate status and we wont get one * tell the callback */ if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected) && s->ctx->tlsext_status_cb) { int r; /* Set resp to NULL, resplen to -1 so callback knows * there is no response. */ if (s->tlsext_ocsp_resp) { OPENSSL_free(s->tlsext_ocsp_resp); s->tlsext_ocsp_resp = NULL; } s->tlsext_ocsp_resplen = -1; r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); if (r == 0) { al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; ret = SSL_TLSEXT_ERR_ALERT_FATAL; } if (r < 0) { al = SSL_AD_INTERNAL_ERROR; ret = SSL_TLSEXT_ERR_ALERT_FATAL; } } switch (ret) { case SSL_TLSEXT_ERR_ALERT_FATAL: ssl3_send_alert(s,SSL3_AL_FATAL,al); return -1; case SSL_TLSEXT_ERR_ALERT_WARNING: ssl3_send_alert(s,SSL3_AL_WARNING,al); return 1; case SSL_TLSEXT_ERR_NOACK: s->servername_done=0; default: return 1; } }
int tls13_process_certificate_verify(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; int ret = 0; uint8_t *msg = NULL; size_t msg_len; if (hs->peer_pubkey == NULL) { goto err; } CBS cbs, signature; uint16_t signature_algorithm; CBS_init(&cbs, ssl->init_msg, ssl->init_num); if (!CBS_get_u16(&cbs, &signature_algorithm) || !CBS_get_u16_length_prefixed(&cbs, &signature) || 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; } int al; if (!tls12_check_peer_sigalg(ssl, &al, signature_algorithm)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, al); goto err; } ssl->s3->new_session->peer_signature_algorithm = signature_algorithm; if (!tls13_get_cert_verify_signature_input( ssl, &msg, &msg_len, ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); goto err; } int sig_ok = ssl_public_key_verify(ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm, hs->peer_pubkey, msg, msg_len); #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) sig_ok = 1; ERR_clear_error(); #endif if (!sig_ok) { OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SIGNATURE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); goto err; } ret = 1; err: OPENSSL_free(msg); return ret; }
static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) { if (!tls13_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) { return ssl_hs_error; } struct ssl_early_callback_ctx client_hello; if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg, ssl->init_num)) { OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return ssl_hs_error; } assert(ssl->s3->have_version); /* Load the client random. */ if (client_hello.random_len != SSL3_RANDOM_SIZE) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; } memcpy(ssl->s3->client_random, client_hello.random, client_hello.random_len); SSL_set_session(ssl, NULL); if (!ssl_get_new_session(ssl, 1 /* server */)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; } if (ssl->ctx->dos_protection_cb != NULL && ssl->ctx->dos_protection_cb(&client_hello) == 0) { /* Connection rejected for DOS reasons. */ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ACCESS_DENIED); return ssl_hs_error; } /* TLS 1.3 requires the peer only advertise the null compression. */ if (client_hello.compression_methods_len != 1 || client_hello.compression_methods[0] != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); return ssl_hs_error; } /* TLS extensions. */ if (!ssl_parse_clienthello_tlsext(ssl, &client_hello)) { OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); return ssl_hs_error; } hs->state = state_select_parameters; return ssl_hs_ok; }
int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, int peek) { assert(!SSL_in_init(ssl)); assert(ssl->s3->initial_handshake_complete); *out_got_handshake = 0; SSL3_RECORD *rr = &ssl->s3->rrec; for (;;) { /* A previous iteration may have read a partial handshake message. Do not * allow more app data in that case. */ int has_hs_data = ssl->init_buf != NULL && ssl->init_buf->length > 0; /* Get new packet if necessary. */ if (rr->length == 0 && !has_hs_data) { int ret = ssl3_get_record(ssl); if (ret <= 0) { return ret; } } if (has_hs_data || rr->type == SSL3_RT_HANDSHAKE) { /* Post-handshake data prior to TLS 1.3 is always renegotiation, which we * never accept as a server. Otherwise |ssl3_get_message| will send * |SSL_R_EXCESSIVE_MESSAGE_SIZE|. */ if (ssl->server && ssl3_protocol_version(ssl) < TLS1_3_VERSION) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_NO_RENEGOTIATION); OPENSSL_PUT_ERROR(SSL, SSL_R_NO_RENEGOTIATION); return -1; } /* Parse post-handshake handshake messages. */ int ret = ssl3_get_message(ssl, -1, ssl_dont_hash_message); if (ret <= 0) { return ret; } *out_got_handshake = 1; return -1; } if (rr->type != SSL3_RT_APPLICATION_DATA) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); return -1; } if (rr->length != 0) { return consume_record(ssl, buf, len, peek); } /* Discard empty records and loop again. */ } }
int ssl3_read_handshake_bytes(SSL *ssl, uint8_t *buf, int len) { SSL3_RECORD *rr = &ssl->s3->rrec; for (;;) { /* Get new packet if necessary. */ if (rr->length == 0) { int ret = ssl3_get_record(ssl); if (ret <= 0) { return ret; } } if (rr->type != SSL3_RT_HANDSHAKE) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); return -1; } if (rr->length != 0) { return consume_record(ssl, buf, len, 0 /* consume data */); } /* Discard empty records and loop again. */ } }
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; }
/* ssl3_get_record reads a new input record. On success, it places it in * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if * more data is needed. */ static int ssl3_get_record(SSL *ssl) { again: switch (ssl->s3->recv_shutdown) { case ssl_shutdown_none: break; case ssl_shutdown_fatal_alert: OPENSSL_PUT_ERROR(SSL, SSL_R_PROTOCOL_IS_SHUTDOWN); return -1; case ssl_shutdown_close_notify: return 0; } CBS body; uint8_t type, alert; size_t consumed; enum ssl_open_record_t open_ret = tls_open_record(ssl, &type, &body, &consumed, &alert, ssl_read_buffer(ssl), ssl_read_buffer_len(ssl)); if (open_ret != ssl_open_record_partial) { ssl_read_buffer_consume(ssl, consumed); } switch (open_ret) { case ssl_open_record_partial: { int read_ret = ssl_read_buffer_extend_to(ssl, consumed); if (read_ret <= 0) { return read_ret; } goto again; } case ssl_open_record_success: if (CBS_len(&body) > 0xffff) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); return -1; } SSL3_RECORD *rr = &ssl->s3->rrec; rr->type = type; rr->length = (uint16_t)CBS_len(&body); rr->data = (uint8_t *)CBS_data(&body); return 1; case ssl_open_record_discard: goto again; case ssl_open_record_close_notify: return 0; case ssl_open_record_fatal_alert: return -1; case ssl_open_record_error: ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return -1; } assert(0); OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; }
int dtls1_read_failed(SSL *s, int code) { DTLS1_STATE *state; BIO *bio; int send_alert = 0; if ( code > 0) { fprintf( stderr, "invalid state reached %s:%d", __FILE__, __LINE__); return 1; } bio = SSL_get_rbio(s); if ( ! BIO_dgram_recv_timedout(bio)) { /* not a timeout, none of our business, let higher layers handle this. in fact it's probably an error */ return code; } if ( ! SSL_in_init(s)) /* done, no need to send a retransmit */ { BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ); return code; } state = s->d1; state->timeout.num_alerts++; if ( state->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT) { /* fail the connection, enough alerts have been sent */ SSLerr(SSL_F_DTLS1_READ_FAILED,SSL_R_READ_TIMEOUT_EXPIRED); return 0; } state->timeout.read_timeouts++; if ( state->timeout.read_timeouts > DTLS1_TMO_READ_COUNT) { send_alert = 1; state->timeout.read_timeouts = 1; } #if 0 /* for now, each alert contains only one record number */ item = pqueue_peek(state->rcvd_records); if ( item ) { /* send an alert immediately for all the missing records */ } else #endif #if 0 /* no more alert sending, just retransmit the last set of messages */ if ( send_alert) ssl3_send_alert(s,SSL3_AL_WARNING, DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); #endif return dtls1_retransmit_buffered_messages(s) ; }
int ssl3_get_finished(SSL *s, int a, int b) { int al, i, ok; long n; unsigned char *p; #ifdef OPENSSL_NO_NEXTPROTONEG /* * the mac has already been generated when we received the change cipher * spec message and is in s->s3->tmp.peer_finish_md */ #endif /* 64 argument should actually be 36+4 :-) */ n = s->method->ssl_get_message(s, a, b, SSL3_MT_FINISHED, 64, &ok); if (!ok) return ((int)n); /* If this occurs, we have missed a message */ if (!s->s3->change_cipher_spec) { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS); goto f_err; } s->s3->change_cipher_spec = 0; p = (unsigned char *)s->init_msg; i = s->s3->tmp.peer_finish_md_len; if (i != n) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_BAD_DIGEST_LENGTH); goto f_err; } if (CRYPTO_memcmp(p, s->s3->tmp.peer_finish_md, i) != 0) { al = SSL_AD_DECRYPT_ERROR; SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_DIGEST_CHECK_FAILED); goto f_err; } /* * Copy the finished so we can use it for renegotiation checks */ if (s->type == SSL_ST_ACCEPT) { OPENSSL_assert(i <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_client_finished, s->s3->tmp.peer_finish_md, i); s->s3->previous_client_finished_len = i; } else { OPENSSL_assert(i <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_server_finished, s->s3->tmp.peer_finish_md, i); s->s3->previous_server_finished_len = i; } return (1); f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); return (0); }
static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL *ssl, SSL_HANDSHAKE *hs) { if (!tls13_check_message_type(ssl, SSL3_MT_ENCRYPTED_EXTENSIONS)) { return ssl_hs_error; } CBS cbs; CBS_init(&cbs, ssl->init_msg, ssl->init_num); if (!ssl_parse_serverhello_tlsext(ssl, &cbs)) { OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); return ssl_hs_error; } if (CBS_len(&cbs) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return ssl_hs_error; } if (!ssl->method->hash_current_message(ssl)) { return ssl_hs_error; } hs->state = state_process_certificate_request; return ssl_hs_read_message; }
int ssl3_get_finished(SSL *s, int a, int b) { int al, ok, md_len; long n; CBS cbs; n = s->method->ssl_get_message(s, a, b, SSL3_MT_FINISHED, 64, /* should actually be 36+4 :-) */ &ok); if (!ok) return ((int)n); /* If this occurs, we have missed a message */ if (!s->s3->change_cipher_spec) { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS); goto f_err; } s->s3->change_cipher_spec = 0; md_len = s->s3->tmp.peer_finish_md_len; if (n < 0) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_BAD_DIGEST_LENGTH); goto f_err; } CBS_init(&cbs, s->init_msg, n); if (s->s3->tmp.peer_finish_md_len != md_len || (int)CBS_len(&cbs) != md_len) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_BAD_DIGEST_LENGTH); goto f_err; } if (!CBS_mem_equal(&cbs, s->s3->tmp.peer_finish_md, CBS_len(&cbs))) { al = SSL_AD_DECRYPT_ERROR; SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_DIGEST_CHECK_FAILED); goto f_err; } /* Copy the finished so we can use it for renegotiation checks */ if (s->type == SSL_ST_ACCEPT) { OPENSSL_assert(md_len <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_client_finished, s->s3->tmp.peer_finish_md, md_len); s->s3->previous_client_finished_len = md_len; } else { OPENSSL_assert(md_len <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_server_finished, s->s3->tmp.peer_finish_md, md_len); s->s3->previous_server_finished_len = md_len; } return (1); f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); return (0); }
int ssl3_get_finished(SSL *ssl) { int al, finished_len, ok; long message_len; uint8_t *p; message_len = ssl->method->ssl_get_message(ssl, SSL3_MT_FINISHED, ssl_dont_hash_message, &ok); if (!ok) { return message_len; } /* Snapshot the finished hash before incorporating the new message. */ ssl3_take_mac(ssl); if (!ssl3_hash_current_message(ssl)) { goto err; } p = ssl->init_msg; finished_len = ssl->s3->tmp.peer_finish_md_len; if (finished_len != message_len) { al = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_DIGEST_LENGTH); goto f_err; } int finished_ret = CRYPTO_memcmp(p, ssl->s3->tmp.peer_finish_md, finished_len); #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) finished_ret = 0; #endif if (finished_ret != 0) { al = SSL_AD_DECRYPT_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); goto f_err; } /* Copy the finished so we can use it for renegotiation checks */ if (ssl->server) { assert(finished_len <= EVP_MAX_MD_SIZE); memcpy(ssl->s3->previous_client_finished, ssl->s3->tmp.peer_finish_md, finished_len); ssl->s3->previous_client_finished_len = finished_len; } else { assert(finished_len <= EVP_MAX_MD_SIZE); memcpy(ssl->s3->previous_server_finished, ssl->s3->tmp.peer_finish_md, finished_len); ssl->s3->previous_server_finished_len = finished_len; } return 1; f_err: ssl3_send_alert(ssl, SSL3_AL_FATAL, al); err: return 0; }
int dtls1_get_hello_verify(SSL *s) { long n; int al, ok = 0; size_t cookie_len; uint16_t ssl_version; CBS hello_verify_request, cookie; n = s->method->internal->ssl_get_message(s, DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A, DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B, -1, s->internal->max_cert_list, &ok); if (!ok) return ((int)n); if (S3I(s)->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) { D1I(s)->send_cookie = 0; S3I(s)->tmp.reuse_message = 1; return (1); } if (n < 0) goto truncated; CBS_init(&hello_verify_request, s->internal->init_msg, n); if (!CBS_get_u16(&hello_verify_request, &ssl_version)) goto truncated; if (ssl_version != s->version) { SSLerror(s, SSL_R_WRONG_SSL_VERSION); s->version = (s->version & 0xff00) | (ssl_version & 0xff); al = SSL_AD_PROTOCOL_VERSION; goto f_err; } if (!CBS_get_u8_length_prefixed(&hello_verify_request, &cookie)) goto truncated; if (!CBS_write_bytes(&cookie, D1I(s)->cookie, sizeof(D1I(s)->cookie), &cookie_len)) { D1I(s)->cookie_len = 0; al = SSL_AD_ILLEGAL_PARAMETER; goto f_err; } D1I(s)->cookie_len = cookie_len; D1I(s)->send_cookie = 1; return 1; truncated: al = SSL_AD_DECODE_ERROR; f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); return -1; }
int tls_construct_change_cipher_spec(SSL *s, WPACKET *pkt) { if (!WPACKET_put_bytes_u8(pkt, SSL3_MT_CCS)) { SSLerr(SSL_F_TLS_CONSTRUCT_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return 0; } return 1; }
static int tls13_receive_key_update(SSL *ssl) { if (ssl->init_num != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return 0; } // TODO(svaldez): Send KeyUpdate. return tls13_rotate_traffic_key(ssl, evp_aead_open); }
/* dtls1_get_record reads a new input record. On success, it places it in * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if * more data is needed. */ static int dtls1_get_record(SSL *ssl) { again: /* Read a new packet if there is no unconsumed one. */ if (ssl_read_buffer_len(ssl) == 0) { int ret = ssl_read_buffer_extend_to(ssl, 0 /* unused */); if (ret <= 0) { return ret; } } assert(ssl_read_buffer_len(ssl) > 0); /* Ensure the packet is large enough to decrypt in-place. */ if (ssl_read_buffer_len(ssl) < ssl_record_prefix_len(ssl)) { ssl_read_buffer_clear(ssl); goto again; } uint8_t *out = ssl_read_buffer(ssl) + ssl_record_prefix_len(ssl); size_t max_out = ssl_read_buffer_len(ssl) - ssl_record_prefix_len(ssl); uint8_t type, alert; size_t len, consumed; switch (dtls_open_record(ssl, &type, out, &len, &consumed, &alert, max_out, ssl_read_buffer(ssl), ssl_read_buffer_len(ssl))) { case ssl_open_record_success: ssl_read_buffer_consume(ssl, consumed); if (len > 0xffff) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); return -1; } SSL3_RECORD *rr = &ssl->s3->rrec; rr->type = type; rr->length = (uint16_t)len; rr->data = out; return 1; case ssl_open_record_discard: ssl_read_buffer_consume(ssl, consumed); goto again; case ssl_open_record_error: ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return -1; case ssl_open_record_partial: /* Impossible in DTLS. */ break; } assert(0); OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; }
static int dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok) { /* (0) check whether the desired fragment is available * if so: * (1) copy over the fragment to s->init_buf->data[] * (2) update s->init_num */ pitem *item; hm_fragment *frag; int al; *ok = 0; item = pqueue_peek(s->d1->buffered_messages); if ( item == NULL) return 0; frag = (hm_fragment *)item->data; /* Don't return if reassembly still in progress */ if (frag->reassembly != NULL) return 0; if ( s->d1->handshake_read_seq == frag->msg_header.seq) { unsigned long frag_len = frag->msg_header.frag_len; pqueue_pop(s->d1->buffered_messages); al=dtls1_preprocess_fragment(s,&frag->msg_header,max); if (al==0) /* no alert */ { unsigned char *p = (unsigned char *)s->init_buf->data+DTLS1_HM_HEADER_LENGTH; memcpy(&p[frag->msg_header.frag_off], frag->fragment,frag->msg_header.frag_len); } dtls1_hm_fragment_free(frag); pitem_free(item); if (al==0) { *ok = 1; return frag_len; } ssl3_send_alert(s,SSL3_AL_FATAL,al); s->init_num = 0; *ok = 0; return -1; } else return 0; }
int tls13_check_message_type(SSL *ssl, int type) { if (ssl->s3->tmp.message_type != type) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE); ERR_add_error_dataf("got type %d, wanted type %d", ssl->s3->tmp.message_type, type); return 0; } return 1; }
static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) { /* At this point, most ClientHello extensions have already been processed by * the common handshake logic. Resolve the remaining non-PSK parameters. */ SSL *const ssl = hs->ssl; SSL_CLIENT_HELLO client_hello; if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, ssl->init_num)) { OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return ssl_hs_error; } /* Negotiate the cipher suite. */ hs->new_cipher = choose_tls13_cipher(ssl, &client_hello); if (hs->new_cipher == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); return ssl_hs_error; } /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was * deferred. Complete it now. */ uint8_t alert = SSL_AD_DECODE_ERROR; if (!ssl_negotiate_alpn(hs, &alert, &client_hello)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return ssl_hs_error; } /* The PRF hash is now known. Set up the key schedule and hash the * ClientHello. */ if (!tls13_init_key_schedule(hs) || !ssl_hash_current_message(hs)) { return ssl_hs_error; } hs->tls13_state = state_select_session; return ssl_hs_ok; }
int tls_construct_finished(SSL *s, const char *sender, int slen) { int i; WPACKET pkt; if (!WPACKET_init(&pkt, s->init_buf) || !ssl_set_handshake_header2(s, &pkt, SSL3_MT_FINISHED)) { SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR); goto err; } i = s->method->ssl3_enc->final_finish_mac(s, sender, slen, s->s3->tmp.finish_md); if (i <= 0) { SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR); goto err; } s->s3->tmp.finish_md_len = i; if (!WPACKET_memcpy(&pkt, s->s3->tmp.finish_md, i)) { SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR); goto err; } /* * Copy the finished so we can use it for renegotiation checks */ if (!s->server) { OPENSSL_assert(i <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_client_finished, s->s3->tmp.finish_md, i); s->s3->previous_client_finished_len = i; } else { OPENSSL_assert(i <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_server_finished, s->s3->tmp.finish_md, i); s->s3->previous_server_finished_len = i; } if (!ssl_close_construct_packet(s, &pkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR); goto err; } return 1; err: ossl_statem_set_error(s); WPACKET_cleanup(&pkt); ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return 0; }
/* ssl3_get_record reads a new input record. On success, it places it in * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if * more data is needed. */ static int ssl3_get_record(SSL *ssl) { int ret; again: /* Ensure the buffer is large enough to decrypt in-place. */ ret = ssl_read_buffer_extend_to(ssl, ssl_record_prefix_len(ssl)); if (ret <= 0) { return ret; } assert(ssl_read_buffer_len(ssl) >= ssl_record_prefix_len(ssl)); uint8_t *out = ssl_read_buffer(ssl) + ssl_record_prefix_len(ssl); size_t max_out = ssl_read_buffer_len(ssl) - ssl_record_prefix_len(ssl); uint8_t type, alert; size_t len, consumed; switch (tls_open_record(ssl, &type, out, &len, &consumed, &alert, max_out, ssl_read_buffer(ssl), ssl_read_buffer_len(ssl))) { case ssl_open_record_success: ssl_read_buffer_consume(ssl, consumed); if (len > 0xffff) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); return -1; } SSL3_RECORD *rr = &ssl->s3->rrec; rr->type = type; rr->length = (uint16_t)len; rr->off = 0; rr->data = out; return 1; case ssl_open_record_partial: ret = ssl_read_buffer_extend_to(ssl, consumed); if (ret <= 0) { return ret; } goto again; case ssl_open_record_discard: ssl_read_buffer_consume(ssl, consumed); goto again; case ssl_open_record_error: ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return -1; } assert(0); OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; }
int ssl3_get_finished(SSL *s, int a, int b) { int al,i,ok; long n; unsigned char *p; /* the mac has already been generated when we received the * change cipher spec message and is in s->s3->tmp.peer_finish_md */ n=s->method->ssl_get_message(s, a, b, SSL3_MT_FINISHED, 64, /* should actually be 36+4 :-) */ &ok); if (!ok) return((int)n); /* If this occurs, we have missed a message */ if (!s->s3->change_cipher_spec) { al=SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_GOT_A_FIN_BEFORE_A_CCS); goto f_err; } s->s3->change_cipher_spec=0; p = (unsigned char *)s->init_msg; i = s->s3->tmp.peer_finish_md_len; if (i != n) { al=SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_BAD_DIGEST_LENGTH); goto f_err; } if (memcmp(p, s->s3->tmp.peer_finish_md, i) != 0) { al=SSL_AD_DECRYPT_ERROR; SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_DIGEST_CHECK_FAILED); goto f_err; } return(1); f_err: ssl3_send_alert(s,SSL3_AL_FATAL,al); return(0); }