18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * IKEv2 common routines for initiator and responder 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/md5.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/sha1.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ikev2_common.h" 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 191d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidtstatic const struct ikev2_integ_alg ikev2_integ_algs[] = { 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { AUTH_HMAC_SHA1_96, 20, 12 }, 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { AUTH_HMAC_MD5_96, 16, 12 } 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define NUM_INTEG_ALGS ARRAY_SIZE(ikev2_integ_algs) 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 271d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidtstatic const struct ikev2_prf_alg ikev2_prf_algs[] = { 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { PRF_HMAC_SHA1, 20, 20 }, 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { PRF_HMAC_MD5, 16, 16 } 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define NUM_PRF_ALGS ARRAY_SIZE(ikev2_prf_algs) 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 351d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidtstatic const struct ikev2_encr_alg ikev2_encr_algs[] = { 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { ENCR_AES_CBC, 16, 16 }, /* only 128-bit keys supported for now */ 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { ENCR_3DES, 24, 8 } 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define NUM_ENCR_ALGS ARRAY_SIZE(ikev2_encr_algs) 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct ikev2_integ_alg * ikev2_get_integ(int id) 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < NUM_INTEG_ALGS; i++) { 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_integ_algs[i].id == id) 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return &ikev2_integ_algs[i]; 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data, 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t data_len, u8 *hash) 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 tmphash[IKEV2_MAX_HASH_LEN]; 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (alg) { 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case AUTH_HMAC_SHA1_96: 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key_len != 20) 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_sha1(key, key_len, data, data_len, tmphash); 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(hash, tmphash, 12); 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case AUTH_HMAC_MD5_96: 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key_len != 16) 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5(key, key_len, data, data_len, tmphash); 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(hash, tmphash, 12); 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct ikev2_prf_alg * ikev2_get_prf(int id) 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < NUM_PRF_ALGS; i++) { 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_prf_algs[i].id == id) 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return &ikev2_prf_algs[i]; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_prf_hash(int alg, const u8 *key, size_t key_len, 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t num_elem, const u8 *addr[], const size_t *len, 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *hash) 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (alg) { 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case PRF_HMAC_SHA1: 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_sha1_vector(key, key_len, num_elem, addr, len, hash); 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case PRF_HMAC_MD5: 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hmac_md5_vector(key, key_len, num_elem, addr, len, hash); 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_prf_plus(int alg, const u8 *key, size_t key_len, 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *data, size_t data_len, 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *out, size_t out_len) 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[IKEV2_MAX_HASH_LEN]; 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t hash_len; 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 iter, *pos, *end; 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[3]; 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len[3]; 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_prf_alg *prf; 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int res; 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prf = ikev2_get_prf(alg); 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (prf == NULL) 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash_len = prf->hash_len; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = hash; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[0] = hash_len; 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = data; 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[1] = data_len; 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = &iter; 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len[2] = 1; 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = out; 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = out + out_len; 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iter = 1; 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < end) { 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t clen; 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iter == 1) 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1], 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &len[1], hash); 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = ikev2_prf_hash(alg, key, key_len, 3, addr, len, 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash); 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res < 0) 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt clen = hash_len; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((int) clen > end - pos) 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt clen = end - pos; 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, hash, clen); 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += clen; 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iter++; 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct ikev2_encr_alg * ikev2_get_encr(int id) 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < NUM_ENCR_ALGS; i++) { 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_encr_algs[i].id == id) 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return &ikev2_encr_algs[i]; 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *plain, u8 *crypt, size_t len) 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct crypto_cipher *cipher; 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int encr_alg; 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (alg) { 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ENCR_3DES: 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encr_alg = CRYPTO_CIPHER_ALG_3DES; 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ENCR_AES_CBC: 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encr_alg = CRYPTO_CIPHER_ALG_AES; 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cipher = crypto_cipher_init(encr_alg, iv, key, key_len); 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cipher == NULL) { 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) { 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Encryption failed"); 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt crypto_cipher_deinit(cipher); 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt crypto_cipher_deinit(cipher); 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *crypt, u8 *plain, size_t len) 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct crypto_cipher *cipher; 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int encr_alg; 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (alg) { 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ENCR_3DES: 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encr_alg = CRYPTO_CIPHER_ALG_3DES; 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ENCR_AES_CBC: 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encr_alg = CRYPTO_CIPHER_ALG_AES; 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cipher = crypto_cipher_init(encr_alg, iv, key, key_len); 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cipher == NULL) { 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) { 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Decryption failed"); 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt crypto_cipher_deinit(cipher); 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt crypto_cipher_deinit(cipher); 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_parse_payloads(struct ikev2_payloads *payloads, 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 next_payload, const u8 *pos, const u8 *end) 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_payload_hdr *phdr; 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(payloads, 0, sizeof(*payloads)); 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) { 2546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt unsigned int plen, pdatalen, left; 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pdata; 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u", 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_payload); 2586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (end < pos) 2596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 2606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt left = end - pos; 2616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (left < sizeof(*phdr)) { 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Too short message for " 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "payload header (left=%ld)", 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (long) (end - pos)); 2656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt return -1; 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr = (const struct ikev2_payload_hdr *) pos; 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = WPA_GET_BE16(phdr->payload_length); 2696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt if (plen < sizeof(*phdr) || plen > left) { 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Invalid payload header " 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "length %d", plen); 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Flags: 0x%x" 2766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt " Payload Length: %u", 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->next_payload, phdr->flags, plen); 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pdata = (const u8 *) (phdr + 1); 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pdatalen = plen - sizeof(*phdr); 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (next_payload) { 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_PAYLOAD_SA: 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Payload: Security " 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Association"); 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->sa = pdata; 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->sa_len = pdatalen; 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_PAYLOAD_KEY_EXCHANGE: 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Payload: Key " 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Exchange"); 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->ke = pdata; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->ke_len = pdatalen; 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_PAYLOAD_IDi: 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDi"); 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->idi = pdata; 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->idi_len = pdatalen; 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_PAYLOAD_IDr: 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDr"); 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->idr = pdata; 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->idr_len = pdatalen; 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_PAYLOAD_CERTIFICATE: 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Payload: Certificate"); 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->cert = pdata; 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->cert_len = pdatalen; 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_PAYLOAD_AUTHENTICATION: 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Payload: " 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Authentication"); 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->auth = pdata; 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->auth_len = pdatalen; 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_PAYLOAD_NONCE: 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Payload: Nonce"); 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->nonce = pdata; 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->nonce_len = pdatalen; 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_PAYLOAD_ENCRYPTED: 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Payload: Encrypted"); 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->encrypted = pdata; 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->encrypted_len = pdatalen; 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case IKEV2_PAYLOAD_NOTIFICATION: 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Payload: " 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Notification"); 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->notification = pdata; 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->notification_len = pdatalen; 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) { 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported " 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "critical payload %u - reject the " 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "entire message", next_payload); 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Skipped " 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "unsupported payload %u", 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_payload); 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (next_payload == IKEV2_PAYLOAD_ENCRYPTED && 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos + plen == end) { 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Next Payload in the case of Encrypted Payload is 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * actually the payload type for the first embedded 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * payload. 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt payloads->encr_next_payload = phdr->next_payload; 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD; 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_payload = phdr->next_payload; 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += plen; 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos != end) { 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after " 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "payloads"); 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg, 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *ID, size_t ID_len, u8 ID_type, 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_keys *keys, int initiator, 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *shared_secret, size_t shared_secret_len, 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *nonce, size_t nonce_len, 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *key_pad, size_t key_pad_len, 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *auth_data) 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t sign_len, buf_len; 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN]; 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_prf_alg *prf; 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr; 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prf = ikev2_get_prf(prf_alg); 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sign_msg == NULL || ID == NULL || SK_p == NULL || 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt shared_secret == NULL || nonce == NULL || prf == NULL) 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* prf(SK_pi/r,IDi/r') */ 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf_len = 4 + ID_len; 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf = os_zalloc(buf_len); 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buf == NULL) 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[0] = ID_type; 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(buf + 4, ID, ID_len); 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len, 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1, (const u8 **) &buf, &buf_len, hash) < 0) { 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(buf); 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */ 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len; 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sign_data = os_malloc(sign_len); 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sign_data == NULL) 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = sign_data; 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg)); 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += wpabuf_len(sign_msg); 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, nonce, nonce_len); 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += nonce_len; 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(pos, hash, prf->hash_len); 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* AUTH = prf(prf(Shared Secret, key pad, sign_data) */ 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1, 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &key_pad, &key_pad_len, hash) < 0 || 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_prf_hash(prf->id, hash, prf->hash_len, 1, 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (const u8 **) &sign_data, &sign_len, auth_data) < 0) 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(sign_data); 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(sign_data); 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtu8 * ikev2_decrypt_payload(int encr_id, int integ_id, 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_keys *keys, int initiator, 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_hdr *hdr, 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *encrypted, size_t encrypted_len, 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t *res_len) 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t iv_len; 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end, *iv, *integ; 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[IKEV2_MAX_HASH_LEN], *decrypted; 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t decrypted_len, pad_len; 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_integ_alg *integ_alg; 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_encr_alg *encr_alg; 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (encrypted == NULL) { 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH"); 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encr_alg = ikev2_get_encr(encr_id); 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (encr_alg == NULL) { 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iv_len = encr_alg->block_size; 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt integ_alg = ikev2_get_integ(integ_id); 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (integ_alg == NULL) { 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (encrypted_len < iv_len + 1 + integ_alg->hash_len) { 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity " 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Checksum"); 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iv = encrypted; 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = iv + iv_len; 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = encrypted + encrypted_len; 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt integ = end - integ_alg->hash_len; 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (SK_a == NULL) { 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (const u8 *) hdr, 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt integ - (const u8 *) hdr, hash) < 0) { 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity " 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "hash"); 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 484c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt if (os_memcmp_const(integ, hash, integ_alg->hash_len) != 0) { 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum " 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Data"); 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (SK_e == NULL) { 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt decrypted_len = integ - pos; 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt decrypted = os_malloc(decrypted_len); 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (decrypted == NULL) 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos, 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt decrypted, decrypted_len) < 0) { 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(decrypted); 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pad_len = decrypted[decrypted_len - 1]; 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (decrypted_len < pad_len + 1) { 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted " 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "payload"); 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(decrypted); 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt decrypted_len -= pad_len + 1; 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *res_len = decrypted_len; 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return decrypted; 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ikev2_update_hdr(struct wpabuf *msg) 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_hdr *hdr; 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Update lenth field in HDR */ 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr = wpabuf_mhead(msg); 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE32(hdr->length, wpabuf_len(msg)); 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys, 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int initiator, struct wpabuf *msg, 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *plain, u8 next_payload) 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_payload_hdr *phdr; 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t plen; 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t iv_len, pad_len; 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *icv, *iv; 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_integ_alg *integ_alg; 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_encr_alg *encr_alg; 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload"); 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Encr - RFC 4306, Sect. 3.14 */ 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt encr_alg = ikev2_get_encr(encr_id); 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (encr_alg == NULL) { 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iv_len = encr_alg->block_size; 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt integ_alg = ikev2_get_integ(integ_id); 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (integ_alg == NULL) { 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (SK_e == NULL) { 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (SK_a == NULL) { 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr = wpabuf_put(msg, sizeof(*phdr)); 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->next_payload = next_payload; 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt phdr->flags = 0; 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iv = wpabuf_put(msg, iv_len); 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (random_get_bytes(iv, iv_len)) { 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "IKEV2: Could not generate IV"); 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len; 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pad_len == iv_len) 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pad_len = 0; 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put(plain, pad_len); 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(plain, pad_len); 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_head(plain), wpabuf_mhead(plain), 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(plain)) < 0) 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_buf(msg, plain); 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Need to update all headers (Length fields) prior to hash func */ 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt icv = wpabuf_put(msg, integ_alg->hash_len); 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt WPA_PUT_BE16(phdr->payload_length, plen); 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_update_hdr(msg); 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_head(msg), 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_len(msg) - integ_alg->hash_len, icv); 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_keys_set(struct ikev2_keys *keys) 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei && 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_er && keys->SK_pi && keys->SK_pr; 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ikev2_free_keys(struct ikev2_keys *keys) 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(keys->SK_d); 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(keys->SK_ai); 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(keys->SK_ar); 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(keys->SK_ei); 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(keys->SK_er); 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(keys->SK_pi); 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(keys->SK_pr); 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er = 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_pi = keys->SK_pr = NULL; 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf, 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_integ_alg *integ, 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ikev2_encr_alg *encr, 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *skeyseed, const u8 *data, size_t data_len, 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ikev2_keys *keys) 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *keybuf, *pos; 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t keybuf_len; 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } = 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * prf+(SKEYSEED, Ni | Nr | SPIi | SPIr ) 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_free_keys(keys); 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_d_len = prf->key_len; 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_integ_len = integ->key_len; 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_encr_len = encr->key_len; 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_prf_len = prf->key_len; 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len + 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2 * keys->SK_encr_len + 2 * keys->SK_prf_len; 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keybuf = os_malloc(keybuf_len); 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keybuf == NULL) 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len, 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data, data_len, keybuf, keybuf_len)) { 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(keybuf); 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = keybuf; 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_d = os_malloc(keys->SK_d_len); 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys->SK_d) { 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(keys->SK_d, pos, keys->SK_d_len); 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d", 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_d, keys->SK_d_len); 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += keys->SK_d_len; 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_ai = os_malloc(keys->SK_integ_len); 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys->SK_ai) { 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(keys->SK_ai, pos, keys->SK_integ_len); 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai", 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_ai, keys->SK_integ_len); 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += keys->SK_integ_len; 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_ar = os_malloc(keys->SK_integ_len); 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys->SK_ar) { 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(keys->SK_ar, pos, keys->SK_integ_len); 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar", 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_ar, keys->SK_integ_len); 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += keys->SK_integ_len; 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_ei = os_malloc(keys->SK_encr_len); 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys->SK_ei) { 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(keys->SK_ei, pos, keys->SK_encr_len); 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei", 6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_ei, keys->SK_encr_len); 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += keys->SK_encr_len; 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_er = os_malloc(keys->SK_encr_len); 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys->SK_er) { 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(keys->SK_er, pos, keys->SK_encr_len); 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er", 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_er, keys->SK_encr_len); 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += keys->SK_encr_len; 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_pi = os_malloc(keys->SK_prf_len); 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys->SK_pi) { 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(keys->SK_pi, pos, keys->SK_prf_len); 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi", 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_pi, keys->SK_prf_len); 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += keys->SK_prf_len; 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_pr = os_malloc(keys->SK_prf_len); 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (keys->SK_pr) { 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(keys->SK_pr, pos, keys->SK_prf_len); 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr", 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt keys->SK_pr, keys->SK_prf_len); 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(keybuf); 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ikev2_keys_set(keys)) { 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ikev2_free_keys(keys); 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 727