Annotation of embedaddon/strongswan/src/libipsec/esp_context.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2012-2013 Tobias Brunner
! 3: * Copyright (C) 2012 Giuliano Grassi
! 4: * Copyright (C) 2012 Ralf Sager
! 5: * HSR Hochschule fuer Technik Rapperswil
! 6: *
! 7: * This program is free software; you can redistribute it and/or modify it
! 8: * under the terms of the GNU General Public License as published by the
! 9: * Free Software Foundation; either version 2 of the License, or (at your
! 10: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 11: *
! 12: * This program is distributed in the hope that it will be useful, but
! 13: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 14: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 15: * for more details.
! 16: */
! 17:
! 18: #include <limits.h>
! 19: #include <stdint.h>
! 20:
! 21: #include "esp_context.h"
! 22:
! 23: #include <library.h>
! 24: #include <utils/debug.h>
! 25:
! 26: /**
! 27: * Should be a multiple of 8
! 28: */
! 29: #define ESP_DEFAULT_WINDOW_SIZE 128
! 30:
! 31: typedef struct private_esp_context_t private_esp_context_t;
! 32:
! 33: /**
! 34: * Private additions to esp_context_t.
! 35: */
! 36: struct private_esp_context_t {
! 37:
! 38: /**
! 39: * Public members
! 40: */
! 41: esp_context_t public;
! 42:
! 43: /**
! 44: * AEAD wrapper or method to encrypt/decrypt/authenticate ESP packets
! 45: */
! 46: aead_t *aead;
! 47:
! 48: /**
! 49: * The highest sequence number that was successfully verified
! 50: * and authenticated, or assigned in an outbound context
! 51: */
! 52: uint32_t last_seqno;
! 53:
! 54: /**
! 55: * The bit in the window of the highest authenticated sequence number
! 56: */
! 57: u_int seqno_index;
! 58:
! 59: /**
! 60: * The size of the anti-replay window (in bits)
! 61: */
! 62: u_int window_size;
! 63:
! 64: /**
! 65: * The anti-replay window buffer
! 66: */
! 67: chunk_t window;
! 68:
! 69: /**
! 70: * TRUE in case of an inbound ESP context
! 71: */
! 72: bool inbound;
! 73: };
! 74:
! 75: /**
! 76: * Set or unset a bit in the window.
! 77: */
! 78: static inline void set_window_bit(private_esp_context_t *this,
! 79: u_int index, bool set)
! 80: {
! 81: u_int i = index / CHAR_BIT;
! 82:
! 83: if (set)
! 84: {
! 85: this->window.ptr[i] |= 1 << (index % CHAR_BIT);
! 86: }
! 87: else
! 88: {
! 89: this->window.ptr[i] &= ~(1 << (index % CHAR_BIT));
! 90: }
! 91: }
! 92:
! 93: /**
! 94: * Get a bit from the window.
! 95: */
! 96: static inline bool get_window_bit(private_esp_context_t *this, u_int index)
! 97: {
! 98: u_int i = index / CHAR_BIT;
! 99:
! 100: return this->window.ptr[i] & (1 << index % CHAR_BIT);
! 101: }
! 102:
! 103: /**
! 104: * Returns TRUE if the supplied seqno is not already marked in the window
! 105: */
! 106: static bool check_window(private_esp_context_t *this, uint32_t seqno)
! 107: {
! 108: u_int offset;
! 109:
! 110: offset = this->last_seqno - seqno;
! 111: offset = (this->seqno_index - offset) % this->window_size;
! 112: return !get_window_bit(this, offset);
! 113: }
! 114:
! 115: METHOD(esp_context_t, verify_seqno, bool,
! 116: private_esp_context_t *this, uint32_t seqno)
! 117: {
! 118: if (!this->inbound)
! 119: {
! 120: return FALSE;
! 121: }
! 122:
! 123: if (seqno > this->last_seqno)
! 124: { /* |----------------------------------------|
! 125: * <---------^ ^ or <---------^ ^
! 126: * WIN H S WIN H S
! 127: */
! 128: return TRUE;
! 129: }
! 130: else if (seqno > 0 && this->window_size > this->last_seqno - seqno)
! 131: { /* |----------------------------------------|
! 132: * <---------^ or <---------^
! 133: * WIN ^ H WIN ^ H
! 134: * S S
! 135: */
! 136: return check_window(this, seqno);
! 137: }
! 138: else
! 139: { /* |----------------------------------------|
! 140: * ^ <---------^
! 141: * S WIN H
! 142: */
! 143: return FALSE;
! 144: }
! 145: }
! 146:
! 147: METHOD(esp_context_t, set_authenticated_seqno, void,
! 148: private_esp_context_t *this, uint32_t seqno)
! 149: {
! 150: u_int i, shift;
! 151:
! 152: if (!this->inbound)
! 153: {
! 154: return;
! 155: }
! 156:
! 157: if (seqno > this->last_seqno)
! 158: { /* shift the window to the new highest authenticated seqno */
! 159: shift = seqno - this->last_seqno;
! 160: shift = shift < this->window_size ? shift : this->window_size;
! 161: for (i = 0; i < shift; ++i)
! 162: {
! 163: this->seqno_index = (this->seqno_index + 1) % this->window_size;
! 164: set_window_bit(this, this->seqno_index, FALSE);
! 165: }
! 166: set_window_bit(this, this->seqno_index, TRUE);
! 167: this->last_seqno = seqno;
! 168: }
! 169: else
! 170: { /* seqno is inside the window, set the corresponding window bit */
! 171: i = this->last_seqno - seqno;
! 172: set_window_bit(this, (this->seqno_index - i) % this->window_size, TRUE);
! 173: }
! 174: }
! 175:
! 176: METHOD(esp_context_t, get_seqno, uint32_t,
! 177: private_esp_context_t *this)
! 178: {
! 179: return this->last_seqno;
! 180: }
! 181:
! 182: METHOD(esp_context_t, next_seqno, bool,
! 183: private_esp_context_t *this, uint32_t *seqno)
! 184: {
! 185: if (this->inbound || this->last_seqno == UINT32_MAX)
! 186: { /* inbound or segno would cycle */
! 187: return FALSE;
! 188: }
! 189: *seqno = ++this->last_seqno;
! 190: return TRUE;
! 191: }
! 192:
! 193: METHOD(esp_context_t, get_aead, aead_t*,
! 194: private_esp_context_t *this)
! 195: {
! 196: return this->aead;
! 197: }
! 198:
! 199: METHOD(esp_context_t, destroy, void,
! 200: private_esp_context_t *this)
! 201: {
! 202: chunk_free(&this->window);
! 203: DESTROY_IF(this->aead);
! 204: free(this);
! 205: }
! 206:
! 207: /**
! 208: * Create an AEAD algorithm
! 209: */
! 210: static bool create_aead(private_esp_context_t *this, int alg,
! 211: chunk_t key)
! 212: {
! 213: size_t salt = 0;
! 214:
! 215: switch (alg)
! 216: {
! 217: case ENCR_AES_GCM_ICV8:
! 218: case ENCR_AES_GCM_ICV12:
! 219: case ENCR_AES_GCM_ICV16:
! 220: case ENCR_CHACHA20_POLY1305:
! 221: salt = 4;
! 222: break;
! 223: case ENCR_AES_CCM_ICV8:
! 224: case ENCR_AES_CCM_ICV12:
! 225: case ENCR_AES_CCM_ICV16:
! 226: case ENCR_CAMELLIA_CCM_ICV8:
! 227: case ENCR_CAMELLIA_CCM_ICV12:
! 228: case ENCR_CAMELLIA_CCM_ICV16:
! 229: salt = 3;
! 230: break;
! 231: default:
! 232: break;
! 233: }
! 234: if (salt)
! 235: {
! 236: this->aead = lib->crypto->create_aead(lib->crypto, alg,
! 237: key.len - salt, salt);
! 238: }
! 239: if (!this->aead)
! 240: {
! 241: DBG1(DBG_ESP, "failed to create ESP context: unsupported AEAD "
! 242: "algorithm %N", encryption_algorithm_names, alg);
! 243: return FALSE;
! 244: }
! 245: if (!this->aead->set_key(this->aead, key))
! 246: {
! 247: DBG1(DBG_ESP, "failed to create ESP context: setting AEAD key failed");
! 248: return FALSE;
! 249: }
! 250: return TRUE;
! 251: }
! 252:
! 253: /**
! 254: * Create AEAD wrapper around traditional encryption/integrity algorithms
! 255: */
! 256: static bool create_traditional(private_esp_context_t *this, int enc_alg,
! 257: chunk_t enc_key, int int_alg, chunk_t int_key)
! 258: {
! 259: crypter_t *crypter = NULL;
! 260: signer_t *signer = NULL;
! 261: iv_gen_t *ivg;
! 262:
! 263: switch (enc_alg)
! 264: {
! 265: case ENCR_AES_CTR:
! 266: case ENCR_CAMELLIA_CTR:
! 267: /* the key includes a 4 byte salt */
! 268: crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
! 269: enc_key.len - 4);
! 270: break;
! 271: default:
! 272: crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
! 273: enc_key.len);
! 274: break;
! 275: }
! 276: if (!crypter)
! 277: {
! 278: DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption "
! 279: "algorithm %N", encryption_algorithm_names, enc_alg);
! 280: goto failed;
! 281: }
! 282: if (!crypter->set_key(crypter, enc_key))
! 283: {
! 284: DBG1(DBG_ESP, "failed to create ESP context: setting encryption key "
! 285: "failed");
! 286: goto failed;
! 287: }
! 288:
! 289: signer = lib->crypto->create_signer(lib->crypto, int_alg);
! 290: if (!signer)
! 291: {
! 292: DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity "
! 293: "algorithm %N", integrity_algorithm_names, int_alg);
! 294: goto failed;
! 295: }
! 296: if (!signer->set_key(signer, int_key))
! 297: {
! 298: DBG1(DBG_ESP, "failed to create ESP context: setting signature key "
! 299: "failed");
! 300: goto failed;
! 301: }
! 302: ivg = iv_gen_create_for_alg(enc_alg);
! 303: if (!ivg)
! 304: {
! 305: DBG1(DBG_ESP, "failed to create ESP context: creating iv gen failed");
! 306: goto failed;
! 307: }
! 308: this->aead = aead_create(crypter, signer, ivg);
! 309: return TRUE;
! 310:
! 311: failed:
! 312: DESTROY_IF(crypter);
! 313: DESTROY_IF(signer);
! 314: return FALSE;
! 315: }
! 316:
! 317: /**
! 318: * Described in header.
! 319: */
! 320: esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
! 321: int int_alg, chunk_t int_key, bool inbound)
! 322: {
! 323: private_esp_context_t *this;
! 324:
! 325: INIT(this,
! 326: .public = {
! 327: .get_aead = _get_aead,
! 328: .get_seqno = _get_seqno,
! 329: .next_seqno = _next_seqno,
! 330: .verify_seqno = _verify_seqno,
! 331: .set_authenticated_seqno = _set_authenticated_seqno,
! 332: .destroy = _destroy,
! 333: },
! 334: .inbound = inbound,
! 335: .window_size = ESP_DEFAULT_WINDOW_SIZE,
! 336: );
! 337:
! 338: if (encryption_algorithm_is_aead(enc_alg))
! 339: {
! 340: if (!create_aead(this, enc_alg, enc_key))
! 341: {
! 342: destroy(this);
! 343: return NULL;
! 344: }
! 345: }
! 346: else
! 347: {
! 348: if (!create_traditional(this, enc_alg, enc_key, int_alg, int_key))
! 349: {
! 350: destroy(this);
! 351: return NULL;
! 352: }
! 353: }
! 354:
! 355: if (inbound)
! 356: {
! 357: this->window = chunk_alloc(this->window_size / CHAR_BIT + 1);
! 358: memset(this->window.ptr, 0, this->window.len);
! 359: }
! 360: return &this->public;
! 361: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>