/* 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 ) );
*/
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",
/* 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;
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
*
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 */
/* 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;
}
}
/* 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 ) );
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 ) );
/** 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 */
/** 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 */
#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 */
/** 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;
/** 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,
};
/**
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 );
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;
}
*/
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 */
}
/* 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;
}
/* 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;
*
* @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;
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 );
/** 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 */
*/
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 );
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.
*
* @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;
&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 );
#include <stdlib.h>
#include <string.h>
#include <ipxe/x509.h>
+#include <ipxe/rootcert.h>
#include <ipxe/ocsp.h>
#include <ipxe/test.h>
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 );
}
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__ )
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" );
}
/* 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;