xref: /openbsd/lib/libradius/radius_userpass.c (revision 09467b48)
1 /*	$OpenBSD: radius_userpass.c,v 1.1 2015/07/20 23:52:29 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 <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 
33 #include <stdbool.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include <openssl/md5.h>
39 
40 #include "radius.h"
41 
42 #include "radius_local.h"
43 
44 int
45 radius_encrypt_user_password_attr(void *cipher, size_t * clen,
46     const char *plain, const void *ra, const char *secret)
47 {
48 	size_t		 plen = strlen(plain);
49 	size_t		 slen = strlen(secret);
50 	char		 b[16], p[16], *c;
51 	size_t		 off;
52 	MD5_CTX		 ctx;
53 	unsigned int	 i;
54 
55 	if (*clen < ROUNDUP(plen, 16))
56 		return (-1);
57 
58 	for (off = 0; off < plen; off += sizeof(p)) {
59 		c = ((char *)cipher) + off;
60 		memset(p, 0, sizeof(p));
61 		strncpy(p, plain + off, sizeof(p));	/* not strlcpy() */
62 		MD5_Init(&ctx);
63 		MD5_Update(&ctx, secret, slen);
64 		if (off == 0)
65 			MD5_Update(&ctx, ra, 16);
66 		else
67 			MD5_Update(&ctx, c - 16, 16);
68 		MD5_Final(b, &ctx);
69 		for (i = 0; i < 16; i++)
70 			c[i] = p[i] ^ b[i];
71 	}
72 
73 	*clen = off;
74 	return (0);
75 }
76 
77 int
78 radius_decrypt_user_password_attr(char *plain, size_t plen, const void *cipher,
79     size_t clen, const void *ra, const char *secret)
80 {
81 	size_t slen = strlen(secret);
82 	char b[16];
83 	size_t off;
84 	char *p, *c;
85 	MD5_CTX ctx;
86 	unsigned int i;
87 
88 	if (clen % 16 != 0)
89 		return (-1);
90 	if (plen < clen + 1)
91 		return (-1);
92 
93 	for (off = 0; off < clen; off += 16) {
94 		c = ((char *)cipher) + off;
95 		p = plain + off;
96 		MD5_Init(&ctx);
97 		MD5_Update(&ctx, secret, slen);
98 		if (off == 0)
99 			MD5_Update(&ctx, ra, 16);
100 		else
101 			MD5_Update(&ctx, c - 16, 16);
102 		MD5_Final(b, &ctx);
103 		for (i = 0; i < 16; i++)
104 			p[i] = c[i] ^ b[i];
105 	}
106 
107 	p = memchr(plain, '\0', off);
108 	if (p == NULL)
109 		plain[off] = '\0';
110 	else {
111 		/* memcspn() does not exist... */
112 		for (p++; p < plain + off; p++) {
113 			if (*p != '\0')
114 				return (-1);
115 		}
116 	}
117 
118 	return (0);
119 }
120 
121 int
122 radius_get_user_password_attr(const RADIUS_PACKET * packet, char *buf,
123     size_t len, const char *secret)
124 {
125 	char	 cipher[256];
126 	size_t	 clen = sizeof(cipher);
127 
128 	if (radius_get_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher,
129 	    &clen) != 0)
130 		return (-1);
131 	if (radius_decrypt_user_password_attr(buf, len, cipher, clen,
132 	    radius_get_authenticator_retval(packet), secret) != 0)
133 		return (-1);
134 
135 	return (0);
136 }
137 
138 int
139 radius_put_user_password_attr(RADIUS_PACKET * packet, const char *buf,
140     const char *secret)
141 {
142 	char	 cipher[256];
143 	size_t	 clen = sizeof(cipher);
144 
145 	if (radius_encrypt_user_password_attr(cipher, &clen, buf,
146 	    radius_get_authenticator_retval(packet), secret) != 0)
147 		return (-1);
148 	if (radius_put_raw_attr(packet, RADIUS_TYPE_USER_PASSWORD, cipher,
149 	    clen) != 0)
150 		return (-1);
151 
152 	return (0);
153 }
154