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