ikev2_common.c revision 289549
1189251Ssam/* 2189251Ssam * IKEv2 common routines for initiator and responder 3189251Ssam * Copyright (c) 2007, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12214734Srpaulo#include "crypto/crypto.h" 13214734Srpaulo#include "crypto/md5.h" 14214734Srpaulo#include "crypto/sha1.h" 15252726Srpaulo#include "crypto/random.h" 16189251Ssam#include "ikev2_common.h" 17189251Ssam 18189251Ssam 19289549Srpaulostatic const struct ikev2_integ_alg ikev2_integ_algs[] = { 20189251Ssam { AUTH_HMAC_SHA1_96, 20, 12 }, 21189251Ssam { AUTH_HMAC_MD5_96, 16, 12 } 22189251Ssam}; 23189251Ssam 24281806Srpaulo#define NUM_INTEG_ALGS ARRAY_SIZE(ikev2_integ_algs) 25189251Ssam 26189251Ssam 27289549Srpaulostatic const struct ikev2_prf_alg ikev2_prf_algs[] = { 28189251Ssam { PRF_HMAC_SHA1, 20, 20 }, 29189251Ssam { PRF_HMAC_MD5, 16, 16 } 30189251Ssam}; 31189251Ssam 32281806Srpaulo#define NUM_PRF_ALGS ARRAY_SIZE(ikev2_prf_algs) 33189251Ssam 34189251Ssam 35289549Srpaulostatic const struct ikev2_encr_alg ikev2_encr_algs[] = { 36189251Ssam { ENCR_AES_CBC, 16, 16 }, /* only 128-bit keys supported for now */ 37189251Ssam { ENCR_3DES, 24, 8 } 38189251Ssam}; 39189251Ssam 40281806Srpaulo#define NUM_ENCR_ALGS ARRAY_SIZE(ikev2_encr_algs) 41189251Ssam 42189251Ssam 43189251Ssamconst struct ikev2_integ_alg * ikev2_get_integ(int id) 44189251Ssam{ 45189251Ssam size_t i; 46189251Ssam 47189251Ssam for (i = 0; i < NUM_INTEG_ALGS; i++) { 48189251Ssam if (ikev2_integ_algs[i].id == id) 49189251Ssam return &ikev2_integ_algs[i]; 50189251Ssam } 51189251Ssam 52189251Ssam return NULL; 53189251Ssam} 54189251Ssam 55189251Ssam 56189251Ssamint ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data, 57189251Ssam size_t data_len, u8 *hash) 58189251Ssam{ 59189251Ssam u8 tmphash[IKEV2_MAX_HASH_LEN]; 60189251Ssam 61189251Ssam switch (alg) { 62189251Ssam case AUTH_HMAC_SHA1_96: 63189251Ssam if (key_len != 20) 64189251Ssam return -1; 65189251Ssam hmac_sha1(key, key_len, data, data_len, tmphash); 66189251Ssam os_memcpy(hash, tmphash, 12); 67189251Ssam break; 68189251Ssam case AUTH_HMAC_MD5_96: 69189251Ssam if (key_len != 16) 70189251Ssam return -1; 71189251Ssam hmac_md5(key, key_len, data, data_len, tmphash); 72189251Ssam os_memcpy(hash, tmphash, 12); 73189251Ssam break; 74189251Ssam default: 75189251Ssam return -1; 76189251Ssam } 77189251Ssam 78189251Ssam return 0; 79189251Ssam} 80189251Ssam 81189251Ssam 82189251Ssamconst struct ikev2_prf_alg * ikev2_get_prf(int id) 83189251Ssam{ 84189251Ssam size_t i; 85189251Ssam 86189251Ssam for (i = 0; i < NUM_PRF_ALGS; i++) { 87189251Ssam if (ikev2_prf_algs[i].id == id) 88189251Ssam return &ikev2_prf_algs[i]; 89189251Ssam } 90189251Ssam 91189251Ssam return NULL; 92189251Ssam} 93189251Ssam 94189251Ssam 95189251Ssamint ikev2_prf_hash(int alg, const u8 *key, size_t key_len, 96189251Ssam size_t num_elem, const u8 *addr[], const size_t *len, 97189251Ssam u8 *hash) 98189251Ssam{ 99189251Ssam switch (alg) { 100189251Ssam case PRF_HMAC_SHA1: 101189251Ssam hmac_sha1_vector(key, key_len, num_elem, addr, len, hash); 102189251Ssam break; 103189251Ssam case PRF_HMAC_MD5: 104189251Ssam hmac_md5_vector(key, key_len, num_elem, addr, len, hash); 105189251Ssam break; 106189251Ssam default: 107189251Ssam return -1; 108189251Ssam } 109189251Ssam 110189251Ssam return 0; 111189251Ssam} 112189251Ssam 113189251Ssam 114189251Ssamint ikev2_prf_plus(int alg, const u8 *key, size_t key_len, 115189251Ssam const u8 *data, size_t data_len, 116189251Ssam u8 *out, size_t out_len) 117189251Ssam{ 118189251Ssam u8 hash[IKEV2_MAX_HASH_LEN]; 119189251Ssam size_t hash_len; 120189251Ssam u8 iter, *pos, *end; 121189251Ssam const u8 *addr[3]; 122189251Ssam size_t len[3]; 123189251Ssam const struct ikev2_prf_alg *prf; 124189251Ssam int res; 125189251Ssam 126189251Ssam prf = ikev2_get_prf(alg); 127189251Ssam if (prf == NULL) 128189251Ssam return -1; 129189251Ssam hash_len = prf->hash_len; 130189251Ssam 131189251Ssam addr[0] = hash; 132189251Ssam len[0] = hash_len; 133189251Ssam addr[1] = data; 134189251Ssam len[1] = data_len; 135189251Ssam addr[2] = &iter; 136189251Ssam len[2] = 1; 137189251Ssam 138189251Ssam pos = out; 139189251Ssam end = out + out_len; 140189251Ssam iter = 1; 141189251Ssam while (pos < end) { 142189251Ssam size_t clen; 143189251Ssam if (iter == 1) 144189251Ssam res = ikev2_prf_hash(alg, key, key_len, 2, &addr[1], 145189251Ssam &len[1], hash); 146189251Ssam else 147189251Ssam res = ikev2_prf_hash(alg, key, key_len, 3, addr, len, 148189251Ssam hash); 149189251Ssam if (res < 0) 150189251Ssam return -1; 151189251Ssam clen = hash_len; 152189251Ssam if ((int) clen > end - pos) 153189251Ssam clen = end - pos; 154189251Ssam os_memcpy(pos, hash, clen); 155189251Ssam pos += clen; 156189251Ssam iter++; 157189251Ssam } 158189251Ssam 159189251Ssam return 0; 160189251Ssam} 161189251Ssam 162189251Ssam 163189251Ssamconst struct ikev2_encr_alg * ikev2_get_encr(int id) 164189251Ssam{ 165189251Ssam size_t i; 166189251Ssam 167189251Ssam for (i = 0; i < NUM_ENCR_ALGS; i++) { 168189251Ssam if (ikev2_encr_algs[i].id == id) 169189251Ssam return &ikev2_encr_algs[i]; 170189251Ssam } 171189251Ssam 172189251Ssam return NULL; 173189251Ssam} 174189251Ssam 175189251Ssam 176189251Ssamint ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, 177189251Ssam const u8 *plain, u8 *crypt, size_t len) 178189251Ssam{ 179189251Ssam struct crypto_cipher *cipher; 180189251Ssam int encr_alg; 181189251Ssam 182189251Ssam switch (alg) { 183189251Ssam case ENCR_3DES: 184189251Ssam encr_alg = CRYPTO_CIPHER_ALG_3DES; 185189251Ssam break; 186189251Ssam case ENCR_AES_CBC: 187189251Ssam encr_alg = CRYPTO_CIPHER_ALG_AES; 188189251Ssam break; 189189251Ssam default: 190189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); 191189251Ssam return -1; 192189251Ssam } 193189251Ssam 194189251Ssam cipher = crypto_cipher_init(encr_alg, iv, key, key_len); 195189251Ssam if (cipher == NULL) { 196189251Ssam wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); 197189251Ssam return -1; 198189251Ssam } 199189251Ssam 200189251Ssam if (crypto_cipher_encrypt(cipher, plain, crypt, len) < 0) { 201189251Ssam wpa_printf(MSG_INFO, "IKEV2: Encryption failed"); 202189251Ssam crypto_cipher_deinit(cipher); 203189251Ssam return -1; 204189251Ssam } 205189251Ssam crypto_cipher_deinit(cipher); 206189251Ssam 207189251Ssam return 0; 208189251Ssam} 209189251Ssam 210189251Ssam 211189251Ssamint ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, 212189251Ssam const u8 *crypt, u8 *plain, size_t len) 213189251Ssam{ 214189251Ssam struct crypto_cipher *cipher; 215189251Ssam int encr_alg; 216189251Ssam 217189251Ssam switch (alg) { 218189251Ssam case ENCR_3DES: 219189251Ssam encr_alg = CRYPTO_CIPHER_ALG_3DES; 220189251Ssam break; 221189251Ssam case ENCR_AES_CBC: 222189251Ssam encr_alg = CRYPTO_CIPHER_ALG_AES; 223189251Ssam break; 224189251Ssam default: 225189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Unsupported encr alg %d", alg); 226189251Ssam return -1; 227189251Ssam } 228189251Ssam 229189251Ssam cipher = crypto_cipher_init(encr_alg, iv, key, key_len); 230189251Ssam if (cipher == NULL) { 231189251Ssam wpa_printf(MSG_INFO, "IKEV2: Failed to initialize cipher"); 232189251Ssam return -1; 233189251Ssam } 234189251Ssam 235189251Ssam if (crypto_cipher_decrypt(cipher, crypt, plain, len) < 0) { 236189251Ssam wpa_printf(MSG_INFO, "IKEV2: Decryption failed"); 237189251Ssam crypto_cipher_deinit(cipher); 238189251Ssam return -1; 239189251Ssam } 240189251Ssam crypto_cipher_deinit(cipher); 241189251Ssam 242189251Ssam return 0; 243189251Ssam} 244189251Ssam 245189251Ssam 246189251Ssamint ikev2_parse_payloads(struct ikev2_payloads *payloads, 247189251Ssam u8 next_payload, const u8 *pos, const u8 *end) 248189251Ssam{ 249189251Ssam const struct ikev2_payload_hdr *phdr; 250189251Ssam 251189251Ssam os_memset(payloads, 0, sizeof(*payloads)); 252189251Ssam 253189251Ssam while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) { 254281806Srpaulo unsigned int plen, pdatalen, left; 255189251Ssam const u8 *pdata; 256189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u", 257189251Ssam next_payload); 258281806Srpaulo if (end < pos) 259281806Srpaulo return -1; 260281806Srpaulo left = end - pos; 261281806Srpaulo if (left < sizeof(*phdr)) { 262189251Ssam wpa_printf(MSG_INFO, "IKEV2: Too short message for " 263189251Ssam "payload header (left=%ld)", 264189251Ssam (long) (end - pos)); 265281806Srpaulo return -1; 266189251Ssam } 267189251Ssam phdr = (const struct ikev2_payload_hdr *) pos; 268189251Ssam plen = WPA_GET_BE16(phdr->payload_length); 269281806Srpaulo if (plen < sizeof(*phdr) || plen > left) { 270189251Ssam wpa_printf(MSG_INFO, "IKEV2: Invalid payload header " 271189251Ssam "length %d", plen); 272189251Ssam return -1; 273189251Ssam } 274189251Ssam 275189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Next Payload: %u Flags: 0x%x" 276281806Srpaulo " Payload Length: %u", 277189251Ssam phdr->next_payload, phdr->flags, plen); 278189251Ssam 279189251Ssam pdata = (const u8 *) (phdr + 1); 280189251Ssam pdatalen = plen - sizeof(*phdr); 281189251Ssam 282189251Ssam switch (next_payload) { 283189251Ssam case IKEV2_PAYLOAD_SA: 284189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Payload: Security " 285189251Ssam "Association"); 286189251Ssam payloads->sa = pdata; 287189251Ssam payloads->sa_len = pdatalen; 288189251Ssam break; 289189251Ssam case IKEV2_PAYLOAD_KEY_EXCHANGE: 290189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Payload: Key " 291189251Ssam "Exchange"); 292189251Ssam payloads->ke = pdata; 293189251Ssam payloads->ke_len = pdatalen; 294189251Ssam break; 295189251Ssam case IKEV2_PAYLOAD_IDi: 296189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDi"); 297189251Ssam payloads->idi = pdata; 298189251Ssam payloads->idi_len = pdatalen; 299189251Ssam break; 300189251Ssam case IKEV2_PAYLOAD_IDr: 301189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Payload: IDr"); 302189251Ssam payloads->idr = pdata; 303189251Ssam payloads->idr_len = pdatalen; 304189251Ssam break; 305189251Ssam case IKEV2_PAYLOAD_CERTIFICATE: 306189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Payload: Certificate"); 307189251Ssam payloads->cert = pdata; 308189251Ssam payloads->cert_len = pdatalen; 309189251Ssam break; 310189251Ssam case IKEV2_PAYLOAD_AUTHENTICATION: 311189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Payload: " 312189251Ssam "Authentication"); 313189251Ssam payloads->auth = pdata; 314189251Ssam payloads->auth_len = pdatalen; 315189251Ssam break; 316189251Ssam case IKEV2_PAYLOAD_NONCE: 317189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Payload: Nonce"); 318189251Ssam payloads->nonce = pdata; 319189251Ssam payloads->nonce_len = pdatalen; 320189251Ssam break; 321189251Ssam case IKEV2_PAYLOAD_ENCRYPTED: 322189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Payload: Encrypted"); 323189251Ssam payloads->encrypted = pdata; 324189251Ssam payloads->encrypted_len = pdatalen; 325189251Ssam break; 326189251Ssam case IKEV2_PAYLOAD_NOTIFICATION: 327189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Payload: " 328189251Ssam "Notification"); 329189251Ssam payloads->notification = pdata; 330189251Ssam payloads->notification_len = pdatalen; 331189251Ssam break; 332189251Ssam default: 333189251Ssam if (phdr->flags & IKEV2_PAYLOAD_FLAGS_CRITICAL) { 334189251Ssam wpa_printf(MSG_INFO, "IKEV2: Unsupported " 335189251Ssam "critical payload %u - reject the " 336189251Ssam "entire message", next_payload); 337189251Ssam return -1; 338189251Ssam } else { 339189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Skipped " 340189251Ssam "unsupported payload %u", 341189251Ssam next_payload); 342189251Ssam } 343189251Ssam } 344189251Ssam 345189251Ssam if (next_payload == IKEV2_PAYLOAD_ENCRYPTED && 346189251Ssam pos + plen == end) { 347189251Ssam /* 348189251Ssam * Next Payload in the case of Encrypted Payload is 349189251Ssam * actually the payload type for the first embedded 350189251Ssam * payload. 351189251Ssam */ 352189251Ssam payloads->encr_next_payload = phdr->next_payload; 353189251Ssam next_payload = IKEV2_PAYLOAD_NO_NEXT_PAYLOAD; 354189251Ssam } else 355189251Ssam next_payload = phdr->next_payload; 356189251Ssam 357189251Ssam pos += plen; 358189251Ssam } 359189251Ssam 360189251Ssam if (pos != end) { 361189251Ssam wpa_printf(MSG_INFO, "IKEV2: Unexpected extra data after " 362189251Ssam "payloads"); 363189251Ssam return -1; 364189251Ssam } 365189251Ssam 366189251Ssam return 0; 367189251Ssam} 368189251Ssam 369189251Ssam 370189251Ssamint ikev2_derive_auth_data(int prf_alg, const struct wpabuf *sign_msg, 371189251Ssam const u8 *ID, size_t ID_len, u8 ID_type, 372189251Ssam struct ikev2_keys *keys, int initiator, 373189251Ssam const u8 *shared_secret, size_t shared_secret_len, 374189251Ssam const u8 *nonce, size_t nonce_len, 375189251Ssam const u8 *key_pad, size_t key_pad_len, 376189251Ssam u8 *auth_data) 377189251Ssam{ 378189251Ssam size_t sign_len, buf_len; 379189251Ssam u8 *sign_data, *pos, *buf, hash[IKEV2_MAX_HASH_LEN]; 380189251Ssam const struct ikev2_prf_alg *prf; 381189251Ssam const u8 *SK_p = initiator ? keys->SK_pi : keys->SK_pr; 382189251Ssam 383189251Ssam prf = ikev2_get_prf(prf_alg); 384189251Ssam if (sign_msg == NULL || ID == NULL || SK_p == NULL || 385189251Ssam shared_secret == NULL || nonce == NULL || prf == NULL) 386189251Ssam return -1; 387189251Ssam 388189251Ssam /* prf(SK_pi/r,IDi/r') */ 389189251Ssam buf_len = 4 + ID_len; 390189251Ssam buf = os_zalloc(buf_len); 391189251Ssam if (buf == NULL) 392189251Ssam return -1; 393189251Ssam buf[0] = ID_type; 394189251Ssam os_memcpy(buf + 4, ID, ID_len); 395189251Ssam if (ikev2_prf_hash(prf->id, SK_p, keys->SK_prf_len, 396189251Ssam 1, (const u8 **) &buf, &buf_len, hash) < 0) { 397189251Ssam os_free(buf); 398189251Ssam return -1; 399189251Ssam } 400189251Ssam os_free(buf); 401189251Ssam 402189251Ssam /* sign_data = msg | Nr/i | prf(SK_pi/r,IDi/r') */ 403189251Ssam sign_len = wpabuf_len(sign_msg) + nonce_len + prf->hash_len; 404189251Ssam sign_data = os_malloc(sign_len); 405189251Ssam if (sign_data == NULL) 406189251Ssam return -1; 407189251Ssam pos = sign_data; 408189251Ssam os_memcpy(pos, wpabuf_head(sign_msg), wpabuf_len(sign_msg)); 409189251Ssam pos += wpabuf_len(sign_msg); 410189251Ssam os_memcpy(pos, nonce, nonce_len); 411189251Ssam pos += nonce_len; 412189251Ssam os_memcpy(pos, hash, prf->hash_len); 413189251Ssam 414189251Ssam /* AUTH = prf(prf(Shared Secret, key pad, sign_data) */ 415189251Ssam if (ikev2_prf_hash(prf->id, shared_secret, shared_secret_len, 1, 416189251Ssam &key_pad, &key_pad_len, hash) < 0 || 417189251Ssam ikev2_prf_hash(prf->id, hash, prf->hash_len, 1, 418189251Ssam (const u8 **) &sign_data, &sign_len, auth_data) < 0) 419189251Ssam { 420189251Ssam os_free(sign_data); 421189251Ssam return -1; 422189251Ssam } 423189251Ssam os_free(sign_data); 424189251Ssam 425189251Ssam return 0; 426189251Ssam} 427189251Ssam 428189251Ssam 429189251Ssamu8 * ikev2_decrypt_payload(int encr_id, int integ_id, 430189251Ssam struct ikev2_keys *keys, int initiator, 431189251Ssam const struct ikev2_hdr *hdr, 432189251Ssam const u8 *encrypted, size_t encrypted_len, 433189251Ssam size_t *res_len) 434189251Ssam{ 435189251Ssam size_t iv_len; 436189251Ssam const u8 *pos, *end, *iv, *integ; 437189251Ssam u8 hash[IKEV2_MAX_HASH_LEN], *decrypted; 438189251Ssam size_t decrypted_len, pad_len; 439189251Ssam const struct ikev2_integ_alg *integ_alg; 440189251Ssam const struct ikev2_encr_alg *encr_alg; 441189251Ssam const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; 442189251Ssam const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; 443189251Ssam 444189251Ssam if (encrypted == NULL) { 445189251Ssam wpa_printf(MSG_INFO, "IKEV2: No Encrypted payload in SA_AUTH"); 446189251Ssam return NULL; 447189251Ssam } 448189251Ssam 449189251Ssam encr_alg = ikev2_get_encr(encr_id); 450189251Ssam if (encr_alg == NULL) { 451189251Ssam wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); 452189251Ssam return NULL; 453189251Ssam } 454189251Ssam iv_len = encr_alg->block_size; 455189251Ssam 456189251Ssam integ_alg = ikev2_get_integ(integ_id); 457189251Ssam if (integ_alg == NULL) { 458189251Ssam wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); 459189251Ssam return NULL; 460189251Ssam } 461189251Ssam 462189251Ssam if (encrypted_len < iv_len + 1 + integ_alg->hash_len) { 463189251Ssam wpa_printf(MSG_INFO, "IKEV2: No room for IV or Integrity " 464189251Ssam "Checksum"); 465189251Ssam return NULL; 466189251Ssam } 467189251Ssam 468189251Ssam iv = encrypted; 469189251Ssam pos = iv + iv_len; 470189251Ssam end = encrypted + encrypted_len; 471189251Ssam integ = end - integ_alg->hash_len; 472189251Ssam 473189251Ssam if (SK_a == NULL) { 474189251Ssam wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); 475189251Ssam return NULL; 476189251Ssam } 477189251Ssam if (ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, 478189251Ssam (const u8 *) hdr, 479189251Ssam integ - (const u8 *) hdr, hash) < 0) { 480189251Ssam wpa_printf(MSG_INFO, "IKEV2: Failed to calculate integrity " 481189251Ssam "hash"); 482189251Ssam return NULL; 483189251Ssam } 484281806Srpaulo if (os_memcmp_const(integ, hash, integ_alg->hash_len) != 0) { 485189251Ssam wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum " 486189251Ssam "Data"); 487189251Ssam return NULL; 488189251Ssam } 489189251Ssam 490189251Ssam if (SK_e == NULL) { 491189251Ssam wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); 492189251Ssam return NULL; 493189251Ssam } 494189251Ssam 495189251Ssam decrypted_len = integ - pos; 496189251Ssam decrypted = os_malloc(decrypted_len); 497189251Ssam if (decrypted == NULL) 498189251Ssam return NULL; 499189251Ssam 500189251Ssam if (ikev2_encr_decrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, pos, 501189251Ssam decrypted, decrypted_len) < 0) { 502189251Ssam os_free(decrypted); 503189251Ssam return NULL; 504189251Ssam } 505189251Ssam 506189251Ssam pad_len = decrypted[decrypted_len - 1]; 507189251Ssam if (decrypted_len < pad_len + 1) { 508189251Ssam wpa_printf(MSG_INFO, "IKEV2: Invalid padding in encrypted " 509189251Ssam "payload"); 510189251Ssam os_free(decrypted); 511189251Ssam return NULL; 512189251Ssam } 513189251Ssam 514189251Ssam decrypted_len -= pad_len + 1; 515189251Ssam 516189251Ssam *res_len = decrypted_len; 517189251Ssam return decrypted; 518189251Ssam} 519189251Ssam 520189251Ssam 521189251Ssamvoid ikev2_update_hdr(struct wpabuf *msg) 522189251Ssam{ 523189251Ssam struct ikev2_hdr *hdr; 524189251Ssam 525189251Ssam /* Update lenth field in HDR */ 526189251Ssam hdr = wpabuf_mhead(msg); 527189251Ssam WPA_PUT_BE32(hdr->length, wpabuf_len(msg)); 528189251Ssam} 529189251Ssam 530189251Ssam 531189251Ssamint ikev2_build_encrypted(int encr_id, int integ_id, struct ikev2_keys *keys, 532189251Ssam int initiator, struct wpabuf *msg, 533189251Ssam struct wpabuf *plain, u8 next_payload) 534189251Ssam{ 535189251Ssam struct ikev2_payload_hdr *phdr; 536189251Ssam size_t plen; 537189251Ssam size_t iv_len, pad_len; 538189251Ssam u8 *icv, *iv; 539189251Ssam const struct ikev2_integ_alg *integ_alg; 540189251Ssam const struct ikev2_encr_alg *encr_alg; 541189251Ssam const u8 *SK_e = initiator ? keys->SK_ei : keys->SK_er; 542189251Ssam const u8 *SK_a = initiator ? keys->SK_ai : keys->SK_ar; 543189251Ssam 544189251Ssam wpa_printf(MSG_DEBUG, "IKEV2: Adding Encrypted payload"); 545189251Ssam 546189251Ssam /* Encr - RFC 4306, Sect. 3.14 */ 547189251Ssam 548189251Ssam encr_alg = ikev2_get_encr(encr_id); 549189251Ssam if (encr_alg == NULL) { 550189251Ssam wpa_printf(MSG_INFO, "IKEV2: Unsupported encryption type"); 551189251Ssam return -1; 552189251Ssam } 553189251Ssam iv_len = encr_alg->block_size; 554189251Ssam 555189251Ssam integ_alg = ikev2_get_integ(integ_id); 556189251Ssam if (integ_alg == NULL) { 557189251Ssam wpa_printf(MSG_INFO, "IKEV2: Unsupported intergrity type"); 558189251Ssam return -1; 559189251Ssam } 560189251Ssam 561189251Ssam if (SK_e == NULL) { 562189251Ssam wpa_printf(MSG_INFO, "IKEV2: No SK_e available"); 563189251Ssam return -1; 564189251Ssam } 565189251Ssam 566189251Ssam if (SK_a == NULL) { 567189251Ssam wpa_printf(MSG_INFO, "IKEV2: No SK_a available"); 568189251Ssam return -1; 569189251Ssam } 570189251Ssam 571189251Ssam phdr = wpabuf_put(msg, sizeof(*phdr)); 572189251Ssam phdr->next_payload = next_payload; 573189251Ssam phdr->flags = 0; 574189251Ssam 575189251Ssam iv = wpabuf_put(msg, iv_len); 576252726Srpaulo if (random_get_bytes(iv, iv_len)) { 577189251Ssam wpa_printf(MSG_INFO, "IKEV2: Could not generate IV"); 578189251Ssam return -1; 579189251Ssam } 580189251Ssam 581189251Ssam pad_len = iv_len - (wpabuf_len(plain) + 1) % iv_len; 582189251Ssam if (pad_len == iv_len) 583189251Ssam pad_len = 0; 584189251Ssam wpabuf_put(plain, pad_len); 585189251Ssam wpabuf_put_u8(plain, pad_len); 586189251Ssam 587189251Ssam if (ikev2_encr_encrypt(encr_alg->id, SK_e, keys->SK_encr_len, iv, 588189251Ssam wpabuf_head(plain), wpabuf_mhead(plain), 589189251Ssam wpabuf_len(plain)) < 0) 590189251Ssam return -1; 591189251Ssam 592189251Ssam wpabuf_put_buf(msg, plain); 593189251Ssam 594189251Ssam /* Need to update all headers (Length fields) prior to hash func */ 595189251Ssam icv = wpabuf_put(msg, integ_alg->hash_len); 596189251Ssam plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) phdr; 597189251Ssam WPA_PUT_BE16(phdr->payload_length, plen); 598189251Ssam 599189251Ssam ikev2_update_hdr(msg); 600189251Ssam 601189251Ssam return ikev2_integ_hash(integ_id, SK_a, keys->SK_integ_len, 602189251Ssam wpabuf_head(msg), 603189251Ssam wpabuf_len(msg) - integ_alg->hash_len, icv); 604189251Ssam 605189251Ssam return 0; 606189251Ssam} 607189251Ssam 608189251Ssam 609189251Ssamint ikev2_keys_set(struct ikev2_keys *keys) 610189251Ssam{ 611189251Ssam return keys->SK_d && keys->SK_ai && keys->SK_ar && keys->SK_ei && 612189251Ssam keys->SK_er && keys->SK_pi && keys->SK_pr; 613189251Ssam} 614189251Ssam 615189251Ssam 616189251Ssamvoid ikev2_free_keys(struct ikev2_keys *keys) 617189251Ssam{ 618189251Ssam os_free(keys->SK_d); 619189251Ssam os_free(keys->SK_ai); 620189251Ssam os_free(keys->SK_ar); 621189251Ssam os_free(keys->SK_ei); 622189251Ssam os_free(keys->SK_er); 623189251Ssam os_free(keys->SK_pi); 624189251Ssam os_free(keys->SK_pr); 625189251Ssam keys->SK_d = keys->SK_ai = keys->SK_ar = keys->SK_ei = keys->SK_er = 626189251Ssam keys->SK_pi = keys->SK_pr = NULL; 627189251Ssam} 628189251Ssam 629189251Ssam 630189251Ssamint ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf, 631189251Ssam const struct ikev2_integ_alg *integ, 632189251Ssam const struct ikev2_encr_alg *encr, 633189251Ssam const u8 *skeyseed, const u8 *data, size_t data_len, 634189251Ssam struct ikev2_keys *keys) 635189251Ssam{ 636189251Ssam u8 *keybuf, *pos; 637189251Ssam size_t keybuf_len; 638189251Ssam 639189251Ssam /* 640189251Ssam * {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } = 641189251Ssam * prf+(SKEYSEED, Ni | Nr | SPIi | SPIr ) 642189251Ssam */ 643189251Ssam ikev2_free_keys(keys); 644189251Ssam keys->SK_d_len = prf->key_len; 645189251Ssam keys->SK_integ_len = integ->key_len; 646189251Ssam keys->SK_encr_len = encr->key_len; 647189251Ssam keys->SK_prf_len = prf->key_len; 648189251Ssam 649189251Ssam keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len + 650189251Ssam 2 * keys->SK_encr_len + 2 * keys->SK_prf_len; 651189251Ssam keybuf = os_malloc(keybuf_len); 652189251Ssam if (keybuf == NULL) 653189251Ssam return -1; 654189251Ssam 655189251Ssam if (ikev2_prf_plus(prf->id, skeyseed, prf->hash_len, 656189251Ssam data, data_len, keybuf, keybuf_len)) { 657189251Ssam os_free(keybuf); 658189251Ssam return -1; 659189251Ssam } 660189251Ssam 661189251Ssam pos = keybuf; 662189251Ssam 663189251Ssam keys->SK_d = os_malloc(keys->SK_d_len); 664189251Ssam if (keys->SK_d) { 665189251Ssam os_memcpy(keys->SK_d, pos, keys->SK_d_len); 666189251Ssam wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_d", 667189251Ssam keys->SK_d, keys->SK_d_len); 668189251Ssam } 669189251Ssam pos += keys->SK_d_len; 670189251Ssam 671189251Ssam keys->SK_ai = os_malloc(keys->SK_integ_len); 672189251Ssam if (keys->SK_ai) { 673189251Ssam os_memcpy(keys->SK_ai, pos, keys->SK_integ_len); 674189251Ssam wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ai", 675189251Ssam keys->SK_ai, keys->SK_integ_len); 676189251Ssam } 677189251Ssam pos += keys->SK_integ_len; 678189251Ssam 679189251Ssam keys->SK_ar = os_malloc(keys->SK_integ_len); 680189251Ssam if (keys->SK_ar) { 681189251Ssam os_memcpy(keys->SK_ar, pos, keys->SK_integ_len); 682189251Ssam wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ar", 683189251Ssam keys->SK_ar, keys->SK_integ_len); 684189251Ssam } 685189251Ssam pos += keys->SK_integ_len; 686189251Ssam 687189251Ssam keys->SK_ei = os_malloc(keys->SK_encr_len); 688189251Ssam if (keys->SK_ei) { 689189251Ssam os_memcpy(keys->SK_ei, pos, keys->SK_encr_len); 690189251Ssam wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_ei", 691189251Ssam keys->SK_ei, keys->SK_encr_len); 692189251Ssam } 693189251Ssam pos += keys->SK_encr_len; 694189251Ssam 695189251Ssam keys->SK_er = os_malloc(keys->SK_encr_len); 696189251Ssam if (keys->SK_er) { 697189251Ssam os_memcpy(keys->SK_er, pos, keys->SK_encr_len); 698189251Ssam wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_er", 699189251Ssam keys->SK_er, keys->SK_encr_len); 700189251Ssam } 701189251Ssam pos += keys->SK_encr_len; 702189251Ssam 703189251Ssam keys->SK_pi = os_malloc(keys->SK_prf_len); 704189251Ssam if (keys->SK_pi) { 705189251Ssam os_memcpy(keys->SK_pi, pos, keys->SK_prf_len); 706189251Ssam wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pi", 707189251Ssam keys->SK_pi, keys->SK_prf_len); 708189251Ssam } 709189251Ssam pos += keys->SK_prf_len; 710189251Ssam 711189251Ssam keys->SK_pr = os_malloc(keys->SK_prf_len); 712189251Ssam if (keys->SK_pr) { 713189251Ssam os_memcpy(keys->SK_pr, pos, keys->SK_prf_len); 714189251Ssam wpa_hexdump_key(MSG_DEBUG, "IKEV2: SK_pr", 715189251Ssam keys->SK_pr, keys->SK_prf_len); 716189251Ssam } 717189251Ssam 718189251Ssam os_free(keybuf); 719189251Ssam 720189251Ssam if (!ikev2_keys_set(keys)) { 721189251Ssam ikev2_free_keys(keys); 722189251Ssam return -1; 723189251Ssam } 724189251Ssam 725189251Ssam return 0; 726189251Ssam} 727