File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / charon-nm / nm / nm_creds.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:44 2020 UTC (4 years, 3 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    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>