1*7426d5d9Syasuoka /* $OpenBSD: radius_userpass.c,v 1.2 2023/07/08 08:53:26 yasuoka Exp $ */
20eaf192dSyasuoka
30eaf192dSyasuoka /*-
40eaf192dSyasuoka * Copyright (c) 2013 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 <stdio.h>
300eaf192dSyasuoka #include <string.h>
310eaf192dSyasuoka
320eaf192dSyasuoka #include <openssl/md5.h>
330eaf192dSyasuoka
340eaf192dSyasuoka #include "radius.h"
350eaf192dSyasuoka
360eaf192dSyasuoka #include "radius_local.h"
370eaf192dSyasuoka
380eaf192dSyasuoka int
radius_encrypt_user_password_attr(void * cipher,size_t * clen,const char * plain,const void * ra,const char * secret)390eaf192dSyasuoka radius_encrypt_user_password_attr(void *cipher, size_t * clen,
400eaf192dSyasuoka const char *plain, const void *ra, const char *secret)
410eaf192dSyasuoka {
420eaf192dSyasuoka size_t plen = strlen(plain);
430eaf192dSyasuoka size_t slen = strlen(secret);
440eaf192dSyasuoka char b[16], p[16], *c;
450eaf192dSyasuoka size_t off;
460eaf192dSyasuoka MD5_CTX ctx;
470eaf192dSyasuoka unsigned int i;
480eaf192dSyasuoka
490eaf192dSyasuoka if (*clen < ROUNDUP(plen, 16))
500eaf192dSyasuoka return (-1);
510eaf192dSyasuoka
520eaf192dSyasuoka for (off = 0; off < plen; off += sizeof(p)) {
530eaf192dSyasuoka c = ((char *)cipher) + off;
540eaf192dSyasuoka memset(p, 0, sizeof(p));
550eaf192dSyasuoka strncpy(p, plain + off, sizeof(p)); /* not strlcpy() */
560eaf192dSyasuoka MD5_Init(&ctx);
570eaf192dSyasuoka MD5_Update(&ctx, secret, slen);
580eaf192dSyasuoka if (off == 0)
590eaf192dSyasuoka MD5_Update(&ctx, ra, 16);
600eaf192dSyasuoka else
610eaf192dSyasuoka MD5_Update(&ctx, c - 16, 16);
620eaf192dSyasuoka MD5_Final(b, &ctx);
630eaf192dSyasuoka for (i = 0; i < 16; i++)
640eaf192dSyasuoka c[i] = p[i] ^ b[i];
650eaf192dSyasuoka }
660eaf192dSyasuoka
670eaf192dSyasuoka *clen = off;
680eaf192dSyasuoka return (0);
690eaf192dSyasuoka }
700eaf192dSyasuoka
710eaf192dSyasuoka int
radius_decrypt_user_password_attr(char * plain,size_t plen,const void * cipher,size_t clen,const void * ra,const char * secret)720eaf192dSyasuoka radius_decrypt_user_password_attr(char *plain, size_t plen, const void *cipher,
730eaf192dSyasuoka size_t clen, const void *ra, const char *secret)
740eaf192dSyasuoka {
750eaf192dSyasuoka size_t slen = strlen(secret);
760eaf192dSyasuoka char b[16];
770eaf192dSyasuoka size_t off;
780eaf192dSyasuoka char *p, *c;
790eaf192dSyasuoka MD5_CTX ctx;
800eaf192dSyasuoka unsigned int i;
810eaf192dSyasuoka
820eaf192dSyasuoka if (clen % 16 != 0)
830eaf192dSyasuoka return (-1);
840eaf192dSyasuoka if (plen < clen + 1)
850eaf192dSyasuoka return (-1);
860eaf192dSyasuoka
870eaf192dSyasuoka for (off = 0; off < clen; off += 16) {
880eaf192dSyasuoka c = ((char *)cipher) + off;
890eaf192dSyasuoka p = plain + off;
900eaf192dSyasuoka MD5_Init(&ctx);
910eaf192dSyasuoka MD5_Update(&ctx, secret, slen);
920eaf192dSyasuoka if (off == 0)
930eaf192dSyasuoka MD5_Update(&ctx, ra, 16);
940eaf192dSyasuoka else
950eaf192dSyasuoka MD5_Update(&ctx, c - 16, 16);
960eaf192dSyasuoka MD5_Final(b, &ctx);
970eaf192dSyasuoka for (i = 0; i < 16; i++)
980eaf192dSyasuoka p[i] = c[i] ^ b[i];
990eaf192dSyasuoka }
1000eaf192dSyasuoka
1010eaf192dSyasuoka p = memchr(plain, '\0', off);
1020eaf192dSyasuoka if (p == NULL)
1030eaf192dSyasuoka plain[off] = '\0';
1040eaf192dSyasuoka else {
1050eaf192dSyasuoka /* memcspn() does not exist... */
1060eaf192dSyasuoka for (p++; p < plain + off; p++) {
1070eaf192dSyasuoka if (*p != '\0')
1080eaf192dSyasuoka return (-1);
1090eaf192dSyasuoka }
1100eaf192dSyasuoka }
1110eaf192dSyasuoka
1120eaf192dSyasuoka return (0);
1130eaf192dSyasuoka }
1140eaf192dSyasuoka
1150eaf192dSyasuoka int
radius_get_user_password_attr(const RADIUS_PACKET * packet,char * buf,size_t len,const char * secret)1160eaf192dSyasuoka radius_get_user_password_attr(const RADIUS_PACKET * packet, char *buf,
1170eaf192dSyasuoka size_t len, const char *secret)
1180eaf192dSyasuoka {
1190eaf192dSyasuoka char cipher[256];
1200eaf192dSyasuoka size_t clen = sizeof(cipher);
1210eaf192dSyasuoka
1220eaf192dSyasuoka if (radius_get_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher,
1230eaf192dSyasuoka &clen) != 0)
1240eaf192dSyasuoka return (-1);
1250eaf192dSyasuoka if (radius_decrypt_user_password_attr(buf, len, cipher, clen,
1260eaf192dSyasuoka radius_get_authenticator_retval(packet), secret) != 0)
1270eaf192dSyasuoka return (-1);
1280eaf192dSyasuoka
1290eaf192dSyasuoka return (0);
1300eaf192dSyasuoka }
1310eaf192dSyasuoka
1320eaf192dSyasuoka int
radius_put_user_password_attr(RADIUS_PACKET * packet,const char * buf,const char * secret)1330eaf192dSyasuoka radius_put_user_password_attr(RADIUS_PACKET * packet, const char *buf,
1340eaf192dSyasuoka const char *secret)
1350eaf192dSyasuoka {
1360eaf192dSyasuoka char cipher[256];
1370eaf192dSyasuoka size_t clen = sizeof(cipher);
1380eaf192dSyasuoka
1390eaf192dSyasuoka if (radius_encrypt_user_password_attr(cipher, &clen, buf,
1400eaf192dSyasuoka radius_get_authenticator_retval(packet), secret) != 0)
1410eaf192dSyasuoka return (-1);
1420eaf192dSyasuoka if (radius_put_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher,
1430eaf192dSyasuoka clen) != 0)
1440eaf192dSyasuoka return (-1);
1450eaf192dSyasuoka
1460eaf192dSyasuoka return (0);
1470eaf192dSyasuoka }
148