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