1*8fbd69a9Sjsg /* $OpenBSD: eap2mschap_local.h,v 1.3 2024/09/15 05:49:05 jsg Exp $ */ 2b0e7e43dSyasuoka 3b0e7e43dSyasuoka /* 4b0e7e43dSyasuoka * Copyright (c) 2024 Internet Initiative Japan Inc. 5b0e7e43dSyasuoka * 6b0e7e43dSyasuoka * Permission to use, copy, modify, and distribute this software for any 7b0e7e43dSyasuoka * purpose with or without fee is hereby granted, provided that the above 8b0e7e43dSyasuoka * copyright notice and this permission notice appear in all copies. 9b0e7e43dSyasuoka * 10b0e7e43dSyasuoka * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11b0e7e43dSyasuoka * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12b0e7e43dSyasuoka * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13b0e7e43dSyasuoka * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14b0e7e43dSyasuoka * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15b0e7e43dSyasuoka * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16b0e7e43dSyasuoka * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17b0e7e43dSyasuoka */ 18b0e7e43dSyasuoka 19b0e7e43dSyasuoka #define EAP_CODE_REQUEST 1 20b0e7e43dSyasuoka #define EAP_CODE_RESPONSE 2 21b0e7e43dSyasuoka #define EAP_CODE_SUCCESS 3 22b0e7e43dSyasuoka #define EAP_CODE_FAILURE 4 23b0e7e43dSyasuoka 24b0e7e43dSyasuoka #define EAP_TYPE_IDENTITY 1 25b0e7e43dSyasuoka #define EAP_TYPE_NOTIFICATION 2 26b0e7e43dSyasuoka #define EAP_TYPE_NAK 3 27b0e7e43dSyasuoka #define EAP_TYPE_MSCHAPV2 0x1a /* [MS-CHAP] MS-EAP-Authentication */ 28b0e7e43dSyasuoka 29b0e7e43dSyasuoka #define CHAP_CHALLENGE 1 30b0e7e43dSyasuoka #define CHAP_RESPONSE 2 31b0e7e43dSyasuoka #define CHAP_SUCCESS 3 32b0e7e43dSyasuoka #define CHAP_FAILURE 4 33b0e7e43dSyasuoka 34b0e7e43dSyasuoka /* From [MS-CHAP] */ 35b0e7e43dSyasuoka enum eap_chap_status { 36b0e7e43dSyasuoka EAP_CHAP_NONE, 37b0e7e43dSyasuoka EAP_CHAP_CHALLENGE_SENT, 38b0e7e43dSyasuoka EAP_CHAP_SUCCESS_REQUEST_SENT, 39b0e7e43dSyasuoka EAP_CHAP_FAILURE_REQUEST_SENT, 40b0e7e43dSyasuoka EAP_CHAP_CHANGE_PASSWORD_SENT, 41b0e7e43dSyasuoka EAP_CHAP_FAILED, 42b0e7e43dSyasuoka EAP_CHAP_SUCCESS 43b0e7e43dSyasuoka }; 44b0e7e43dSyasuoka 45b0e7e43dSyasuoka struct eap { 46b0e7e43dSyasuoka uint8_t code; 47b0e7e43dSyasuoka uint8_t id; 48b0e7e43dSyasuoka uint16_t length; 49b0e7e43dSyasuoka uint8_t value[0]; 50b0e7e43dSyasuoka } __packed; 51b0e7e43dSyasuoka 52b0e7e43dSyasuoka struct chap { 53b0e7e43dSyasuoka uint8_t code; 54b0e7e43dSyasuoka uint8_t id; 55b0e7e43dSyasuoka uint16_t length; 56b0e7e43dSyasuoka int8_t value[0]; 57b0e7e43dSyasuoka } __packed; 58b0e7e43dSyasuoka 59b0e7e43dSyasuoka struct eap_chap { 60b0e7e43dSyasuoka struct eap eap; 61b0e7e43dSyasuoka uint8_t eap_type; 62b0e7e43dSyasuoka struct chap chap; 63b0e7e43dSyasuoka }; 64b0e7e43dSyasuoka 65b0e7e43dSyasuoka struct eap_mschap_challenge { 66b0e7e43dSyasuoka struct eap eap; 67b0e7e43dSyasuoka uint8_t eap_type; 68b0e7e43dSyasuoka struct chap chap; 69b0e7e43dSyasuoka uint8_t challsiz; 70b0e7e43dSyasuoka uint8_t chall[16]; 71b0e7e43dSyasuoka char chap_name[0]; 72b0e7e43dSyasuoka } __packed; 73*8fbd69a9Sjsg #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L 74b0e7e43dSyasuoka static_assert(sizeof(struct eap_mschap_challenge) == 26, ""); 75b0e7e43dSyasuoka static_assert(offsetof(struct eap_mschap_challenge, chap) == 5, ""); 76b0e7e43dSyasuoka static_assert(offsetof(struct eap_mschap_challenge, chall) == 10, ""); 77ca9586a4Smiod #endif 78b0e7e43dSyasuoka 79b0e7e43dSyasuoka struct eap_mschap_response { 80b0e7e43dSyasuoka struct eap eap; 81b0e7e43dSyasuoka uint8_t eap_type; 82b0e7e43dSyasuoka struct chap chap; 83b0e7e43dSyasuoka uint8_t challsiz; 84b0e7e43dSyasuoka uint8_t peerchall[16]; 85b0e7e43dSyasuoka uint8_t reserved[8]; 86b0e7e43dSyasuoka uint8_t ntresponse[24]; 87b0e7e43dSyasuoka uint8_t flags; 88b0e7e43dSyasuoka uint8_t chap_name[0]; 89b0e7e43dSyasuoka } __packed; 90*8fbd69a9Sjsg #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L 91b0e7e43dSyasuoka static_assert(sizeof(struct eap_mschap_response) == 59, ""); 92b0e7e43dSyasuoka static_assert(offsetof(struct eap_mschap_response, chap) == 5, ""); 93b0e7e43dSyasuoka static_assert(offsetof(struct eap_mschap_response, peerchall) == 10, ""); 94ca9586a4Smiod #endif 95b0e7e43dSyasuoka 96b0e7e43dSyasuoka struct radius_ms_chap2_response { 97b0e7e43dSyasuoka uint8_t ident; 98b0e7e43dSyasuoka uint8_t flags; 99b0e7e43dSyasuoka uint8_t peerchall[16]; 100b0e7e43dSyasuoka uint8_t reserved[8]; 101b0e7e43dSyasuoka uint8_t ntresponse[24]; 102b0e7e43dSyasuoka } __packed; 103b0e7e43dSyasuoka 104b0e7e43dSyasuoka 105b0e7e43dSyasuoka struct eap2mschap; 106b0e7e43dSyasuoka 107b0e7e43dSyasuoka struct access_req { 108b0e7e43dSyasuoka struct eap2mschap *eap2mschap; 109b0e7e43dSyasuoka char *username; 110b0e7e43dSyasuoka u_int q_id; 111b0e7e43dSyasuoka TAILQ_ENTRY(access_req) next; 112b0e7e43dSyasuoka RB_ENTRY(access_req) tree; 113b0e7e43dSyasuoka /* for EAP */ 114b0e7e43dSyasuoka enum eap_chap_status eap_chap_status; 115b0e7e43dSyasuoka char state[16]; 116b0e7e43dSyasuoka unsigned char chap_id; 117b0e7e43dSyasuoka unsigned char eap_id; 118b0e7e43dSyasuoka time_t eap_time; 119b0e7e43dSyasuoka char chall[16]; 120b0e7e43dSyasuoka RADIUS_PACKET *pkt; 121b0e7e43dSyasuoka 122b0e7e43dSyasuoka }; 123b0e7e43dSyasuoka TAILQ_HEAD(access_reqq, access_req); 124b0e7e43dSyasuoka RB_HEAD(access_reqt, access_req); 125b0e7e43dSyasuoka 126b0e7e43dSyasuoka #define CHAP_NAME_MAX 40 127b0e7e43dSyasuoka 128b0e7e43dSyasuoka struct eap2mschap { 129b0e7e43dSyasuoka struct module_base *base; 130b0e7e43dSyasuoka char *secret; 131b0e7e43dSyasuoka char chap_name[CHAP_NAME_MAX + 1]; 132b0e7e43dSyasuoka struct access_reqq reqq; 133b0e7e43dSyasuoka struct access_reqt eapt; 134b0e7e43dSyasuoka struct event ev_eapt; 135b0e7e43dSyasuoka }; 136b0e7e43dSyasuoka 137b0e7e43dSyasuoka /* Attributes copied from CHAP Access-Accept to EAP Access-Access-Accept */ 138b0e7e43dSyasuoka struct preserve_attrs { 139b0e7e43dSyasuoka uint8_t type; 140b0e7e43dSyasuoka uint32_t vendor; 141b0e7e43dSyasuoka } preserve_attrs[] = { 142b0e7e43dSyasuoka { RADIUS_TYPE_FRAMED_PROTOCOL, 0}, 143b0e7e43dSyasuoka { RADIUS_TYPE_FRAMED_IP_ADDRESS, 0}, 144b0e7e43dSyasuoka { RADIUS_TYPE_FRAMED_IP_NETMASK, 0}, 145b0e7e43dSyasuoka { RADIUS_TYPE_FRAMED_IPV6_ADDRESS, 0}, 146b0e7e43dSyasuoka { RADIUS_TYPE_DNS_SERVER_IPV6_ADDRESS, 0}, 147b0e7e43dSyasuoka { RADIUS_TYPE_FRAMED_ROUTING, 0}, 148b0e7e43dSyasuoka { RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER, RADIUS_VENDOR_MICROSOFT }, 149b0e7e43dSyasuoka { RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER, RADIUS_VENDOR_MICROSOFT }, 150b0e7e43dSyasuoka { RADIUS_VTYPE_MS_PRIMARY_NBNS_SERVER, RADIUS_VENDOR_MICROSOFT }, 151b0e7e43dSyasuoka { RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER,RADIUS_VENDOR_MICROSOFT }, 152b0e7e43dSyasuoka { RADIUS_VTYPE_MPPE_SEND_KEY, RADIUS_VENDOR_MICROSOFT }, 153b0e7e43dSyasuoka { RADIUS_VTYPE_MPPE_RECV_KEY, RADIUS_VENDOR_MICROSOFT } 154b0e7e43dSyasuoka }; 155b0e7e43dSyasuoka 156b0e7e43dSyasuoka #ifndef EAP2MSCHAP_DEBUG 157b0e7e43dSyasuoka #define EAP2MSCHAP_DBG(...) 158b0e7e43dSyasuoka #define EAP2MSCHAP_ASSERT(_cond) 159b0e7e43dSyasuoka #else 160b0e7e43dSyasuoka #define EAP2MSCHAP_DBG(...) logit(LOG_DEBUG, __VA_ARGS__) 161b0e7e43dSyasuoka #define EAP2MSCHAP_ASSERT(_cond) \ 162b0e7e43dSyasuoka do { \ 163b0e7e43dSyasuoka if (!(_cond)) { \ 164b0e7e43dSyasuoka log_warnx( \ 165b0e7e43dSyasuoka "ASSERT(%s) failed in %s() at %s:%d",\ 166b0e7e43dSyasuoka #_cond, __func__, __FILE__, __LINE__);\ 167b0e7e43dSyasuoka abort(); \ 168b0e7e43dSyasuoka } \ 169b0e7e43dSyasuoka } while (0/* CONSTCOND */); 170b0e7e43dSyasuoka #endif 171b0e7e43dSyasuoka #ifndef nitems 172b0e7e43dSyasuoka #define nitems(_x) (sizeof((_x)) / sizeof((_x)[0])) 173b0e7e43dSyasuoka #endif 174b0e7e43dSyasuoka 175b0e7e43dSyasuoka static void eap2mschap_init(struct eap2mschap *); 176b0e7e43dSyasuoka static void eap2mschap_start(void *); 177b0e7e43dSyasuoka static void eap2mschap_config_set(void *, const char *, int, 178b0e7e43dSyasuoka char * const *); 179b0e7e43dSyasuoka static void eap2mschap_stop(void *); 180b0e7e43dSyasuoka static void eap2mschap_access_request(void *, u_int, const u_char *, 181b0e7e43dSyasuoka size_t); 182b0e7e43dSyasuoka static void eap2mschap_next_response(void *, u_int, const u_char *, 183b0e7e43dSyasuoka size_t); 184b0e7e43dSyasuoka 185b0e7e43dSyasuoka static void eap2mschap_on_eapt (int, short, void *); 186b0e7e43dSyasuoka static void eap2mschap_reset_eaptimer (struct eap2mschap *); 187b0e7e43dSyasuoka 188b0e7e43dSyasuoka static struct access_req 189b0e7e43dSyasuoka *access_request_new(struct eap2mschap *, u_int); 190b0e7e43dSyasuoka static void access_request_free(struct access_req *); 191b0e7e43dSyasuoka static int access_request_compar(struct access_req *, 192b0e7e43dSyasuoka struct access_req *); 193b0e7e43dSyasuoka 194b0e7e43dSyasuoka 195b0e7e43dSyasuoka static struct access_req 196b0e7e43dSyasuoka *eap_recv(struct eap2mschap *, u_int, RADIUS_PACKET *); 197b0e7e43dSyasuoka static struct access_req 198b0e7e43dSyasuoka *eap_recv_mschap(struct eap2mschap *, struct access_req *, 199b0e7e43dSyasuoka RADIUS_PACKET *, struct eap_chap *); 200b0e7e43dSyasuoka static void eap_resp_mschap(struct eap2mschap *, struct access_req *, 201b0e7e43dSyasuoka RADIUS_PACKET *); 202b0e7e43dSyasuoka static void eap_send_reject(struct access_req *, RADIUS_PACKET *, u_int); 203b0e7e43dSyasuoka static const char 204b0e7e43dSyasuoka *eap_chap_status_string(enum eap_chap_status); 205b0e7e43dSyasuoka static const char 206b0e7e43dSyasuoka *hex_string(const char *, size_t, char *, size_t); 207b0e7e43dSyasuoka static time_t monotime(void); 208b0e7e43dSyasuoka 209b0e7e43dSyasuoka RB_PROTOTYPE_STATIC(access_reqt, access_req, tree, access_request_compar); 210