]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[cmdline] Add certificate management commands
authorMichael Brown <mcb30@ipxe.org>
Thu, 25 Aug 2016 14:40:27 +0000 (15:40 +0100)
committerMichael Brown <mcb30@ipxe.org>
Wed, 31 Aug 2016 16:11:14 +0000 (17:11 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/config/config.c
src/config/general.h
src/hci/commands/cert_cmd.c [new file with mode: 0644]
src/include/ipxe/errfile.h

index c6683261f82de4a76fffc7c725ffab6231d62c43..faf9aefa84423b8ebe981a94e0e5b843b0bbac26 100644 (file)
@@ -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
index 4b990489847f1880c7ace74bc0faf8de2fc11f6f..d2bbeb067e9a823079a6a249ee33a5f6c503da65 100644 (file)
@@ -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 (file)
index 0000000..24b18bf
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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 <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/x509.h>
+#include <ipxe/certstore.h>
+#include <ipxe/image.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+#include <usr/imgmgmt.h>
+#include <usr/certmgmt.h>
+
+/** @file
+ *
+ * Certificate management commands
+ *
+ */
+
+/** "cert<xxx>" options */
+struct cert_options {
+       /** Certificate subject name */
+       char *name;
+       /** Keep certificate file after parsing */
+       int keep;
+};
+
+/** "cert<xxx>" 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<xxx>" 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<xxx>" 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<xxx>" 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,
+                           "[<uri|image>]", 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,
+       },
+};
index 9ec22fb01110176b2e0261c6d25f77032230836e..08e166ce786e144556fa620cffbc0f9fd34d6ee8 100644 (file)
@@ -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 )
 
 /** @} */