Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
Showing
4 changed files
with
309 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters