[cmdline] Add certificate management commands
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
1e277ab062
commit
eed1258038
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
|
@ -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 )
|
||||
|
||||
/** @} */
|
||||
|
||||
|
|
Reference in New Issue