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