Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[cmdline] Add certificate management commands
Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Aug 31, 2016
1 parent 1e277ab commit eed1258
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/config/config.c
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/config/general.h
Expand Up @@ -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
Expand Down
304 changes: 304 additions & 0 deletions src/hci/commands/cert_cmd.c
@@ -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,
},
};
1 change: 1 addition & 0 deletions src/include/ipxe/errfile.h
Expand Up @@ -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 )

/** @} */

Expand Down

0 comments on commit eed1258

Please sign in to comment.