@@ -287,8 +287,9 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
287287{
288288 MYSQL * mysql = mpvio -> mysql ;
289289 NET * net = & mysql -> net ;
290- char * buff , * end ;
291- size_t conn_attr_len = (mysql -> options .extension ) ?
290+ char * buff , * end , * pre_ssl_end , * early_data = NULL ;
291+ size_t early_data_len ;
292+ size_t conn_attr_len = (mysql -> options .extension ) ?
292293 mysql -> options .extension -> connect_attrs_len : 0 ;
293294 size_t proxy_header_len = 0 ;
294295 char * proxy_header =
@@ -415,6 +416,73 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
415416 int3store (buff + 2 , net -> max_packet_size );
416417 end = buff + 5 ;
417418 }
419+ /* The rest of the packet is built before the TLS handshake starts,
420+ so that it can be sent as early data in ma_pvio_start_ssl() */
421+ pre_ssl_end = end ;
422+
423+ if (mysql -> user && mysql -> user [0 ])
424+ ma_strmake (end , mysql -> user , USERNAME_LENGTH );
425+ else
426+ read_user_name (end );
427+
428+ /* We have to handle different version of handshake here */
429+ end += strlen (end ) + 1 ;
430+ if (data_len )
431+ {
432+ if (mysql -> server_capabilities & CLIENT_SECURE_CONNECTION )
433+ {
434+ if (mysql -> server_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA )
435+ {
436+ end = (char * )mysql_net_store_length ((uchar * )end , data_len );
437+ }
438+ else {
439+ /* Without CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA capability password
440+ length is limited up to 255 chars */
441+ if (data_len > 0xFF )
442+ goto error ;
443+ * end ++ = data_len ;
444+ }
445+ memcpy (end , data , data_len );
446+ end += data_len ;
447+ }
448+ else
449+ {
450+ DBUG_ASSERT (data_len == SCRAMBLE_LENGTH_323 + 1 ); /* incl. \0 at the end */
451+ memcpy (end , data , data_len );
452+ end += data_len ;
453+ }
454+ }
455+ else
456+ * end ++ = 0 ;
457+
458+ /* Add database if needed */
459+ if (mpvio -> db && (mysql -> server_capabilities & CLIENT_CONNECT_WITH_DB ))
460+ {
461+ end = ma_strmake (end , mpvio -> db , NAME_LEN ) + 1 ;
462+ mysql -> db = strdup (mpvio -> db );
463+ }
464+
465+ if (mysql -> server_capabilities & CLIENT_PLUGIN_AUTH )
466+ end = ma_strmake (end , mpvio -> plugin -> name , NAME_LEN ) + 1 ;
467+
468+ end = ma_send_connect_attr (mysql , (unsigned char * )end );
469+
470+ /* MySQL 8.0:
471+ If zstd compresson was specified, the server expects
472+ 1 byte for compression level
473+ */
474+ if (mysql -> client_flag & CLIENT_ZSTD_COMPRESSION )
475+ {
476+ uchar compression_level = 3 ;
477+ if (mysql -> options .extension &&
478+ mysql -> options .extension -> zstd_compression_level >= 1 &&
479+ mysql -> options .extension -> zstd_compression_level <= 20 )
480+ {
481+ compression_level = mysql -> options .extension -> zstd_compression_level ;
482+ }
483+ * end ++ = compression_level ;
484+ }
485+
418486#ifdef HAVE_TLS
419487 if (mysql -> options .ssl_key ||
420488 mysql -> options .ssl_cert ||
@@ -428,8 +496,7 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
428496#endif
429497 )
430498 mysql -> options .use_ssl = 1 ;
431- if (mysql -> options .use_ssl &&
432- (mysql -> client_flag & CLIENT_SSL ))
499+ if (mysql -> options .use_ssl && (mysql -> client_flag & CLIENT_SSL ))
433500 {
434501 unsigned int verify_flags = 0 ;
435502 /*
@@ -444,7 +511,8 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
444511 proxy_header = NULL ;
445512 }
446513
447- if (ma_net_write (net , (unsigned char * )buff , (size_t ) (end - buff )) || ma_net_flush (net ))
514+ if (ma_net_write (net , (uchar * )buff , (size_t ) (pre_ssl_end - buff ))
515+ || ma_net_flush (net ))
448516 {
449517 my_set_error (mysql , CR_SERVER_LOST , SQLSTATE_UNKNOWN ,
450518 ER (CR_SERVER_LOST_EXTENDED ),
@@ -453,7 +521,16 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
453521 goto error ;
454522 }
455523 mysql -> net .tls_verify_status = 0 ;
456- if (ma_pvio_start_ssl (mysql -> net .pvio ))
524+
525+ /* Early data aren't fully protected by TLS, so only used with
526+ password_and_hashing() plugins. */
527+ if (password_and_hashing (mysql , mpvio -> plugin ))
528+ {
529+ early_data = buff ;
530+ early_data_len = end - buff ;
531+ }
532+
533+ if (ma_pvio_start_ssl (mysql -> net .pvio , (uchar * )early_data , early_data_len ))
457534 goto error ;
458535
459536 verify_flags = MARIADB_TLS_VERIFY_PERIOD ;
@@ -487,83 +564,26 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio,
487564 if (!password_and_hashing (mysql , mpvio -> plugin ))
488565 goto error ;
489566 }
567+ /* Need to resent if early data wasn't accepted */
568+ if (!ma_tls_early_data_accepted (mysql -> net .pvio -> ctls ))
569+ early_data = NULL ;
490570 }
491571#endif /* HAVE_TLS */
492572
493- /* This needs to be changed as it's not useful with big packets */
494- if (mysql -> user && mysql -> user [0 ])
495- ma_strmake (end , mysql -> user , USERNAME_LENGTH );
496- else
497- read_user_name (end );
498-
499- /* We have to handle different version of handshake here */
500- end += strlen (end ) + 1 ;
501- if (data_len )
502- {
503- if (mysql -> server_capabilities & CLIENT_SECURE_CONNECTION )
504- {
505- if (mysql -> server_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA )
506- {
507- end = (char * )mysql_net_store_length ((uchar * )end , data_len );
508- }
509- else {
510- /* Without CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA capability password
511- length is limited up to 255 chars */
512- if (data_len > 0xFF )
513- goto error ;
514- * end ++ = data_len ;
515- }
516- memcpy (end , data , data_len );
517- end += data_len ;
518- }
519- else
520- {
521- DBUG_ASSERT (data_len == SCRAMBLE_LENGTH_323 + 1 ); /* incl. \0 at the end */
522- memcpy (end , data , data_len );
523- end += data_len ;
524- }
525- }
526- else
527- * end ++ = 0 ;
528-
529- /* Add database if needed */
530- if (mpvio -> db && (mysql -> server_capabilities & CLIENT_CONNECT_WITH_DB ))
531- {
532- end = ma_strmake (end , mpvio -> db , NAME_LEN ) + 1 ;
533- mysql -> db = strdup (mpvio -> db );
534- }
535-
536- if (mysql -> server_capabilities & CLIENT_PLUGIN_AUTH )
537- end = ma_strmake (end , mpvio -> plugin -> name , NAME_LEN ) + 1 ;
538-
539- end = ma_send_connect_attr (mysql , (unsigned char * )end );
540-
541- /* MySQL 8.0:
542- If zstd compresson was specified, the server expects
543- 1 byte for compression level
544- */
545- if (mysql -> client_flag & CLIENT_ZSTD_COMPRESSION )
573+ if (!early_data )
546574 {
547- uchar compression_level = 3 ;
548- if (mysql -> options .extension &&
549- mysql -> options .extension -> zstd_compression_level >= 1 &&
550- mysql -> options .extension -> zstd_compression_level <= 20 )
575+ if (proxy_header_len )
576+ ma_net_write_buff (net , proxy_header , proxy_header_len );
577+ /* Write authentication package */
578+ if (ma_net_write (net , (uchar * )buff , (size_t ) (end - buff ))
579+ || ma_net_flush (net ))
551580 {
552- compression_level = mysql -> options .extension -> zstd_compression_level ;
581+ my_set_error (mysql , CR_SERVER_LOST , SQLSTATE_UNKNOWN ,
582+ ER (CR_SERVER_LOST_EXTENDED ),
583+ "sending authentication information" ,
584+ errno );
585+ goto error ;
553586 }
554- * end ++ = compression_level ;
555- }
556-
557- if (proxy_header_len )
558- ma_net_write_buff (net , proxy_header , proxy_header_len );
559- /* Write authentication package */
560- if (ma_net_write (net , (unsigned char * )buff , (size_t ) (end - buff )) || ma_net_flush (net ))
561- {
562- my_set_error (mysql , CR_SERVER_LOST , SQLSTATE_UNKNOWN ,
563- ER (CR_SERVER_LOST_EXTENDED ),
564- "sending authentication information" ,
565- errno );
566- goto error ;
567587 }
568588 free (buff );
569589 return 0 ;
0 commit comments