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