Return to pki.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / pki |
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: }