Annotation of embedaddon/strongswan/src/scepclient/scepclient.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012 Tobias Brunner
3: * Copyright (C) 2005 Jan Hutter, Martin Willi
4: * HSR Hochschule fuer Technik Rapperswil
5: *
6: * This program is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2 of the License, or (at your
9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10: *
11: * This program is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14: * for more details.
15: */
16:
17: #include <stdarg.h>
18: #include <stdio.h>
19: #include <stdlib.h>
20: #include <string.h>
21: #include <getopt.h>
22: #include <ctype.h>
23: #include <unistd.h>
24: #include <time.h>
25: #include <limits.h>
26: #include <syslog.h>
27: #include <errno.h>
28:
29: #include <library.h>
30: #include <utils/debug.h>
31: #include <asn1/asn1.h>
32: #include <asn1/oid.h>
33: #include <utils/optionsfrom.h>
34: #include <collections/enumerator.h>
35: #include <collections/linked_list.h>
36: #include <crypto/hashers/hasher.h>
37: #include <crypto/crypters/crypter.h>
38: #include <crypto/proposal/proposal_keywords.h>
39: #include <credentials/keys/private_key.h>
40: #include <credentials/keys/public_key.h>
41: #include <credentials/certificates/certificate.h>
42: #include <credentials/certificates/x509.h>
43: #include <credentials/certificates/pkcs10.h>
44: #include <credentials/sets/mem_cred.h>
45: #include <plugins/plugin.h>
46:
47: #include "scep.h"
48:
49: /*
50: * definition of some defaults
51: */
52:
53: /* some paths */
54: #define REQ_PATH IPSEC_CONFDIR "/ipsec.d/reqs"
55: #define HOST_CERT_PATH IPSEC_CONFDIR "/ipsec.d/certs"
56: #define CA_CERT_PATH IPSEC_CONFDIR "/ipsec.d/cacerts"
57: #define PRIVATE_KEY_PATH IPSEC_CONFDIR "/ipsec.d/private"
58:
59: /* default name of DER-encoded PKCS#1 private key file */
60: #define DEFAULT_FILENAME_PKCS1 "myKey.der"
61:
62: /* default name of DER-encoded PKCS#10 certificate request file */
63: #define DEFAULT_FILENAME_PKCS10 "myReq.der"
64:
65: /* default name of DER-encoded PKCS#7 file */
66: #define DEFAULT_FILENAME_PKCS7 "pkcs7.der"
67:
68: /* default name of DER-encoded self-signed X.509 certificate file */
69: #define DEFAULT_FILENAME_CERT_SELF "selfCert.der"
70:
71: /* default name of DER-encoded X.509 certificate file */
72: #define DEFAULT_FILENAME_CERT "myCert.der"
73:
74: /* default name of DER-encoded CA cert file used for key encipherment */
75: #define DEFAULT_FILENAME_CACERT_ENC "caCert.der"
76:
77: /* default name of the der encoded CA cert file used for signature verification */
78: #define DEFAULT_FILENAME_CACERT_SIG "caCert.der"
79:
80: /* default prefix of the der encoded CA certificates received from the SCEP server */
81: #define DEFAULT_FILENAME_PREFIX_CACERT "caCert.der"
82:
83: /* default certificate validity */
84: #define DEFAULT_CERT_VALIDITY 5 * 3600 * 24 * 365 /* seconds */
85:
86: /* default polling time interval in SCEP manual mode */
87: #define DEFAULT_POLL_INTERVAL 20 /* seconds */
88:
89: /* default key length for self-generated RSA keys */
90: #define DEFAULT_RSA_KEY_LENGTH 2048 /* bits */
91:
92: /* default distinguished name */
93: #define DEFAULT_DN "C=CH, O=Linux strongSwan, CN="
94:
95: /* minimum RSA key size */
96: #define RSA_MIN_OCTETS (512 / BITS_PER_BYTE)
97:
98: /* challenge password buffer size */
99: #define MAX_PASSWORD_LENGTH 256
100:
101: /* Max length of filename for tempfile */
102: #define MAX_TEMP_FILENAME_LENGTH 256
103:
104:
105: /* current scepclient version */
106: static const char *scepclient_version = "1.0";
107:
108: /* by default the CRL policy is lenient */
109: bool strict_crl_policy = FALSE;
110:
111: /* by default pluto does not check crls dynamically */
112: long crl_check_interval = 0;
113:
114: /* by default pluto logs out after every smartcard use */
115: bool pkcs11_keep_state = FALSE;
116:
117: /* by default HTTP fetch timeout is 30s */
118: static u_int http_timeout = 30;
119:
120: /* address to bind for HTTP fetches */
121: static char* http_bind = NULL;
122:
123: /* options read by optionsfrom */
124: options_t *options;
125:
126: /*
127: * Global variables
128: */
129: chunk_t pkcs1;
130: chunk_t pkcs7;
131: chunk_t challengePassword;
132: chunk_t serialNumber;
133: chunk_t transID;
134: chunk_t fingerprint;
135: chunk_t encoding;
136: chunk_t pkcs10_encoding;
137: chunk_t issuerAndSubject;
138: chunk_t getCertInitial;
139: chunk_t scep_response;
140:
141: linked_list_t *subjectAltNames;
142:
143: identification_t *subject = NULL;
144: private_key_t *private_key = NULL;
145: public_key_t *public_key = NULL;
146: certificate_t *x509_signer = NULL;
147: certificate_t *x509_ca_enc = NULL;
148: certificate_t *x509_ca_sig = NULL;
149: certificate_t *pkcs10_req = NULL;
150:
151: mem_cred_t *creds = NULL;
152:
153: /* logging */
154: static bool log_to_stderr = TRUE;
155: static bool log_to_syslog = TRUE;
156: static level_t default_loglevel = 1;
157:
158: /**
159: * logging function for scepclient
160: */
161: static void scepclient_dbg(debug_t group, level_t level, char *fmt, ...)
162: {
163: char buffer[8192];
164: char *current = buffer, *next;
165: va_list args;
166:
167: if (level <= default_loglevel)
168: {
169: if (log_to_stderr)
170: {
171: va_start(args, fmt);
172: vfprintf(stderr, fmt, args);
173: va_end(args);
174: fprintf(stderr, "\n");
175: }
176: if (log_to_syslog)
177: {
178: /* write in memory buffer first */
179: va_start(args, fmt);
180: vsnprintf(buffer, sizeof(buffer), fmt, args);
181: va_end(args);
182:
183: /* do a syslog with every line */
184: while (current)
185: {
186: next = strchr(current, '\n');
187: if (next)
188: {
189: *(next++) = '\0';
190: }
191: syslog(LOG_INFO, "%s\n", current);
192: current = next;
193: }
194: }
195: }
196: }
197:
198: /**
199: * Initialize logging to stderr/syslog
200: */
201: static void init_log(const char *program)
202: {
203: dbg = scepclient_dbg;
204:
205: if (log_to_stderr)
206: {
207: setbuf(stderr, NULL);
208: }
209: if (log_to_syslog)
210: {
211: openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
212: }
213: }
214:
215: /**
216: * join two paths if filename is not absolute
217: */
218: static void join_paths(char *target, size_t target_size, char *parent,
219: char *filename)
220: {
221: if (*filename == '/' || *filename == '.')
222: {
223: snprintf(target, target_size, "%s", filename);
224: }
225: else
226: {
227: snprintf(target, target_size, "%s/%s", parent, filename);
228: }
229: }
230:
231: /**
232: * add a suffix to a given filename, properly handling extensions like '.der'
233: */
234: static void add_path_suffix(char *target, size_t target_size, char *filename,
235: char *suffix_fmt, ...)
236: {
237: char suffix[PATH_MAX], *start, *dot;
238: va_list args;
239:
240: va_start(args, suffix_fmt);
241: vsnprintf(suffix, sizeof(suffix), suffix_fmt, args);
242: va_end(args);
243:
244: start = strrchr(filename, '/');
245: start = start ?: filename;
246: dot = strrchr(start, '.');
247:
248: if (!dot || dot == start || dot[1] == '\0')
249: { /* no extension add suffix at the end */
250: snprintf(target, target_size, "%s%s", filename, suffix);
251: }
252: else
253: { /* add the suffix between the filename and the extension */
254: snprintf(target, target_size, "%.*s%s%s", (int)(dot - filename),
255: filename, suffix, dot);
256: }
257: }
258:
259: /**
260: * @brief exit scepclient
261: *
262: * @param status 0 = OK, 1 = general discomfort
263: */
264: static void exit_scepclient(err_t message, ...)
265: {
266: int status = 0;
267:
268: if (creds)
269: {
270: lib->credmgr->remove_set(lib->credmgr, &creds->set);
271: creds->destroy(creds);
272: }
273:
274: DESTROY_IF(subject);
275: DESTROY_IF(private_key);
276: DESTROY_IF(public_key);
277: DESTROY_IF(x509_signer);
278: DESTROY_IF(x509_ca_enc);
279: DESTROY_IF(x509_ca_sig);
280: DESTROY_IF(pkcs10_req);
281: subjectAltNames->destroy_offset(subjectAltNames,
282: offsetof(identification_t, destroy));
283: free(pkcs1.ptr);
284: free(pkcs7.ptr);
285: free(serialNumber.ptr);
286: free(transID.ptr);
287: free(fingerprint.ptr);
288: free(encoding.ptr);
289: free(pkcs10_encoding.ptr);
290: free(issuerAndSubject.ptr);
291: free(getCertInitial.ptr);
292: free(scep_response.ptr);
293: options->destroy(options);
294:
295: /* print any error message to stderr */
296: if (message != NULL && *message != '\0')
297: {
298: va_list args;
299: char m[8192];
300:
301: va_start(args, message);
302: vsnprintf(m, sizeof(m), message, args);
303: va_end(args);
304:
305: fprintf(stderr, "error: %s\n", m);
306: status = -1;
307: }
308: library_deinit();
309: exit(status);
310: }
311:
312: /**
313: * @brief prints the program version and exits
314: *
315: */
316: static void version(void)
317: {
318: printf("scepclient %s\n", scepclient_version);
319: exit_scepclient(NULL);
320: }
321:
322: /**
323: * @brief prints the usage of the program to the stderr output
324: *
325: * If message is set, program is exited with 1 (error)
326: * @param message message in case of an error
327: */
328: static void usage(const char *message)
329: {
330: fprintf(stderr,
331: "Usage: scepclient\n"
332: " --help (-h) show usage and exit\n"
333: " --version (-v) show version and exit\n"
334: " --quiet (-q) do not write log output to stderr\n"
335: " --in (-i) <type>[=<filename>] use <filename> of <type> for input\n"
336: " <type> = pkcs1 | pkcs10 | cert-self\n"
337: " cacert-enc | cacert-sig\n"
338: " - if no pkcs1 input is defined, an RSA\n"
339: " key will be generated\n"
340: " - if no pkcs10 input is defined, a\n"
341: " PKCS#10 request will be generated\n"
342: " - if no cert-self input is defined, a\n"
343: " self-signed certificate will be generated\n"
344: " - if no filename is given, default is used\n"
345: " --out (-o) <type>[=<filename>] write output of <type> to <filename>\n"
346: " multiple outputs are allowed\n"
347: " <type> = pkcs1 | pkcs10 | pkcs7 | cert-self |\n"
348: " cert | cacert\n"
349: " - type cacert defines filename prefix of\n"
350: " received CA certificate(s)\n"
351: " - if no filename is given, default is used\n"
352: " --optionsfrom (-+) <filename> reads additional options from given file\n"
353: " --force (-f) force existing file(s)\n"
354: " --httptimeout (-T) timeout for HTTP operations (default: 30s)\n"
355: " --bind (-b) source address to bind for HTTP operations\n"
356: "\n"
357: "Options for key generation (pkcs1):\n"
358: " --keylength (-k) <bits> key length for RSA key generation\n"
359: " (default: 2048 bits)\n"
360: "\n"
361: "Options for validity:\n"
362: " --days (-D) <days> validity in days\n"
363: " --startdate (-S) <YYMMDDHHMMSS>Z not valid before date\n"
364: " --enddate (-E) <YYMMDDHHMMSS>Z not valid after date\n"
365: "\n"
366: "Options for request generation (pkcs10):\n"
367: " --dn (-d) <dn> comma separated list of distinguished names\n"
368: " --subjectAltName (-s) <t>=<v> include subjectAltName in certificate request\n"
369: " <t> = email | dns | ip \n"
370: " --password (-p) <pw> challenge password\n"
371: " - use '%%prompt' as pw for a password prompt\n"
372: " --algorithm (-a) [<type>=]<algo> algorithm to be used for PKCS#7 encryption,\n"
373: " PKCS#7 digest or PKCS#10 signature\n"
374: " <type> = enc | dgst | sig\n"
375: " - if no type is given enc is assumed\n"
376: " <algo> = des (default) | 3des | aes128 |\n"
377: " aes192 | aes256 | camellia128 |\n"
378: " camellia192 | camellia256\n"
379: " <algo> = md5 (default) | sha1 | sha256 |\n"
380: " sha384 | sha512\n"
381: "\n"
382: "Options for CA certificate acquisition:\n"
383: " --caname (-c) <name> name of CA to fetch CA certificate(s)\n"
384: " (default: CAIdentifier)\n"
385: "Options for enrollment (cert):\n"
386: " --url (-u) <url> url of the SCEP server\n"
387: " --method (-m) post | get http request type\n"
388: " --interval (-t) <seconds> poll interval in seconds (default 20s)\n"
389: " --maxpolltime (-x) <seconds> max poll time in seconds when in manual mode\n"
390: " (default: unlimited)\n"
391: "\n"
392: "Debugging output:\n"
393: " --debug (-l) <level> changes the log level (-1..4, default: 1)\n"
394: );
395: exit_scepclient(message);
396: }
397:
398: /**
399: * @brief main of scepclient
400: *
401: * @param argc number of arguments
402: * @param argv pointer to the argument values
403: */
404: int main(int argc, char **argv)
405: {
406: /* external values */
407: extern char * optarg;
408: extern int optind;
409:
410: /* type of input and output files */
411: typedef enum {
412: PKCS1 = 0x01,
413: PKCS10 = 0x02,
414: PKCS7 = 0x04,
415: CERT_SELF = 0x08,
416: CERT = 0x10,
417: CACERT_ENC = 0x20,
418: CACERT_SIG = 0x40,
419: } scep_filetype_t;
420:
421: /* filetype to read from, defaults to "generate a key" */
422: scep_filetype_t filetype_in = 0;
423:
424: /* filetype to write to, no default here */
425: scep_filetype_t filetype_out = 0;
426:
427: /* input files */
428: char *file_in_pkcs1 = DEFAULT_FILENAME_PKCS1;
429: char *file_in_pkcs10 = DEFAULT_FILENAME_PKCS10;
430: char *file_in_cert_self = DEFAULT_FILENAME_CERT_SELF;
431: char *file_in_cacert_enc = DEFAULT_FILENAME_CACERT_ENC;
432: char *file_in_cacert_sig = DEFAULT_FILENAME_CACERT_SIG;
433:
434: /* output files */
435: char *file_out_pkcs1 = DEFAULT_FILENAME_PKCS1;
436: char *file_out_pkcs10 = DEFAULT_FILENAME_PKCS10;
437: char *file_out_pkcs7 = DEFAULT_FILENAME_PKCS7;
438: char *file_out_cert_self = DEFAULT_FILENAME_CERT_SELF;
439: char *file_out_cert = DEFAULT_FILENAME_CERT;
440: char *file_out_ca_cert = DEFAULT_FILENAME_CACERT_ENC;
441:
442: /* by default user certificate is requested */
443: bool request_ca_certificate = FALSE;
444:
445: /* by default existing files are not overwritten */
446: bool force = FALSE;
447:
448: /* length of RSA key in bits */
449: u_int rsa_keylength = DEFAULT_RSA_KEY_LENGTH;
450:
451: /* validity of self-signed certificate */
452: time_t validity = DEFAULT_CERT_VALIDITY;
453: time_t notBefore = 0;
454: time_t notAfter = 0;
455:
456: /* distinguished name for requested certificate, ASCII format */
457: char *distinguishedName = NULL;
458: char default_distinguished_name[BUF_LEN];
459:
460: /* challenge password */
461: char challenge_password_buffer[MAX_PASSWORD_LENGTH];
462:
463: /* symmetric encryption algorithm used by pkcs7, default is DES */
464: encryption_algorithm_t pkcs7_symmetric_cipher = ENCR_DES;
465: size_t pkcs7_key_size = 0;
466:
467: /* digest algorithm used by pkcs7, default is MD5 */
468: hash_algorithm_t pkcs7_digest_alg = HASH_MD5;
469:
470: /* signature algorithm used by pkcs10, default is MD5 */
471: hash_algorithm_t pkcs10_signature_alg = HASH_MD5;
472:
473: /* URL of the SCEP-Server */
474: char *scep_url = NULL;
475:
476: /* Name of CA to fetch CA certs for */
477: char *ca_name = "CAIdentifier";
478:
479: /* http request method, default is GET */
480: bool http_get_request = TRUE;
481:
482: /* poll interval time in manual mode in seconds */
483: u_int poll_interval = DEFAULT_POLL_INTERVAL;
484:
485: /* maximum poll time */
486: u_int max_poll_time = 0;
487:
488: err_t ugh = NULL;
489:
490: /* initialize library */
491: if (!library_init(NULL, "scepclient"))
492: {
493: library_deinit();
494: exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
495: }
496: if (lib->integrity &&
497: !lib->integrity->check_file(lib->integrity, "scepclient", argv[0]))
498: {
499: fprintf(stderr, "integrity check of scepclient failed\n");
500: library_deinit();
501: exit(SS_RC_DAEMON_INTEGRITY);
502: }
503:
504: /* initialize global variables */
505: pkcs1 = chunk_empty;
506: pkcs7 = chunk_empty;
507: serialNumber = chunk_empty;
508: transID = chunk_empty;
509: fingerprint = chunk_empty;
510: encoding = chunk_empty;
511: pkcs10_encoding = chunk_empty;
512: issuerAndSubject = chunk_empty;
513: challengePassword = chunk_empty;
514: getCertInitial = chunk_empty;
515: scep_response = chunk_empty;
516: subjectAltNames = linked_list_create();
517: options = options_create();
518:
519: for (;;)
520: {
521: static const struct option long_opts[] = {
522: /* name, has_arg, flag, val */
523: { "help", no_argument, NULL, 'h' },
524: { "version", no_argument, NULL, 'v' },
525: { "optionsfrom", required_argument, NULL, '+' },
526: { "quiet", no_argument, NULL, 'q' },
527: { "debug", required_argument, NULL, 'l' },
528: { "in", required_argument, NULL, 'i' },
529: { "out", required_argument, NULL, 'o' },
530: { "force", no_argument, NULL, 'f' },
531: { "httptimeout", required_argument, NULL, 'T' },
532: { "bind", required_argument, NULL, 'b' },
533: { "keylength", required_argument, NULL, 'k' },
534: { "dn", required_argument, NULL, 'd' },
535: { "days", required_argument, NULL, 'D' },
536: { "startdate", required_argument, NULL, 'S' },
537: { "enddate", required_argument, NULL, 'E' },
538: { "subjectAltName", required_argument, NULL, 's' },
539: { "password", required_argument, NULL, 'p' },
540: { "algorithm", required_argument, NULL, 'a' },
541: { "url", required_argument, NULL, 'u' },
542: { "caname", required_argument, NULL, 'c'},
543: { "method", required_argument, NULL, 'm' },
544: { "interval", required_argument, NULL, 't' },
545: { "maxpolltime", required_argument, NULL, 'x' },
546: { 0,0,0,0 }
547: };
548:
549: /* parse next option */
550: int c = getopt_long(argc, argv, "hv+:ql:i:o:fT:k:d:s:p:a:u:c:m:t:x:APRCMS", long_opts, NULL);
551:
552: switch (c)
553: {
554: case EOF: /* end of flags */
555: break;
556:
557: case 'h': /* --help */
558: usage(NULL);
559:
560: case 'v': /* --version */
561: version();
562:
563: case 'q': /* --quiet */
564: log_to_stderr = FALSE;
565: continue;
566:
567: case 'l': /* --debug <level> */
568: default_loglevel = atoi(optarg);
569: continue;
570:
571: case 'i': /* --in <type> [= <filename>] */
572: {
573: char *filename = strstr(optarg, "=");
574:
575: if (filename)
576: {
577: /* replace '=' by '\0' */
578: *filename = '\0';
579: /* set pointer to start of filename */
580: filename++;
581: }
582: if (strcaseeq("pkcs1", optarg))
583: {
584: filetype_in |= PKCS1;
585: if (filename)
586: file_in_pkcs1 = filename;
587: }
588: else if (strcaseeq("pkcs10", optarg))
589: {
590: filetype_in |= PKCS10;
591: if (filename)
592: file_in_pkcs10 = filename;
593: }
594: else if (strcaseeq("cacert-enc", optarg))
595: {
596: filetype_in |= CACERT_ENC;
597: if (filename)
598: file_in_cacert_enc = filename;
599: }
600: else if (strcaseeq("cacert-sig", optarg))
601: {
602: filetype_in |= CACERT_SIG;
603: if (filename)
604: file_in_cacert_sig = filename;
605: }
606: else if (strcaseeq("cert-self", optarg))
607: {
608: filetype_in |= CERT_SELF;
609: if (filename)
610: file_in_cert_self = filename;
611: }
612: else
613: {
614: usage("invalid --in file type");
615: }
616: continue;
617: }
618:
619: case 'o': /* --out <type> [= <filename>] */
620: {
621: char *filename = strstr(optarg, "=");
622:
623: if (filename)
624: {
625: /* replace '=' by '\0' */
626: *filename = '\0';
627: /* set pointer to start of filename */
628: filename++;
629: }
630: if (strcaseeq("pkcs1", optarg))
631: {
632: filetype_out |= PKCS1;
633: if (filename)
634: file_out_pkcs1 = filename;
635: }
636: else if (strcaseeq("pkcs10", optarg))
637: {
638: filetype_out |= PKCS10;
639: if (filename)
640: file_out_pkcs10 = filename;
641: }
642: else if (strcaseeq("pkcs7", optarg))
643: {
644: filetype_out |= PKCS7;
645: if (filename)
646: file_out_pkcs7 = filename;
647: }
648: else if (strcaseeq("cert-self", optarg))
649: {
650: filetype_out |= CERT_SELF;
651: if (filename)
652: file_out_cert_self = filename;
653: }
654: else if (strcaseeq("cert", optarg))
655: {
656: filetype_out |= CERT;
657: if (filename)
658: file_out_cert = filename;
659: }
660: else if (strcaseeq("cacert", optarg))
661: {
662: request_ca_certificate = TRUE;
663: if (filename)
664: file_out_ca_cert = filename;
665: }
666: else
667: {
668: usage("invalid --out file type");
669: }
670: continue;
671: }
672:
673: case 'f': /* --force */
674: force = TRUE;
675: continue;
676:
677: case 'T': /* --httptimeout */
678: http_timeout = atoi(optarg);
679: if (http_timeout <= 0)
680: {
681: usage("invalid httptimeout specified");
682: }
683: continue;
684:
685: case 'b': /* --bind */
686: http_bind = optarg;
687: continue;
688:
689: case '+': /* --optionsfrom <filename> */
690: if (!options->from(options, optarg, &argc, &argv, optind))
691: {
692: exit_scepclient("optionsfrom failed");
693: }
694: continue;
695:
696: case 'k': /* --keylength <length> */
697: {
698: div_t q;
699:
700: rsa_keylength = atoi(optarg);
701: if (rsa_keylength == 0)
702: usage("invalid keylength");
703:
704: /* check if key length is a multiple of 8 bits */
705: q = div(rsa_keylength, 2*BITS_PER_BYTE);
706: if (q.rem != 0)
707: {
708: exit_scepclient("keylength is not a multiple of %d bits!"
709: , 2*BITS_PER_BYTE);
710: }
711: continue;
712: }
713:
714: case 'D': /* --days */
715: if (optarg == NULL || !isdigit(optarg[0]))
716: {
717: usage("missing number of days");
718: }
719: else
720: {
721: char *endptr;
722: long days = strtol(optarg, &endptr, 0);
723:
724: if (*endptr != '\0' || endptr == optarg
725: || days <= 0)
726: usage("<days> must be a positive number");
727: validity = 24*3600*days;
728: }
729: continue;
730:
731: case 'S': /* --startdate */
732: if (optarg == NULL || strlen(optarg) != 13 || optarg[12] != 'Z')
733: {
734: usage("date format must be YYMMDDHHMMSSZ");
735: }
736: else
737: {
738: chunk_t date = { optarg, 13 };
739: notBefore = asn1_to_time(&date, ASN1_UTCTIME);
740: }
741: continue;
742:
743: case 'E': /* --enddate */
744: if (optarg == NULL || strlen(optarg) != 13 || optarg[12] != 'Z')
745: {
746: usage("date format must be YYMMDDHHMMSSZ");
747: }
748: else
749: {
750: chunk_t date = { optarg, 13 };
751: notAfter = asn1_to_time(&date, ASN1_UTCTIME);
752: }
753: continue;
754:
755: case 'd': /* --dn */
756: if (distinguishedName)
757: {
758: usage("only one distinguished name allowed");
759: }
760: distinguishedName = optarg;
761: continue;
762:
763: case 's': /* --subjectAltName */
764: {
765: char *value = strstr(optarg, "=");
766:
767: if (value)
768: {
769: /* replace '=' by '\0' */
770: *value = '\0';
771: /* set pointer to start of value */
772: value++;
773: }
774:
775: if (strcaseeq("email", optarg) ||
776: strcaseeq("dns", optarg) ||
777: strcaseeq("ip", optarg))
778: {
779: subjectAltNames->insert_last(subjectAltNames,
780: identification_create_from_string(value));
781: continue;
782: }
783: else
784: {
785: usage("invalid --subjectAltName type");
786: continue;
787: }
788: }
789:
790: case 'p': /* --password */
791: if (challengePassword.len > 0)
792: {
793: usage("only one challenge password allowed");
794: }
795: if (strcaseeq("%prompt", optarg))
796: {
797: printf("Challenge password: ");
798: if (fgets(challenge_password_buffer,
799: sizeof(challenge_password_buffer) - 1, stdin))
800: {
801: challengePassword.ptr = challenge_password_buffer;
802: /* discard the terminating '\n' from the input */
803: challengePassword.len = strlen(challenge_password_buffer) - 1;
804: }
805: else
806: {
807: usage("challenge password could not be read");
808: }
809: }
810: else
811: {
812: challengePassword.ptr = optarg;
813: challengePassword.len = strlen(optarg);
814: }
815: continue;
816:
817: case 'u': /* -- url */
818: if (scep_url)
819: {
820: usage("only one URL argument allowed");
821: }
822: scep_url = optarg;
823: continue;
824:
825: case 'c': /* -- caname */
826: ca_name = optarg;
827: continue;
828:
829: case 'm': /* --method */
830: if (strcaseeq("get", optarg))
831: {
832: http_get_request = TRUE;
833: }
834: else if (strcaseeq("post", optarg))
835: {
836: http_get_request = FALSE;
837: }
838: else
839: {
840: usage("invalid http request method specified");
841: }
842: continue;
843:
844: case 't': /* --interval */
845: poll_interval = atoi(optarg);
846: if (poll_interval <= 0)
847: {
848: usage("invalid interval specified");
849: }
850: continue;
851:
852: case 'x': /* --maxpolltime */
853: max_poll_time = atoi(optarg);
854: continue;
855:
856: case 'a': /*--algorithm [<type>=]algo */
857: {
858: const proposal_token_t *token;
859: char *type = optarg;
860: char *algo = strstr(optarg, "=");
861:
862: if (algo)
863: {
864: *algo = '\0';
865: algo++;
866: }
867: else
868: {
869: type = "enc";
870: algo = optarg;
871: }
872:
873: if (strcaseeq("enc", type))
874: {
875: token = lib->proposal->get_token(lib->proposal, algo);
876: if (token == NULL || token->type != ENCRYPTION_ALGORITHM)
877: {
878: usage("invalid algorithm specified");
879: }
880: pkcs7_symmetric_cipher = token->algorithm;
881: pkcs7_key_size = token->keysize;
882: if (encryption_algorithm_to_oid(token->algorithm,
883: token->keysize) == OID_UNKNOWN)
884: {
885: usage("unsupported encryption algorithm specified");
886: }
887: }
888: else if (strcaseeq("dgst", type) ||
889: strcaseeq("sig", type))
890: {
891: hash_algorithm_t hash;
892:
893: token = lib->proposal->get_token(lib->proposal, algo);
894: if (token == NULL || token->type != INTEGRITY_ALGORITHM)
895: {
896: usage("invalid algorithm specified");
897: }
898: hash = hasher_algorithm_from_integrity(token->algorithm,
899: NULL);
900: if (hash == (hash_algorithm_t)OID_UNKNOWN)
901: {
902: usage("invalid algorithm specified");
903: }
904: if (strcaseeq("dgst", type))
905: {
906: pkcs7_digest_alg = hash;
907: }
908: else
909: {
910: pkcs10_signature_alg = hash;
911: }
912: }
913: else
914: {
915: usage("invalid --algorithm type");
916: }
917: continue;
918: }
919: default:
920: usage("unknown option");
921: }
922: /* break from loop */
923: break;
924: }
925:
926: init_log("scepclient");
927:
928: /* load plugins, further infrastructure may need it */
929: if (!lib->plugins->load(lib->plugins,
930: lib->settings->get_str(lib->settings, "scepclient.load", PLUGINS)))
931: {
932: exit_scepclient("plugin loading failed");
933: }
934: lib->plugins->status(lib->plugins, LEVEL_DIAG);
935:
936: if ((filetype_out == 0) && (!request_ca_certificate))
937: {
938: usage("--out filetype required");
939: }
940: if (request_ca_certificate && (filetype_out > 0 || filetype_in > 0))
941: {
942: usage("in CA certificate request, no other --in or --out option allowed");
943: }
944:
945: /* check if url is given, if cert output defined */
946: if (((filetype_out & CERT) || request_ca_certificate) && !scep_url)
947: {
948: usage("URL of SCEP server required");
949: }
950:
951: /* check for sanity of --in/--out */
952: if (!filetype_in && (filetype_in > filetype_out))
953: {
954: usage("cannot generate --out of given --in!");
955: }
956:
957: /* get CA cert */
958: if (request_ca_certificate)
959: {
960: char ca_path[PATH_MAX];
961: container_t *container;
962: pkcs7_t *p7;
963:
964: if (!scep_http_request(scep_url, chunk_create(ca_name, strlen(ca_name)),
965: SCEP_GET_CA_CERT, http_get_request,
966: http_timeout, http_bind, &scep_response))
967: {
968: exit_scepclient("did not receive a valid scep response");
969: }
970:
971: join_paths(ca_path, sizeof(ca_path), CA_CERT_PATH, file_out_ca_cert);
972:
973: p7 = lib->creds->create(lib->creds, CRED_CONTAINER, CONTAINER_PKCS7,
974: BUILD_BLOB_ASN1_DER, scep_response, BUILD_END);
975:
976: if (!p7)
977: { /* no PKCS#7 encoded CA+RA certificates, assume simple CA cert */
978:
979: DBG1(DBG_APP, "unable to parse PKCS#7, assuming plain CA cert");
980: if (!chunk_write(scep_response, ca_path, 0022, force))
981: {
982: exit_scepclient("could not write ca cert file '%s': %s",
983: ca_path, strerror(errno));
984: }
985: }
986: else
987: {
988: enumerator_t *enumerator;
989: certificate_t *cert;
990: int ra_certs = 0, ca_certs = 0;
991: int ra_index = 1, ca_index = 1;
992:
993: enumerator = p7->create_cert_enumerator(p7);
994: while (enumerator->enumerate(enumerator, &cert))
995: {
996: x509_t *x509 = (x509_t*)cert;
997: if (x509->get_flags(x509) & X509_CA)
998: {
999: ca_certs++;
1000: }
1001: else
1002: {
1003: ra_certs++;
1004: }
1005: }
1006: enumerator->destroy(enumerator);
1007:
1008: enumerator = p7->create_cert_enumerator(p7);
1009: while (enumerator->enumerate(enumerator, &cert))
1010: {
1011: x509_t *x509 = (x509_t*)cert;
1012: bool ca_cert = x509->get_flags(x509) & X509_CA;
1013: char cert_path[PATH_MAX], *path = ca_path;
1014:
1015: if (ca_cert && ca_certs > 1)
1016: {
1017: add_path_suffix(cert_path, sizeof(cert_path), ca_path,
1018: "-%.1d", ca_index++);
1019: path = cert_path;
1020: }
1021: else if (!ca_cert)
1022: { /* use CA name as base for RA certs */
1023: if (ra_certs > 1)
1024: {
1025: add_path_suffix(cert_path, sizeof(cert_path), ca_path,
1026: "-ra-%.1d", ra_index++);
1027: }
1028: else
1029: {
1030: add_path_suffix(cert_path, sizeof(cert_path), ca_path,
1031: "-ra");
1032: }
1033: path = cert_path;
1034: }
1035:
1036: if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding) ||
1037: !chunk_write(encoding, path, 0022, force))
1038: {
1039: exit_scepclient("could not write cert file '%s': %s",
1040: path, strerror(errno));
1041: }
1042: chunk_free(&encoding);
1043: }
1044: enumerator->destroy(enumerator);
1045: container = &p7->container;
1046: container->destroy(container);
1047: }
1048: exit_scepclient(NULL); /* no further output required */
1049: }
1050:
1051: creds = mem_cred_create();
1052: lib->credmgr->add_set(lib->credmgr, &creds->set);
1053:
1054: /*
1055: * input of PKCS#1 file
1056: */
1057: if (filetype_in & PKCS1) /* load an RSA key pair from file */
1058: {
1059: char path[PATH_MAX];
1060:
1061: join_paths(path, sizeof(path), PRIVATE_KEY_PATH, file_in_pkcs1);
1062:
1063: private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
1064: BUILD_FROM_FILE, path, BUILD_END);
1065: }
1066: else /* generate an RSA key pair */
1067: {
1068: private_key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
1069: BUILD_KEY_SIZE, rsa_keylength,
1070: BUILD_END);
1071: }
1072: if (private_key == NULL)
1073: {
1074: exit_scepclient("no RSA private key available");
1075: }
1076: creds->add_key(creds, private_key->get_ref(private_key));
1077: public_key = private_key->get_public_key(private_key);
1078:
1079: /* check for minimum key length */
1080: if (private_key->get_keysize(private_key) < RSA_MIN_OCTETS / BITS_PER_BYTE)
1081: {
1082: exit_scepclient("length of RSA key has to be at least %d bits",
1083: RSA_MIN_OCTETS * BITS_PER_BYTE);
1084: }
1085:
1086: /*
1087: * input of PKCS#10 file
1088: */
1089: if (filetype_in & PKCS10)
1090: {
1091: char path[PATH_MAX];
1092:
1093: join_paths(path, sizeof(path), REQ_PATH, file_in_pkcs10);
1094:
1095: pkcs10_req = lib->creds->create(lib->creds, CRED_CERTIFICATE,
1096: CERT_PKCS10_REQUEST, BUILD_FROM_FILE,
1097: path, BUILD_END);
1098: if (!pkcs10_req)
1099: {
1100: exit_scepclient("could not read certificate request '%s'", path);
1101: }
1102: subject = pkcs10_req->get_subject(pkcs10_req);
1103: subject = subject->clone(subject);
1104: }
1105: else
1106: {
1107: if (distinguishedName == NULL)
1108: {
1109: int n = sprintf(default_distinguished_name, DEFAULT_DN);
1110:
1111: /* set the common name to the hostname */
1112: if (gethostname(default_distinguished_name + n, BUF_LEN - n) ||
1113: strlen(default_distinguished_name) == n)
1114: {
1115: exit_scepclient("no hostname defined, use "
1116: "--dn <distinguished name> option");
1117: }
1118: distinguishedName = default_distinguished_name;
1119: }
1120:
1121: DBG2(DBG_APP, "dn: '%s'", distinguishedName);
1122: subject = identification_create_from_string(distinguishedName);
1123: if (subject->get_type(subject) != ID_DER_ASN1_DN)
1124: {
1125: exit_scepclient("parsing of distinguished name failed");
1126: }
1127:
1128: DBG2(DBG_APP, "building pkcs10 object:");
1129: pkcs10_req = lib->creds->create(lib->creds, CRED_CERTIFICATE,
1130: CERT_PKCS10_REQUEST,
1131: BUILD_SIGNING_KEY, private_key,
1132: BUILD_SUBJECT, subject,
1133: BUILD_SUBJECT_ALTNAMES, subjectAltNames,
1134: BUILD_CHALLENGE_PWD, challengePassword,
1135: BUILD_DIGEST_ALG, pkcs10_signature_alg,
1136: BUILD_END);
1137: if (!pkcs10_req)
1138: {
1139: exit_scepclient("generating pkcs10 request failed");
1140: }
1141: }
1142: pkcs10_req->get_encoding(pkcs10_req, CERT_ASN1_DER, &pkcs10_encoding);
1143: fingerprint = scep_generate_pkcs10_fingerprint(pkcs10_encoding);
1144: DBG1(DBG_APP, " fingerprint: %s", fingerprint.ptr);
1145:
1146: /*
1147: * output of PKCS#10 file
1148: */
1149: if (filetype_out & PKCS10)
1150: {
1151: char path[PATH_MAX];
1152:
1153: join_paths(path, sizeof(path), REQ_PATH, file_out_pkcs10);
1154:
1155: if (!chunk_write(pkcs10_encoding, path, 0022, force))
1156: {
1157: exit_scepclient("could not write pkcs10 file '%s': %s",
1158: path, strerror(errno));
1159: }
1160: filetype_out &= ~PKCS10; /* delete PKCS10 flag */
1161: }
1162:
1163: if (!filetype_out)
1164: {
1165: exit_scepclient(NULL); /* no further output required */
1166: }
1167:
1168: /*
1169: * output of PKCS#1 file
1170: */
1171: if (filetype_out & PKCS1)
1172: {
1173: char path[PATH_MAX];
1174:
1175: join_paths(path, sizeof(path), PRIVATE_KEY_PATH, file_out_pkcs1);
1176:
1177: DBG2(DBG_APP, "building pkcs1 object:");
1178: if (!private_key->get_encoding(private_key, PRIVKEY_ASN1_DER, &pkcs1) ||
1179: !chunk_write(pkcs1, path, 0066, force))
1180: {
1181: exit_scepclient("could not write pkcs1 file '%s': %s",
1182: path, strerror(errno));
1183: }
1184: filetype_out &= ~PKCS1; /* delete PKCS1 flag */
1185: }
1186:
1187: if (!filetype_out)
1188: {
1189: exit_scepclient(NULL); /* no further output required */
1190: }
1191:
1192: scep_generate_transaction_id(public_key, &transID, &serialNumber);
1193: DBG1(DBG_APP, " transaction ID: %.*s", (int)transID.len, transID.ptr);
1194:
1195: /*
1196: * read or generate self-signed X.509 certificate
1197: */
1198: if (filetype_in & CERT_SELF)
1199: {
1200: char path[PATH_MAX];
1201:
1202: join_paths(path, sizeof(path), HOST_CERT_PATH, file_in_cert_self);
1203:
1204: x509_signer = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
1205: BUILD_FROM_FILE, path, BUILD_END);
1206: if (!x509_signer)
1207: {
1208: exit_scepclient("could not read certificate file '%s'", path);
1209: }
1210: }
1211: else
1212: {
1213: notBefore = notBefore ? notBefore : time(NULL);
1214: notAfter = notAfter ? notAfter : (notBefore + validity);
1215: x509_signer = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
1216: BUILD_SIGNING_KEY, private_key,
1217: BUILD_PUBLIC_KEY, public_key,
1218: BUILD_SUBJECT, subject,
1219: BUILD_NOT_BEFORE_TIME, notBefore,
1220: BUILD_NOT_AFTER_TIME, notAfter,
1221: BUILD_SERIAL, serialNumber,
1222: BUILD_SUBJECT_ALTNAMES, subjectAltNames,
1223: BUILD_END);
1224: if (!x509_signer)
1225: {
1226: exit_scepclient("generating certificate failed");
1227: }
1228: }
1229: creds->add_cert(creds, TRUE, x509_signer->get_ref(x509_signer));
1230:
1231: /*
1232: * output of self-signed X.509 certificate file
1233: */
1234: if (filetype_out & CERT_SELF)
1235: {
1236: char path[PATH_MAX];
1237:
1238: join_paths(path, sizeof(path), HOST_CERT_PATH, file_out_cert_self);
1239:
1240: if (!x509_signer->get_encoding(x509_signer, CERT_ASN1_DER, &encoding))
1241: {
1242: exit_scepclient("encoding certificate failed");
1243: }
1244: if (!chunk_write(encoding, path, 0022, force))
1245: {
1246: exit_scepclient("could not write self-signed cert file '%s': %s",
1247: path, strerror(errno));
1248: }
1249: chunk_free(&encoding);
1250: filetype_out &= ~CERT_SELF; /* delete CERT_SELF flag */
1251: }
1252:
1253: if (!filetype_out)
1254: {
1255: exit_scepclient(NULL); /* no further output required */
1256: }
1257:
1258: /*
1259: * load ca encryption certificate
1260: */
1261: {
1262: char path[PATH_MAX];
1263:
1264: join_paths(path, sizeof(path), CA_CERT_PATH, file_in_cacert_enc);
1265:
1266: x509_ca_enc = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
1267: BUILD_FROM_FILE, path, BUILD_END);
1268: if (!x509_ca_enc)
1269: {
1270: exit_scepclient("could not load encryption cacert file '%s'", path);
1271: }
1272: }
1273:
1274: /*
1275: * input of PKCS#7 file
1276: */
1277: if (filetype_in & PKCS7)
1278: {
1279: /* user wants to load a pkcs7 encrypted request
1280: * operation is not yet supported!
1281: * would require additional parsing of transaction-id
1282:
1283: pkcs7 = pkcs7_read_from_file(file_in_pkcs7);
1284:
1285: */
1286: }
1287: else
1288: {
1289: DBG2(DBG_APP, "building pkcs7 request");
1290: pkcs7 = scep_build_request(pkcs10_encoding,
1291: transID, SCEP_PKCSReq_MSG, x509_ca_enc,
1292: pkcs7_symmetric_cipher, pkcs7_key_size,
1293: x509_signer, pkcs7_digest_alg, private_key);
1294: if (!pkcs7.ptr)
1295: {
1296: exit_scepclient("failed to build pkcs7 request");
1297: }
1298: }
1299:
1300: /*
1301: * output pkcs7 encrypted and signed certificate request
1302: */
1303: if (filetype_out & PKCS7)
1304: {
1305: char path[PATH_MAX];
1306:
1307: join_paths(path, sizeof(path), REQ_PATH, file_out_pkcs7);
1308:
1309: if (!chunk_write(pkcs7, path, 0022, force))
1310: {
1311: exit_scepclient("could not write pkcs7 file '%s': %s",
1312: path, strerror(errno));
1313: }
1314: filetype_out &= ~PKCS7; /* delete PKCS7 flag */
1315: }
1316:
1317: if (!filetype_out)
1318: {
1319: exit_scepclient(NULL); /* no further output required */
1320: }
1321:
1322: /*
1323: * output certificate fetch from SCEP server
1324: */
1325: if (filetype_out & CERT)
1326: {
1327: bool stored = FALSE;
1328: certificate_t *cert;
1329: enumerator_t *enumerator;
1330: char path[PATH_MAX];
1331: time_t poll_start = 0;
1332: pkcs7_t *p7;
1333: container_t *container = NULL;
1334: chunk_t chunk;
1335: scep_attributes_t attrs = empty_scep_attributes;
1336:
1337: join_paths(path, sizeof(path), CA_CERT_PATH, file_in_cacert_sig);
1338:
1339: x509_ca_sig = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
1340: BUILD_FROM_FILE, path, BUILD_END);
1341: if (!x509_ca_sig)
1342: {
1343: exit_scepclient("could not load signature cacert file '%s'", path);
1344: }
1345:
1346: creds->add_cert(creds, TRUE, x509_ca_sig->get_ref(x509_ca_sig));
1347:
1348: if (!scep_http_request(scep_url, pkcs7, SCEP_PKI_OPERATION,
1349: http_get_request, http_timeout, http_bind, &scep_response))
1350: {
1351: exit_scepclient("did not receive a valid scep response");
1352: }
1353: ugh = scep_parse_response(scep_response, transID, &container, &attrs);
1354: if (ugh != NULL)
1355: {
1356: exit_scepclient(ugh);
1357: }
1358:
1359: /* in case of manual mode, we are going into a polling loop */
1360: if (attrs.pkiStatus == SCEP_PENDING)
1361: {
1362: identification_t *issuer = x509_ca_sig->get_subject(x509_ca_sig);
1363:
1364: DBG1(DBG_APP, " scep request pending, polling every %d seconds",
1365: poll_interval);
1366: poll_start = time_monotonic(NULL);
1367: issuerAndSubject = asn1_wrap(ASN1_SEQUENCE, "cc",
1368: issuer->get_encoding(issuer),
1369: subject->get_encoding(subject));
1370: }
1371: while (attrs.pkiStatus == SCEP_PENDING)
1372: {
1373: if (max_poll_time > 0 &&
1374: (time_monotonic(NULL) - poll_start >= max_poll_time))
1375: {
1376: exit_scepclient("maximum poll time reached: %d seconds"
1377: , max_poll_time);
1378: }
1379: DBG2(DBG_APP, "going to sleep for %d seconds", poll_interval);
1380: sleep(poll_interval);
1381: free(scep_response.ptr);
1382: container->destroy(container);
1383:
1384: DBG2(DBG_APP, "fingerprint: %.*s",
1385: (int)fingerprint.len, fingerprint.ptr);
1386: DBG2(DBG_APP, "transaction ID: %.*s",
1387: (int)transID.len, transID.ptr);
1388:
1389: chunk_free(&getCertInitial);
1390: getCertInitial = scep_build_request(issuerAndSubject,
1391: transID, SCEP_GetCertInitial_MSG, x509_ca_enc,
1392: pkcs7_symmetric_cipher, pkcs7_key_size,
1393: x509_signer, pkcs7_digest_alg, private_key);
1394: if (!getCertInitial.ptr)
1395: {
1396: exit_scepclient("failed to build scep request");
1397: }
1398: if (!scep_http_request(scep_url, getCertInitial, SCEP_PKI_OPERATION,
1399: http_get_request, http_timeout, http_bind, &scep_response))
1400: {
1401: exit_scepclient("did not receive a valid scep response");
1402: }
1403: ugh = scep_parse_response(scep_response, transID, &container, &attrs);
1404: if (ugh != NULL)
1405: {
1406: exit_scepclient(ugh);
1407: }
1408: }
1409:
1410: if (attrs.pkiStatus != SCEP_SUCCESS)
1411: {
1412: container->destroy(container);
1413: exit_scepclient("reply status is not 'SUCCESS'");
1414: }
1415:
1416: if (!container->get_data(container, &chunk))
1417: {
1418: container->destroy(container);
1419: exit_scepclient("extracting signed-data failed");
1420: }
1421: container->destroy(container);
1422:
1423: /* decrypt enveloped-data container */
1424: container = lib->creds->create(lib->creds,
1425: CRED_CONTAINER, CONTAINER_PKCS7,
1426: BUILD_BLOB_ASN1_DER, chunk,
1427: BUILD_END);
1428: free(chunk.ptr);
1429: if (!container)
1430: {
1431: exit_scepclient("could not decrypt envelopedData");
1432: }
1433:
1434: if (!container->get_data(container, &chunk))
1435: {
1436: container->destroy(container);
1437: exit_scepclient("extracting encrypted-data failed");
1438: }
1439: container->destroy(container);
1440:
1441: /* parse signed-data container */
1442: container = lib->creds->create(lib->creds,
1443: CRED_CONTAINER, CONTAINER_PKCS7,
1444: BUILD_BLOB_ASN1_DER, chunk,
1445: BUILD_END);
1446: free(chunk.ptr);
1447: if (!container)
1448: {
1449: exit_scepclient("could not parse singed-data");
1450: }
1451: /* no need to verify the signed-data container, the signature does NOT
1452: * cover the contained certificates */
1453:
1454: /* store the end entity certificate */
1455: join_paths(path, sizeof(path), HOST_CERT_PATH, file_out_cert);
1456:
1457: p7 = (pkcs7_t*)container;
1458: enumerator = p7->create_cert_enumerator(p7);
1459: while (enumerator->enumerate(enumerator, &cert))
1460: {
1461: x509_t *x509 = (x509_t*)cert;
1462:
1463: if (!(x509->get_flags(x509) & X509_CA))
1464: {
1465: if (stored)
1466: {
1467: exit_scepclient("multiple certs received, only first stored");
1468: }
1469: if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoding) ||
1470: !chunk_write(encoding, path, 0022, force))
1471: {
1472: exit_scepclient("could not write cert file '%s': %s",
1473: path, strerror(errno));
1474: }
1475: chunk_free(&encoding);
1476: stored = TRUE;
1477: }
1478: }
1479: enumerator->destroy(enumerator);
1480: container->destroy(container);
1481: chunk_free(&attrs.transID);
1482: chunk_free(&attrs.senderNonce);
1483: chunk_free(&attrs.recipientNonce);
1484:
1485: filetype_out &= ~CERT; /* delete CERT flag */
1486: }
1487:
1488: exit_scepclient(NULL);
1489: return -1; /* should never be reached */
1490: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>