69
* Everything's OK, add a digest authentication type.
71
if (pairfind(request->config_items, PW_AUTHTYPE) == NULL) {
72
DEBUG("rlm_digest: Adding Auth-Type = DIGEST");
73
pairadd(&request->config_items,
74
pairmake("Auth-Type", "DIGEST", T_OP_EQ));
81
* Perform all of the wondrous variants of digest authentication.
83
static int digest_authenticate(void *instance, REQUEST *request)
86
size_t a1_len, a2_len, kd_len;
87
uint8_t a1[(MAX_STRING_LEN + 1) * 5]; /* can be 5 attributes */
88
uint8_t a2[(MAX_STRING_LEN + 1) * 3]; /* can be 3 attributes */
89
uint8_t kd[(MAX_STRING_LEN + 1) * 5];
90
uint8_t hash[16]; /* MD5 output */
91
VALUE_PAIR *vp, *passwd, *algo;
92
VALUE_PAIR *qop, *nonce;
94
instance = instance; /* -Wunused */
97
* We require access to the plain-text password.
99
passwd = pairfind(request->config_items, PW_DIGEST_HA1);
101
if (passwd->length != 32) {
102
radlog(L_AUTH, "rlm_digest: Digest-HA1 has invalid length, authentication failed.");
103
return RLM_MODULE_INVALID;
106
passwd = pairfind(request->config_items, PW_PASSWORD);
109
radlog(L_AUTH, "rlm_digest: Configuration item \"User-Password\" or Digest-HA1 is required for authentication.");
110
return RLM_MODULE_INVALID;
114
* We need these, too.
116
vp = pairfind(request->packet->vps, PW_DIGEST_ATTRIBUTES);
118
DEBUG("ERROR: You set 'Auth-Type = Digest' for a request that did not contain any digest attributes!");
119
return RLM_MODULE_INVALID;
71
123
* Loop through the Digest-Attributes, sanity checking them.
73
125
DEBUG(" rlm_digest: Converting Digest-Attributes to something sane...");
152
* Everything's OK, add a digest authentication type.
154
if (pairfind(request->config_items, PW_AUTHTYPE) == NULL) {
155
DEBUG("rlm_digest: Adding Auth-Type = DIGEST");
156
pairadd(&request->config_items,
157
pairmake("Auth-Type", "DIGEST", T_OP_EQ));
160
return RLM_MODULE_OK;
164
* Convert a string in hex to one in binary
166
static void hex2bin(uint8_t *out, const uint8_t *in)
171
sscanf(in, "%02x", &tmp);
179
* Perform all of the wondrous variants of digest authentication.
181
static int digest_authenticate(void *instance, REQUEST *request)
184
int a1_len, a2_len, kd_len;
185
uint8_t a1[(MAX_STRING_LEN + 1) * 5]; /* can be 5 attributes */
186
uint8_t a2[(MAX_STRING_LEN + 1) * 3]; /* can be 3 attributes */
187
uint8_t kd[(MAX_STRING_LEN + 1) * 5];
188
uint8_t hash[16]; /* MD5 output */
190
VALUE_PAIR *qop, *nonce;
193
* We require access to the plain-text password.
195
vp = pairfind(request->config_items, PW_PASSWORD);
197
radlog(L_AUTH, "rlm_digest: Configuration item \"User-Password\" is required for authentication.");
198
return RLM_MODULE_INVALID;
202
204
* We require access to the Digest-Nonce-Value
204
206
nonce = pairfind(request->packet->vps, PW_DIGEST_NONCE);
232
234
a1[a1_len] = ':';
235
vp = pairfind(request->config_items, PW_PASSWORD);
237
DEBUG("ERROR: No User-Password: Cannot perform Digest authentication");
238
return RLM_MODULE_INVALID;
237
if (passwd->attribute == PW_USER_PASSWORD) {
238
memcpy(&a1[a1_len], &passwd->strvalue[0], passwd->length);
239
a1_len += passwd->length;
241
DEBUG2("A1 = %s", a1);
244
DEBUG2("A1 = %s (using Digest-HA1)", a1);
240
memcpy(&a1[a1_len], &vp->strvalue[0], vp->length);
241
a1_len += vp->length;
244
DEBUG2("A1 = %s", a1);
247
249
* See which variant we calculate.
250
* Assume MD5 if no Digest-Algorithm attribute received
249
vp = pairfind(request->packet->vps, PW_DIGEST_ALGORITHM);
251
(strcasecmp(vp->strvalue, "MD5-sess") == 0)) {
252
librad_md5_calc(hash, &a1[0], a1_len);
253
memcpy(&a1[0], hash, 16);
252
algo = pairfind(request->packet->vps, PW_DIGEST_ALGORITHM);
253
if ((algo == NULL) ||
254
(strcasecmp(algo->strvalue, "MD5") == 0)) {
256
* Set A1 to Digest-HA1 if no User-Password found
258
if (passwd->attribute == PW_DIGEST_HA1) {
259
lrad_hex2bin(passwd->strvalue, &a1[0], 16);
262
} else if (strcasecmp(algo->strvalue, "MD5-sess") == 0) {
264
* K1 = H(A1) : Digest-Nonce ... : H(A2)
266
* If we find Digest-HA1, we assume it contains
269
if (passwd->attribute == PW_USER_PASSWORD) {
270
librad_md5_calc(hash, &a1[0], a1_len);
271
lrad_bin2hex(hash, &a1[0], 16);
272
} else { /* MUST be Digest-HA1 */
273
memcpy(&a1[0], passwd->strvalue, 32);
256
277
a1[a1_len] = ':';
260
* Tack on the Digest-Nonce
281
* Tack on the Digest-Nonce. Length must be even
262
hex2bin(&a1[a1_len], &nonce->strvalue[0]);
263
a1_len += (nonce->length >> 1); /* FIXME: CHECK LENGTH */
283
if ((nonce->length & 1) != 0) {
284
DEBUG("ERROR: Received Digest-Nonce hex string with invalid length: Cannot perform Digest authentication");
285
return RLM_MODULE_INVALID;
287
memcpy(&a1[a1_len], &nonce->strvalue[0], nonce->length);
288
a1_len += nonce->length;
265
290
a1[a1_len] = ':';
268
293
vp = pairfind(request->packet->vps, PW_DIGEST_CNONCE);
270
DEBUG("ERROR: No Digest-CNonce: Cannot perform Digest authentication");
271
return RLM_MODULE_INVALID;
274
hex2bin(&a1[a1_len], &vp->strvalue[0]);
275
a1_len += (vp->length >> 1); /* FIXME: CHECK LENGTH */
277
} else if ((vp != NULL) &&
278
(strcasecmp(vp->strvalue, "MD5") != 0)) {
295
DEBUG("ERROR: No Digest-CNonce: Cannot perform Digest authentication");
296
return RLM_MODULE_INVALID;
300
* Digest-CNonce length must be even
302
if ((vp->length & 1) != 0) {
303
DEBUG("ERROR: Received Digest-CNonce hex string with invalid length: Cannot perform Digest authentication");
304
return RLM_MODULE_INVALID;
306
memcpy(&a1[a1_len], &vp->strvalue[0], vp->length);
307
a1_len += vp->length;
309
} else if ((algo != NULL) &&
310
(strcasecmp(algo->strvalue, "MD5") != 0)) {
280
312
* We check for "MD5-sess" and "MD5".
281
313
* Anything else is an error.
329
361
return RLM_MODULE_INVALID;
332
rad_assert(body->length == 32); /* FIXME: check in 'auth' */
333
hex2bin(&a2[a2_len], &body->strvalue[0]);
334
a2_len += (body->length >> 1);
364
if ((a2_len + body->length) > sizeof(a2)) {
365
DEBUG("ERROR: Digest-Body-Digest is too long");
366
return RLM_MODULE_INVALID;
369
memcpy(a2 + a2_len, body->strvalue, body->length);
370
a2_len += body->length;
336
372
} else if ((qop != NULL) &&
337
373
(strcasecmp(qop->strvalue, "auth") != 0)) {
343
379
DEBUG2("A2 = %s", a2);
346
* KD = H(A1) : Digest-Nonce ... : H(A2)
382
* KD = H(A1) : Digest-Nonce ... : H(A2).
383
* Compute MD5 if Digest-Algorithm == "MD5-Sess",
384
* or if we found a User-Password.
348
librad_md5_calc(&hash[0], &a1[0], a1_len);
350
for (i = 0; i < 16; i++) {
351
sprintf(&kd[i * 2], "%02x", hash[i]);
386
if (((algo != NULL) &&
387
(strcasecmp(algo->strvalue, "MD5-Sess") == 0)) ||
388
(passwd->attribute == PW_USER_PASSWORD)) {
390
librad_md5_calc(&hash[0], &a1[0], a1_len);
392
memcpy(&hash[0], &a1[0], a1_len);
394
lrad_bin2hex(hash, kd, sizeof(hash));
355
397
if (debug_flag) {