Annotation of embedaddon/strongswan/src/pki/pki.c, revision 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>