diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 2aa2b06d..49401e6b 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -87,9 +87,10 @@ enum tls_rx_state { /** TLS TX pending flags */ enum tls_tx_pending { TLS_TX_CLIENT_HELLO = 0x0001, - TLS_TX_CLIENT_KEY_EXCHANGE = 0x0002, - TLS_TX_CHANGE_CIPHER = 0x0004, - TLS_TX_FINISHED = 0x0008, + TLS_TX_CERTIFICATE = 0x0002, + TLS_TX_CLIENT_KEY_EXCHANGE = 0x0004, + TLS_TX_CHANGE_CIPHER = 0x0008, + TLS_TX_FINISHED = 0x0010, }; /** A TLS cipher specification */ diff --git a/src/net/tls.c b/src/net/tls.c index 28a4ba4e..0249ed7c 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -684,6 +684,27 @@ static int tls_send_client_hello ( struct tls_session *tls ) { return tls_send_handshake ( tls, &hello, sizeof ( hello ) ); } +/** + * Transmit Certificate record + * + * @v tls TLS session + * @ret rc Return status code + */ +static int tls_send_certificate ( struct tls_session *tls ) { + struct { + uint32_t type_length; + uint8_t length[3]; + } __attribute__ (( packed )) certificate; + + memset ( &certificate, 0, sizeof ( certificate ) ); + certificate.type_length = ( cpu_to_le32 ( TLS_CERTIFICATE ) | + htonl ( sizeof ( certificate ) - + sizeof ( certificate.type_length))); + + return tls_send_handshake ( tls, &certificate, sizeof ( certificate ) ); +} + + /** * Transmit Client Key Exchange record * @@ -955,6 +976,30 @@ static int tls_new_certificate ( struct tls_session *tls, return -EINVAL; } +/** + * Receive new Certificate Request handshake record + * + * @v tls TLS session + * @v data Plaintext handshake record + * @v len Length of plaintext handshake record + * @ret rc Return status code + */ +static int tls_new_certificate_request ( struct tls_session *tls, + void *data __unused, + size_t len __unused ) { + + /* We can only send an empty certificate (as mandated by + * TLSv1.2), so there is no point in parsing the Certificate + * Request. + */ + + /* Schedule Certificate transmission */ + tls->tx_pending |= TLS_TX_CERTIFICATE; + tls_tx_resume ( tls ); + + return 0; +} + /** * Receive new Server Hello Done handshake record * @@ -1070,6 +1115,10 @@ static int tls_new_handshake ( struct tls_session *tls, case TLS_CERTIFICATE: rc = tls_new_certificate ( tls, payload, payload_len ); break; + case TLS_CERTIFICATE_REQUEST: + rc = tls_new_certificate_request ( tls, payload, + payload_len ); + break; case TLS_SERVER_HELLO_DONE: rc = tls_new_server_hello_done ( tls, payload, payload_len ); @@ -1741,6 +1790,14 @@ static void tls_tx_step ( struct tls_session *tls ) { goto err; } tls->tx_pending &= ~TLS_TX_CLIENT_HELLO; + } else if ( tls->tx_pending & TLS_TX_CERTIFICATE ) { + /* Send Certificate */ + if ( ( rc = tls_send_certificate ( tls ) ) != 0 ) { + DBGC ( tls, "TLS %p cold not send Certificate: %s\n", + tls, strerror ( rc ) ); + goto err; + } + tls->tx_pending &= ~TLS_TX_CERTIFICATE; } else if ( tls->tx_pending & TLS_TX_CLIENT_KEY_EXCHANGE ) { /* Send Client Key Exchange */ if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) {