Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/lib/krad/attr.c
39536 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* lib/krad/attr.c - RADIUS attribute functions for libkrad */
3
/*
4
* Copyright 2013 Red Hat, Inc. All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions are met:
8
*
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
*
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in
14
* the documentation and/or other materials provided with the
15
* distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
*/
29
30
#include <k5-int.h>
31
#include "internal.h"
32
33
#include <string.h>
34
35
/* RFC 2865 */
36
#define BLOCKSIZE 16
37
38
typedef krb5_error_code
39
(*attribute_transform_fn)(krb5_context ctx, const char *secret,
40
const unsigned char *auth, const krb5_data *in,
41
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
42
43
typedef struct {
44
const char *name;
45
unsigned char minval;
46
unsigned char maxval;
47
attribute_transform_fn encode;
48
attribute_transform_fn decode;
49
} attribute_record;
50
51
static krb5_error_code
52
user_password_encode(krb5_context ctx, const char *secret,
53
const unsigned char *auth, const krb5_data *in,
54
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
55
56
static krb5_error_code
57
user_password_decode(krb5_context ctx, const char *secret,
58
const unsigned char *auth, const krb5_data *in,
59
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
60
61
static const attribute_record attributes[UCHAR_MAX] = {
62
{"User-Name", 1, MAX_ATTRSIZE, NULL, NULL},
63
{"User-Password", 1, 128, user_password_encode, user_password_decode},
64
{"CHAP-Password", 17, 17, NULL, NULL},
65
{"NAS-IP-Address", 4, 4, NULL, NULL},
66
{"NAS-Port", 4, 4, NULL, NULL},
67
{"Service-Type", 4, 4, NULL, NULL},
68
{"Framed-Protocol", 4, 4, NULL, NULL},
69
{"Framed-IP-Address", 4, 4, NULL, NULL},
70
{"Framed-IP-Netmask", 4, 4, NULL, NULL},
71
{"Framed-Routing", 4, 4, NULL, NULL},
72
{"Filter-Id", 1, MAX_ATTRSIZE, NULL, NULL},
73
{"Framed-MTU", 4, 4, NULL, NULL},
74
{"Framed-Compression", 4, 4, NULL, NULL},
75
{"Login-IP-Host", 4, 4, NULL, NULL},
76
{"Login-Service", 4, 4, NULL, NULL},
77
{"Login-TCP-Port", 4, 4, NULL, NULL},
78
{NULL, 0, 0, NULL, NULL}, /* Unassigned */
79
{"Reply-Message", 1, MAX_ATTRSIZE, NULL, NULL},
80
{"Callback-Number", 1, MAX_ATTRSIZE, NULL, NULL},
81
{"Callback-Id", 1, MAX_ATTRSIZE, NULL, NULL},
82
{NULL, 0, 0, NULL, NULL}, /* Unassigned */
83
{"Framed-Route", 1, MAX_ATTRSIZE, NULL, NULL},
84
{"Framed-IPX-Network", 4, 4, NULL, NULL},
85
{"State", 1, MAX_ATTRSIZE, NULL, NULL},
86
{"Class", 1, MAX_ATTRSIZE, NULL, NULL},
87
{"Vendor-Specific", 5, MAX_ATTRSIZE, NULL, NULL},
88
{"Session-Timeout", 4, 4, NULL, NULL},
89
{"Idle-Timeout", 4, 4, NULL, NULL},
90
{"Termination-Action", 4, 4, NULL, NULL},
91
{"Called-Station-Id", 1, MAX_ATTRSIZE, NULL, NULL},
92
{"Calling-Station-Id", 1, MAX_ATTRSIZE, NULL, NULL},
93
{"NAS-Identifier", 1, MAX_ATTRSIZE, NULL, NULL},
94
{"Proxy-State", 1, MAX_ATTRSIZE, NULL, NULL},
95
{"Login-LAT-Service", 1, MAX_ATTRSIZE, NULL, NULL},
96
{"Login-LAT-Node", 1, MAX_ATTRSIZE, NULL, NULL},
97
{"Login-LAT-Group", 32, 32, NULL, NULL},
98
{"Framed-AppleTalk-Link", 4, 4, NULL, NULL},
99
{"Framed-AppleTalk-Network", 4, 4, NULL, NULL},
100
{"Framed-AppleTalk-Zone", 1, MAX_ATTRSIZE, NULL, NULL},
101
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
102
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
103
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
104
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
105
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
106
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
107
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
108
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
109
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
110
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
111
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
112
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
113
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
114
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
115
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
116
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
117
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
118
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
119
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
120
{NULL, 0, 0, NULL, NULL}, /* Reserved for accounting */
121
{"CHAP-Challenge", 5, MAX_ATTRSIZE, NULL, NULL},
122
{"NAS-Port-Type", 4, 4, NULL, NULL},
123
{"Port-Limit", 4, 4, NULL, NULL},
124
{"Login-LAT-Port", 1, MAX_ATTRSIZE, NULL, NULL},
125
{NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
126
{NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
127
{NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
128
{NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
129
{NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
130
{NULL, 0, 0, NULL, NULL}, /* Reserved for tunnelling */
131
{NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
132
{NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
133
{NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
134
{NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
135
{NULL, 0, 0, NULL, NULL}, /* Reserved for Apple Remote Access Protocol */
136
{NULL, 0, 0, NULL, NULL}, /* Password-Retry */
137
{NULL, 0, 0, NULL, NULL}, /* Prompt */
138
{NULL, 0, 0, NULL, NULL}, /* Connect-Info */
139
{NULL, 0, 0, NULL, NULL}, /* Configuration-Token */
140
{NULL, 0, 0, NULL, NULL}, /* EAP-Message */
141
{"Message-Authenticator", MD5_DIGEST_SIZE, MD5_DIGEST_SIZE, NULL, NULL},
142
};
143
144
/* Encode User-Password attribute. */
145
static krb5_error_code
146
user_password_encode(krb5_context ctx, const char *secret,
147
const unsigned char *auth, const krb5_data *in,
148
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
149
{
150
const unsigned char *indx;
151
krb5_error_code retval;
152
unsigned int seclen;
153
krb5_checksum sum;
154
size_t blck, len, i;
155
krb5_data tmp;
156
157
/* Copy the input buffer to the (zero-padded) output buffer. */
158
len = (in->length + BLOCKSIZE - 1) / BLOCKSIZE * BLOCKSIZE;
159
if (len > MAX_ATTRSIZE)
160
return ENOBUFS;
161
memset(outbuf, 0, len);
162
memcpy(outbuf, in->data, in->length);
163
164
/* Create our temporary space for processing each block. */
165
seclen = strlen(secret);
166
retval = alloc_data(&tmp, seclen + BLOCKSIZE);
167
if (retval != 0)
168
return retval;
169
170
memcpy(tmp.data, secret, seclen);
171
for (blck = 0, indx = auth; blck * BLOCKSIZE < len; blck++) {
172
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
173
174
retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
175
&sum);
176
if (retval != 0) {
177
zap(tmp.data, tmp.length);
178
zap(outbuf, len);
179
krb5_free_data_contents(ctx, &tmp);
180
return retval;
181
}
182
183
for (i = 0; i < BLOCKSIZE; i++)
184
outbuf[blck * BLOCKSIZE + i] ^= sum.contents[i];
185
krb5_free_checksum_contents(ctx, &sum);
186
187
indx = &outbuf[blck * BLOCKSIZE];
188
}
189
190
zap(tmp.data, tmp.length);
191
krb5_free_data_contents(ctx, &tmp);
192
*outlen = len;
193
return 0;
194
}
195
196
/* Decode User-Password attribute. */
197
static krb5_error_code
198
user_password_decode(krb5_context ctx, const char *secret,
199
const unsigned char *auth, const krb5_data *in,
200
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
201
{
202
const unsigned char *indx;
203
krb5_error_code retval;
204
unsigned int seclen;
205
krb5_checksum sum;
206
ssize_t blck, i;
207
krb5_data tmp;
208
209
if (in->length % BLOCKSIZE != 0)
210
return EINVAL;
211
if (in->length > MAX_ATTRSIZE)
212
return ENOBUFS;
213
214
/* Create our temporary space for processing each block. */
215
seclen = strlen(secret);
216
retval = alloc_data(&tmp, seclen + BLOCKSIZE);
217
if (retval != 0)
218
return retval;
219
220
memcpy(tmp.data, secret, seclen);
221
for (blck = 0, indx = auth; blck * BLOCKSIZE < in->length; blck++) {
222
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
223
224
retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
225
&tmp, &sum);
226
if (retval != 0) {
227
zap(tmp.data, tmp.length);
228
zap(outbuf, in->length);
229
krb5_free_data_contents(ctx, &tmp);
230
return retval;
231
}
232
233
for (i = 0; i < BLOCKSIZE; i++) {
234
outbuf[blck * BLOCKSIZE + i] = in->data[blck * BLOCKSIZE + i] ^
235
sum.contents[i];
236
}
237
krb5_free_checksum_contents(ctx, &sum);
238
239
indx = (const unsigned char *)&in->data[blck * BLOCKSIZE];
240
}
241
242
/* Strip off trailing NULL bytes. */
243
*outlen = in->length;
244
while (*outlen > 0 && outbuf[*outlen - 1] == '\0')
245
(*outlen)--;
246
247
krb5_free_data_contents(ctx, &tmp);
248
return 0;
249
}
250
251
krb5_error_code
252
kr_attr_valid(krad_attr type, const krb5_data *data)
253
{
254
const attribute_record *ar;
255
256
if (type == 0)
257
return EINVAL;
258
259
ar = &attributes[type - 1];
260
return (data->length >= ar->minval && data->length <= ar->maxval) ? 0 :
261
EMSGSIZE;
262
}
263
264
krb5_error_code
265
kr_attr_encode(krb5_context ctx, const char *secret,
266
const unsigned char *auth, krad_attr type,
267
const krb5_data *in, unsigned char outbuf[MAX_ATTRSIZE],
268
size_t *outlen)
269
{
270
krb5_error_code retval;
271
272
retval = kr_attr_valid(type, in);
273
if (retval != 0)
274
return retval;
275
276
if (attributes[type - 1].encode == NULL) {
277
if (in->length > MAX_ATTRSIZE)
278
return ENOBUFS;
279
280
*outlen = in->length;
281
memcpy(outbuf, in->data, in->length);
282
return 0;
283
}
284
285
return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen);
286
}
287
288
krb5_error_code
289
kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
290
krad_attr type, const krb5_data *in,
291
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
292
{
293
krb5_error_code retval;
294
295
retval = kr_attr_valid(type, in);
296
if (retval != 0)
297
return retval;
298
299
if (attributes[type - 1].encode == NULL) {
300
if (in->length > MAX_ATTRSIZE)
301
return ENOBUFS;
302
303
*outlen = in->length;
304
memcpy(outbuf, in->data, in->length);
305
return 0;
306
}
307
308
return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen);
309
}
310
311
krad_attr
312
krad_attr_name2num(const char *name)
313
{
314
unsigned char i;
315
316
for (i = 0; i < UCHAR_MAX; i++) {
317
if (attributes[i].name == NULL)
318
continue;
319
320
if (strcmp(attributes[i].name, name) == 0)
321
return i + 1;
322
}
323
324
return 0;
325
}
326
327
const char *
328
krad_attr_num2name(krad_attr type)
329
{
330
if (type == 0)
331
return NULL;
332
333
return attributes[type - 1].name;
334
}
335
336