xref: /openbsd/lib/libradius/radius_userpass.c (revision 7426d5d9)
1 /*	$OpenBSD: radius_userpass.c,v 1.2 2023/07/08 08:53:26 yasuoka Exp $ */
2 
3 /*-
4  * Copyright (c) 2013 Internet Initiative Japan Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include <openssl/md5.h>
33 
34 #include "radius.h"
35 
36 #include "radius_local.h"
37 
38 int
radius_encrypt_user_password_attr(void * cipher,size_t * clen,const char * plain,const void * ra,const char * secret)39 radius_encrypt_user_password_attr(void *cipher, size_t * clen,
40     const char *plain, const void *ra, const char *secret)
41 {
42 	size_t		 plen = strlen(plain);
43 	size_t		 slen = strlen(secret);
44 	char		 b[16], p[16], *c;
45 	size_t		 off;
46 	MD5_CTX		 ctx;
47 	unsigned int	 i;
48 
49 	if (*clen < ROUNDUP(plen, 16))
50 		return (-1);
51 
52 	for (off = 0; off < plen; off += sizeof(p)) {
53 		c = ((char *)cipher) + off;
54 		memset(p, 0, sizeof(p));
55 		strncpy(p, plain + off, sizeof(p));	/* not strlcpy() */
56 		MD5_Init(&ctx);
57 		MD5_Update(&ctx, secret, slen);
58 		if (off == 0)
59 			MD5_Update(&ctx, ra, 16);
60 		else
61 			MD5_Update(&ctx, c - 16, 16);
62 		MD5_Final(b, &ctx);
63 		for (i = 0; i < 16; i++)
64 			c[i] = p[i] ^ b[i];
65 	}
66 
67 	*clen = off;
68 	return (0);
69 }
70 
71 int
radius_decrypt_user_password_attr(char * plain,size_t plen,const void * cipher,size_t clen,const void * ra,const char * secret)72 radius_decrypt_user_password_attr(char *plain, size_t plen, const void *cipher,
73     size_t clen, const void *ra, const char *secret)
74 {
75 	size_t slen = strlen(secret);
76 	char b[16];
77 	size_t off;
78 	char *p, *c;
79 	MD5_CTX ctx;
80 	unsigned int i;
81 
82 	if (clen % 16 != 0)
83 		return (-1);
84 	if (plen < clen + 1)
85 		return (-1);
86 
87 	for (off = 0; off < clen; off += 16) {
88 		c = ((char *)cipher) + off;
89 		p = plain + off;
90 		MD5_Init(&ctx);
91 		MD5_Update(&ctx, secret, slen);
92 		if (off == 0)
93 			MD5_Update(&ctx, ra, 16);
94 		else
95 			MD5_Update(&ctx, c - 16, 16);
96 		MD5_Final(b, &ctx);
97 		for (i = 0; i < 16; i++)
98 			p[i] = c[i] ^ b[i];
99 	}
100 
101 	p = memchr(plain, '\0', off);
102 	if (p == NULL)
103 		plain[off] = '\0';
104 	else {
105 		/* memcspn() does not exist... */
106 		for (p++; p < plain + off; p++) {
107 			if (*p != '\0')
108 				return (-1);
109 		}
110 	}
111 
112 	return (0);
113 }
114 
115 int
radius_get_user_password_attr(const RADIUS_PACKET * packet,char * buf,size_t len,const char * secret)116 radius_get_user_password_attr(const RADIUS_PACKET * packet, char *buf,
117     size_t len, const char *secret)
118 {
119 	char	 cipher[256];
120 	size_t	 clen = sizeof(cipher);
121 
122 	if (radius_get_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher,
123 	    &clen) != 0)
124 		return (-1);
125 	if (radius_decrypt_user_password_attr(buf, len, cipher, clen,
126 	    radius_get_authenticator_retval(packet), secret) != 0)
127 		return (-1);
128 
129 	return (0);
130 }
131 
132 int
radius_put_user_password_attr(RADIUS_PACKET * packet,const char * buf,const char * secret)133 radius_put_user_password_attr(RADIUS_PACKET * packet, const char *buf,
134     const char *secret)
135 {
136 	char	 cipher[256];
137 	size_t	 clen = sizeof(cipher);
138 
139 	if (radius_encrypt_user_password_attr(cipher, &clen, buf,
140 	    radius_get_authenticator_retval(packet), secret) != 0)
141 		return (-1);
142 	if (radius_put_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher,
143 	    clen) != 0)
144 		return (-1);
145 
146 	return (0);
147 }
148