📄 eap_tls_common.c
字号:
wpabuf_put_be32(*out_data, data->tls_out_len); } wpabuf_put_data(*out_data, &data->tls_out[data->tls_out_pos], len); data->tls_out_pos += len; if (!more_fragments) eap_peer_tls_reset_output(data); return ret;}/** * eap_peer_tls_process_helper - Process TLS handshake message * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) * @peap_version: Version number for EAP-PEAP/TTLS * @id: EAP identifier for the response * @in_data: Message received from the server * @in_len: Length of in_data * @out_data: Buffer for returning a pointer to the response message * Returns: 0 on success, 1 if more input data is needed, 2 if application data * is available, or -1 on failure * * This function can be used to process TLS handshake messages. It reassembles * the received fragments and uses a TLS library to process the messages. The * response data from the TLS library is fragmented to suitable output messages * that the caller can send out. * * out_data is used to return the response message if the return value of this * function is 0, 2, or -1. In case of failure, the message is likely a TLS * alarm message. The caller is responsible for freeing the allocated buffer if * *out_data is not %NULL. * * This function is called for each received TLS message during the TLS * handshake after eap_peer_tls_process_init() call and possible processing of * TLS Flags field. Once the handshake has been completed, i.e., when * tls_connection_established() returns 1, EAP method specific decrypting of * the tunneled data is used. */int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, EapType eap_type, int peap_version, u8 id, const u8 *in_data, size_t in_len, struct wpabuf **out_data){ int ret = 0; *out_data = NULL; if (data->tls_out_len > 0 && in_len > 0) { wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output " "fragments are waiting to be sent out"); return -1; } if (data->tls_out_len == 0) { /* * No more data to send out - expect to receive more data from * the AS. */ int res = eap_tls_process_input(sm, data, in_data, in_len, out_data); if (res) { /* * Input processing failed (res = -1) or more data is * needed (res = 1). */ return res; } /* * The incoming message has been reassembled and processed. The * response was allocated into data->tls_out buffer. */ } if (data->tls_out == NULL) { /* * No outgoing fragments remaining from the previous message * and no new message generated. This indicates an error in TLS * processing. */ eap_peer_tls_reset_output(data); return -1; } if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) { /* TLS processing has failed - return error */ wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to " "report error"); ret = -1; /* TODO: clean pin if engine used? */ } if (data->tls_out_len == 0) { /* * TLS negotiation should now be complete since all other cases * needing more data should have been caught above based on * the TLS Message Length field. */ wpa_printf(MSG_DEBUG, "SSL: No data to be sent out"); os_free(data->tls_out); data->tls_out = NULL; return 1; } /* Send the pending message (in fragments, if needed). */ return eap_tls_process_output(data, eap_type, peap_version, id, ret, out_data);}/** * eap_peer_tls_build_ack - Build a TLS ACK frame * @id: EAP identifier for the response * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) * @peap_version: Version number for EAP-PEAP/TTLS * Returns: Pointer to the allocated ACK frame or %NULL on failure */struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, int peap_version){ struct wpabuf *resp; resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_RESPONSE, id); if (resp == NULL) return NULL; wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)", (int) eap_type, id, peap_version); wpabuf_put_u8(resp, peap_version); /* Flags */ return resp;}/** * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * Returns: 0 on success, -1 on failure */int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data){ eap_peer_tls_reset_input(data); eap_peer_tls_reset_output(data); return tls_connection_shutdown(sm->ssl_ctx, data->conn);}/** * eap_peer_tls_status - Get TLS status * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * @buf: Buffer for status information * @buflen: Maximum buffer length * @verbose: Whether to include verbose status information * Returns: Number of bytes written to buf. */int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf, size_t buflen, int verbose){ char name[128]; int len = 0, ret; if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) { ret = os_snprintf(buf + len, buflen - len, "EAP TLS cipher=%s\n", name); if (ret < 0 || (size_t) ret >= buflen - len) return len; len += ret; } return len;}/** * eap_peer_tls_process_init - Initial validation/processing of EAP requests * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) * @ret: Return values from EAP request validation and processing * @reqData: EAP request to be processed (eapReqData) * @len: Buffer for returning length of the remaining payload * @flags: Buffer for returning TLS flags * Returns: Pointer to payload after TLS flags and length or %NULL on failure * * This function validates the EAP header and processes the optional TLS * Message Length field. If this is the first fragment of a TLS message, the * TLS reassembly code is initialized to receive the indicated number of bytes. * * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this * function as the first step in processing received messages. They will need * to process the flags (apart from Message Length Included) that are returned * through the flags pointer and the message payload that will be returned (and * the length is returned through the len pointer). Return values (ret) are set * for continuation of EAP method processing. The caller is responsible for * setting these to indicate completion (either success or failure) based on * the authentication result. */const u8 * eap_peer_tls_process_init(struct eap_sm *sm, struct eap_ssl_data *data, EapType eap_type, struct eap_method_ret *ret, const struct wpabuf *reqData, size_t *len, u8 *flags){ const u8 *pos; size_t left; unsigned int tls_msg_len; if (tls_get_errors(sm->ssl_ctx)) { wpa_printf(MSG_INFO, "SSL: TLS errors detected"); ret->ignore = TRUE; return NULL; } pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, &left); if (pos == NULL) { ret->ignore = TRUE; return NULL; } *flags = *pos++; left--; wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - " "Flags 0x%02x", (unsigned long) wpabuf_len(reqData), *flags); if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) { if (left < 4) { wpa_printf(MSG_INFO, "SSL: Short frame with TLS " "length"); ret->ignore = TRUE; return NULL; } tls_msg_len = WPA_GET_BE32(pos); wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d", tls_msg_len); if (data->tls_in_left == 0) { data->tls_in_total = tls_msg_len; data->tls_in_left = tls_msg_len; os_free(data->tls_in); data->tls_in = NULL; data->tls_in_len = 0; } pos += 4; left -= 4; } ret->ignore = FALSE; ret->methodState = METHOD_MAY_CONT; ret->decision = DECISION_FAIL; ret->allowNotifications = TRUE; *len = left; return pos;}/** * eap_peer_tls_reset_input - Reset input buffers * @data: Data for TLS processing * * This function frees any allocated memory for input buffers and resets input * state. */void eap_peer_tls_reset_input(struct eap_ssl_data *data){ data->tls_in_left = data->tls_in_total = data->tls_in_len = 0; os_free(data->tls_in); data->tls_in = NULL;}/** * eap_peer_tls_reset_output - Reset output buffers * @data: Data for TLS processing * * This function frees any allocated memory for output buffers and resets * output state. */void eap_peer_tls_reset_output(struct eap_ssl_data *data){ data->tls_out_len = 0; data->tls_out_pos = 0; os_free(data->tls_out); data->tls_out = NULL;}/** * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * @in_data: Message received from the server * @in_decrypted: Buffer for returning a pointer to the decrypted message * Returns: 0 on success, 1 if more input data is needed, or -1 on failure */int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, const struct wpabuf *in_data, struct wpabuf **in_decrypted){ int res; const u8 *msg; size_t msg_len, buf_len; int need_more_input; msg = eap_peer_tls_data_reassemble(data, wpabuf_head(in_data), wpabuf_len(in_data), &msg_len, &need_more_input); if (msg == NULL) return need_more_input ? 1 : -1; buf_len = wpabuf_len(in_data); if (data->tls_in_total > buf_len) buf_len = data->tls_in_total; /* * Even though we try to disable TLS compression, it is possible that * this cannot be done with all TLS libraries. Add extra buffer space * to handle the possibility of the decrypted data being longer than * input data. */ buf_len += 500; buf_len *= 3; *in_decrypted = wpabuf_alloc(buf_len ? buf_len : 1); if (*in_decrypted == NULL) { eap_peer_tls_reset_input(data); wpa_printf(MSG_WARNING, "SSL: Failed to allocate memory for " "decryption"); return -1; } res = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg, msg_len, wpabuf_mhead(*in_decrypted), buf_len); eap_peer_tls_reset_input(data); if (res < 0) { wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data"); return -1; } wpabuf_put(*in_decrypted, res); return 0;}/** * eap_peer_tls_encrypt - Encrypt phase 2 TLS message * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) * @peap_version: Version number for EAP-PEAP/TTLS * @id: EAP identifier for the response * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments * @out_data: Buffer for returning a pointer to the encrypted response message * Returns: 0 on success, -1 on failure */int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, EapType eap_type, int peap_version, u8 id, const struct wpabuf *in_data, struct wpabuf **out_data){ int res; size_t len; if (in_data) { eap_peer_tls_reset_output(data); len = wpabuf_len(in_data) + 100; data->tls_out = os_malloc(len); if (data->tls_out == NULL) return -1; res = tls_connection_encrypt(sm->ssl_ctx, data->conn, wpabuf_head(in_data), wpabuf_len(in_data), data->tls_out, len); if (res < 0) { wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 " "data (in_len=%lu)", (unsigned long) wpabuf_len(in_data)); eap_peer_tls_reset_output(data); return -1; } data->tls_out_len = res; } return eap_tls_process_output(data, eap_type, peap_version, id, 0, out_data);}/** * eap_peer_select_phase2_methods - Select phase 2 EAP method * @config: Pointer to the network configuration * @prefix: 'phase2' configuration prefix, e.g., "auth=" * @types: Buffer for returning allocated list of allowed EAP methods * @num_types: Buffer for returning number of allocated EAP methods * Returns: 0 on success, -1 on failure * * This function is used to parse EAP method list and select allowed methods * for Phase2 authentication. */int eap_peer_select_phase2_methods(struct eap_peer_config *config, const char *prefix, struct eap_method_type **types, size_t *num_types){ char *start, *pos, *buf; struct eap_method_type *methods = NULL, *_methods; u8 method; size_t num_methods = 0, prefix_len; if (config == NULL || config->phase2 == NULL) goto get_defaults; start = buf = os_strdup(config->phase2); if (buf == NULL) return -1; prefix_len = os_strlen(prefix); while (start && *start != '\0') { int vendor; pos = os_strstr(start, prefix); if (pos == NULL) break; if (start != pos && *(pos - 1) != ' ') { start = pos + prefix_len; continue; } start = pos + prefix_len; pos = os_strchr(start, ' '); if (pos) *pos++ = '\0'; method = eap_get_phase2_type(start, &vendor); if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " "method '%s'", start); } else { num_methods++; _methods = os_realloc(methods, num_methods * sizeof(*methods)); if (_methods == NULL) { os_free(methods); os_free(buf); return -1; } methods = _methods; methods[num_methods - 1].vendor = vendor; methods[num_methods - 1].method = method; } start = pos; } os_free(buf);get_defaults: if (methods == NULL) methods = eap_get_phase2_types(config, &num_methods); if (methods == NULL) { wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available"); return -1; } wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types", (u8 *) methods, num_methods * sizeof(struct eap_method_type)); *types = methods; *num_types = num_methods; return 0;}/** * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2 * @types: Buffer for returning allocated list of allowed EAP methods * @num_types: Buffer for returning number of allocated EAP methods * @hdr: EAP-Request header (and the following EAP type octet) * @resp: Buffer for returning the EAP-Nak message * Returns: 0 on success, -1 on failure */int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, struct eap_hdr *hdr, struct wpabuf **resp){ u8 *pos = (u8 *) (hdr + 1); size_t i; /* TODO: add support for expanded Nak */ wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos); wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types", (u8 *) types, num_types * sizeof(struct eap_method_type)); *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types, EAP_CODE_RESPONSE, hdr->identifier); if (*resp == NULL) return -1; for (i = 0; i < num_types; i++) { if (types[i].vendor == EAP_VENDOR_IETF && types[i].method < 256) wpabuf_put_u8(*resp, types[i].method); } eap_update_len(*resp); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -