4 * @brief Generation of X.509 attribute certificates.
9 * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
10 * Copyright (C) 2004,2007 Andreas Steffen
11 * Hochschule fuer Technik Rapperswil, Switzerland
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>.
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
37 #include <asn1/asn1.h>
38 #include <asn1/ttodata.h>
39 #include <crypto/ac.h>
40 #include <crypto/ietf_attr_list.h>
41 #include <utils/optionsfrom.h>
44 #include <fips/fips.h>
45 #include <fips_signature.h>
46 #endif /* INTEGRITY_TEST */
50 #define OPENAC_PATH IPSEC_CONFDIR "/openac"
51 #define OPENAC_SERIAL IPSEC_CONFDIR "/openac/serial"
54 * @brief prints the usage of the program to the stderr
56 static void usage(const char *message
)
58 if (message
!= NULL
&& *message
!= '\0')
60 fprintf(stderr
, "%s\n", message
);
62 fprintf(stderr
, "Usage: openac"
65 " [--optionsfrom <filename>]"
68 " [--debug <level 0..4>]"
73 " [--startdate <YYYYMMDDHHMMSSZ>]"
74 " [--enddate <YYYYMMDDHHMMSSZ>]"
78 " [--password <password>]"
80 " --usercert <certfile>"
81 " --groups <attr1,attr2,..>"
89 * convert a chunk into a multi-precision integer
91 static void chunk_to_mpz(chunk_t chunk
, mpz_t number
)
93 mpz_import(number
, chunk
.len
, 1, 1, 1, 0, chunk
.ptr
);
97 * convert a multi-precision integer into a chunk
99 static chunk_t
mpz_to_chunk(mpz_t number
)
103 chunk
.len
= 1 + mpz_sizeinbase(number
, 2)/BITS_PER_BYTE
;
104 chunk
.ptr
= mpz_export(NULL
, NULL
, 1, chunk
.len
, 1, 0, number
);
109 * read the last serial number from file
111 static chunk_t
read_serial(void)
115 char buf
[BUF_LEN
], buf1
[BUF_LEN
];
116 chunk_t last_serial
= { buf1
, BUF_LEN
};
119 FILE *fd
= fopen(OPENAC_SERIAL
, "r");
121 /* last serial number defaults to 0 */
122 *last_serial
.ptr
= 0x00;
127 if (fscanf(fd
, "%s", buf
))
129 err_t ugh
= ttodata(buf
, 0, 16, last_serial
.ptr
, BUF_LEN
, &last_serial
.len
);
133 DBG1(" error reading serial number from %s: %s",
141 DBG1(" file '%s' does not exist yet - serial number set to 01", OPENAC_SERIAL
);
145 * conversion of read serial number to a multiprecision integer
146 * and incrementing it by one
147 * and representing it as a two's complement octet string
150 chunk_to_mpz(last_serial
, number
);
151 mpz_add_ui(number
, number
, 0x01);
152 serial
= mpz_to_chunk(number
);
159 * write back the last serial number to file
161 static void write_serial(chunk_t serial
)
163 FILE *fd
= fopen(OPENAC_SERIAL
, "w");
167 DBG1(" serial number is %#B", &serial
);
168 fprintf(fd
, "%#B\n", &serial
);
173 DBG1(" could not open file '%s' for writing", OPENAC_SERIAL
);
178 * global variables accessible by both main() and build.c
180 x509_t
*usercert
= NULL
;
181 x509_t
*signercert
= NULL
;
183 linked_list_t
*groups
= NULL
;
184 rsa_private_key_t
*signerkey
= NULL
;
186 time_t notBefore
= UNDEFINED_TIME
;
187 time_t notAfter
= UNDEFINED_TIME
;
191 static int debug_level
= 1;
192 static bool stderr_quiet
= FALSE
;
195 * openac dbg function
197 static void openac_dbg(int level
, char *fmt
, ...)
199 int priority
= LOG_INFO
;
202 if (level
<= debug_level
)
207 vfprintf(stderr
, fmt
, args
);
208 fprintf(stderr
, "\n");
210 vsyslog(priority
, fmt
, args
);
216 * @brief openac main program
218 * @param argc number of arguments
219 * @param argv pointer to the argument values
221 int main(int argc
, char **argv
)
223 char *keyfile
= NULL
;
224 char *certfile
= NULL
;
225 char *usercertfile
= NULL
;
226 char *outfile
= NULL
;
229 chunk_t passphrase
= { buf
, 0 };
230 chunk_t attr_cert
= chunk_empty
;
233 const time_t default_validity
= 24*3600; /* 24 hours */
237 /* enable openac debugging hook */
240 passphrase
.ptr
[0] = '\0';
241 groups
= linked_list_create();
243 openlog("openac", 0, LOG_AUTHPRIV
);
245 /* handle arguments */
248 static const struct option long_opts
[] = {
249 /* name, has_arg, flag, val */
250 { "help", no_argument
, NULL
, 'h' },
251 { "version", no_argument
, NULL
, 'v' },
252 { "optionsfrom", required_argument
, NULL
, '+' },
253 { "quiet", no_argument
, NULL
, 'q' },
254 { "cert", required_argument
, NULL
, 'c' },
255 { "key", required_argument
, NULL
, 'k' },
256 { "password", required_argument
, NULL
, 'p' },
257 { "usercert", required_argument
, NULL
, 'u' },
258 { "groups", required_argument
, NULL
, 'g' },
259 { "days", required_argument
, NULL
, 'D' },
260 { "hours", required_argument
, NULL
, 'H' },
261 { "startdate", required_argument
, NULL
, 'S' },
262 { "enddate", required_argument
, NULL
, 'E' },
263 { "out", required_argument
, NULL
, 'o' },
264 { "debug", required_argument
, NULL
, 'd' },
268 int c
= getopt_long(argc
, argv
, "hv+:qc:k:p;u:g:D:H:S:E:o:d:", long_opts
, NULL
);
270 /* Note: "breaking" from case terminates loop */
273 case EOF
: /* end of flags */
276 case 0: /* long option already handled */
279 case ':': /* diagnostic already printed by getopt_long */
280 case '?': /* diagnostic already printed by getopt_long */
281 case 'h': /* --help */
286 case 'v': /* --version */
287 printf("openac (strongSwan %s)\n", VERSION
);
291 case '+': /* --optionsfrom <filename> */
295 if (*optarg
== '/') /* absolute pathname */
297 strncpy(path
, optarg
, BUF_LEN
);
299 else /* relative pathname */
301 snprintf(path
, BUF_LEN
, "%s/%s", OPENAC_PATH
, optarg
);
303 if (!optionsfrom(path
, &argc
, &argv
, optind
))
311 case 'q': /* --quiet */
315 case 'c': /* --cert */
319 case 'k': /* --key */
323 case 'p': /* --key */
324 if (strlen(optarg
) > BUF_LEN
)
326 usage("passphrase too long");
329 strncpy(passphrase
.ptr
, optarg
, BUF_LEN
);
330 passphrase
.len
= min(strlen(optarg
), BUF_LEN
);
333 case 'u': /* --usercert */
334 usercertfile
= optarg
;
337 case 'g': /* --groups */
338 ietfAttr_list_create_from_string(optarg
, groups
);
341 case 'D': /* --days */
342 if (optarg
== NULL
|| !isdigit(optarg
[0]))
344 usage("missing number of days");
350 long days
= strtol(optarg
, &endptr
, 0);
352 if (*endptr
!= '\0' || endptr
== optarg
|| days
<= 0)
354 usage("<days> must be a positive number");
357 validity
+= 24*3600*days
;
361 case 'H': /* --hours */
362 if (optarg
== NULL
|| !isdigit(optarg
[0]))
364 usage("missing number of hours");
370 long hours
= strtol(optarg
, &endptr
, 0);
372 if (*endptr
!= '\0' || endptr
== optarg
|| hours
<= 0)
374 usage("<hours> must be a positive number");
377 validity
+= 3600*hours
;
381 case 'S': /* --startdate */
382 if (optarg
== NULL
|| strlen(optarg
) != 15 || optarg
[14] != 'Z')
384 usage("date format must be YYYYMMDDHHMMSSZ");
389 chunk_t date
= { optarg
, 15 };
391 notBefore
= asn1totime(&date
, ASN1_GENERALIZEDTIME
);
395 case 'E': /* --enddate */
396 if (optarg
== NULL
|| strlen(optarg
) != 15 || optarg
[14] != 'Z')
398 usage("date format must be YYYYMMDDHHMMSSZ");
403 chunk_t date
= { optarg
, 15 };
404 notAfter
= asn1totime(&date
, ASN1_GENERALIZEDTIME
);
408 case 'o': /* --out */
412 case 'd': /* --debug */
413 debug_level
= atoi(optarg
);
421 /* break from loop */
427 usage("unexpected argument");
431 DBG1("starting openac (strongSwan Version %s)", VERSION
);
433 #ifdef INTEGRITY_TEST
434 DBG1("integrity test of libstrongswan code");
435 if (fips_verify_hmac_signature(hmac_key
, hmac_signature
))
437 DBG1(" integrity test passed");
441 DBG1(" integrity test failed");
445 #endif /* INTEGRITY_TEST */
447 /* load the signer's RSA private key */
450 signerkey
= rsa_private_key_create_from_file(keyfile
, &passphrase
);
452 if (signerkey
== NULL
)
458 /* load the signer's X.509 certificate */
459 if (certfile
!= NULL
)
461 signercert
= x509_create_from_file(certfile
, "signer cert");
463 if (signercert
== NULL
)
469 /* load the users's X.509 certificate */
470 if (usercertfile
!= NULL
)
472 usercert
= x509_create_from_file(usercertfile
, "user cert");
474 if (usercert
== NULL
)
480 /* compute validity interval */
481 validity
= (validity
)? validity
: default_validity
;
482 notBefore
= (notBefore
== UNDEFINED_TIME
) ?
time(NULL
) : notBefore
;
483 notAfter
= (notAfter
== UNDEFINED_TIME
) ?
time(NULL
) + validity
: notAfter
;
485 /* build and parse attribute certificate */
486 if (usercert
!= NULL
&& signercert
!= NULL
&& signerkey
!= NULL
)
488 /* read the serial number and increment it by one */
489 serial
= read_serial();
491 attr_cert
= build_attr_cert();
492 ac
= x509ac_create_from_chunk(attr_cert
);
494 /* write the attribute certificate to file */
495 if (chunk_write(attr_cert
, outfile
, "attribute cert", 0022, TRUE
))
497 write_serial(serial
);
503 /* delete all dynamically allocated objects */
504 DESTROY_IF(signerkey
);
505 DESTROY_IF(signercert
);
506 DESTROY_IF(usercert
);
508 ietfAttr_list_destroy(groups
);