From a8a83b316ee3b6717a6df35ca6d0f14a3963524b Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 11 Feb 2013 21:02:08 +0100 Subject: l2tp: Use separate function for computing CHAP-MD5 Move challenge computation out of tunnel allocation by using a generic CHAP-MD5 calculation function. This will allow to initiate tunnels on the host side (i.e. sending SCCRQ) and to compute the challenge response later on, when handling the peer response (i.e. during SCCRP handling). Signed-off-by: Guillaume Nault --- accel-pppd/ctrl/l2tp/l2tp.c | 113 ++++++++++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 29 deletions(-) diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index eed750a..a3e829e 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.c +++ b/accel-pppd/ctrl/l2tp/l2tp.c @@ -98,7 +98,7 @@ struct l2tp_conn_t uint16_t peer_tid; uint32_t framing_cap; uint16_t challenge_len; - l2tp_value_t challenge; + uint8_t *challenge; int retransmit; uint16_t Ns, Nr; @@ -126,6 +126,21 @@ static int l2tp_conn_read(struct triton_md_handler_t *); static void l2tp_tunnel_session_freed(void *data); +static inline void comp_chap_md5(uint8_t *md5, uint8_t ident, + const void *secret, size_t secret_len, + const void *chall, size_t chall_len) +{ + MD5_CTX md5_ctx; + + memset(md5, 0, MD5_DIGEST_LENGTH); + + MD5_Init(&md5_ctx); + MD5_Update(&md5_ctx, &ident, sizeof(ident)); + MD5_Update(&md5_ctx, secret, secret_len); + MD5_Update(&md5_ctx, chall, chall_len); + MD5_Final(md5, &md5_ctx); +} + static inline struct l2tp_conn_t *l2tp_tunnel_self(void) { return container_of(triton_context_self(), struct l2tp_conn_t, ctx); @@ -136,7 +151,8 @@ static inline struct l2tp_sess_t *l2tp_session_self(void) return container_of(triton_context_self(), struct l2tp_sess_t, sctx); } -static void l2tp_conn_log(void (*print)(const char *fmt, ...), struct l2tp_conn_t *conn) +static void l2tp_conn_log(void (*print)(const char *fmt, ...), + const struct l2tp_conn_t *conn) { char addr[17]; @@ -164,6 +180,52 @@ static struct l2tp_sess_t *l2tp_tunnel_get_session(struct l2tp_conn_t *conn, return (res) ? *res : NULL; } +static int l2tp_tunnel_storechall(struct l2tp_conn_t *conn, + const struct l2tp_attr_t *chall) +{ + void *ptr = NULL; + + if (chall == NULL) { + if (conn->challenge) { + _free(conn->challenge); + conn->challenge = NULL; + } + conn->challenge_len = 0; + return 0; + } + + if (conf_secret == NULL || strlen(conf_secret) == 0) { + l2tp_conn_log(log_error, conn); + log_error("l2tp: Authentication required by peer," + " but no secret has been set for this tunnel\n"); + goto err; + } + + if (conn->challenge_len != chall->length) { + ptr = realloc(conn->challenge, chall->length); + if (ptr == NULL) { + l2tp_conn_log(log_error, conn); + log_error("l2tp: Impossible to store received" + " challenge: Memory allocation failed\n"); + goto err; + } + conn->challenge = ptr; + conn->challenge_len = chall->length; + } + + memcpy(conn->challenge, chall->val.octets, chall->length); + + return 0; + +err: + if (conn->challenge) { + _free(conn->challenge); + conn->challenge = NULL; + } + conn->challenge_len = 0; + return -1; +} + static int l2tp_send_StopCCN(struct l2tp_conn_t *conn, uint16_t res, uint16_t err) { @@ -382,8 +444,8 @@ static void l2tp_tunnel_free(struct l2tp_conn_t *conn) l2tp_packet_free(pack); } - if (conn->challenge_len) - _free(conn->challenge.octets); + if (conn->challenge) + _free(conn->challenge); mempool_free(conn); } @@ -590,8 +652,7 @@ out_err: static struct l2tp_conn_t *l2tp_tunnel_alloc(struct l2tp_serv_t *serv, const struct sockaddr_in *peer, const struct sockaddr_in *host, - uint32_t framing_cap, - struct l2tp_attr_t *challenge) + uint32_t framing_cap) { struct l2tp_conn_t *conn; uint16_t tid; @@ -676,23 +737,6 @@ static struct l2tp_conn_t *l2tp_tunnel_alloc(struct l2tp_serv_t *serv, memcpy(&conn->lns_addr, host, sizeof(*host)); conn->framing_cap = framing_cap; - /* If challenge set in SCCRQ, we need to calculate response for SCCRP */ - if (challenge && challenge->length <= 16) { - char state = 2; /* SCCRP, TODO: define them in some .h? */ - MD5_CTX md5_ctx; - uint8_t md5[MD5_DIGEST_LENGTH]; - - MD5_Init(&md5_ctx); - MD5_Update(&md5_ctx, &state, 1); - MD5_Update(&md5_ctx, conf_secret, strlen(conf_secret)); - MD5_Update(&md5_ctx, challenge->val.octets, challenge->length); - MD5_Final(md5, &md5_ctx); - - conn->challenge_len = MD5_DIGEST_LENGTH; - conn->challenge.octets = _malloc(MD5_DIGEST_LENGTH); - memcpy(conn->challenge.octets, &md5, MD5_DIGEST_LENGTH); - } - conn->ctx.before_switch = log_switch; conn->ctx.close = l2tp_conn_close; conn->hnd.read = l2tp_conn_read; @@ -957,6 +1001,7 @@ static void l2tp_send_HELLO(struct triton_timer_t *t) static void l2tp_send_SCCRP(struct l2tp_conn_t *conn) { struct l2tp_packet_t *pack; + uint8_t chall_resp[MD5_DIGEST_LENGTH]; pack = l2tp_packet_alloc(2, Message_Type_Start_Ctrl_Conn_Reply, &conn->lac_addr); if (!pack) @@ -973,9 +1018,15 @@ static void l2tp_send_SCCRP(struct l2tp_conn_t *conn) if (l2tp_packet_add_string(pack, Vendor_Name, "accel-ppp", 0)) goto out_err; /* If challenge response available */ - if (conn->challenge_len) { - if (l2tp_packet_add_octets(pack, Challenge_Response, conn->challenge.octets, 16, 1)) - goto out_err; + if (conn->challenge_len && conn->challenge) { + if (conf_secret == NULL || strlen(conf_secret) == 0) + goto out_err; + comp_chap_md5(chall_resp, Message_Type_Start_Ctrl_Conn_Reply, + conf_secret, strlen(conf_secret), + conn->challenge, conn->challenge_len); + if (l2tp_packet_add_octets(pack, Challenge_Response, + chall_resp, MD5_DIGEST_LENGTH, 1)) + goto out_err; } if (l2tp_send(conn, pack, 0)) @@ -1132,7 +1183,7 @@ static int l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, host_addr.sin_port = 0; conn = l2tp_tunnel_alloc(serv, &pack->addr, &host_addr, - framing_cap->val.uint32, challenge); + framing_cap->val.uint32); if (conn == NULL) return -1; @@ -1142,6 +1193,11 @@ static int l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, l2tp_packet_print(pack, log_ppp_info2); } + if (l2tp_tunnel_storechall(conn, challenge) < 0) { + l2tp_tunnel_free(conn); + return -1; + } + conn->peer_tid = assigned_tid->val.uint16; if (l2tp_tunnel_start(conn, (triton_event_func)l2tp_send_SCCRP, conn) < 0) { @@ -1158,10 +1214,9 @@ static int l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, return -1; } - if (conf_secret && !challenge) { + if (conf_secret && strlen(conf_secret) > 0 && conn->challenge == NULL) { if (conf_verbose) log_warn("l2tp: SCCRQ: no Challenge present in message\n"); - return -1; } return 0; -- cgit v1.2.3