diff --git a/src/config/config.c b/src/config/config.c index c6683261..faf9aefa 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -275,6 +275,9 @@ REQUIRE_OBJECT ( profstat_cmd ); #ifdef NTP_CMD REQUIRE_OBJECT ( ntp_cmd ); #endif +#ifdef CERT_CMD +REQUIRE_OBJECT ( cert_cmd ); +#endif /* * Drag in miscellaneous objects diff --git a/src/config/general.h b/src/config/general.h index 4b990489..d2bbeb06 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -150,6 +150,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); //#define IPSTAT_CMD /* IP statistics commands */ //#define PROFSTAT_CMD /* Profiling commands */ //#define NTP_CMD /* NTP commands */ +//#define CERT_CMD /* Certificate management commands */ /* * ROM-specific options diff --git a/src/hci/commands/cert_cmd.c b/src/hci/commands/cert_cmd.c new file mode 100644 index 00000000..24b18bf5 --- /dev/null +++ b/src/hci/commands/cert_cmd.c @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2016 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 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. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Certificate management commands + * + */ + +/** "cert" options */ +struct cert_options { + /** Certificate subject name */ + char *name; + /** Keep certificate file after parsing */ + int keep; +}; + +/** "cert" option list */ +static union { + /* "certstore" takes both options */ + struct option_descriptor certstore[2]; + /* "certstat" takes only --subject */ + struct option_descriptor certstat[1]; + /* "certfree" takes only --subject */ + struct option_descriptor certfree[1]; +} opts = { + .certstore = { + OPTION_DESC ( "subject", 's', required_argument, + struct cert_options, name, parse_string ), + OPTION_DESC ( "keep", 'k', no_argument, + struct cert_options, keep, parse_flag ), + }, +}; + +/** A "cert" command descriptor */ +struct cert_command_descriptor { + /** Command descriptor */ + struct command_descriptor cmd; + /** Payload + * + * @v cert X.509 certificate + * @ret rc Return status code + */ + int ( * payload ) ( struct x509_certificate *cert ); +}; + +/** + * Construct "cert" command descriptor + * + * @v _struct Options structure type + * @v _options Option descriptor array + * @v _min_args Minimum number of non-option arguments + * @v _max_args Maximum number of non-option arguments + * @v _usage Command usage + * @v _payload Payload method + * @ret _command Command descriptor + */ +#define CERT_COMMAND_DESC( _struct, _options, _min_args, _max_args, \ + _usage, _payload ) \ + { \ + .cmd = COMMAND_DESC ( _struct, _options, _min_args, \ + _max_args, _usage ), \ + .payload = _payload, \ + } + +/** + * Execute "cert" command + * + * @v argc Argument count + * @v argv Argument list + * @v certcmd Command descriptor + * @ret rc Return status code + */ +static int cert_exec ( int argc, char **argv, + struct cert_command_descriptor *certcmd ) { + struct command_descriptor *cmd = &certcmd->cmd; + struct cert_options opts; + struct image *image = NULL; + struct x509_certificate *cert; + struct x509_certificate *tmp; + unsigned int count = 0; + size_t offset = 0; + int next; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 ) + goto err_parse; + + /* Acquire image, if applicable */ + if ( ( optind < argc ) && + ( ( rc = imgacquire ( argv[optind], 0, &image ) ) != 0 ) ) + goto err_acquire; + + /* Get first entry in certificate store */ + tmp = list_first_entry ( &certstore.links, struct x509_certificate, + store.list ); + + /* Iterate over certificates */ + while ( 1 ) { + + /* Get next certificate from image or store as applicable */ + if ( image ) { + + /* Get next certificate from image */ + if ( offset >= image->len ) + break; + next = image_x509 ( image, offset, &cert ); + if ( next < 0 ) { + rc = next; + printf ( "Could not parse certificate: %s\n", + strerror ( rc ) ); + goto err_x509; + } + offset = next; + + } else { + + /* Get next certificate from store */ + cert = tmp; + if ( ! cert ) + break; + tmp = list_next_entry ( tmp, &certstore.links, + store.list ); + x509_get ( cert ); + } + + /* Skip non-matching names, if a name was specified */ + if ( opts.name && ( x509_check_name ( cert, opts.name ) != 0 )){ + x509_put ( cert ); + continue; + } + + /* Execute payload */ + if ( ( rc = certcmd->payload ( cert ) ) != 0 ) { + x509_put ( cert ); + goto err_payload; + } + + /* Count number of certificates processed */ + count++; + + /* Drop reference to certificate */ + x509_put ( cert ); + } + + /* Fail if a name was specified and no matching certificates + * were found. + */ + if ( opts.name && ( count == 0 ) ) { + printf ( "\"%s\" : no such certificate\n", opts.name ); + rc = -ENOENT; + goto err_none; + } + + err_none: + err_payload: + err_x509: + if ( image && ( ! opts.keep ) ) + unregister_image ( image ); + err_acquire: + err_parse: + return rc; +} + +/** + * "certstat" payload + * + * @v cert X.509 certificate + * @ret rc Return status code + */ +static int certstat_payload ( struct x509_certificate *cert ) { + + certstat ( cert ); + return 0; +} + +/** "certstat" command descriptor */ +static struct cert_command_descriptor certstat_cmd = + CERT_COMMAND_DESC ( struct cert_options, opts.certstat, 0, 0, NULL, + certstat_payload ); + +/** + * The "certstat" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int certstat_exec ( int argc, char **argv ) { + + return cert_exec ( argc, argv, &certstat_cmd ); +} + +/** + * "certstore" payload + * + * @v cert X.509 certificate + * @ret rc Return status code + */ +static int certstore_payload ( struct x509_certificate *cert ) { + + /* Mark certificate as having been added explicitly */ + cert->flags |= X509_FL_EXPLICIT; + + return 0; +} + +/** "certstore" command descriptor */ +static struct cert_command_descriptor certstore_cmd = + CERT_COMMAND_DESC ( struct cert_options, opts.certstore, 0, 1, + "[]", certstore_payload ); + +/** + * The "certstore" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int certstore_exec ( int argc, char **argv ) { + + return cert_exec ( argc, argv, &certstore_cmd ); +} + +/** + * "certfree" payload + * + * @v cert X.509 certificate + * @ret rc Return status code + */ +static int certfree_payload ( struct x509_certificate *cert ) { + + /* Remove from certificate store */ + certstore_del ( cert ); + + return 0; +} + +/** "certfree" command descriptor */ +static struct cert_command_descriptor certfree_cmd = + CERT_COMMAND_DESC ( struct cert_options, opts.certfree, 0, 0, NULL, + certfree_payload ); + +/** + * The "certfree" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int certfree_exec ( int argc, char **argv ) { + + return cert_exec ( argc, argv, &certfree_cmd ); +} + +/** Certificate management commands */ +struct command certmgmt_commands[] __command = { + { + .name = "certstat", + .exec = certstat_exec, + }, + { + .name = "certstore", + .exec = certstore_exec, + }, + { + .name = "certfree", + .exec = certfree_exec, + }, +}; diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 9ec22fb0..08e166ce 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -359,6 +359,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_efi_fbcon ( ERRFILE_OTHER | 0x004c0000 ) #define ERRFILE_efi_local ( ERRFILE_OTHER | 0x004d0000 ) #define ERRFILE_efi_entropy ( ERRFILE_OTHER | 0x004e0000 ) +#define ERRFILE_cert_cmd ( ERRFILE_OTHER | 0x004f0000 ) /** @} */