mirror of https://github.com/ipxe/ipxe.git
[x509] Record root of trust used when validating a certificate
Record the root of trust used at the point that a certificate is validated, redefine validation as checking a certificate against a specific root of trust, and pass an explicit root of trust when creating a TLS connection. This allows a custom TLS connection to be used with a custom root of trust, without causing any validated certificates to be treated as valid for normal purposes. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/181/head
parent
6e92d6213d
commit
39f5293492
|
@ -284,7 +284,7 @@ int ocsp_check ( struct x509_certificate *cert,
|
|||
/* Sanity checks */
|
||||
assert ( cert != NULL );
|
||||
assert ( issuer != NULL );
|
||||
assert ( x509_is_valid ( issuer ) );
|
||||
assert ( issuer->root != NULL );
|
||||
|
||||
/* Allocate and initialise check */
|
||||
*ocsp = zalloc ( sizeof ( **ocsp ) );
|
||||
|
@ -915,7 +915,7 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) {
|
|||
*/
|
||||
x509_invalidate ( signer );
|
||||
if ( ( rc = x509_validate ( signer, ocsp->issuer, time,
|
||||
NULL ) ) != 0 ) {
|
||||
ocsp->issuer->root ) ) != 0 ) {
|
||||
DBGC ( ocsp, "OCSP %p \"%s\" could not validate ",
|
||||
ocsp, x509_name ( ocsp->cert ) );
|
||||
DBGC ( ocsp, "signer \"%s\": %s\n",
|
||||
|
@ -961,7 +961,7 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) {
|
|||
|
||||
/* Validate certificate against issuer */
|
||||
if ( ( rc = x509_validate ( ocsp->cert, ocsp->issuer, time,
|
||||
NULL ) ) != 0 ) {
|
||||
ocsp->issuer->root ) ) != 0 ) {
|
||||
DBGC ( ocsp, "OCSP %p \"%s\" could not validate certificate: "
|
||||
"%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ));
|
||||
return rc;
|
||||
|
|
|
@ -1295,6 +1295,21 @@ int x509_check_time ( struct x509_certificate *cert, time_t time ) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if X.509 certificate is valid
|
||||
*
|
||||
* @v cert X.509 certificate
|
||||
* @v root Root certificate list, or NULL to use default
|
||||
*/
|
||||
int x509_is_valid ( struct x509_certificate *cert, struct x509_root *root ) {
|
||||
|
||||
/* Use default root certificate store if none specified */
|
||||
if ( ! root )
|
||||
root = &root_certificates;
|
||||
|
||||
return ( cert->root == root );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate X.509 certificate
|
||||
*
|
||||
|
@ -1321,7 +1336,7 @@ int x509_validate ( struct x509_certificate *cert,
|
|||
root = &root_certificates;
|
||||
|
||||
/* Return success if certificate has already been validated */
|
||||
if ( x509_is_valid ( cert ) )
|
||||
if ( x509_is_valid ( cert, root ) )
|
||||
return 0;
|
||||
|
||||
/* Fail if certificate is invalid at specified time */
|
||||
|
@ -1330,7 +1345,7 @@ int x509_validate ( struct x509_certificate *cert,
|
|||
|
||||
/* Succeed if certificate is a trusted root certificate */
|
||||
if ( x509_check_root ( cert, root ) == 0 ) {
|
||||
cert->flags |= X509_FL_VALIDATED;
|
||||
cert->root = root;
|
||||
cert->path_remaining = ( cert->extensions.basic.path_len + 1 );
|
||||
return 0;
|
||||
}
|
||||
|
@ -1343,7 +1358,7 @@ int x509_validate ( struct x509_certificate *cert,
|
|||
}
|
||||
|
||||
/* Fail unless issuer has already been validated */
|
||||
if ( ! x509_is_valid ( issuer ) ) {
|
||||
if ( ! x509_is_valid ( issuer, root ) ) {
|
||||
DBGC ( cert, "X509 %p \"%s\" ", cert, x509_name ( cert ) );
|
||||
DBGC ( cert, "issuer %p \"%s\" has not yet been validated\n",
|
||||
issuer, x509_name ( issuer ) );
|
||||
|
@ -1376,7 +1391,7 @@ int x509_validate ( struct x509_certificate *cert,
|
|||
cert->path_remaining = max_path_remaining;
|
||||
|
||||
/* Mark certificate as valid */
|
||||
cert->flags |= X509_FL_VALIDATED;
|
||||
cert->root = root;
|
||||
|
||||
DBGC ( cert, "X509 %p \"%s\" successfully validated using ",
|
||||
cert, x509_name ( cert ) );
|
||||
|
|
|
@ -326,6 +326,8 @@ struct tls_connection {
|
|||
/** Verification data */
|
||||
struct tls_verify_data verify;
|
||||
|
||||
/** Root of trust (or NULL to use default) */
|
||||
struct x509_root *root;
|
||||
/** Server certificate chain */
|
||||
struct x509_chain *chain;
|
||||
/** Certificate validator */
|
||||
|
@ -378,6 +380,7 @@ struct tls_connection {
|
|||
/** RX I/O buffer alignment */
|
||||
#define TLS_RX_ALIGN 16
|
||||
|
||||
extern int add_tls ( struct interface *xfer, const char *name );
|
||||
extern int add_tls ( struct interface *xfer, const char *name,
|
||||
struct x509_root *root );
|
||||
|
||||
#endif /* _IPXE_TLS_H */
|
||||
|
|
|
@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
#include <ipxe/interface.h>
|
||||
#include <ipxe/x509.h>
|
||||
|
||||
extern int create_validator ( struct interface *job, struct x509_chain *chain );
|
||||
extern int create_validator ( struct interface *job, struct x509_chain *chain,
|
||||
struct x509_root *root );
|
||||
|
||||
#endif /* _IPXE_VALIDATOR_H */
|
||||
|
|
|
@ -191,6 +191,8 @@ struct x509_certificate {
|
|||
|
||||
/** Flags */
|
||||
unsigned int flags;
|
||||
/** Root against which certificate has been validated (if any) */
|
||||
struct x509_root *root;
|
||||
/** Maximum number of subsequent certificates in chain */
|
||||
unsigned int path_remaining;
|
||||
|
||||
|
@ -218,12 +220,10 @@ struct x509_certificate {
|
|||
|
||||
/** X.509 certificate flags */
|
||||
enum x509_flags {
|
||||
/** Certificate has been validated */
|
||||
X509_FL_VALIDATED = 0x0001,
|
||||
/** Certificate was added at build time */
|
||||
X509_FL_PERMANENT = 0x0002,
|
||||
X509_FL_PERMANENT = 0x0001,
|
||||
/** Certificate was added explicitly at run time */
|
||||
X509_FL_EXPLICIT = 0x0004,
|
||||
X509_FL_EXPLICIT = 0x0002,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -355,6 +355,8 @@ extern int x509_parse ( struct x509_certificate *cert,
|
|||
const struct asn1_cursor *raw );
|
||||
extern int x509_certificate ( const void *data, size_t len,
|
||||
struct x509_certificate **cert );
|
||||
extern int x509_is_valid ( struct x509_certificate *cert,
|
||||
struct x509_root *root );
|
||||
extern int x509_validate ( struct x509_certificate *cert,
|
||||
struct x509_certificate *issuer,
|
||||
time_t time, struct x509_root *root );
|
||||
|
@ -383,22 +385,13 @@ extern int x509_check_root ( struct x509_certificate *cert,
|
|||
struct x509_root *root );
|
||||
extern int x509_check_time ( struct x509_certificate *cert, time_t time );
|
||||
|
||||
/**
|
||||
* Check if X.509 certificate is valid
|
||||
*
|
||||
* @v cert X.509 certificate
|
||||
*/
|
||||
static inline int x509_is_valid ( struct x509_certificate *cert ) {
|
||||
return ( cert->flags & X509_FL_VALIDATED );
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate X.509 certificate
|
||||
*
|
||||
* @v cert X.509 certificate
|
||||
*/
|
||||
static inline void x509_invalidate ( struct x509_certificate *cert ) {
|
||||
cert->flags &= ~X509_FL_VALIDATED;
|
||||
cert->root = NULL;
|
||||
cert->path_remaining = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ FEATURE ( FEATURE_PROTOCOL, "HTTPS", DHCP_EB_FEATURE_HTTPS, 1 );
|
|||
*/
|
||||
static int https_filter ( struct http_connection *conn ) {
|
||||
|
||||
return add_tls ( &conn->socket, conn->uri->host );
|
||||
return add_tls ( &conn->socket, conn->uri->host, NULL );
|
||||
}
|
||||
|
||||
/** HTTPS URI opener */
|
||||
|
|
|
@ -246,7 +246,7 @@ static int apply_syslogs_settings ( void ) {
|
|||
}
|
||||
|
||||
/* Add TLS filter */
|
||||
if ( ( rc = add_tls ( &syslogs, server ) ) != 0 ) {
|
||||
if ( ( rc = add_tls ( &syslogs, server, NULL ) ) != 0 ) {
|
||||
DBG ( "SYSLOGS cannot create TLS filter: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto err_add_tls;
|
||||
|
|
|
@ -1938,7 +1938,8 @@ static int tls_new_server_hello_done ( struct tls_connection *tls,
|
|||
}
|
||||
|
||||
/* Begin certificate validation */
|
||||
if ( ( rc = create_validator ( &tls->validator, tls->chain ) ) != 0 ) {
|
||||
if ( ( rc = create_validator ( &tls->validator, tls->chain,
|
||||
tls->root ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p could not start certificate validation: "
|
||||
"%s\n", tls, strerror ( rc ) );
|
||||
return rc;
|
||||
|
@ -3140,9 +3141,11 @@ static int tls_session ( struct tls_connection *tls, const char *name ) {
|
|||
*
|
||||
* @v xfer Data transfer interface
|
||||
* @v name Host name
|
||||
* @v root Root of trust (or NULL to use default)
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int add_tls ( struct interface *xfer, const char *name ) {
|
||||
int add_tls ( struct interface *xfer, const char *name,
|
||||
struct x509_root *root ) {
|
||||
struct tls_connection *tls;
|
||||
int rc;
|
||||
|
||||
|
@ -3160,6 +3163,7 @@ int add_tls ( struct interface *xfer, const char *name ) {
|
|||
intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt );
|
||||
process_init_stopped ( &tls->process, &tls_process_desc,
|
||||
&tls->refcnt );
|
||||
tls->root = root;
|
||||
tls->version = TLS_VERSION_TLS_1_2;
|
||||
tls_clear_cipher ( tls, &tls->tx_cipherspec );
|
||||
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
|
||||
|
|
|
@ -73,6 +73,8 @@ struct validator {
|
|||
/** Process */
|
||||
struct process process;
|
||||
|
||||
/** Root of trust (or NULL to use default) */
|
||||
struct x509_root *root;
|
||||
/** X.509 certificate chain */
|
||||
struct x509_chain *chain;
|
||||
/** OCSP check */
|
||||
|
@ -554,7 +556,7 @@ static void validator_step ( struct validator *validator ) {
|
|||
*/
|
||||
now = time ( NULL );
|
||||
if ( ( rc = x509_validate_chain ( validator->chain, now, NULL,
|
||||
NULL ) ) == 0 ) {
|
||||
validator->root ) ) == 0 ) {
|
||||
DBGC ( validator, "VALIDATOR %p \"%s\" validated\n",
|
||||
validator, validator_name ( validator ) );
|
||||
validator_finished ( validator, 0 );
|
||||
|
@ -569,7 +571,7 @@ static void validator_step ( struct validator *validator ) {
|
|||
issuer = link->cert;
|
||||
if ( ! cert )
|
||||
continue;
|
||||
if ( ! x509_is_valid ( issuer ) )
|
||||
if ( ! x509_is_valid ( issuer, validator->root ) )
|
||||
continue;
|
||||
/* The issuer is valid, but this certificate is not
|
||||
* yet valid. If OCSP is applicable, start it.
|
||||
|
@ -621,9 +623,11 @@ static struct process_descriptor validator_process_desc =
|
|||
*
|
||||
* @v job Job control interface
|
||||
* @v chain X.509 certificate chain
|
||||
* @v root Root of trust, or NULL to use default
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int create_validator ( struct interface *job, struct x509_chain *chain ) {
|
||||
int create_validator ( struct interface *job, struct x509_chain *chain,
|
||||
struct x509_root *root ) {
|
||||
struct validator *validator;
|
||||
int rc;
|
||||
|
||||
|
@ -646,6 +650,7 @@ int create_validator ( struct interface *job, struct x509_chain *chain ) {
|
|||
&validator->refcnt );
|
||||
process_init ( &validator->process, &validator_process_desc,
|
||||
&validator->refcnt );
|
||||
validator->root = root;
|
||||
validator->chain = x509_chain_get ( chain );
|
||||
xferbuf_malloc_init ( &validator->buffer );
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/x509.h>
|
||||
#include <ipxe/rootcert.h>
|
||||
#include <ipxe/ocsp.h>
|
||||
#include <ipxe/test.h>
|
||||
|
||||
|
@ -110,7 +111,7 @@ static void ocsp_prepare_test ( struct ocsp_test *test ) {
|
|||
x509_invalidate ( cert );
|
||||
|
||||
/* Force-validate issuer certificate */
|
||||
issuer->flags |= X509_FL_VALIDATED;
|
||||
issuer->root = &root_certificates;
|
||||
issuer->path_remaining = ( issuer->extensions.basic.path_len + 1 );
|
||||
}
|
||||
|
||||
|
|
|
@ -943,6 +943,10 @@ static void x509_validate_chain_okx ( struct x509_test_chain *chn, time_t time,
|
|||
x509_invalidate_chain ( chn->chain );
|
||||
okx ( x509_validate_chain ( chn->chain, time, store, root ) == 0,
|
||||
file, line );
|
||||
okx ( x509_is_valid ( chn->certs[0]->cert, root ),
|
||||
file, line );
|
||||
okx ( ! x509_is_valid ( chn->certs[0]->cert, &dummy_root ),
|
||||
file, line );
|
||||
}
|
||||
#define x509_validate_chain_ok( chn, time, store, root ) \
|
||||
x509_validate_chain_okx ( chn, time, store, root, __FILE__, __LINE__ )
|
||||
|
|
|
@ -57,7 +57,7 @@ void certstat ( struct x509_certificate *cert ) {
|
|||
printf ( " [PERMANENT]" );
|
||||
if ( cert->flags & X509_FL_EXPLICIT )
|
||||
printf ( " [EXPLICIT]" );
|
||||
if ( x509_is_valid ( cert ) )
|
||||
if ( x509_is_valid ( cert, NULL ) )
|
||||
printf ( " [VALIDATED]" );
|
||||
printf ( "\n" );
|
||||
}
|
||||
|
|
|
@ -77,7 +77,8 @@ int imgverify ( struct image *image, struct image *signature,
|
|||
|
||||
/* Complete all certificate chains */
|
||||
list_for_each_entry ( info, &sig->info, list ) {
|
||||
if ( ( rc = create_validator ( &monojob, info->chain ) ) != 0 )
|
||||
if ( ( rc = create_validator ( &monojob, info->chain,
|
||||
NULL ) ) != 0 )
|
||||
goto err_create_validator;
|
||||
if ( ( rc = monojob_wait ( NULL, 0 ) ) != 0 )
|
||||
goto err_validator_wait;
|
||||
|
|
Loading…
Reference in New Issue