xref: /openbsd-src/lib/libradius/radius_msgauth.c (revision 9c3f005cd02b40e370de9b1ede64b4bf61e542f0)
1*9c3f005cSyasuoka /*	$OpenBSD: radius_msgauth.c,v 1.5 2024/08/14 04:50:31 yasuoka Exp $ */
20eaf192dSyasuoka 
30eaf192dSyasuoka /*-
40eaf192dSyasuoka  * Copyright (c) 2009 Internet Initiative Japan Inc.
50eaf192dSyasuoka  * All rights reserved.
60eaf192dSyasuoka  *
70eaf192dSyasuoka  * Redistribution and use in source and binary forms, with or without
80eaf192dSyasuoka  * modification, are permitted provided that the following conditions
90eaf192dSyasuoka  * are met:
100eaf192dSyasuoka  * 1. Redistributions of source code must retain the above copyright
110eaf192dSyasuoka  *    notice, this list of conditions and the following disclaimer.
120eaf192dSyasuoka  * 2. Redistributions in binary form must reproduce the above copyright
130eaf192dSyasuoka  *    notice, this list of conditions and the following disclaimer in the
140eaf192dSyasuoka  *    documentation and/or other materials provided with the distribution.
150eaf192dSyasuoka  *
160eaf192dSyasuoka  * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
170eaf192dSyasuoka  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180eaf192dSyasuoka  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190eaf192dSyasuoka  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
200eaf192dSyasuoka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210eaf192dSyasuoka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220eaf192dSyasuoka  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230eaf192dSyasuoka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240eaf192dSyasuoka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250eaf192dSyasuoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260eaf192dSyasuoka  * SUCH DAMAGE.
270eaf192dSyasuoka  */
280eaf192dSyasuoka 
290eaf192dSyasuoka #include <sys/types.h>
300eaf192dSyasuoka #include <sys/socket.h>
310eaf192dSyasuoka #include <netinet/in.h>
320eaf192dSyasuoka 
330eaf192dSyasuoka #include <stdbool.h>
340eaf192dSyasuoka #include <stdio.h>
350eaf192dSyasuoka #include <stdlib.h>
360eaf192dSyasuoka #include <string.h>
370eaf192dSyasuoka 
380eaf192dSyasuoka #include <openssl/hmac.h>
390eaf192dSyasuoka 
400eaf192dSyasuoka #include "radius.h"
410eaf192dSyasuoka 
420eaf192dSyasuoka #include "radius_local.h"
430eaf192dSyasuoka 
44c1c8152cStb static int
450eaf192dSyasuoka radius_calc_message_authenticator(RADIUS_PACKET * packet, const char *secret,
460eaf192dSyasuoka     void *ma)
470eaf192dSyasuoka {
480eaf192dSyasuoka 	const RADIUS_ATTRIBUTE	*attr;
490eaf192dSyasuoka 	const RADIUS_ATTRIBUTE	*end;
500eaf192dSyasuoka 	u_char			 zero16[16];
51c1c8152cStb 	HMAC_CTX		*ctx;
520eaf192dSyasuoka 	int			 mdlen;
53c1c8152cStb 	int			 ret = -1;
540eaf192dSyasuoka 
550eaf192dSyasuoka 	memset(zero16, 0, sizeof(zero16));
560eaf192dSyasuoka 
57c1c8152cStb 	if ((ctx = HMAC_CTX_new()) == NULL)
58c1c8152cStb 		goto err;
59c1c8152cStb 
60c1c8152cStb 	if (!HMAC_Init_ex(ctx, secret, strlen(secret), EVP_md5(), NULL))
61c1c8152cStb 		goto err;
620eaf192dSyasuoka 
630eaf192dSyasuoka 	/*
640eaf192dSyasuoka 	 * Traverse the radius packet.
650eaf192dSyasuoka 	 */
660eaf192dSyasuoka 	if (packet->request != NULL) {
67c1c8152cStb 		if (!HMAC_Update(ctx, (const u_char *)packet->pdata, 4))
68c1c8152cStb 			goto err;
69c1c8152cStb 		if (!HMAC_Update(ctx, (unsigned char *)packet->request->pdata
70c1c8152cStb 		    ->authenticator, 16))
71c1c8152cStb 			goto err;
720eaf192dSyasuoka 	} else {
73c1c8152cStb 		if (!HMAC_Update(ctx, (const u_char *)packet->pdata,
74c1c8152cStb 		    sizeof(RADIUS_PACKET_DATA)))
75c1c8152cStb 			goto err;
760eaf192dSyasuoka 	}
770eaf192dSyasuoka 
780eaf192dSyasuoka 	attr = ATTRS_BEGIN(packet->pdata);
790eaf192dSyasuoka 	end = ATTRS_END(packet->pdata);
800eaf192dSyasuoka 
810eaf192dSyasuoka 	for (; attr < end; ATTRS_ADVANCE(attr)) {
820eaf192dSyasuoka 		if (attr->type == RADIUS_TYPE_MESSAGE_AUTHENTICATOR) {
83c1c8152cStb 			if (!HMAC_Update(ctx, (u_char *)attr, 2))
84c1c8152cStb 				goto err;
85c1c8152cStb 			if (!HMAC_Update(ctx, (u_char *)zero16, sizeof(zero16)))
86c1c8152cStb 				goto err;
87c1c8152cStb 		} else {
88c1c8152cStb 			if (!HMAC_Update(ctx, (u_char *)attr,
89c1c8152cStb 			    (int)attr->length))
90c1c8152cStb 				goto err;
91c1c8152cStb 		}
920eaf192dSyasuoka 	}
930eaf192dSyasuoka 
94c1c8152cStb 	if (!HMAC_Final(ctx, (u_char *)ma, &mdlen))
95c1c8152cStb 		goto err;
960eaf192dSyasuoka 
97c1c8152cStb 	ret = 0;
98c1c8152cStb 
99c1c8152cStb  err:
100c1c8152cStb 	HMAC_CTX_free(ctx);
101c1c8152cStb 
102c1c8152cStb 	return (ret);
1030eaf192dSyasuoka }
1040eaf192dSyasuoka 
1050eaf192dSyasuoka int
1060eaf192dSyasuoka radius_put_message_authenticator(RADIUS_PACKET * packet, const char *secret)
1070eaf192dSyasuoka {
1080eaf192dSyasuoka 	u_char	 ma[16];
1090eaf192dSyasuoka 
1100eaf192dSyasuoka 	/*
1110eaf192dSyasuoka 	 * It is not required to initialize ma
1120eaf192dSyasuoka 	 * because content of Message-Authenticator attribute is assumed zero
1130eaf192dSyasuoka 	 * during calculation.
1140eaf192dSyasuoka 	 */
115834c20a7Syasuoka 	if (radius_unshift_raw_attr(packet, RADIUS_TYPE_MESSAGE_AUTHENTICATOR,
1160eaf192dSyasuoka 	    ma, sizeof(ma)) != 0)
1170eaf192dSyasuoka 		return (-1);
1180eaf192dSyasuoka 
1190eaf192dSyasuoka 	return (radius_set_message_authenticator(packet, secret));
1200eaf192dSyasuoka }
1210eaf192dSyasuoka 
1220eaf192dSyasuoka int
1230eaf192dSyasuoka radius_set_message_authenticator(RADIUS_PACKET * packet, const char *secret)
1240eaf192dSyasuoka {
1250eaf192dSyasuoka 	u_char	 ma[16];
1260eaf192dSyasuoka 
127c1c8152cStb 	if (radius_calc_message_authenticator(packet, secret, ma) != 0)
128c1c8152cStb 		return (-1);
1290eaf192dSyasuoka 
1300eaf192dSyasuoka 	return (radius_set_raw_attr(packet, RADIUS_TYPE_MESSAGE_AUTHENTICATOR,
1310eaf192dSyasuoka 	    ma, sizeof(ma)));
1320eaf192dSyasuoka }
1330eaf192dSyasuoka 
1340eaf192dSyasuoka int
1350eaf192dSyasuoka radius_check_message_authenticator(RADIUS_PACKET * packet, const char *secret)
1360eaf192dSyasuoka {
1370eaf192dSyasuoka 	int	 rval;
1380eaf192dSyasuoka 	size_t	 len;
1390eaf192dSyasuoka 	u_char	 ma0[16], ma1[16];
1400eaf192dSyasuoka 
141c1c8152cStb 	if (radius_calc_message_authenticator(packet, secret, ma0) != 0)
142c1c8152cStb 		return (-1);
1430eaf192dSyasuoka 
1440eaf192dSyasuoka 	len = sizeof(ma1);
1450eaf192dSyasuoka 	if ((rval = radius_get_raw_attr(packet,
1460eaf192dSyasuoka 		    RADIUS_TYPE_MESSAGE_AUTHENTICATOR, ma1, &len)) != 0)
1470eaf192dSyasuoka 		return (rval);
1480eaf192dSyasuoka 
1490eaf192dSyasuoka 	if (len != sizeof(ma1))
1500eaf192dSyasuoka 		return (-1);
1510eaf192dSyasuoka 
152*9c3f005cSyasuoka 	return (timingsafe_bcmp(ma0, ma1, sizeof(ma1)));
1530eaf192dSyasuoka }
154