]>
Commit | Line | Data |
---|---|---|
a9522e16 AS |
1 | /** |
2 | * @file openac.c | |
7daf5226 | 3 | * |
a9522e16 | 4 | * @brief Generation of X.509 attribute certificates. |
7daf5226 | 5 | * |
a9522e16 AS |
6 | */ |
7 | ||
8 | /* | |
997358a6 | 9 | * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler |
a9522e16 AS |
10 | * Copyright (C) 2004,2007 Andreas Steffen |
11 | * Hochschule fuer Technik Rapperswil, Switzerland | |
997358a6 MW |
12 | * |
13 | * This program is free software; you can redistribute it and/or modify it | |
14 | * under the terms of the GNU General Public License as published by the | |
15 | * Free Software Foundation; either version 2 of the License, or (at your | |
16 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
17 | * | |
18 | * This program is distributed in the hope that it will be useful, but | |
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
20 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
21 | * for more details. | |
997358a6 MW |
22 | */ |
23 | ||
24 | #include <stdio.h> | |
25 | #include <stdlib.h> | |
26 | #include <string.h> | |
a9522e16 | 27 | #include <syslog.h> |
997358a6 MW |
28 | #include <unistd.h> |
29 | #include <getopt.h> | |
30 | #include <ctype.h> | |
31 | #include <time.h> | |
997358a6 | 32 | |
3d48f330 | 33 | #include <library.h> |
f05b4272 | 34 | #include <utils/debug.h> |
b4979ff7 | 35 | #include <asn1/asn1.h> |
bdec2e4f AS |
36 | #include <credentials/certificates/x509.h> |
37 | #include <credentials/certificates/ac.h> | |
e24aaddd | 38 | #include <credentials/keys/private_key.h> |
15177f57 | 39 | #include <credentials/sets/mem_cred.h> |
b4979ff7 | 40 | #include <utils/optionsfrom.h> |
997358a6 | 41 | |
68e92751 TB |
42 | #define OPENAC_PATH IPSEC_CONFDIR "/openac" |
43 | #define OPENAC_SERIAL IPSEC_CONFDIR "/openac/serial" | |
bdec2e4f AS |
44 | |
45 | #define DEFAULT_VALIDITY 24*3600 /* seconds */ | |
997358a6 | 46 | |
26c49478 AS |
47 | /** |
48 | * @brief prints the usage of the program to the stderr | |
49 | */ | |
50 | static void usage(const char *message) | |
997358a6 | 51 | { |
26c49478 | 52 | if (message != NULL && *message != '\0') |
241ab32c | 53 | { |
26c49478 | 54 | fprintf(stderr, "%s\n", message); |
241ab32c AS |
55 | } |
56 | fprintf(stderr, "Usage: openac" | |
57 | " [--help]" | |
58 | " [--version]" | |
59 | " [--optionsfrom <filename>]" | |
60 | " [--quiet]" | |
241ab32c | 61 | " \\\n\t" |
a9522e16 | 62 | " [--debug <level 0..4>]" |
241ab32c AS |
63 | " \\\n\t" |
64 | " [--days <days>]" | |
65 | " [--hours <hours>]" | |
66 | " \\\n\t" | |
67 | " [--startdate <YYYYMMDDHHMMSSZ>]" | |
68 | " [--enddate <YYYYMMDDHHMMSSZ>]" | |
69 | " \\\n\t" | |
70 | " --cert <certfile>" | |
71 | " --key <keyfile>" | |
72 | " [--password <password>]" | |
73 | " \\\n\t" | |
74 | " --usercert <certfile>" | |
75 | " --groups <attr1,attr2,..>" | |
76 | " --out <filename>" | |
77 | "\n" | |
78 | ); | |
997358a6 MW |
79 | } |
80 | ||
241ab32c | 81 | /** |
997358a6 MW |
82 | * read the last serial number from file |
83 | */ | |
241ab32c | 84 | static chunk_t read_serial(void) |
997358a6 | 85 | { |
d16fd64d MW |
86 | chunk_t hex, serial = chunk_empty; |
87 | char one[] = {0x01}; | |
88 | FILE *fd; | |
7daf5226 | 89 | |
d16fd64d | 90 | fd = fopen(OPENAC_SERIAL, "r"); |
241ab32c | 91 | if (fd) |
997358a6 | 92 | { |
d16fd64d MW |
93 | hex = chunk_alloca(64); |
94 | hex.len = fread(hex.ptr, 1, hex.len, fd); | |
95 | if (hex.len) | |
241ab32c | 96 | { |
afdaa9e5 AS |
97 | /* remove any terminating newline character */ |
98 | if (hex.ptr[hex.len-1] == '\n') | |
99 | { | |
100 | hex.len--; | |
101 | } | |
d16fd64d MW |
102 | serial = chunk_alloca((hex.len / 2) + (hex.len % 2)); |
103 | serial = chunk_from_hex(hex, serial.ptr); | |
241ab32c AS |
104 | } |
105 | fclose(fd); | |
997358a6 | 106 | } |
241ab32c AS |
107 | else |
108 | { | |
8b0e0910 TB |
109 | DBG1(DBG_LIB, " file '%s' does not exist yet - serial number " |
110 | "set to 01", OPENAC_SERIAL); | |
241ab32c | 111 | } |
d16fd64d MW |
112 | if (!serial.len) |
113 | { | |
114 | return chunk_clone(chunk_create(one, 1)); | |
115 | } | |
116 | if (chunk_increment(serial)) | |
117 | { /* overflow, prepend 0x01 */ | |
118 | return chunk_cat("cc", chunk_create(one, 1), serial); | |
119 | } | |
120 | return chunk_clone(serial); | |
997358a6 MW |
121 | } |
122 | ||
241ab32c | 123 | /** |
997358a6 MW |
124 | * write back the last serial number to file |
125 | */ | |
241ab32c | 126 | static void write_serial(chunk_t serial) |
997358a6 | 127 | { |
241ab32c AS |
128 | FILE *fd = fopen(OPENAC_SERIAL, "w"); |
129 | ||
130 | if (fd) | |
131 | { | |
36fecdb8 AS |
132 | chunk_t hex_serial; |
133 | ||
8b0e0910 | 134 | DBG1(DBG_LIB, " serial number is %#B", &serial); |
36fecdb8 | 135 | hex_serial = chunk_to_hex(serial, NULL, FALSE); |
47786557 | 136 | fprintf(fd, "%.*s\n", (int)hex_serial.len, hex_serial.ptr); |
241ab32c | 137 | fclose(fd); |
36fecdb8 | 138 | free(hex_serial.ptr); |
241ab32c AS |
139 | } |
140 | else | |
141 | { | |
8b0e0910 | 142 | DBG1(DBG_LIB, " could not open file '%s' for writing", OPENAC_SERIAL); |
241ab32c | 143 | } |
997358a6 MW |
144 | } |
145 | ||
bdec2e4f AS |
146 | /** |
147 | * global variables accessible by both main() and build.c | |
148 | */ | |
997358a6 | 149 | |
a9522e16 AS |
150 | static int debug_level = 1; |
151 | static bool stderr_quiet = FALSE; | |
b6072034 | 152 | |
a9522e16 AS |
153 | /** |
154 | * openac dbg function | |
155 | */ | |
613ceca9 | 156 | static void openac_dbg(debug_t group, level_t level, char *fmt, ...) |
a9522e16 AS |
157 | { |
158 | int priority = LOG_INFO; | |
815510e6 AS |
159 | char buffer[8192]; |
160 | char *current = buffer, *next; | |
a9522e16 | 161 | va_list args; |
7daf5226 | 162 | |
a9522e16 AS |
163 | if (level <= debug_level) |
164 | { | |
a9522e16 AS |
165 | if (!stderr_quiet) |
166 | { | |
51dfa7f5 | 167 | va_start(args, fmt); |
a9522e16 AS |
168 | vfprintf(stderr, fmt, args); |
169 | fprintf(stderr, "\n"); | |
51dfa7f5 | 170 | va_end(args); |
a9522e16 | 171 | } |
815510e6 AS |
172 | |
173 | /* write in memory buffer first */ | |
51dfa7f5 | 174 | va_start(args, fmt); |
815510e6 | 175 | vsnprintf(buffer, sizeof(buffer), fmt, args); |
a9522e16 | 176 | va_end(args); |
815510e6 AS |
177 | |
178 | /* do a syslog with every line */ | |
179 | while (current) | |
180 | { | |
181 | next = strchr(current, '\n'); | |
182 | if (next) | |
183 | { | |
184 | *(next++) = '\0'; | |
185 | } | |
186 | syslog(priority, "%s\n", current); | |
187 | current = next; | |
188 | } | |
a9522e16 AS |
189 | } |
190 | } | |
191 | ||
a9522e16 | 192 | /** |
b73595a3 | 193 | * @brief openac main program |
26c49478 AS |
194 | * |
195 | * @param argc number of arguments | |
196 | * @param argv pointer to the argument values | |
a9522e16 | 197 | */ |
241ab32c | 198 | int main(int argc, char **argv) |
997358a6 | 199 | { |
bdec2e4f | 200 | certificate_t *attr_cert = NULL; |
63cb8a7f AS |
201 | certificate_t *userCert = NULL; |
202 | certificate_t *signerCert = NULL; | |
203 | private_key_t *signerKey = NULL; | |
bdec2e4f AS |
204 | |
205 | time_t notBefore = UNDEFINED_TIME; | |
206 | time_t notAfter = UNDEFINED_TIME; | |
207 | time_t validity = 0; | |
208 | ||
241ab32c AS |
209 | char *keyfile = NULL; |
210 | char *certfile = NULL; | |
211 | char *usercertfile = NULL; | |
212 | char *outfile = NULL; | |
bdec2e4f | 213 | char *groups = ""; |
b4979ff7 | 214 | char buf[BUF_LEN]; |
997358a6 | 215 | |
b4979ff7 | 216 | chunk_t passphrase = { buf, 0 }; |
3d48f330 | 217 | chunk_t serial = chunk_empty; |
bdec2e4f | 218 | chunk_t attr_chunk = chunk_empty; |
997358a6 | 219 | |
a9522e16 | 220 | int status = 1; |
7daf5226 | 221 | |
324abae2 MW |
222 | /* enable openac debugging hook */ |
223 | dbg = openac_dbg; | |
997358a6 | 224 | |
b4979ff7 | 225 | passphrase.ptr[0] = '\0'; |
997358a6 | 226 | |
a9522e16 AS |
227 | openlog("openac", 0, LOG_AUTHPRIV); |
228 | ||
3d48f330 | 229 | /* initialize library */ |
8fb4edc4 | 230 | atexit(library_deinit); |
356b2b27 | 231 | if (!library_init(NULL)) |
2f5b1e0e | 232 | { |
2f5b1e0e AS |
233 | exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); |
234 | } | |
bde541ac AS |
235 | if (lib->integrity && |
236 | !lib->integrity->check_file(lib->integrity, "openac", argv[0])) | |
237 | { | |
238 | fprintf(stderr, "integrity check of openac failed\n"); | |
bde541ac AS |
239 | exit(SS_RC_DAEMON_INTEGRITY); |
240 | } | |
5b03a350 | 241 | if (!lib->plugins->load(lib->plugins, NULL, |
8fb4edc4 MW |
242 | lib->settings->get_str(lib->settings, "openac.load", PLUGINS))) |
243 | { | |
244 | exit(SS_RC_INITIALIZATION_FAILED); | |
245 | } | |
3d48f330 AS |
246 | |
247 | /* initialize optionsfrom */ | |
248 | options_t *options = options_create(); | |
249 | ||
241ab32c AS |
250 | /* handle arguments */ |
251 | for (;;) | |
252 | { | |
241ab32c AS |
253 | static const struct option long_opts[] = { |
254 | /* name, has_arg, flag, val */ | |
255 | { "help", no_argument, NULL, 'h' }, | |
256 | { "version", no_argument, NULL, 'v' }, | |
257 | { "optionsfrom", required_argument, NULL, '+' }, | |
258 | { "quiet", no_argument, NULL, 'q' }, | |
259 | { "cert", required_argument, NULL, 'c' }, | |
a9522e16 | 260 | { "key", required_argument, NULL, 'k' }, |
241ab32c AS |
261 | { "password", required_argument, NULL, 'p' }, |
262 | { "usercert", required_argument, NULL, 'u' }, | |
263 | { "groups", required_argument, NULL, 'g' }, | |
264 | { "days", required_argument, NULL, 'D' }, | |
265 | { "hours", required_argument, NULL, 'H' }, | |
266 | { "startdate", required_argument, NULL, 'S' }, | |
267 | { "enddate", required_argument, NULL, 'E' }, | |
268 | { "out", required_argument, NULL, 'o' }, | |
a9522e16 | 269 | { "debug", required_argument, NULL, 'd' }, |
241ab32c AS |
270 | { 0,0,0,0 } |
271 | }; | |
7daf5226 | 272 | |
a9522e16 | 273 | int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:d:", long_opts, NULL); |
241ab32c AS |
274 | |
275 | /* Note: "breaking" from case terminates loop */ | |
276 | switch (c) | |
277 | { | |
278 | case EOF: /* end of flags */ | |
279 | break; | |
280 | ||
281 | case 0: /* long option already handled */ | |
b9b8a98f | 282 | continue; |
241ab32c AS |
283 | |
284 | case ':': /* diagnostic already printed by getopt_long */ | |
285 | case '?': /* diagnostic already printed by getopt_long */ | |
241ab32c AS |
286 | case 'h': /* --help */ |
287 | usage(NULL); | |
a9522e16 AS |
288 | status = 1; |
289 | goto end; | |
241ab32c AS |
290 | |
291 | case 'v': /* --version */ | |
a9522e16 AS |
292 | printf("openac (strongSwan %s)\n", VERSION); |
293 | status = 0; | |
294 | goto end; | |
241ab32c AS |
295 | |
296 | case '+': /* --optionsfrom <filename> */ | |
297 | { | |
298 | char path[BUF_LEN]; | |
299 | ||
300 | if (*optarg == '/') /* absolute pathname */ | |
b4979ff7 | 301 | { |
323f9f99 | 302 | strncpy(path, optarg, BUF_LEN); |
68e92751 | 303 | path[BUF_LEN-1] = '\0'; |
b4979ff7 | 304 | } |
241ab32c | 305 | else /* relative pathname */ |
b4979ff7 | 306 | { |
323f9f99 | 307 | snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg); |
b4979ff7 | 308 | } |
7094e840 | 309 | if (!options->from(options, path, &argc, &argv, optind)) |
6a8e7381 | 310 | { |
99670c37 MW |
311 | status = 1; |
312 | goto end; | |
6a8e7381 | 313 | } |
b9b8a98f | 314 | } |
241ab32c AS |
315 | continue; |
316 | ||
317 | case 'q': /* --quiet */ | |
a9522e16 | 318 | stderr_quiet = TRUE; |
241ab32c AS |
319 | continue; |
320 | ||
321 | case 'c': /* --cert */ | |
322 | certfile = optarg; | |
323 | continue; | |
324 | ||
325 | case 'k': /* --key */ | |
326 | keyfile = optarg; | |
327 | continue; | |
328 | ||
329 | case 'p': /* --key */ | |
2bf1d44f | 330 | if (strlen(optarg) >= BUF_LEN) |
b4979ff7 AS |
331 | { |
332 | usage("passphrase too long"); | |
a9522e16 | 333 | goto end; |
b4979ff7 AS |
334 | } |
335 | strncpy(passphrase.ptr, optarg, BUF_LEN); | |
336 | passphrase.len = min(strlen(optarg), BUF_LEN); | |
241ab32c AS |
337 | continue; |
338 | ||
339 | case 'u': /* --usercert */ | |
340 | usercertfile = optarg; | |
341 | continue; | |
342 | ||
343 | case 'g': /* --groups */ | |
bdec2e4f | 344 | groups = optarg; |
241ab32c AS |
345 | continue; |
346 | ||
347 | case 'D': /* --days */ | |
348 | if (optarg == NULL || !isdigit(optarg[0])) | |
b4979ff7 | 349 | { |
241ab32c | 350 | usage("missing number of days"); |
a9522e16 | 351 | goto end; |
b4979ff7 AS |
352 | } |
353 | else | |
241ab32c AS |
354 | { |
355 | char *endptr; | |
356 | long days = strtol(optarg, &endptr, 0); | |
357 | ||
358 | if (*endptr != '\0' || endptr == optarg || days <= 0) | |
b4979ff7 | 359 | { |
241ab32c | 360 | usage("<days> must be a positive number"); |
a9522e16 | 361 | goto end; |
b4979ff7 | 362 | } |
241ab32c AS |
363 | validity += 24*3600*days; |
364 | } | |
365 | continue; | |
366 | ||
367 | case 'H': /* --hours */ | |
368 | if (optarg == NULL || !isdigit(optarg[0])) | |
b4979ff7 | 369 | { |
241ab32c | 370 | usage("missing number of hours"); |
a9522e16 | 371 | goto end; |
b4979ff7 AS |
372 | } |
373 | else | |
241ab32c AS |
374 | { |
375 | char *endptr; | |
376 | long hours = strtol(optarg, &endptr, 0); | |
377 | ||
378 | if (*endptr != '\0' || endptr == optarg || hours <= 0) | |
b4979ff7 | 379 | { |
241ab32c | 380 | usage("<hours> must be a positive number"); |
a9522e16 | 381 | goto end; |
b4979ff7 | 382 | } |
241ab32c AS |
383 | validity += 3600*hours; |
384 | } | |
385 | continue; | |
386 | ||
387 | case 'S': /* --startdate */ | |
388 | if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') | |
b4979ff7 | 389 | { |
241ab32c | 390 | usage("date format must be YYYYMMDDHHMMSSZ"); |
a9522e16 | 391 | goto end; |
b4979ff7 AS |
392 | } |
393 | else | |
241ab32c AS |
394 | { |
395 | chunk_t date = { optarg, 15 }; | |
b4979ff7 | 396 | |
d3d7e46b | 397 | notBefore = asn1_to_time(&date, ASN1_GENERALIZEDTIME); |
241ab32c AS |
398 | } |
399 | continue; | |
400 | ||
401 | case 'E': /* --enddate */ | |
402 | if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') | |
b4979ff7 | 403 | { |
241ab32c | 404 | usage("date format must be YYYYMMDDHHMMSSZ"); |
a9522e16 | 405 | goto end; |
b4979ff7 AS |
406 | } |
407 | else | |
241ab32c AS |
408 | { |
409 | chunk_t date = { optarg, 15 }; | |
d3d7e46b | 410 | notAfter = asn1_to_time(&date, ASN1_GENERALIZEDTIME); |
241ab32c AS |
411 | } |
412 | continue; | |
413 | ||
a9522e16 | 414 | case 'o': /* --out */ |
241ab32c AS |
415 | outfile = optarg; |
416 | continue; | |
997358a6 | 417 | |
a9522e16 AS |
418 | case 'd': /* --debug */ |
419 | debug_level = atoi(optarg); | |
241ab32c | 420 | continue; |
a9522e16 | 421 | |
241ab32c | 422 | default: |
b4979ff7 | 423 | usage(""); |
a9522e16 AS |
424 | status = 0; |
425 | goto end; | |
241ab32c | 426 | } |
26c49478 | 427 | /* break from loop */ |
241ab32c | 428 | break; |
997358a6 | 429 | } |
997358a6 | 430 | |
241ab32c | 431 | if (optind != argc) |
b4979ff7 | 432 | { |
241ab32c | 433 | usage("unexpected argument"); |
a9522e16 | 434 | goto end; |
b4979ff7 | 435 | } |
997358a6 | 436 | |
8b0e0910 | 437 | DBG1(DBG_LIB, "starting openac (strongSwan Version %s)", VERSION); |
a9522e16 | 438 | |
241ab32c AS |
439 | /* load the signer's RSA private key */ |
440 | if (keyfile != NULL) | |
441 | { | |
15177f57 MW |
442 | mem_cred_t *mem; |
443 | shared_key_t *shared; | |
444 | ||
445 | mem = mem_cred_create(); | |
446 | lib->credmgr->add_set(lib->credmgr, &mem->set); | |
447 | shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, | |
448 | chunk_clone(passphrase)); | |
449 | mem->add_shared(mem, shared, NULL); | |
28046992 MW |
450 | signerKey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, |
451 | BUILD_FROM_FILE, keyfile, | |
28046992 | 452 | BUILD_END); |
15177f57 MW |
453 | lib->credmgr->remove_set(lib->credmgr, &mem->set); |
454 | mem->destroy(mem); | |
63cb8a7f | 455 | if (signerKey == NULL) |
241ab32c | 456 | { |
a9522e16 | 457 | goto end; |
241ab32c | 458 | } |
8b0e0910 | 459 | DBG1(DBG_LIB, " loaded private key file '%s'", keyfile); |
241ab32c | 460 | } |
997358a6 | 461 | |
241ab32c AS |
462 | /* load the signer's X.509 certificate */ |
463 | if (certfile != NULL) | |
464 | { | |
26930a8c AS |
465 | signerCert = lib->creds->create(lib->creds, |
466 | CRED_CERTIFICATE, CERT_X509, | |
467 | BUILD_FROM_FILE, certfile, | |
26930a8c AS |
468 | BUILD_END); |
469 | if (signerCert == NULL) | |
b4979ff7 | 470 | { |
a9522e16 | 471 | goto end; |
b4979ff7 | 472 | } |
241ab32c | 473 | } |
997358a6 | 474 | |
241ab32c AS |
475 | /* load the users's X.509 certificate */ |
476 | if (usercertfile != NULL) | |
997358a6 | 477 | { |
26930a8c AS |
478 | userCert = lib->creds->create(lib->creds, |
479 | CRED_CERTIFICATE, CERT_X509, | |
480 | BUILD_FROM_FILE, usercertfile, | |
26930a8c AS |
481 | BUILD_END); |
482 | if (userCert == NULL) | |
b4979ff7 | 483 | { |
a9522e16 | 484 | goto end; |
b4979ff7 | 485 | } |
997358a6 | 486 | } |
241ab32c AS |
487 | |
488 | /* compute validity interval */ | |
bdec2e4f | 489 | validity = (validity)? validity : DEFAULT_VALIDITY; |
a9522e16 AS |
490 | notBefore = (notBefore == UNDEFINED_TIME) ? time(NULL) : notBefore; |
491 | notAfter = (notAfter == UNDEFINED_TIME) ? time(NULL) + validity : notAfter; | |
241ab32c AS |
492 | |
493 | /* build and parse attribute certificate */ | |
81b598ca TB |
494 | if (userCert != NULL && signerCert != NULL && signerKey != NULL && |
495 | outfile != NULL) | |
241ab32c AS |
496 | { |
497 | /* read the serial number and increment it by one */ | |
498 | serial = read_serial(); | |
499 | ||
bdec2e4f | 500 | attr_cert = lib->creds->create(lib->creds, |
63cb8a7f | 501 | CRED_CERTIFICATE, CERT_X509_AC, |
46eb4164 | 502 | BUILD_CERT, userCert, |
63cb8a7f AS |
503 | BUILD_NOT_BEFORE_TIME, notBefore, |
504 | BUILD_NOT_AFTER_TIME, notAfter, | |
505 | BUILD_SERIAL, serial, | |
506 | BUILD_IETF_GROUP_ATTR, groups, | |
46eb4164 MW |
507 | BUILD_SIGNING_CERT, signerCert, |
508 | BUILD_SIGNING_KEY, signerKey, | |
63cb8a7f | 509 | BUILD_END); |
3d48f330 AS |
510 | if (!attr_cert) |
511 | { | |
3d48f330 AS |
512 | goto end; |
513 | } | |
7daf5226 | 514 | |
241ab32c | 515 | /* write the attribute certificate to file */ |
0406eeaa | 516 | if (attr_cert->get_encoding(attr_cert, CERT_ASN1_DER, &attr_chunk)) |
b4979ff7 | 517 | { |
0406eeaa MW |
518 | if (chunk_write(attr_chunk, outfile, "attribute cert", 0022, TRUE)) |
519 | { | |
520 | write_serial(serial); | |
521 | status = 0; | |
522 | } | |
b4979ff7 | 523 | } |
241ab32c | 524 | } |
3d48f330 AS |
525 | else |
526 | { | |
81b598ca | 527 | usage("some of the mandatory parameters --usercert --cert --key --out " |
3d48f330 AS |
528 | "are missing"); |
529 | } | |
241ab32c | 530 | |
a9522e16 | 531 | end: |
b4979ff7 | 532 | /* delete all dynamically allocated objects */ |
63cb8a7f AS |
533 | DESTROY_IF(signerKey); |
534 | DESTROY_IF(signerCert); | |
535 | DESTROY_IF(userCert); | |
93da2684 | 536 | DESTROY_IF(attr_cert); |
bdec2e4f | 537 | free(attr_chunk.ptr); |
b4979ff7 | 538 | free(serial.ptr); |
a9522e16 | 539 | closelog(); |
324abae2 | 540 | dbg = dbg_default; |
7094e840 | 541 | options->destroy(options); |
a9522e16 | 542 | exit(status); |
997358a6 | 543 | } |