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