esp_context.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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. #include <limits.h>
  18. #include <stdint.h>
  19. #include "esp_context.h"
  20. #include <library.h>
  21. #include <utils/debug.h>
  22. /**
  23. * Should be a multiple of 8
  24. */
  25. #define ESP_DEFAULT_WINDOW_SIZE 128
  26. typedef struct private_esp_context_t private_esp_context_t;
  27. /**
  28. * Private additions to esp_context_t.
  29. */
  30. struct private_esp_context_t {
  31. /**
  32. * Public members
  33. */
  34. esp_context_t public;
  35. /**
  36. * AEAD wrapper or method to encrypt/decrypt/authenticate ESP packets
  37. */
  38. aead_t *aead;
  39. /**
  40. * The highest sequence number that was successfully verified
  41. * and authenticated, or assigned in an outbound context
  42. */
  43. uint32_t last_seqno;
  44. /**
  45. * The bit in the window of the highest authenticated sequence number
  46. */
  47. u_int seqno_index;
  48. /**
  49. * The size of the anti-replay window (in bits)
  50. */
  51. u_int window_size;
  52. /**
  53. * The anti-replay window buffer
  54. */
  55. chunk_t window;
  56. /**
  57. * TRUE in case of an inbound ESP context
  58. */
  59. bool inbound;
  60. };
  61. /**
  62. * Set or unset a bit in the window.
  63. */
  64. static inline void set_window_bit(private_esp_context_t *this,
  65. u_int index, bool set)
  66. {
  67. u_int i = index / CHAR_BIT;
  68. if (set)
  69. {
  70. this->window.ptr[i] |= 1 << (index % CHAR_BIT);
  71. }
  72. else
  73. {
  74. this->window.ptr[i] &= ~(1 << (index % CHAR_BIT));
  75. }
  76. }
  77. /**
  78. * Get a bit from the window.
  79. */
  80. static inline bool get_window_bit(private_esp_context_t *this, u_int index)
  81. {
  82. u_int i = index / CHAR_BIT;
  83. return this->window.ptr[i] & (1 << index % CHAR_BIT);
  84. }
  85. /**
  86. * Returns TRUE if the supplied seqno is not already marked in the window
  87. */
  88. static bool check_window(private_esp_context_t *this, uint32_t seqno)
  89. {
  90. u_int offset;
  91. offset = this->last_seqno - seqno;
  92. offset = (this->seqno_index - offset) % this->window_size;
  93. return !get_window_bit(this, offset);
  94. }
  95. METHOD(esp_context_t, verify_seqno, bool,
  96. private_esp_context_t *this, uint32_t seqno)
  97. {
  98. if (!this->inbound)
  99. {
  100. return FALSE;
  101. }
  102. if (seqno > this->last_seqno)
  103. { /* |----------------------------------------|
  104. * <---------^ ^ or <---------^ ^
  105. * WIN H S WIN H S
  106. */
  107. return TRUE;
  108. }
  109. else if (seqno > 0 && this->window_size > this->last_seqno - seqno)
  110. { /* |----------------------------------------|
  111. * <---------^ or <---------^
  112. * WIN ^ H WIN ^ H
  113. * S S
  114. */
  115. return check_window(this, seqno);
  116. }
  117. else
  118. { /* |----------------------------------------|
  119. * ^ <---------^
  120. * S WIN H
  121. */
  122. return FALSE;
  123. }
  124. }
  125. METHOD(esp_context_t, set_authenticated_seqno, void,
  126. private_esp_context_t *this, uint32_t seqno)
  127. {
  128. u_int i, shift;
  129. if (!this->inbound)
  130. {
  131. return;
  132. }
  133. if (seqno > this->last_seqno)
  134. { /* shift the window to the new highest authenticated seqno */
  135. shift = seqno - this->last_seqno;
  136. shift = shift < this->window_size ? shift : this->window_size;
  137. for (i = 0; i < shift; ++i)
  138. {
  139. this->seqno_index = (this->seqno_index + 1) % this->window_size;
  140. set_window_bit(this, this->seqno_index, FALSE);
  141. }
  142. set_window_bit(this, this->seqno_index, TRUE);
  143. this->last_seqno = seqno;
  144. }
  145. else
  146. { /* seqno is inside the window, set the corresponding window bit */
  147. i = this->last_seqno - seqno;
  148. set_window_bit(this, (this->seqno_index - i) % this->window_size, TRUE);
  149. }
  150. }
  151. METHOD(esp_context_t, get_seqno, uint32_t,
  152. private_esp_context_t *this)
  153. {
  154. return this->last_seqno;
  155. }
  156. METHOD(esp_context_t, next_seqno, bool,
  157. private_esp_context_t *this, uint32_t *seqno)
  158. {
  159. if (this->inbound || this->last_seqno == UINT32_MAX)
  160. { /* inbound or segno would cycle */
  161. return FALSE;
  162. }
  163. *seqno = ++this->last_seqno;
  164. return TRUE;
  165. }
  166. METHOD(esp_context_t, get_aead, aead_t*,
  167. private_esp_context_t *this)
  168. {
  169. return this->aead;
  170. }
  171. METHOD(esp_context_t, destroy, void,
  172. private_esp_context_t *this)
  173. {
  174. chunk_free(&this->window);
  175. DESTROY_IF(this->aead);
  176. free(this);
  177. }
  178. /**
  179. * Create an AEAD algorithm
  180. */
  181. static bool create_aead(private_esp_context_t *this, int alg,
  182. chunk_t key)
  183. {
  184. size_t salt = 0;
  185. switch (alg)
  186. {
  187. case ENCR_AES_GCM_ICV8:
  188. case ENCR_AES_GCM_ICV12:
  189. case ENCR_AES_GCM_ICV16:
  190. case ENCR_CHACHA20_POLY1305:
  191. salt = 4;
  192. break;
  193. case ENCR_AES_CCM_ICV8:
  194. case ENCR_AES_CCM_ICV12:
  195. case ENCR_AES_CCM_ICV16:
  196. case ENCR_CAMELLIA_CCM_ICV8:
  197. case ENCR_CAMELLIA_CCM_ICV12:
  198. case ENCR_CAMELLIA_CCM_ICV16:
  199. salt = 3;
  200. break;
  201. default:
  202. break;
  203. }
  204. if (salt)
  205. {
  206. this->aead = lib->crypto->create_aead(lib->crypto, alg,
  207. key.len - salt, salt);
  208. }
  209. if (!this->aead)
  210. {
  211. DBG1(DBG_ESP, "failed to create ESP context: unsupported AEAD "
  212. "algorithm %N", encryption_algorithm_names, alg);
  213. return FALSE;
  214. }
  215. if (!this->aead->set_key(this->aead, key))
  216. {
  217. DBG1(DBG_ESP, "failed to create ESP context: setting AEAD key failed");
  218. return FALSE;
  219. }
  220. return TRUE;
  221. }
  222. /**
  223. * Create AEAD wrapper around traditional encryption/integrity algorithms
  224. */
  225. static bool create_traditional(private_esp_context_t *this, int enc_alg,
  226. chunk_t enc_key, int int_alg, chunk_t int_key)
  227. {
  228. crypter_t *crypter = NULL;
  229. signer_t *signer = NULL;
  230. iv_gen_t *ivg;
  231. switch (enc_alg)
  232. {
  233. case ENCR_AES_CTR:
  234. case ENCR_CAMELLIA_CTR:
  235. /* the key includes a 4 byte salt */
  236. crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
  237. enc_key.len - 4);
  238. break;
  239. default:
  240. crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
  241. enc_key.len);
  242. break;
  243. }
  244. if (!crypter)
  245. {
  246. DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption "
  247. "algorithm %N", encryption_algorithm_names, enc_alg);
  248. goto failed;
  249. }
  250. if (!crypter->set_key(crypter, enc_key))
  251. {
  252. DBG1(DBG_ESP, "failed to create ESP context: setting encryption key "
  253. "failed");
  254. goto failed;
  255. }
  256. signer = lib->crypto->create_signer(lib->crypto, int_alg);
  257. if (!signer)
  258. {
  259. DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity "
  260. "algorithm %N", integrity_algorithm_names, int_alg);
  261. goto failed;
  262. }
  263. if (!signer->set_key(signer, int_key))
  264. {
  265. DBG1(DBG_ESP, "failed to create ESP context: setting signature key "
  266. "failed");
  267. goto failed;
  268. }
  269. ivg = iv_gen_create_for_alg(enc_alg);
  270. if (!ivg)
  271. {
  272. DBG1(DBG_ESP, "failed to create ESP context: creating iv gen failed");
  273. goto failed;
  274. }
  275. this->aead = aead_create(crypter, signer, ivg);
  276. return TRUE;
  277. failed:
  278. DESTROY_IF(crypter);
  279. DESTROY_IF(signer);
  280. return FALSE;
  281. }
  282. /**
  283. * Described in header.
  284. */
  285. esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
  286. int int_alg, chunk_t int_key, bool inbound)
  287. {
  288. private_esp_context_t *this;
  289. INIT(this,
  290. .public = {
  291. .get_aead = _get_aead,
  292. .get_seqno = _get_seqno,
  293. .next_seqno = _next_seqno,
  294. .verify_seqno = _verify_seqno,
  295. .set_authenticated_seqno = _set_authenticated_seqno,
  296. .destroy = _destroy,
  297. },
  298. .inbound = inbound,
  299. .window_size = ESP_DEFAULT_WINDOW_SIZE,
  300. );
  301. if (encryption_algorithm_is_aead(enc_alg))
  302. {
  303. if (!create_aead(this, enc_alg, enc_key))
  304. {
  305. destroy(this);
  306. return NULL;
  307. }
  308. }
  309. else
  310. {
  311. if (!create_traditional(this, enc_alg, enc_key, int_alg, int_key))
  312. {
  313. destroy(this);
  314. return NULL;
  315. }
  316. }
  317. if (inbound)
  318. {
  319. this->window = chunk_alloc(this->window_size / CHAR_BIT + 1);
  320. memset(this->window.ptr, 0, this->window.len);
  321. }
  322. return &this->public;
  323. }