Annotation of embedaddon/strongswan/src/pki/pki.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012-2018 Tobias Brunner
3: * Copyright (C) 2009 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: #define _GNU_SOURCE
18: #include "command.h"
19: #include "pki.h"
20:
21: #include <time.h>
22: #include <unistd.h>
23: #include <fcntl.h>
24:
25: #include <utils/debug.h>
26: #include <credentials/sets/mem_cred.h>
27: #include <credentials/sets/callback_cred.h>
28:
29: /**
30: * Convert a form string to a encoding type
31: */
32: bool get_form(char *form, cred_encoding_type_t *enc, credential_type_t type)
33: {
34: if (streq(form, "der"))
35: {
36: switch (type)
37: {
38: case CRED_CERTIFICATE:
39: *enc = CERT_ASN1_DER;
40: return TRUE;
41: case CRED_PRIVATE_KEY:
42: *enc = PRIVKEY_ASN1_DER;
43: return TRUE;
44: case CRED_PUBLIC_KEY:
45: /* der encoded keys usually contain the complete
46: * SubjectPublicKeyInfo */
47: *enc = PUBKEY_SPKI_ASN1_DER;
48: return TRUE;
49: default:
50: return FALSE;
51: }
52: }
53: else if (streq(form, "pem"))
54: {
55: switch (type)
56: {
57: case CRED_CERTIFICATE:
58: *enc = CERT_PEM;
59: return TRUE;
60: case CRED_PRIVATE_KEY:
61: *enc = PRIVKEY_PEM;
62: return TRUE;
63: case CRED_PUBLIC_KEY:
64: *enc = PUBKEY_PEM;
65: return TRUE;
66: default:
67: return FALSE;
68: }
69: }
70: else if (streq(form, "pgp"))
71: {
72: switch (type)
73: {
74: case CRED_PRIVATE_KEY:
75: *enc = PRIVKEY_PGP;
76: return TRUE;
77: case CRED_PUBLIC_KEY:
78: *enc = PUBKEY_PGP;
79: return TRUE;
80: default:
81: return FALSE;
82: }
83: }
84: else if (streq(form, "dnskey"))
85: {
86: switch (type)
87: {
88: case CRED_PUBLIC_KEY:
89: *enc = PUBKEY_DNSKEY;
90: return TRUE;
91: default:
92: return FALSE;
93: }
94: }
95: else if (streq(form, "sshkey"))
96: {
97: switch (type)
98: {
99: case CRED_PUBLIC_KEY:
100: *enc = PUBKEY_SSHKEY;
101: return TRUE;
102: default:
103: return FALSE;
104: }
105: }
106: return FALSE;
107: }
108:
109: /**
110: * Convert a time string to struct tm using strptime format
111: */
112: static bool convert_time(char *str, char *format, struct tm *tm)
113: {
114: #ifdef HAVE_STRPTIME
115:
116: char *end;
117:
118: if (!format)
119: {
120: format = "%d.%m.%y %T";
121: }
122:
123: end = strptime(str, format, tm);
124: if (end == NULL || *end != '\0')
125: {
126: return FALSE;
127: }
128: return TRUE;
129:
130: #else /* !HAVE_STRPTIME */
131:
132: if (format)
133: {
134: fprintf(stderr, "custom datetime string format not supported\n");
135: return FALSE;
136: }
137:
138: if (sscanf(str, "%d.%d.%d %d:%d:%d",
139: &tm->tm_mday, &tm->tm_mon, &tm->tm_year,
140: &tm->tm_hour, &tm->tm_min, &tm->tm_sec) != 6)
141: {
142: return FALSE;
143: }
144: /* strptime() interprets two-digit years > 68 as 19xx, do the same here.
145: * mktime() expects years based on 1900 */
146: if (tm->tm_year <= 68)
147: {
148: tm->tm_year += 100;
149: }
150: else if (tm->tm_year >= 1900)
151: { /* looks like four digits? */
152: tm->tm_year -= 1900;
153: }
154: /* month is specified from 0-11 */
155: tm->tm_mon--;
156: /* automatically detect daylight saving time */
157: tm->tm_isdst = -1;
158: return TRUE;
159:
160: #endif /* !HAVE_STRPTIME */
161: }
162:
163: /**
164: * See header
165: */
166: bool calculate_lifetime(char *format, char *nbstr, char *nastr, time_t span,
167: time_t *nb, time_t *na)
168: {
169: struct tm tm;
170: time_t now;
171:
172: now = time(NULL);
173:
174: localtime_r(&now, &tm);
175: if (nbstr)
176: {
177: if (!convert_time(nbstr, format, &tm))
178: {
179: return FALSE;
180: }
181: }
182: *nb = mktime(&tm);
183: if (*nb == -1)
184: {
185: return FALSE;
186: }
187:
188: localtime_r(&now, &tm);
189: if (nastr)
190: {
191: if (!convert_time(nastr, format, &tm))
192: {
193: return FALSE;
194: }
195: }
196: *na = mktime(&tm);
197: if (*na == -1)
198: {
199: return FALSE;
200: }
201:
202: if (!nbstr && nastr)
203: {
204: *nb = *na - span;
205: }
206: else if (!nastr)
207: {
208: *na = *nb + span;
209: }
210: return TRUE;
211: }
212:
213: /**
214: * Set output file mode appropriate for credential encoding form on Windows
215: */
216: void set_file_mode(FILE *stream, cred_encoding_type_t enc)
217: {
218: #ifdef WIN32
219: int fd;
220:
221: switch (enc)
222: {
223: case CERT_PEM:
224: case PRIVKEY_PEM:
225: case PUBKEY_PEM:
226: /* keep default text mode */
227: return;
228: default:
229: /* switch to binary mode */
230: break;
231: }
232: fd = fileno(stream);
233: if (fd != -1)
234: {
235: _setmode(fd, _O_BINARY);
236: }
237: #endif
238: }
239:
240: /**
241: * Determine a default hash algorithm for the given key
242: */
243: static hash_algorithm_t get_default_digest(private_key_t *private)
244: {
245: enumerator_t *enumerator;
246: signature_params_t *params;
247: hash_algorithm_t alg = HASH_UNKNOWN;
248:
249: enumerator = signature_schemes_for_key(private->get_type(private),
250: private->get_keysize(private));
251: if (enumerator->enumerate(enumerator, ¶ms))
252: {
253: alg = hasher_from_signature_scheme(params->scheme, params->params);
254: }
255: enumerator->destroy(enumerator);
256:
257: /* default to SHA-256 */
258: return alg == HASH_UNKNOWN ? HASH_SHA256 : alg;
259: }
260:
261: /*
262: * Described in header
263: */
264: signature_params_t *get_signature_scheme(private_key_t *private,
265: hash_algorithm_t digest, bool pss)
266: {
267: signature_params_t *scheme, *selected = NULL;
268: enumerator_t *enumerator;
269:
270: if (private->supported_signature_schemes)
271: {
272: enumerator = private->supported_signature_schemes(private);
273: while (enumerator->enumerate(enumerator, &scheme))
274: {
275: if (private->get_type(private) == KEY_RSA &&
276: pss != (scheme->scheme == SIGN_RSA_EMSA_PSS))
277: {
278: continue;
279: }
280: if (digest == HASH_UNKNOWN ||
281: digest == hasher_from_signature_scheme(scheme->scheme,
282: scheme->params))
283: {
284: selected = signature_params_clone(scheme);
285: break;
286: }
287: }
288: enumerator->destroy(enumerator);
289: return selected;
290: }
291:
292: if (digest == HASH_UNKNOWN)
293: {
294: digest = get_default_digest(private);
295: }
296: if (private->get_type(private) == KEY_RSA && pss)
297: {
298: rsa_pss_params_t pss_params = {
299: .hash = digest,
300: .mgf1_hash = digest,
301: .salt_len = RSA_PSS_SALT_LEN_DEFAULT,
302: };
303: signature_params_t pss_scheme = {
304: .scheme = SIGN_RSA_EMSA_PSS,
305: .params = &pss_params,
306: };
307: rsa_pss_params_set_salt_len(&pss_params, 0);
308: scheme = signature_params_clone(&pss_scheme);
309: }
310: else
311: {
312: INIT(scheme,
313: .scheme = signature_scheme_from_oid(
314: hasher_signature_algorithm_to_oid(digest,
315: private->get_type(private))),
316: );
317: }
318: return scheme;
319: }
320:
321: /*
322: * Described in header
323: */
324: traffic_selector_t* parse_ts(char *str)
325: {
326: ts_type_t type = TS_IPV4_ADDR_RANGE;
327: char *to, from[64];
328:
329: if (strchr(str, ':'))
330: {
331: type = TS_IPV6_ADDR_RANGE;
332: }
333: to = strchr(str, '-');
334: if (to)
335: {
336: snprintf(from, sizeof(from), "%.*s", (int)(to - str), str);
337: to++;
338: return traffic_selector_create_from_string(0, type, from, 0, to, 65535);
339: }
340: return traffic_selector_create_from_cidr(str, 0, 0, 65535);
341: }
342:
343: /**
344: * Callback credential set pki uses
345: */
346: static callback_cred_t *cb_set;
347:
348: /**
349: * Credential set to cache entered secrets
350: */
351: static mem_cred_t *cb_creds;
352:
353: static shared_key_type_t prompted;
354:
355: /**
356: * Callback function to receive credentials
357: */
358: static shared_key_t* cb(void *data, shared_key_type_t type,
359: identification_t *me, identification_t *other,
360: id_match_t *match_me, id_match_t *match_other)
361: {
362: char buf[64], *label, *secret = NULL;
363: shared_key_t *shared;
364:
365: if (prompted == type)
366: {
367: return NULL;
368: }
369: switch (type)
370: {
371: case SHARED_PIN:
372: label = "Smartcard PIN";
373: break;
374: case SHARED_PRIVATE_KEY_PASS:
375: label = "Private key passphrase";
376: break;
377: default:
378: return NULL;
379: }
380: snprintf(buf, sizeof(buf), "%s: ", label);
381: #ifdef HAVE_GETPASS
382: secret = getpass(buf);
383: #endif
384: if (secret && strlen(secret))
385: {
386: prompted = type;
387: if (match_me)
388: {
389: *match_me = ID_MATCH_PERFECT;
390: }
391: if (match_other)
392: {
393: *match_other = ID_MATCH_NONE;
394: }
395: shared = shared_key_create(type, chunk_clone(chunk_from_str(secret)));
396: /* cache password in case it is required more than once */
397: cb_creds->add_shared(cb_creds, shared, NULL);
398: return shared->get_ref(shared);
399: }
400: return NULL;
401: }
402:
403: /**
404: * Register PIN/Passphrase callback function
405: */
406: static void add_callback()
407: {
408: cb_set = callback_cred_create_shared(cb, NULL);
409: lib->credmgr->add_set(lib->credmgr, &cb_set->set);
410: cb_creds = mem_cred_create();
411: lib->credmgr->add_set(lib->credmgr, &cb_creds->set);
412: }
413:
414: /**
415: * Unregister PIN/Passphrase callback function
416: */
417: static void remove_callback()
418: {
419: lib->credmgr->remove_set(lib->credmgr, &cb_creds->set);
420: cb_creds->destroy(cb_creds);
421: lib->credmgr->remove_set(lib->credmgr, &cb_set->set);
422: cb_set->destroy(cb_set);
423: }
424:
425: /**
426: * Library initialization and operation parsing
427: */
428: int main(int argc, char *argv[])
429: {
430: char *plugins;
431:
432: atexit(library_deinit);
433: if (!library_init(NULL, "pki"))
434: {
435: exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
436: }
437: if (lib->integrity &&
438: !lib->integrity->check_file(lib->integrity, "pki", argv[0]))
439: {
440: fprintf(stderr, "integrity check of pki failed\n");
441: exit(SS_RC_DAEMON_INTEGRITY);
442: }
443: plugins = getenv("PKI_PLUGINS");
444: if (!plugins)
445: {
446: plugins = lib->settings->get_str(lib->settings, "pki.load", PLUGINS);
447: }
448: if (!lib->plugins->load(lib->plugins, plugins))
449: {
450: exit(SS_RC_INITIALIZATION_FAILED);
451: }
452:
453: add_callback();
454: atexit(remove_callback);
455: return command_dispatch(argc, argv);
456: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>