Annotation of embedaddon/strongswan/src/charon-nm/nm/nm_creds.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008 Martin Willi
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #include "nm_creds.h"
! 17:
! 18: #include <sys/types.h>
! 19: #include <sys/stat.h>
! 20: #include <unistd.h>
! 21:
! 22: #include <daemon.h>
! 23: #include <threading/rwlock.h>
! 24: #include <credentials/certificates/x509.h>
! 25:
! 26: typedef struct private_nm_creds_t private_nm_creds_t;
! 27:
! 28: /**
! 29: * private data of nm_creds
! 30: */
! 31: struct private_nm_creds_t {
! 32:
! 33: /**
! 34: * public functions
! 35: */
! 36: nm_creds_t public;
! 37:
! 38: /**
! 39: * List of trusted certificates, certificate_t*
! 40: */
! 41: linked_list_t *certs;
! 42:
! 43: /**
! 44: * User name
! 45: */
! 46: identification_t *user;
! 47:
! 48: /**
! 49: * User password
! 50: */
! 51: char *pass;
! 52:
! 53: /**
! 54: * Private key decryption password / smartcard pin
! 55: */
! 56: char *keypass;
! 57:
! 58: /**
! 59: * private key ID of smartcard key
! 60: */
! 61: chunk_t keyid;
! 62:
! 63: /**
! 64: * users certificate
! 65: */
! 66: certificate_t *usercert;
! 67:
! 68: /**
! 69: * users private key
! 70: */
! 71: private_key_t *key;
! 72:
! 73: /**
! 74: * read/write lock
! 75: */
! 76: rwlock_t *lock;
! 77: };
! 78:
! 79: /**
! 80: * Enumerator for user certificate
! 81: */
! 82: static enumerator_t *create_usercert_enumerator(private_nm_creds_t *this,
! 83: certificate_type_t cert, key_type_t key)
! 84: {
! 85: public_key_t *public;
! 86:
! 87: if (cert != CERT_ANY && cert != this->usercert->get_type(this->usercert))
! 88: {
! 89: return NULL;
! 90: }
! 91: if (key != KEY_ANY)
! 92: {
! 93: public = this->usercert->get_public_key(this->usercert);
! 94: if (!public)
! 95: {
! 96: return NULL;
! 97: }
! 98: if (public->get_type(public) != key)
! 99: {
! 100: public->destroy(public);
! 101: return NULL;
! 102: }
! 103: public->destroy(public);
! 104: }
! 105: this->lock->read_lock(this->lock);
! 106: return enumerator_create_cleaner(
! 107: enumerator_create_single(this->usercert, NULL),
! 108: (void*)this->lock->unlock, this->lock);
! 109: }
! 110:
! 111: /**
! 112: * CA certificate enumerator data
! 113: */
! 114: typedef struct {
! 115: /** ref to credential credential store */
! 116: private_nm_creds_t *this;
! 117: /** type of key we are looking for */
! 118: key_type_t key;
! 119: /** CA certificate ID */
! 120: identification_t *id;
! 121: } cert_data_t;
! 122:
! 123: CALLBACK(cert_data_destroy, void,
! 124: cert_data_t *data)
! 125: {
! 126: data->this->lock->unlock(data->this->lock);
! 127: free(data);
! 128: }
! 129:
! 130: CALLBACK(cert_filter, bool,
! 131: cert_data_t *data, enumerator_t *orig, va_list args)
! 132: {
! 133: certificate_t *cert, **out;
! 134: public_key_t *public;
! 135:
! 136: VA_ARGS_VGET(args, out);
! 137:
! 138: while (orig->enumerate(orig, &cert))
! 139: {
! 140: public = cert->get_public_key(cert);
! 141: if (!public)
! 142: {
! 143: continue;
! 144: }
! 145: if (data->key != KEY_ANY && public->get_type(public) != data->key)
! 146: {
! 147: public->destroy(public);
! 148: continue;
! 149: }
! 150: if (data->id && data->id->get_type(data->id) == ID_KEY_ID &&
! 151: public->has_fingerprint(public, data->id->get_encoding(data->id)))
! 152: {
! 153: public->destroy(public);
! 154: *out = cert;
! 155: return TRUE;
! 156: }
! 157: public->destroy(public);
! 158: if (data->id && !cert->has_subject(cert, data->id))
! 159: {
! 160: continue;
! 161: }
! 162: *out = cert;
! 163: return TRUE;
! 164: }
! 165: return FALSE;
! 166: }
! 167:
! 168: /**
! 169: * Create enumerator for trusted certificates
! 170: */
! 171: static enumerator_t *create_trusted_cert_enumerator(private_nm_creds_t *this,
! 172: key_type_t key, identification_t *id)
! 173: {
! 174: cert_data_t *data;
! 175:
! 176: INIT(data,
! 177: .this = this,
! 178: .id = id,
! 179: .key = key,
! 180: );
! 181:
! 182: this->lock->read_lock(this->lock);
! 183: return enumerator_create_filter(
! 184: this->certs->create_enumerator(this->certs),
! 185: cert_filter, data, cert_data_destroy);
! 186: }
! 187:
! 188: METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
! 189: private_nm_creds_t *this, certificate_type_t cert, key_type_t key,
! 190: identification_t *id, bool trusted)
! 191: {
! 192: if (id && this->usercert &&
! 193: id->equals(id, this->usercert->get_subject(this->usercert)))
! 194: {
! 195: return create_usercert_enumerator(this, cert, key);
! 196: }
! 197: if (cert == CERT_X509 || cert == CERT_ANY)
! 198: {
! 199: return create_trusted_cert_enumerator(this, key, id);
! 200: }
! 201: return NULL;
! 202: }
! 203:
! 204: METHOD(credential_set_t, create_private_enumerator, enumerator_t*,
! 205: private_nm_creds_t *this, key_type_t type, identification_t *id)
! 206: {
! 207: if (this->key == NULL)
! 208: {
! 209: return NULL;
! 210: }
! 211: if (type != KEY_ANY && type != this->key->get_type(this->key))
! 212: {
! 213: return NULL;
! 214: }
! 215: if (id && id->get_type(id) != ID_ANY)
! 216: {
! 217: if (id->get_type(id) != ID_KEY_ID ||
! 218: !this->key->has_fingerprint(this->key, id->get_encoding(id)))
! 219: {
! 220: return NULL;
! 221: }
! 222: }
! 223: this->lock->read_lock(this->lock);
! 224: return enumerator_create_cleaner(enumerator_create_single(this->key, NULL),
! 225: (void*)this->lock->unlock, this->lock);
! 226: }
! 227:
! 228: /**
! 229: * shared key enumerator implementation
! 230: */
! 231: typedef struct {
! 232: enumerator_t public;
! 233: private_nm_creds_t *this;
! 234: shared_key_t *key;
! 235: bool done;
! 236: } shared_enumerator_t;
! 237:
! 238: METHOD(enumerator_t, shared_enumerate, bool,
! 239: shared_enumerator_t *this, va_list args)
! 240: {
! 241: shared_key_t **key;
! 242: id_match_t *me, *other;
! 243:
! 244: VA_ARGS_VGET(args, key, me, other);
! 245:
! 246: if (this->done)
! 247: {
! 248: return FALSE;
! 249: }
! 250: *key = this->key;
! 251: if (me)
! 252: {
! 253: *me = ID_MATCH_PERFECT;
! 254: }
! 255: if (other)
! 256: {
! 257: *other = ID_MATCH_ANY;
! 258: }
! 259: this->done = TRUE;
! 260: return TRUE;
! 261: }
! 262:
! 263: METHOD(enumerator_t, shared_destroy, void,
! 264: shared_enumerator_t *this)
! 265: {
! 266: this->key->destroy(this->key);
! 267: this->this->lock->unlock(this->this->lock);
! 268: free(this);
! 269: }
! 270:
! 271: METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
! 272: private_nm_creds_t *this, shared_key_type_t type, identification_t *me,
! 273: identification_t *other)
! 274: {
! 275: shared_enumerator_t *enumerator;
! 276: chunk_t key;
! 277:
! 278: this->lock->read_lock(this->lock);
! 279:
! 280: switch (type)
! 281: {
! 282: case SHARED_EAP:
! 283: case SHARED_IKE:
! 284: if (!this->pass || !this->user)
! 285: {
! 286: goto no_secret;
! 287: }
! 288: if (me && !me->matches(me, this->user))
! 289: {
! 290: goto no_secret;
! 291: }
! 292: key = chunk_create(this->pass, strlen(this->pass));
! 293: break;
! 294: case SHARED_PRIVATE_KEY_PASS:
! 295: if (!this->keypass)
! 296: {
! 297: goto no_secret;
! 298: }
! 299: key = chunk_create(this->keypass, strlen(this->keypass));
! 300: break;
! 301: case SHARED_PIN:
! 302: if (!this->keypass || !me ||
! 303: !chunk_equals(me->get_encoding(me), this->keyid))
! 304: {
! 305: goto no_secret;
! 306: }
! 307: key = chunk_create(this->keypass, strlen(this->keypass));
! 308: break;
! 309: default:
! 310: goto no_secret;
! 311: }
! 312:
! 313: INIT(enumerator,
! 314: .public = {
! 315: .enumerate = enumerator_enumerate_default,
! 316: .venumerate = _shared_enumerate,
! 317: .destroy = _shared_destroy,
! 318: },
! 319: .this = this,
! 320: );
! 321: enumerator->key = shared_key_create(type, chunk_clone(key));
! 322: return &enumerator->public;
! 323:
! 324: no_secret:
! 325: this->lock->unlock(this->lock);
! 326: return NULL;
! 327: }
! 328:
! 329: METHOD(nm_creds_t, add_certificate, void,
! 330: private_nm_creds_t *this, certificate_t *cert)
! 331: {
! 332: this->lock->write_lock(this->lock);
! 333: this->certs->insert_last(this->certs, cert);
! 334: this->lock->unlock(this->lock);
! 335: }
! 336:
! 337: /**
! 338: * Load a certificate file
! 339: */
! 340: static void load_ca_file(private_nm_creds_t *this, char *file)
! 341: {
! 342: certificate_t *cert;
! 343:
! 344: /* We add the CA constraint, as many CAs miss it */
! 345: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
! 346: BUILD_FROM_FILE, file, BUILD_END);
! 347: if (!cert)
! 348: {
! 349: DBG1(DBG_CFG, "loading CA certificate '%s' failed", file);
! 350: }
! 351: else
! 352: {
! 353: DBG2(DBG_CFG, "loaded CA certificate '%Y'", cert->get_subject(cert));
! 354: x509_t *x509 = (x509_t*)cert;
! 355: if (!(x509->get_flags(x509) & X509_SELF_SIGNED))
! 356: {
! 357: DBG1(DBG_CFG, "%Y is not self signed", cert->get_subject(cert));
! 358: }
! 359: this->certs->insert_last(this->certs, cert);
! 360: }
! 361: }
! 362:
! 363: METHOD(nm_creds_t, load_ca_dir, void,
! 364: private_nm_creds_t *this, char *dir)
! 365: {
! 366: enumerator_t *enumerator;
! 367: char *rel, *abs;
! 368: struct stat st;
! 369:
! 370: enumerator = enumerator_create_directory(dir);
! 371: if (enumerator)
! 372: {
! 373: while (enumerator->enumerate(enumerator, &rel, &abs, &st))
! 374: {
! 375: /* skip '.', '..' and hidden files */
! 376: if (rel[0] != '.')
! 377: {
! 378: if (S_ISDIR(st.st_mode))
! 379: {
! 380: load_ca_dir(this, abs);
! 381: }
! 382: else if (S_ISREG(st.st_mode))
! 383: {
! 384: load_ca_file(this, abs);
! 385: }
! 386: }
! 387: }
! 388: enumerator->destroy(enumerator);
! 389: }
! 390: }
! 391:
! 392: METHOD(nm_creds_t, set_username_password, void,
! 393: private_nm_creds_t *this, identification_t *id, char *password)
! 394: {
! 395: this->lock->write_lock(this->lock);
! 396: DESTROY_IF(this->user);
! 397: this->user = id->clone(id);
! 398: free(this->pass);
! 399: this->pass = strdupnull(password);
! 400: this->lock->unlock(this->lock);
! 401: }
! 402:
! 403: METHOD(nm_creds_t, set_key_password, void,
! 404: private_nm_creds_t *this, char *password)
! 405: {
! 406: this->lock->write_lock(this->lock);
! 407: free(this->keypass);
! 408: this->keypass = strdupnull(password);
! 409: this->lock->unlock(this->lock);
! 410: }
! 411:
! 412: METHOD(nm_creds_t, set_pin, void,
! 413: private_nm_creds_t *this, chunk_t keyid, char *pin)
! 414: {
! 415: this->lock->write_lock(this->lock);
! 416: free(this->keypass);
! 417: free(this->keyid.ptr);
! 418: this->keypass = strdupnull(pin);
! 419: this->keyid = chunk_clone(keyid);
! 420: this->lock->unlock(this->lock);
! 421: }
! 422:
! 423: METHOD(nm_creds_t, set_cert_and_key, void,
! 424: private_nm_creds_t *this, certificate_t *cert, private_key_t *key)
! 425: {
! 426: this->lock->write_lock(this->lock);
! 427: DESTROY_IF(this->key);
! 428: DESTROY_IF(this->usercert);
! 429: this->key = key;
! 430: this->usercert = cert;
! 431: this->lock->unlock(this->lock);
! 432: }
! 433:
! 434: METHOD(nm_creds_t, clear, void,
! 435: private_nm_creds_t *this)
! 436: {
! 437: certificate_t *cert;
! 438:
! 439: while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS)
! 440: {
! 441: cert->destroy(cert);
! 442: }
! 443: DESTROY_IF(this->user);
! 444: free(this->pass);
! 445: free(this->keypass);
! 446: free(this->keyid.ptr);
! 447: DESTROY_IF(this->usercert);
! 448: DESTROY_IF(this->key);
! 449: this->key = NULL;
! 450: this->usercert = NULL;
! 451: this->pass = NULL;
! 452: this->user = NULL;
! 453: this->keypass = NULL;
! 454: this->keyid = chunk_empty;
! 455: }
! 456:
! 457: METHOD(nm_creds_t, destroy, void,
! 458: private_nm_creds_t *this)
! 459: {
! 460: clear(this);
! 461: this->certs->destroy(this->certs);
! 462: this->lock->destroy(this->lock);
! 463: free(this);
! 464: }
! 465:
! 466: /*
! 467: * see header file
! 468: */
! 469: nm_creds_t *nm_creds_create()
! 470: {
! 471: private_nm_creds_t *this;
! 472:
! 473: INIT(this,
! 474: .public = {
! 475: .set = {
! 476: .create_private_enumerator = _create_private_enumerator,
! 477: .create_cert_enumerator = _create_cert_enumerator,
! 478: .create_shared_enumerator = _create_shared_enumerator,
! 479: .create_cdp_enumerator = (void*)return_null,
! 480: .cache_cert = (void*)nop,
! 481: },
! 482: .add_certificate = _add_certificate,
! 483: .load_ca_dir = _load_ca_dir,
! 484: .set_username_password = _set_username_password,
! 485: .set_key_password = _set_key_password,
! 486: .set_pin = _set_pin,
! 487: .set_cert_and_key = _set_cert_and_key,
! 488: .clear = _clear,
! 489: .destroy = _destroy,
! 490: },
! 491: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
! 492: .certs = linked_list_create(),
! 493: );
! 494: return &this->public;
! 495: }
! 496:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>