Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/iv_manager.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011-2016 Tobias Brunner
! 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 "iv_manager.h"
! 17:
! 18: #include <library.h>
! 19: #include <collections/linked_list.h>
! 20:
! 21: /**
! 22: * Max. number of IVs/QMs to track.
! 23: */
! 24: #define MAX_EXCHANGES_DEFAULT 3
! 25:
! 26: typedef struct private_iv_manager_t private_iv_manager_t;
! 27: typedef struct iv_data_t iv_data_t;
! 28: typedef struct qm_data_t qm_data_t;
! 29:
! 30: /**
! 31: * Data stored for IVs.
! 32: */
! 33: struct iv_data_t {
! 34: /**
! 35: * message ID
! 36: */
! 37: uint32_t mid;
! 38:
! 39: /**
! 40: * current IV
! 41: */
! 42: chunk_t iv;
! 43:
! 44: /**
! 45: * last block of encrypted message
! 46: */
! 47: chunk_t last_block;
! 48: };
! 49:
! 50: /**
! 51: * Private data of a iv_manager_t object.
! 52: */
! 53: struct private_iv_manager_t {
! 54: /**
! 55: * Implement public interface.
! 56: */
! 57: iv_manager_t public;
! 58:
! 59: /**
! 60: * Phase 1 IV.
! 61: */
! 62: iv_data_t phase1_iv;
! 63:
! 64: /**
! 65: * Keep track of IVs for exchanges after phase 1. We store only a limited
! 66: * number of IVs in an MRU sort of way. Stores iv_data_t objects.
! 67: */
! 68: linked_list_t *ivs;
! 69:
! 70: /**
! 71: * Keep track of Nonces during Quick Mode exchanges. Only a limited number
! 72: * of QMs are tracked at the same time. Stores qm_data_t objects.
! 73: */
! 74: linked_list_t *qms;
! 75:
! 76: /**
! 77: * Max. number of IVs/Quick Modes to track.
! 78: */
! 79: int max_exchanges;
! 80:
! 81: /**
! 82: * Hasher used for IV generation.
! 83: */
! 84: hasher_t *hasher;
! 85:
! 86: /*
! 87: * Encryption algorithm the block size.
! 88: */
! 89: size_t block_size;
! 90: };
! 91:
! 92: /**
! 93: * Data stored for Quick Mode exchanges.
! 94: */
! 95: struct qm_data_t {
! 96: /**
! 97: * Message ID.
! 98: */
! 99: uint32_t mid;
! 100:
! 101: /**
! 102: * Ni_b (Nonce from first message).
! 103: */
! 104: chunk_t n_i;
! 105:
! 106: /**
! 107: * Nr_b (Nonce from second message).
! 108: */
! 109: chunk_t n_r;
! 110: };
! 111:
! 112: /**
! 113: * Destroy an iv_data_t object.
! 114: */
! 115: static void iv_data_destroy(iv_data_t *this)
! 116: {
! 117: chunk_free(&this->last_block);
! 118: chunk_free(&this->iv);
! 119: free(this);
! 120: }
! 121:
! 122: /**
! 123: * Destroy a qm_data_t object.
! 124: */
! 125: static void qm_data_destroy(qm_data_t *this)
! 126: {
! 127: chunk_free(&this->n_i);
! 128: chunk_free(&this->n_r);
! 129: free(this);
! 130: }
! 131:
! 132: /**
! 133: * Generate an IV.
! 134: */
! 135: static bool generate_iv(private_iv_manager_t *this, iv_data_t *iv)
! 136: {
! 137: if (iv->mid == 0 || iv->iv.ptr)
! 138: { /* use last block of previous encrypted message */
! 139: chunk_free(&iv->iv);
! 140: iv->iv = iv->last_block;
! 141: iv->last_block = chunk_empty;
! 142: }
! 143: else
! 144: {
! 145: /* initial phase 2 IV = hash(last_phase1_block | mid) */
! 146: uint32_t net;;
! 147: chunk_t data;
! 148:
! 149: net = htonl(iv->mid);
! 150: data = chunk_cata("cc", this->phase1_iv.iv, chunk_from_thing(net));
! 151: if (!this->hasher->allocate_hash(this->hasher, data, &iv->iv))
! 152: {
! 153: return FALSE;
! 154: }
! 155: if (iv->iv.len > this->block_size)
! 156: {
! 157: iv->iv.len = this->block_size;
! 158: }
! 159: }
! 160: DBG4(DBG_IKE, "next IV for MID %u %B", iv->mid, &iv->iv);
! 161: return TRUE;
! 162: }
! 163:
! 164: /**
! 165: * Try to find an IV for the given message ID, if not found, generate it.
! 166: */
! 167: static iv_data_t *lookup_iv(private_iv_manager_t *this, uint32_t mid)
! 168: {
! 169: enumerator_t *enumerator;
! 170: iv_data_t *iv, *found = NULL;
! 171:
! 172: if (mid == 0)
! 173: {
! 174: return &this->phase1_iv;
! 175: }
! 176:
! 177: enumerator = this->ivs->create_enumerator(this->ivs);
! 178: while (enumerator->enumerate(enumerator, &iv))
! 179: {
! 180: if (iv->mid == mid)
! 181: { /* IV gets moved to the front of the list */
! 182: this->ivs->remove_at(this->ivs, enumerator);
! 183: found = iv;
! 184: break;
! 185: }
! 186: }
! 187: enumerator->destroy(enumerator);
! 188: if (!found)
! 189: {
! 190: INIT(found,
! 191: .mid = mid,
! 192: );
! 193: if (!generate_iv(this, found))
! 194: {
! 195: iv_data_destroy(found);
! 196: return NULL;
! 197: }
! 198: }
! 199: this->ivs->insert_first(this->ivs, found);
! 200: /* remove least recently used IV if maximum reached */
! 201: if (this->ivs->get_count(this->ivs) > this->max_exchanges &&
! 202: this->ivs->remove_last(this->ivs, (void**)&iv) == SUCCESS)
! 203: {
! 204: iv_data_destroy(iv);
! 205: }
! 206: return found;
! 207: }
! 208:
! 209: METHOD(iv_manager_t, init_iv_chain, bool,
! 210: private_iv_manager_t *this, chunk_t data, hasher_t *hasher,
! 211: size_t block_size)
! 212: {
! 213: this->hasher = hasher;
! 214: this->block_size = block_size;
! 215:
! 216: if (!this->hasher->allocate_hash(this->hasher, data, &this->phase1_iv.iv))
! 217: {
! 218: return FALSE;
! 219: }
! 220: if (this->phase1_iv.iv.len > this->block_size)
! 221: {
! 222: this->phase1_iv.iv.len = this->block_size;
! 223: }
! 224: DBG4(DBG_IKE, "initial IV %B", &this->phase1_iv.iv);
! 225: return TRUE;
! 226: }
! 227:
! 228: METHOD(iv_manager_t, get_iv, bool,
! 229: private_iv_manager_t *this, uint32_t mid, chunk_t *out)
! 230: {
! 231: iv_data_t *iv;
! 232:
! 233: iv = lookup_iv(this, mid);
! 234: if (iv)
! 235: {
! 236: *out = iv->iv;
! 237: return TRUE;
! 238: }
! 239: return FALSE;
! 240: }
! 241:
! 242: METHOD(iv_manager_t, update_iv, bool,
! 243: private_iv_manager_t *this, uint32_t mid, chunk_t last_block)
! 244: {
! 245: iv_data_t *iv = lookup_iv(this, mid);
! 246: if (iv)
! 247: { /* update last block */
! 248: chunk_free(&iv->last_block);
! 249: iv->last_block = chunk_clone(last_block);
! 250: return TRUE;
! 251: }
! 252: return FALSE;
! 253: }
! 254:
! 255: METHOD(iv_manager_t, confirm_iv, bool,
! 256: private_iv_manager_t *this, uint32_t mid)
! 257: {
! 258: iv_data_t *iv = lookup_iv(this, mid);
! 259: if (iv)
! 260: {
! 261: return generate_iv(this, iv);
! 262: }
! 263: return FALSE;
! 264: }
! 265:
! 266: METHOD(iv_manager_t, lookup_quick_mode, void,
! 267: private_iv_manager_t *this, uint32_t mid, chunk_t **n_i, chunk_t **n_r)
! 268: {
! 269: enumerator_t *enumerator;
! 270: qm_data_t *qm, *found = NULL;
! 271:
! 272: enumerator = this->qms->create_enumerator(this->qms);
! 273: while (enumerator->enumerate(enumerator, &qm))
! 274: {
! 275: if (qm->mid == mid)
! 276: { /* state gets moved to the front of the list */
! 277: this->qms->remove_at(this->qms, enumerator);
! 278: found = qm;
! 279: break;
! 280: }
! 281: }
! 282: enumerator->destroy(enumerator);
! 283: if (!found)
! 284: {
! 285: INIT(found,
! 286: .mid = mid,
! 287: );
! 288: }
! 289:
! 290: *n_i = &found->n_i;
! 291: *n_r = &found->n_r;
! 292:
! 293: this->qms->insert_first(this->qms, found);
! 294: /* remove least recently used state if maximum reached */
! 295: if (this->qms->get_count(this->qms) > this->max_exchanges &&
! 296: this->qms->remove_last(this->qms, (void**)&qm) == SUCCESS)
! 297: {
! 298: qm_data_destroy(qm);
! 299: }
! 300: }
! 301:
! 302: METHOD(iv_manager_t, remove_quick_mode, void,
! 303: private_iv_manager_t *this, uint32_t mid)
! 304: {
! 305: enumerator_t *enumerator;
! 306: qm_data_t *qm;
! 307:
! 308: enumerator = this->qms->create_enumerator(this->qms);
! 309: while (enumerator->enumerate(enumerator, &qm))
! 310: {
! 311: if (qm->mid == mid)
! 312: {
! 313: this->qms->remove_at(this->qms, enumerator);
! 314: qm_data_destroy(qm);
! 315: break;
! 316: }
! 317: }
! 318: enumerator->destroy(enumerator);
! 319: }
! 320:
! 321: METHOD(iv_manager_t, destroy, void,
! 322: private_iv_manager_t *this)
! 323: {
! 324: chunk_free(&this->phase1_iv.iv);
! 325: chunk_free(&this->phase1_iv.last_block);
! 326: this->ivs->destroy_function(this->ivs, (void*)iv_data_destroy);
! 327: this->qms->destroy_function(this->qms, (void*)qm_data_destroy);
! 328: free(this);
! 329: }
! 330:
! 331: iv_manager_t *iv_manager_create(int max_exchanges)
! 332: {
! 333: private_iv_manager_t *this;
! 334:
! 335: INIT(this,
! 336: .public = {
! 337: .init_iv_chain = _init_iv_chain,
! 338: .get_iv = _get_iv,
! 339: .update_iv = _update_iv,
! 340: .confirm_iv = _confirm_iv,
! 341: .lookup_quick_mode = _lookup_quick_mode,
! 342: .remove_quick_mode = _remove_quick_mode,
! 343: .destroy = _destroy,
! 344: },
! 345: .ivs = linked_list_create(),
! 346: .qms = linked_list_create(),
! 347: .max_exchanges = max_exchanges,
! 348: );
! 349:
! 350: if (!this->max_exchanges)
! 351: {
! 352: this->max_exchanges = lib->settings->get_int(lib->settings,
! 353: "%s.max_ikev1_exchanges", MAX_EXCHANGES_DEFAULT, lib->ns);
! 354: }
! 355: return &this->public;
! 356: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>