iPXE
cert_cmd.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdio.h>
00027 #include <errno.h>
00028 #include <getopt.h>
00029 #include <ipxe/x509.h>
00030 #include <ipxe/certstore.h>
00031 #include <ipxe/image.h>
00032 #include <ipxe/command.h>
00033 #include <ipxe/parseopt.h>
00034 #include <usr/imgmgmt.h>
00035 #include <usr/certmgmt.h>
00036 
00037 /** @file
00038  *
00039  * Certificate management commands
00040  *
00041  */
00042 
00043 /** "cert<xxx>" options */
00044 struct cert_options {
00045         /** Certificate subject name */
00046         char *name;
00047         /** Keep certificate file after parsing */
00048         int keep;
00049 };
00050 
00051 /** "cert<xxx>" option list */
00052 static union {
00053         /* "certstore" takes both options */
00054         struct option_descriptor certstore[2];
00055         /* "certstat" takes only --subject */
00056         struct option_descriptor certstat[1];
00057         /* "certfree" takes only --subject */
00058         struct option_descriptor certfree[1];
00059 } opts = {
00060         .certstore = {
00061                 OPTION_DESC ( "subject", 's', required_argument,
00062                               struct cert_options, name, parse_string ),
00063                 OPTION_DESC ( "keep", 'k', no_argument,
00064                               struct cert_options, keep, parse_flag ),
00065         },
00066 };
00067 
00068 /** A "cert<xxx>" command descriptor */
00069 struct cert_command_descriptor {
00070         /** Command descriptor */
00071         struct command_descriptor cmd;
00072         /** Payload
00073          *
00074          * @v cert              X.509 certificate
00075          * @ret rc              Return status code
00076          */
00077         int ( * payload ) ( struct x509_certificate *cert );
00078 };
00079 
00080 /**
00081  * Construct "cert<xxx>" command descriptor
00082  *
00083  * @v _struct           Options structure type
00084  * @v _options          Option descriptor array
00085  * @v _min_args         Minimum number of non-option arguments
00086  * @v _max_args         Maximum number of non-option arguments
00087  * @v _usage            Command usage
00088  * @v _payload          Payload method
00089  * @ret _command        Command descriptor
00090  */
00091 #define CERT_COMMAND_DESC( _struct, _options, _min_args, _max_args,     \
00092                            _usage, _payload )                           \
00093         {                                                               \
00094                 .cmd = COMMAND_DESC ( _struct, _options, _min_args,     \
00095                                       _max_args, _usage ),              \
00096                 .payload = _payload,                                    \
00097         }
00098 
00099 /**
00100  * Execute "cert<xxx>" command
00101  *
00102  * @v argc              Argument count
00103  * @v argv              Argument list
00104  * @v certcmd           Command descriptor
00105  * @ret rc              Return status code
00106  */
00107 static int cert_exec ( int argc, char **argv,
00108                        struct cert_command_descriptor *certcmd ) {
00109         struct command_descriptor *cmd = &certcmd->cmd;
00110         struct cert_options opts;
00111         struct image *image = NULL;
00112         struct x509_certificate *cert;
00113         struct x509_certificate *tmp;
00114         unsigned int count = 0;
00115         size_t offset = 0;
00116         int next;
00117         int rc;
00118 
00119         /* Parse options */
00120         if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 )
00121                 goto err_parse;
00122 
00123         /* Acquire image, if applicable */
00124         if ( ( optind < argc ) &&
00125              ( ( rc = imgacquire ( argv[optind], 0, &image ) ) != 0 ) )
00126                 goto err_acquire;
00127 
00128         /* Get first entry in certificate store */
00129         tmp = list_first_entry ( &certstore.links, struct x509_certificate,
00130                                  store.list );
00131 
00132         /* Iterate over certificates */
00133         while ( 1 ) {
00134 
00135                 /* Get next certificate from image or store as applicable */
00136                 if ( image ) {
00137 
00138                         /* Get next certificate from image */
00139                         if ( offset >= image->len )
00140                                 break;
00141                         next = image_x509 ( image, offset, &cert );
00142                         if ( next < 0 ) {
00143                                 rc = next;
00144                                 printf ( "Could not parse certificate: %s\n",
00145                                          strerror ( rc ) );
00146                                 goto err_x509;
00147                         }
00148                         offset = next;
00149 
00150                 } else {
00151 
00152                         /* Get next certificate from store */
00153                         cert = tmp;
00154                         if ( ! cert )
00155                                 break;
00156                         tmp = list_next_entry ( tmp, &certstore.links,
00157                                                 store.list );
00158                         x509_get ( cert );
00159                 }
00160 
00161                 /* Skip non-matching names, if a name was specified */
00162                 if ( opts.name && ( x509_check_name ( cert, opts.name ) != 0 )){
00163                         x509_put ( cert );
00164                         continue;
00165                 }
00166 
00167                 /* Execute payload */
00168                 if ( ( rc = certcmd->payload ( cert ) ) != 0 ) {
00169                         x509_put ( cert );
00170                         goto err_payload;
00171                 }
00172 
00173                 /* Count number of certificates processed */
00174                 count++;
00175 
00176                 /* Drop reference to certificate */
00177                 x509_put ( cert );
00178         }
00179 
00180         /* Fail if a name was specified and no matching certificates
00181          * were found.
00182          */
00183         if ( opts.name && ( count == 0 ) ) {
00184                 printf ( "\"%s\" : no such certificate\n", opts.name );
00185                 rc = -ENOENT;
00186                 goto err_none;
00187         }
00188 
00189  err_none:
00190  err_payload:
00191  err_x509:
00192         if ( image && ( ! opts.keep ) )
00193                 unregister_image ( image );
00194  err_acquire:
00195  err_parse:
00196         return rc;
00197 }
00198 
00199 /**
00200  * "certstat" payload
00201  *
00202  * @v cert              X.509 certificate
00203  * @ret rc              Return status code
00204  */
00205 static int certstat_payload ( struct x509_certificate *cert ) {
00206 
00207         certstat ( cert );
00208         return 0;
00209 }
00210 
00211 /** "certstat" command descriptor */
00212 static struct cert_command_descriptor certstat_cmd =
00213         CERT_COMMAND_DESC ( struct cert_options, opts.certstat, 0, 0, NULL,
00214                             certstat_payload );
00215 
00216 /**
00217  * The "certstat" command
00218  *
00219  * @v argc              Argument count
00220  * @v argv              Argument list
00221  * @ret rc              Return status code
00222  */
00223 static int certstat_exec ( int argc, char **argv ) {
00224 
00225         return cert_exec ( argc, argv, &certstat_cmd );
00226 }
00227 
00228 /**
00229  * "certstore" payload
00230  *
00231  * @v cert              X.509 certificate
00232  * @ret rc              Return status code
00233  */
00234 static int certstore_payload ( struct x509_certificate *cert ) {
00235 
00236         /* Mark certificate as having been added explicitly */
00237         cert->flags |= X509_FL_EXPLICIT;
00238 
00239         return 0;
00240 }
00241 
00242 /** "certstore" command descriptor */
00243 static struct cert_command_descriptor certstore_cmd =
00244         CERT_COMMAND_DESC ( struct cert_options, opts.certstore, 0, 1,
00245                             "[<uri|image>]", certstore_payload );
00246 
00247 /**
00248  * The "certstore" command
00249  *
00250  * @v argc              Argument count
00251  * @v argv              Argument list
00252  * @ret rc              Return status code
00253  */
00254 static int certstore_exec ( int argc, char **argv ) {
00255 
00256         return cert_exec ( argc, argv, &certstore_cmd );
00257 }
00258 
00259 /**
00260  * "certfree" payload
00261  *
00262  * @v cert              X.509 certificate
00263  * @ret rc              Return status code
00264  */
00265 static int certfree_payload ( struct x509_certificate *cert ) {
00266 
00267         /* Remove from certificate store */
00268         certstore_del ( cert );
00269 
00270         return 0;
00271 }
00272 
00273 /** "certfree" command descriptor */
00274 static struct cert_command_descriptor certfree_cmd =
00275         CERT_COMMAND_DESC ( struct cert_options, opts.certfree, 0, 0, NULL,
00276                             certfree_payload );
00277 
00278 /**
00279  * The "certfree" command
00280  *
00281  * @v argc              Argument count
00282  * @v argv              Argument list
00283  * @ret rc              Return status code
00284  */
00285 static int certfree_exec ( int argc, char **argv ) {
00286 
00287         return cert_exec ( argc, argv, &certfree_cmd );
00288 }
00289 
00290 /** Certificate management commands */
00291 struct command certmgmt_commands[] __command = {
00292         {
00293                 .name = "certstat",
00294                 .exec = certstat_exec,
00295         },
00296         {
00297                 .name = "certstore",
00298                 .exec = certstore_exec,
00299         },
00300         {
00301                 .name = "certfree",
00302                 .exec = certfree_exec,
00303         },
00304 };