1 /*
2  * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <stdio.h>
27 #include <errno.h>
28 #include <getopt.h>
29 #include <ipxe/x509.h>
30 #include <ipxe/certstore.h>
31 #include <ipxe/image.h>
32 #include <ipxe/command.h>
33 #include <ipxe/parseopt.h>
34 #include <usr/imgmgmt.h>
35 #include <usr/certmgmt.h>
36 
37 /** @file
38  *
39  * Certificate management commands
40  *
41  */
42 
43 /** "cert<xxx>" options */
44 struct cert_options {
45 	/** Certificate subject name */
46 	char *name;
47 	/** Keep certificate file after parsing */
48 	int keep;
49 };
50 
51 /** "cert<xxx>" option list */
52 static union {
53 	/* "certstore" takes both options */
54 	struct option_descriptor certstore[2];
55 	/* "certstat" takes only --subject */
56 	struct option_descriptor certstat[1];
57 	/* "certfree" takes only --subject */
58 	struct option_descriptor certfree[1];
59 } opts = {
60 	.certstore = {
61 		OPTION_DESC ( "subject", 's', required_argument,
62 			      struct cert_options, name, parse_string ),
63 		OPTION_DESC ( "keep", 'k', no_argument,
64 			      struct cert_options, keep, parse_flag ),
65 	},
66 };
67 
68 /** A "cert<xxx>" command descriptor */
69 struct cert_command_descriptor {
70 	/** Command descriptor */
71 	struct command_descriptor cmd;
72 	/** Payload
73 	 *
74 	 * @v cert		X.509 certificate
75 	 * @ret rc		Return status code
76 	 */
77 	int ( * payload ) ( struct x509_certificate *cert );
78 };
79 
80 /**
81  * Construct "cert<xxx>" command descriptor
82  *
83  * @v _struct		Options structure type
84  * @v _options		Option descriptor array
85  * @v _min_args		Minimum number of non-option arguments
86  * @v _max_args		Maximum number of non-option arguments
87  * @v _usage		Command usage
88  * @v _payload		Payload method
89  * @ret _command	Command descriptor
90  */
91 #define CERT_COMMAND_DESC( _struct, _options, _min_args, _max_args,	\
92 			   _usage, _payload )				\
93 	{								\
94 		.cmd = COMMAND_DESC ( _struct, _options, _min_args,	\
95 				      _max_args, _usage ),		\
96 		.payload = _payload,					\
97 	}
98 
99 /**
100  * Execute "cert<xxx>" command
101  *
102  * @v argc		Argument count
103  * @v argv		Argument list
104  * @v certcmd		Command descriptor
105  * @ret rc		Return status code
106  */
cert_exec(int argc,char ** argv,struct cert_command_descriptor * certcmd)107 static int cert_exec ( int argc, char **argv,
108 		       struct cert_command_descriptor *certcmd ) {
109 	struct command_descriptor *cmd = &certcmd->cmd;
110 	struct cert_options opts;
111 	struct image *image = NULL;
112 	struct x509_certificate *cert;
113 	struct x509_certificate *tmp;
114 	unsigned int count = 0;
115 	size_t offset = 0;
116 	int next;
117 	int rc;
118 
119 	/* Parse options */
120 	if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 )
121 		goto err_parse;
122 
123 	/* Acquire image, if applicable */
124 	if ( ( optind < argc ) &&
125 	     ( ( rc = imgacquire ( argv[optind], 0, &image ) ) != 0 ) )
126 		goto err_acquire;
127 
128 	/* Get first entry in certificate store */
129 	tmp = list_first_entry ( &certstore.links, struct x509_certificate,
130 				 store.list );
131 
132 	/* Iterate over certificates */
133 	while ( 1 ) {
134 
135 		/* Get next certificate from image or store as applicable */
136 		if ( image ) {
137 
138 			/* Get next certificate from image */
139 			if ( offset >= image->len )
140 				break;
141 			next = image_x509 ( image, offset, &cert );
142 			if ( next < 0 ) {
143 				rc = next;
144 				printf ( "Could not parse certificate: %s\n",
145 					 strerror ( rc ) );
146 				goto err_x509;
147 			}
148 			offset = next;
149 
150 		} else {
151 
152 			/* Get next certificate from store */
153 			cert = tmp;
154 			if ( ! cert )
155 				break;
156 			tmp = list_next_entry ( tmp, &certstore.links,
157 						store.list );
158 			x509_get ( cert );
159 		}
160 
161 		/* Skip non-matching names, if a name was specified */
162 		if ( opts.name && ( x509_check_name ( cert, opts.name ) != 0 )){
163 			x509_put ( cert );
164 			continue;
165 		}
166 
167 		/* Execute payload */
168 		if ( ( rc = certcmd->payload ( cert ) ) != 0 ) {
169 			x509_put ( cert );
170 			goto err_payload;
171 		}
172 
173 		/* Count number of certificates processed */
174 		count++;
175 
176 		/* Drop reference to certificate */
177 		x509_put ( cert );
178 	}
179 
180 	/* Fail if a name was specified and no matching certificates
181 	 * were found.
182 	 */
183 	if ( opts.name && ( count == 0 ) ) {
184 		printf ( "\"%s\" : no such certificate\n", opts.name );
185 		rc = -ENOENT;
186 		goto err_none;
187 	}
188 
189  err_none:
190  err_payload:
191  err_x509:
192 	if ( image && ( ! opts.keep ) )
193 		unregister_image ( image );
194  err_acquire:
195  err_parse:
196 	return rc;
197 }
198 
199 /**
200  * "certstat" payload
201  *
202  * @v cert		X.509 certificate
203  * @ret rc		Return status code
204  */
certstat_payload(struct x509_certificate * cert)205 static int certstat_payload ( struct x509_certificate *cert ) {
206 
207 	certstat ( cert );
208 	return 0;
209 }
210 
211 /** "certstat" command descriptor */
212 static struct cert_command_descriptor certstat_cmd =
213 	CERT_COMMAND_DESC ( struct cert_options, opts.certstat, 0, 0, NULL,
214 			    certstat_payload );
215 
216 /**
217  * The "certstat" command
218  *
219  * @v argc		Argument count
220  * @v argv		Argument list
221  * @ret rc		Return status code
222  */
certstat_exec(int argc,char ** argv)223 static int certstat_exec ( int argc, char **argv ) {
224 
225 	return cert_exec ( argc, argv, &certstat_cmd );
226 }
227 
228 /**
229  * "certstore" payload
230  *
231  * @v cert		X.509 certificate
232  * @ret rc		Return status code
233  */
certstore_payload(struct x509_certificate * cert)234 static int certstore_payload ( struct x509_certificate *cert ) {
235 
236 	/* Mark certificate as having been added explicitly */
237 	cert->flags |= X509_FL_EXPLICIT;
238 
239 	return 0;
240 }
241 
242 /** "certstore" command descriptor */
243 static struct cert_command_descriptor certstore_cmd =
244 	CERT_COMMAND_DESC ( struct cert_options, opts.certstore, 0, 1,
245 			    "[<uri|image>]", certstore_payload );
246 
247 /**
248  * The "certstore" command
249  *
250  * @v argc		Argument count
251  * @v argv		Argument list
252  * @ret rc		Return status code
253  */
certstore_exec(int argc,char ** argv)254 static int certstore_exec ( int argc, char **argv ) {
255 
256 	return cert_exec ( argc, argv, &certstore_cmd );
257 }
258 
259 /**
260  * "certfree" payload
261  *
262  * @v cert		X.509 certificate
263  * @ret rc		Return status code
264  */
certfree_payload(struct x509_certificate * cert)265 static int certfree_payload ( struct x509_certificate *cert ) {
266 
267 	/* Remove from certificate store */
268 	certstore_del ( cert );
269 
270 	return 0;
271 }
272 
273 /** "certfree" command descriptor */
274 static struct cert_command_descriptor certfree_cmd =
275 	CERT_COMMAND_DESC ( struct cert_options, opts.certfree, 0, 0, NULL,
276 			    certfree_payload );
277 
278 /**
279  * The "certfree" command
280  *
281  * @v argc		Argument count
282  * @v argv		Argument list
283  * @ret rc		Return status code
284  */
certfree_exec(int argc,char ** argv)285 static int certfree_exec ( int argc, char **argv ) {
286 
287 	return cert_exec ( argc, argv, &certfree_cmd );
288 }
289 
290 /** Certificate management commands */
291 struct command certmgmt_commands[] __command = {
292 	{
293 		.name = "certstat",
294 		.exec = certstat_exec,
295 	},
296 	{
297 		.name = "certstore",
298 		.exec = certstore_exec,
299 	},
300 	{
301 		.name = "certfree",
302 		.exec = certfree_exec,
303 	},
304 };
305