mirror of
https://github.com/ipxe/ipxe
synced 2025-12-20 03:55:46 +03:00
[tls] Allow provision of a client certificate chain
Use the existing certificate store to automatically append any available issuing certificates to the selected client certificate. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -319,8 +319,8 @@ struct tls_connection {
|
|||||||
struct digest_algorithm *handshake_digest;
|
struct digest_algorithm *handshake_digest;
|
||||||
/** Digest algorithm context used for handshake verification */
|
/** Digest algorithm context used for handshake verification */
|
||||||
uint8_t *handshake_ctx;
|
uint8_t *handshake_ctx;
|
||||||
/** Client certificate (if used) */
|
/** Client certificate chain (if used) */
|
||||||
struct x509_certificate *cert;
|
struct x509_chain *certs;
|
||||||
/** Secure renegotiation flag */
|
/** Secure renegotiation flag */
|
||||||
int secure_renegotiation;
|
int secure_renegotiation;
|
||||||
/** Verification data */
|
/** Verification data */
|
||||||
|
|||||||
107
src/net/tls.c
107
src/net/tls.c
@@ -378,7 +378,7 @@ static void free_tls ( struct refcnt *refcnt ) {
|
|||||||
list_del ( &iobuf->list );
|
list_del ( &iobuf->list );
|
||||||
free_iob ( iobuf );
|
free_iob ( iobuf );
|
||||||
}
|
}
|
||||||
x509_put ( tls->cert );
|
x509_chain_put ( tls->certs );
|
||||||
x509_chain_put ( tls->chain );
|
x509_chain_put ( tls->chain );
|
||||||
|
|
||||||
/* Drop reference to session */
|
/* Drop reference to session */
|
||||||
@@ -1147,41 +1147,57 @@ static int tls_send_client_hello ( struct tls_connection *tls ) {
|
|||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int tls_send_certificate ( struct tls_connection *tls ) {
|
static int tls_send_certificate ( struct tls_connection *tls ) {
|
||||||
|
struct {
|
||||||
|
tls24_t length;
|
||||||
|
uint8_t data[0];
|
||||||
|
} __attribute__ (( packed )) *certificate;
|
||||||
struct {
|
struct {
|
||||||
uint32_t type_length;
|
uint32_t type_length;
|
||||||
tls24_t length;
|
tls24_t length;
|
||||||
struct {
|
typeof ( *certificate ) certificates[0];
|
||||||
tls24_t length;
|
} __attribute__ (( packed )) *certificates;
|
||||||
uint8_t data[ tls->cert->raw.len ];
|
struct x509_link *link;
|
||||||
} __attribute__ (( packed )) certificates[1];
|
struct x509_certificate *cert;
|
||||||
} __attribute__ (( packed )) *certificate;
|
size_t len;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
/* Calculate length of client certificates */
|
||||||
|
len = 0;
|
||||||
|
list_for_each_entry ( link, &tls->certs->links, list ) {
|
||||||
|
cert = link->cert;
|
||||||
|
len += ( sizeof ( *certificate ) + cert->raw.len );
|
||||||
|
DBGC ( tls, "TLS %p sending client certificate %s\n",
|
||||||
|
tls, x509_name ( cert ) );
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate storage for Certificate record (which may be too
|
/* Allocate storage for Certificate record (which may be too
|
||||||
* large for the stack).
|
* large for the stack).
|
||||||
*/
|
*/
|
||||||
certificate = zalloc ( sizeof ( *certificate ) );
|
certificates = zalloc ( sizeof ( *certificates ) + len );
|
||||||
if ( ! certificate )
|
if ( ! certificates )
|
||||||
return -ENOMEM_CERTIFICATE;
|
return -ENOMEM_CERTIFICATE;
|
||||||
|
|
||||||
/* Populate record */
|
/* Populate record */
|
||||||
certificate->type_length =
|
certificates->type_length =
|
||||||
( cpu_to_le32 ( TLS_CERTIFICATE ) |
|
( cpu_to_le32 ( TLS_CERTIFICATE ) |
|
||||||
htonl ( sizeof ( *certificate ) -
|
htonl ( sizeof ( *certificates ) + len -
|
||||||
sizeof ( certificate->type_length ) ) );
|
sizeof ( certificates->type_length ) ) );
|
||||||
tls_set_uint24 ( &certificate->length,
|
tls_set_uint24 ( &certificates->length, len );
|
||||||
sizeof ( certificate->certificates ) );
|
certificate = &certificates->certificates[0];
|
||||||
tls_set_uint24 ( &certificate->certificates[0].length,
|
list_for_each_entry ( link, &tls->certs->links, list ) {
|
||||||
sizeof ( certificate->certificates[0].data ) );
|
cert = link->cert;
|
||||||
memcpy ( certificate->certificates[0].data,
|
tls_set_uint24 ( &certificate->length, cert->raw.len );
|
||||||
tls->cert->raw.data,
|
memcpy ( certificate->data, cert->raw.data, cert->raw.len );
|
||||||
sizeof ( certificate->certificates[0].data ) );
|
certificate = ( ( ( void * ) certificate->data ) +
|
||||||
|
cert->raw.len );
|
||||||
|
}
|
||||||
|
|
||||||
/* Transmit record */
|
/* Transmit record */
|
||||||
rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) );
|
rc = tls_send_handshake ( tls, certificates,
|
||||||
|
( sizeof ( *certificates ) + len ) );
|
||||||
|
|
||||||
/* Free record */
|
/* Free record */
|
||||||
free ( certificate );
|
free ( certificates );
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -1238,7 +1254,7 @@ static int tls_send_client_key_exchange ( struct tls_connection *tls ) {
|
|||||||
*/
|
*/
|
||||||
static int tls_send_certificate_verify ( struct tls_connection *tls ) {
|
static int tls_send_certificate_verify ( struct tls_connection *tls ) {
|
||||||
struct digest_algorithm *digest = tls->handshake_digest;
|
struct digest_algorithm *digest = tls->handshake_digest;
|
||||||
struct x509_certificate *cert = tls->cert;
|
struct x509_certificate *cert = x509_first ( tls->certs );
|
||||||
struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey;
|
struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey;
|
||||||
uint8_t digest_out[ digest->digestsize ];
|
uint8_t digest_out[ digest->digestsize ];
|
||||||
uint8_t ctx[ pubkey->ctxsize ];
|
uint8_t ctx[ pubkey->ctxsize ];
|
||||||
@@ -1845,26 +1861,57 @@ static int tls_new_certificate ( struct tls_connection *tls,
|
|||||||
static int tls_new_certificate_request ( struct tls_connection *tls,
|
static int tls_new_certificate_request ( struct tls_connection *tls,
|
||||||
const void *data __unused,
|
const void *data __unused,
|
||||||
size_t len __unused ) {
|
size_t len __unused ) {
|
||||||
|
struct x509_certificate *cert;
|
||||||
|
int rc;
|
||||||
|
|
||||||
/* We can only send a single certificate, so there is no point
|
/* We can only send a single certificate, so there is no point
|
||||||
* in parsing the Certificate Request.
|
* in parsing the Certificate Request.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Free any existing client certificate */
|
/* Free any existing client certificate chain */
|
||||||
x509_put ( tls->cert );
|
x509_chain_put ( tls->certs );
|
||||||
|
tls->certs = NULL;
|
||||||
|
|
||||||
/* Determine client certificate to be sent */
|
/* Determine client certificate to be sent */
|
||||||
tls->cert = certstore_find_key ( &private_key );
|
cert = certstore_find_key ( &private_key );
|
||||||
if ( ! tls->cert ) {
|
if ( ! cert ) {
|
||||||
DBGC ( tls, "TLS %p could not find certificate corresponding "
|
DBGC ( tls, "TLS %p could not find certificate corresponding "
|
||||||
"to private key\n", tls );
|
"to private key\n", tls );
|
||||||
return -EPERM_CLIENT_CERT;
|
rc = -EPERM_CLIENT_CERT;
|
||||||
|
goto err_find;
|
||||||
}
|
}
|
||||||
x509_get ( tls->cert );
|
x509_get ( cert );
|
||||||
DBGC ( tls, "TLS %p sending client certificate %s\n",
|
DBGC ( tls, "TLS %p selected client certificate %s\n",
|
||||||
tls, x509_name ( tls->cert ) );
|
tls, x509_name ( cert ) );
|
||||||
|
|
||||||
|
/* Create client certificate chain */
|
||||||
|
tls->certs = x509_alloc_chain();
|
||||||
|
if ( ! tls->certs ) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto err_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append client certificate to chain */
|
||||||
|
if ( ( rc = x509_append ( tls->certs, cert ) ) != 0 )
|
||||||
|
goto err_append;
|
||||||
|
|
||||||
|
/* Append any relevant issuer certificates */
|
||||||
|
if ( ( rc = x509_auto_append ( tls->certs, &certstore ) ) != 0 )
|
||||||
|
goto err_auto_append;
|
||||||
|
|
||||||
|
/* Drop local reference to client certificate */
|
||||||
|
x509_put ( cert );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_auto_append:
|
||||||
|
err_append:
|
||||||
|
x509_chain_put ( tls->certs );
|
||||||
|
tls->certs = NULL;
|
||||||
|
err_alloc:
|
||||||
|
x509_put ( cert );
|
||||||
|
err_find:
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2880,7 +2927,7 @@ static void tls_validator_done ( struct tls_connection *tls, int rc ) {
|
|||||||
tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
|
tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE |
|
||||||
TLS_TX_CHANGE_CIPHER |
|
TLS_TX_CHANGE_CIPHER |
|
||||||
TLS_TX_FINISHED );
|
TLS_TX_FINISHED );
|
||||||
if ( tls->cert ) {
|
if ( tls->certs ) {
|
||||||
tls->tx_pending |= ( TLS_TX_CERTIFICATE |
|
tls->tx_pending |= ( TLS_TX_CERTIFICATE |
|
||||||
TLS_TX_CERTIFICATE_VERIFY );
|
TLS_TX_CERTIFICATE_VERIFY );
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user