diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 7de833d0..fbdeb0a3 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -258,6 +258,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_imgtrust ( ERRFILE_OTHER | 0x002b0000 ) #define ERRFILE_menu_ui ( ERRFILE_OTHER | 0x002c0000 ) #define ERRFILE_menu_cmd ( ERRFILE_OTHER | 0x002d0000 ) +#define ERRFILE_validator ( ERRFILE_OTHER | 0x002e0000 ) /** @} */ diff --git a/src/include/ipxe/validator.h b/src/include/ipxe/validator.h new file mode 100644 index 00000000..23bdab42 --- /dev/null +++ b/src/include/ipxe/validator.h @@ -0,0 +1,17 @@ +#ifndef _IPXE_VALIDATOR_H +#define _IPXE_VALIDATOR_H + +/** @file + * + * Certificate validator + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +extern int create_validator ( struct interface *job, struct x509_chain *chain ); + +#endif /* _IPXE_VALIDATOR_H */ diff --git a/src/net/validator.c b/src/net/validator.c new file mode 100644 index 00000000..b6b52a21 --- /dev/null +++ b/src/net/validator.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Certificate validator + * + */ + +/** A certificate validator */ +struct validator { + /** Reference count */ + struct refcnt refcnt; + /** Job control interface */ + struct interface job; + /** Process */ + struct process process; + /** X.509 certificate chain */ + struct x509_chain *chain; +}; + +/** + * Free certificate validator + * + * @v refcnt Reference count + */ +static void validator_free ( struct refcnt *refcnt ) { + struct validator *validator = + container_of ( refcnt, struct validator, refcnt ); + + DBGC ( validator, "VALIDATOR %p freed\n", validator ); + x509_chain_put ( validator->chain ); + free ( validator ); +} + +/** + * Mark certificate validation as finished + * + * @v validator Certificate validator + * @v rc Reason for finishing + */ +static void validator_finished ( struct validator *validator, int rc ) { + + /* Remove process */ + process_del ( &validator->process ); + + /* Close all interfaces */ + intf_shutdown ( &validator->job, rc ); +} + +/**************************************************************************** + * + * Job control interface + * + */ + +/** Certificate validator job control interface operations */ +static struct interface_operation validator_job_operations[] = { + INTF_OP ( intf_close, struct validator *, validator_finished ), +}; + +/** Certificate validator job control interface descriptor */ +static struct interface_descriptor validator_job_desc = + INTF_DESC ( struct validator, job, validator_job_operations ); + +/**************************************************************************** + * + * Validation process + * + */ + +/** + * Certificate validation process + * + * @v validator Certificate validator + */ +static void validator_step ( struct validator *validator ) { + time_t now; + int rc; + + /* Attempt to validate certificate chain */ + now = time ( NULL ); + if ( ( rc = x509_validate_chain ( validator->chain, now, + NULL ) ) != 0 ) { + DBGC ( validator, "VALIDATOR %p could not validate chain: %s\n", + validator, strerror ( rc ) ); + goto err_validate; + } + + /* Mark validation as complete */ + validator_finished ( validator, 0 ); + + return; + + err_validate: + validator_finished ( validator, rc ); +} + +/** Certificate validator process descriptor */ +static struct process_descriptor validator_process_desc = + PROC_DESC_ONCE ( struct validator, process, validator_step ); + +/**************************************************************************** + * + * Instantiator + * + */ + +/** + * Instantiate a certificate validator + * + * @v job Job control interface + * @v chain X.509 certificate chain + * @ret rc Return status code + */ +int create_validator ( struct interface *job, struct x509_chain *chain ) { + struct validator *validator; + int rc; + + /* Sanity check */ + if ( ! chain ) { + rc = -EINVAL; + goto err_sanity; + } + + /* Allocate and initialise structure */ + validator = zalloc ( sizeof ( *validator ) ); + if ( ! validator ) { + rc = -ENOMEM; + goto err_alloc; + } + ref_init ( &validator->refcnt, validator_free ); + intf_init ( &validator->job, &validator_job_desc, + &validator->refcnt ); + process_init ( &validator->process, &validator_process_desc, + &validator->refcnt ); + validator->chain = x509_chain_get ( chain ); + + /* Attach parent interface, mortalise self, and return */ + intf_plug_plug ( &validator->job, job ); + ref_put ( &validator->refcnt ); + DBGC ( validator, "VALIDATOR %p validating X509 chain %p\n", + validator, validator->chain ); + return 0; + + validator_finished ( validator, rc ); + ref_put ( &validator->refcnt ); + err_alloc: + err_sanity: + return rc; +}