|
| 1 | +/* |
| 2 | + * Copyright (c) 2018, Arm Limited and affiliates. |
| 3 | + * SPDX-License-Identifier: Apache-2.0 |
| 4 | + * |
| 5 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | + * you may not use this file except in compliance with the License. |
| 7 | + * You may obtain a copy of the License at |
| 8 | + * |
| 9 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | + * |
| 11 | + * Unless required by applicable law or agreed to in writing, software |
| 12 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | + * See the License for the specific language governing permissions and |
| 15 | + * limitations under the License. |
| 16 | + */ |
| 17 | + |
| 18 | + |
| 19 | + |
| 20 | +#include "nsconfig.h" |
| 21 | + |
| 22 | +#include "ns_types.h" |
| 23 | +#include "eventOS_event.h" |
| 24 | +#include "ns_trace.h" |
| 25 | +#include "string.h" |
| 26 | +#include "common_functions.h" |
| 27 | +#include "Security/PANA/pana_eap_header.h" |
| 28 | +#include "Security/eapol/eapol_helper.h" |
| 29 | + |
| 30 | + |
| 31 | +#define KEY_INFO_VERSION_BIT_MASK 0x0007 |
| 32 | +#define KEY_INFO_VERSION_BIT_SHIFT 0 |
| 33 | +#define KEY_INFO_KEY_TYPE_BIT_MASK 0x0008 |
| 34 | +#define KEY_INFO_KEY_TYPE_BIT_SHIFT 3 |
| 35 | +#define KEY_INFO_INSTALL_BIT_MASK 0x0040 |
| 36 | +#define KEY_INFO_INSTALL_BIT_SHIFT 6 |
| 37 | +#define KEY_INFO_ACK_BIT_MASK 0x0080 |
| 38 | +#define KEY_INFO_ACK_BIT_SHIFT 7 |
| 39 | +#define KEY_INFO_MIC_MASK 0x0100 |
| 40 | +#define KEY_INFO_MIC_SHIFT 8 |
| 41 | +#define KEY_INFO_SECURE_MASK 0x0200 |
| 42 | +#define KEY_INFO_SECURE_SHIFT 9 |
| 43 | +#define KEY_INFO_ERROR_MASK 0x0400 |
| 44 | +#define KEY_INFO_ERROR_SHIFT 10 |
| 45 | +#define KEY_INFO_REQUEST_MASK 0x0800 |
| 46 | +#define KEY_INFO_REQUEST_SHIFT 11 |
| 47 | +#define KEY_INFO_ENC_KEY_DATA_MASK 0x1000 |
| 48 | +#define KEY_INFO_ENC_KEY_DATA_SHIFT 12 |
| 49 | +#define KEY_INFO_SMK_MASK 0x2000 |
| 50 | +#define KEY_INFO_SMK_SHIFT 13 |
| 51 | + |
| 52 | +static uint8_t *eapol_key_information_write(eapol_key_information_t *key_information, uint8_t *ptr) |
| 53 | +{ |
| 54 | + uint16_t key_info = 0; |
| 55 | + key_info |= (key_information->description_version << KEY_INFO_VERSION_BIT_SHIFT); |
| 56 | + key_info |= (key_information->pairwise_key << KEY_INFO_KEY_TYPE_BIT_SHIFT); |
| 57 | + key_info |= (key_information->install << KEY_INFO_INSTALL_BIT_SHIFT); |
| 58 | + key_info |= (key_information->key_ack << KEY_INFO_ACK_BIT_SHIFT); |
| 59 | + key_info |= (key_information->key_mic << KEY_INFO_MIC_SHIFT); |
| 60 | + key_info |= (key_information->secured_key_frame << KEY_INFO_SECURE_SHIFT); |
| 61 | + key_info |= (key_information->error << KEY_INFO_ERROR_SHIFT); |
| 62 | + key_info |= (key_information->request << KEY_INFO_REQUEST_SHIFT); |
| 63 | + key_info |= (key_information->encrypted_key_data << KEY_INFO_ENC_KEY_DATA_SHIFT); |
| 64 | + key_info |= (key_information->smk_handshake << KEY_INFO_SMK_SHIFT); |
| 65 | + return common_write_16_bit(key_info, ptr); |
| 66 | +} |
| 67 | + |
| 68 | +static uint8_t *eapol_key_information_read(eapol_key_information_t *key_information, uint8_t *ptr) |
| 69 | +{ |
| 70 | + uint16_t key_info = common_read_16_bit(ptr); |
| 71 | + key_information->description_version = ((key_info & KEY_INFO_VERSION_BIT_MASK) >> KEY_INFO_VERSION_BIT_SHIFT); |
| 72 | + key_information->pairwise_key = ((key_info & KEY_INFO_KEY_TYPE_BIT_MASK) >> KEY_INFO_KEY_TYPE_BIT_SHIFT); |
| 73 | + key_information->install = ((key_info & KEY_INFO_INSTALL_BIT_MASK) >> KEY_INFO_INSTALL_BIT_SHIFT); |
| 74 | + key_information->key_ack = ((key_info & KEY_INFO_ACK_BIT_MASK) >> KEY_INFO_ACK_BIT_SHIFT); |
| 75 | + key_information->key_mic = ((key_info & KEY_INFO_MIC_MASK) >> KEY_INFO_MIC_SHIFT); |
| 76 | + key_information->secured_key_frame = ((key_info & KEY_INFO_SECURE_MASK) >> KEY_INFO_SECURE_SHIFT); |
| 77 | + key_information->error = ((key_info & KEY_INFO_ERROR_MASK) >> KEY_INFO_ERROR_SHIFT); |
| 78 | + key_information->request = ((key_info & KEY_INFO_REQUEST_MASK) >> KEY_INFO_REQUEST_SHIFT); |
| 79 | + key_information->encrypted_key_data = ((key_info & KEY_INFO_ENC_KEY_DATA_MASK) >> KEY_INFO_ENC_KEY_DATA_SHIFT); |
| 80 | + key_information->smk_handshake = ((key_info & KEY_INFO_SMK_MASK) >> KEY_INFO_SMK_SHIFT); |
| 81 | + return ptr + 2; |
| 82 | +} |
| 83 | + |
| 84 | + |
| 85 | +static bool eapol_parse_eap_packet(eapol_pdu_t * eapol_pdu) |
| 86 | +{ |
| 87 | + return eap_header_parse(eapol_pdu->packet_body, eapol_pdu->packet_length, &eapol_pdu->msg.eap); |
| 88 | +} |
| 89 | + |
| 90 | + |
| 91 | +static bool eapol_parse_key_packet(eapol_pdu_t * eapol_pdu) |
| 92 | +{ |
| 93 | + if (eapol_pdu->packet_length < EAPOL_KEY_FRAME_BASE_SIZE) { |
| 94 | + return false; |
| 95 | + } |
| 96 | + uint8_t * ptr = eapol_pdu->packet_body; |
| 97 | + eapol_key_frame_t *key_frame = &eapol_pdu->msg.key; |
| 98 | + key_frame->key_description = *ptr++; |
| 99 | + if (key_frame->key_description != EAPOL_RSN_KEY_DESCRIPTION) { |
| 100 | + return false; |
| 101 | + } |
| 102 | + ptr = eapol_key_information_read(&key_frame->key_information, ptr); |
| 103 | + if (key_frame->key_information.description_version != KEY_DESCRIPTION_HMAC_SHA1_MIC_AES_ENC) { |
| 104 | + return false; |
| 105 | + } |
| 106 | + key_frame->key_length = common_read_16_bit(ptr); |
| 107 | + ptr += 2; |
| 108 | + |
| 109 | + key_frame->replay_counter = common_read_64_bit(ptr); |
| 110 | + ptr += 8; |
| 111 | + |
| 112 | + key_frame->key_nonce = ptr; |
| 113 | + ptr += 32; |
| 114 | + |
| 115 | + key_frame->key_iv = ptr; |
| 116 | + ptr += 16; |
| 117 | + |
| 118 | + key_frame->key_rsc = ptr; |
| 119 | + ptr += 16; //Skip 8 byte RSC + RESERVED 8 |
| 120 | + |
| 121 | + key_frame->key_mic = ptr; |
| 122 | + ptr += 16; |
| 123 | + |
| 124 | + key_frame->key_data_length = common_read_16_bit(ptr); |
| 125 | + ptr += 2; |
| 126 | + key_frame->key_data = ptr; |
| 127 | + if (key_frame->key_data_length > (eapol_pdu->packet_length - EAPOL_KEY_FRAME_BASE_SIZE)) { |
| 128 | + return false; |
| 129 | + } |
| 130 | + |
| 131 | + return true; |
| 132 | + |
| 133 | +} |
| 134 | + |
| 135 | +bool eapol_parse_pdu_header(uint8_t *ptr, uint16_t data_length, eapol_pdu_t * eapol_pdu) |
| 136 | +{ |
| 137 | + //Validate MIN length |
| 138 | + if (data_length < EAPOL_BASE_LENGTH) { |
| 139 | + return false; |
| 140 | + } |
| 141 | + //Validate Protocol version |
| 142 | + uint8_t protocol = *ptr++; |
| 143 | + if (protocol != EAPOL_PROTOCOL_VERSION) { |
| 144 | + return false; |
| 145 | + } |
| 146 | + eapol_pdu->packet_type = *ptr++; |
| 147 | + eapol_pdu->packet_length = common_read_16_bit(ptr); |
| 148 | + ptr += 2; |
| 149 | + //Validate Body Length |
| 150 | + if (eapol_pdu->packet_length > data_length - EAPOL_BASE_LENGTH) { |
| 151 | + return false; |
| 152 | + } |
| 153 | + eapol_pdu->packet_body = ptr; |
| 154 | + |
| 155 | + if (eapol_pdu->packet_type == EAPOL_EAP_TYPE) { |
| 156 | + return eapol_parse_eap_packet(eapol_pdu); |
| 157 | + } else if (eapol_pdu->packet_type == EAPOL_KEY_TYPE) { |
| 158 | + return eapol_parse_key_packet(eapol_pdu); |
| 159 | + } else { |
| 160 | + return false; |
| 161 | + } |
| 162 | + |
| 163 | +} |
| 164 | + |
| 165 | +void eapol_write_pdu_frame(uint8_t *ptr, eapol_pdu_t * eapol_pdu) |
| 166 | +{ |
| 167 | + *ptr++ = EAPOL_PROTOCOL_VERSION; |
| 168 | + *ptr++ = eapol_pdu->packet_type; |
| 169 | + ptr = common_write_16_bit(eapol_pdu->packet_length, ptr); |
| 170 | + eapol_pdu->packet_body = ptr; |
| 171 | + |
| 172 | + if (eapol_pdu->packet_type == EAPOL_EAP_TYPE) { |
| 173 | + eap_header_t *eap_header = &eapol_pdu->msg.eap; |
| 174 | + ptr = eap_header_build(ptr, eap_header->length, eap_header->eap_code, eap_header->id_seq, eap_header->type); |
| 175 | + memcpy(ptr, eap_header->data_ptr, eap_header->length); |
| 176 | + |
| 177 | + } else if (eapol_pdu->packet_type == EAPOL_KEY_TYPE) { |
| 178 | + eapol_key_frame_t *key_frame = &eapol_pdu->msg.key; |
| 179 | + *ptr++ = key_frame->key_description; |
| 180 | + ptr = eapol_key_information_write(&key_frame->key_information, ptr); |
| 181 | + ptr = common_write_16_bit(key_frame->key_length, ptr); |
| 182 | + ptr = common_write_64_bit(key_frame->replay_counter, ptr); |
| 183 | + |
| 184 | + if (key_frame->key_nonce) { |
| 185 | + memcpy(ptr, key_frame->key_nonce, 32); |
| 186 | + } else { |
| 187 | + memset(ptr, 0, 32); |
| 188 | + } |
| 189 | + ptr += 32; |
| 190 | + |
| 191 | + if (key_frame->key_iv) { |
| 192 | + memcpy(ptr, key_frame->key_iv, 16); |
| 193 | + } else { |
| 194 | + memset(ptr, 0, 16); |
| 195 | + } |
| 196 | + ptr += 16; |
| 197 | + |
| 198 | + if (key_frame->key_rsc) { |
| 199 | + memcpy(ptr, key_frame->key_rsc, 8); |
| 200 | + } else { |
| 201 | + memset(ptr, 0, 8); |
| 202 | + } |
| 203 | + ptr += 8; |
| 204 | + |
| 205 | + //Reserved 8bytes |
| 206 | + memset(ptr, 0, 8); |
| 207 | + ptr += 8; |
| 208 | + |
| 209 | + if (key_frame->key_mic && key_frame->key_information.key_mic) { |
| 210 | + memcpy(ptr, key_frame->key_mic, 16); |
| 211 | + } else { |
| 212 | + memset(ptr, 0, 16); |
| 213 | + } |
| 214 | + ptr += 16; |
| 215 | + ptr = common_write_16_bit(key_frame->key_data_length, ptr); |
| 216 | + if (key_frame->key_data_length) { |
| 217 | + memcpy(ptr, key_frame->key_data, key_frame->key_data_length); |
| 218 | + } |
| 219 | + } |
| 220 | +} |
| 221 | + |
| 222 | + |
| 223 | + |
| 224 | +uint16_t eapol_pdu_eap_frame_init(eapol_pdu_t * eapol_pdu, uint8_t eap_code, uint8_t id_seq, uint8_t type, uint16_t data_length, uint8_t *data_ptr) |
| 225 | +{ |
| 226 | + memset(eapol_pdu, 0, sizeof(eapol_pdu_t)); |
| 227 | + |
| 228 | + eapol_pdu->packet_type = EAPOL_EAP_TYPE; |
| 229 | + eapol_pdu->packet_length = data_length; |
| 230 | + eapol_pdu->msg.eap.eap_code = eap_code; |
| 231 | + eapol_pdu->msg.eap.data_ptr = data_ptr; |
| 232 | + eapol_pdu->msg.eap.length = data_length; |
| 233 | + eapol_pdu->msg.eap.id_seq = id_seq; |
| 234 | + eapol_pdu->msg.eap.type = type; |
| 235 | + |
| 236 | + if (eap_code == EAP_REQ || eap_code == EAP_RESPONSE) { |
| 237 | + eapol_pdu->packet_body += 5; |
| 238 | + eapol_pdu->msg.eap.length++; // Add space for type |
| 239 | + } else { |
| 240 | + eapol_pdu->packet_body += 4; |
| 241 | + } |
| 242 | + |
| 243 | + return eapol_pdu_total_length(eapol_pdu); |
| 244 | + |
| 245 | +} |
| 246 | + |
| 247 | +uint16_t eapol_pdu_key_frame_init(eapol_pdu_t * eapol_pdu, uint16_t data_length, uint8_t *data_ptr) |
| 248 | +{ |
| 249 | + memset(eapol_pdu, 0, sizeof(eapol_pdu_t)); |
| 250 | + |
| 251 | + eapol_pdu->packet_type = EAPOL_KEY_TYPE; |
| 252 | + eapol_pdu->packet_length = data_length + EAPOL_KEY_FRAME_BASE_SIZE; |
| 253 | + eapol_pdu->msg.key.key_data = data_ptr; |
| 254 | + eapol_pdu->msg.key.key_description = EAPOL_RSN_KEY_DESCRIPTION; |
| 255 | + eapol_pdu->msg.key.key_data_length = data_length; |
| 256 | + eapol_pdu->msg.key.key_information.description_version = KEY_DESCRIPTION_HMAC_SHA1_MIC_AES_ENC; |
| 257 | + |
| 258 | + return eapol_pdu_total_length(eapol_pdu); |
| 259 | + |
| 260 | +} |
| 261 | + |
0 commit comments