xref: /freebsd/crypto/krb5/src/lib/krad/packet.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krad/packet.c - Packet 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 "internal.h"
31 
32 #include <string.h>
33 
34 #include <arpa/inet.h>
35 
36 typedef unsigned char uchar;
37 
38 /* RFC 2865 */
39 #define MSGAUTH_SIZE (2 + MD5_DIGEST_SIZE)
40 #define OFFSET_CODE 0
41 #define OFFSET_ID 1
42 #define OFFSET_LENGTH 2
43 #define OFFSET_AUTH 4
44 #define OFFSET_ATTR 20
45 #define AUTH_FIELD_SIZE (OFFSET_ATTR - OFFSET_AUTH)
46 
47 #define offset(d, o) (&(d)->data[o])
48 #define pkt_code_get(p) (*(krad_code *)offset(&(p)->pkt, OFFSET_CODE))
49 #define pkt_code_set(p, v) (*(krad_code *)offset(&(p)->pkt, OFFSET_CODE)) = v
50 #define pkt_id_get(p) (*(uchar *)offset(&(p)->pkt, OFFSET_ID))
51 #define pkt_id_set(p, v) (*(uchar *)offset(&(p)->pkt, OFFSET_ID)) = v
52 #define pkt_len_get(p)  load_16_be(offset(&(p)->pkt, OFFSET_LENGTH))
53 #define pkt_len_set(p, v)  store_16_be(v, offset(&(p)->pkt, OFFSET_LENGTH))
54 #define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH))
55 #define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR))
56 
57 struct krad_packet_st {
58     char buffer[KRAD_PACKET_SIZE_MAX];
59     krad_attrset *attrset;
60     krb5_data pkt;
61 };
62 
63 typedef struct {
64     uchar x[(UCHAR_MAX + 1) / 8];
65 } idmap;
66 
67 /* Ensure the map is empty. */
68 static inline void
idmap_init(idmap * map)69 idmap_init(idmap *map)
70 {
71     memset(map, 0, sizeof(*map));
72 }
73 
74 /* Set an id as already allocated. */
75 static inline void
idmap_set(idmap * map,uchar id)76 idmap_set(idmap *map, uchar id)
77 {
78     map->x[id / 8] |= 1 << (id % 8);
79 }
80 
81 /* Determine whether or not an id is used. */
82 static inline krb5_boolean
idmap_isset(const idmap * map,uchar id)83 idmap_isset(const idmap *map, uchar id)
84 {
85     return (map->x[id / 8] & (1 << (id % 8))) != 0;
86 }
87 
88 /* Find an unused id starting the search at the value specified in id.
89  * NOTE: For optimal security, the initial value of id should be random. */
90 static inline krb5_error_code
idmap_find(const idmap * map,uchar * id)91 idmap_find(const idmap *map, uchar *id)
92 {
93     krb5_int16 i;
94 
95     for (i = *id; i >= 0 && i <= UCHAR_MAX; (*id % 2 == 0) ? i++ : i--) {
96         if (!idmap_isset(map, i))
97             goto success;
98     }
99 
100     for (i = *id; i >= 0 && i <= UCHAR_MAX; (*id % 2 == 1) ? i++ : i--) {
101         if (!idmap_isset(map, i))
102             goto success;
103     }
104 
105     return ERANGE;
106 
107 success:
108     *id = i;
109     return 0;
110 }
111 
112 /* Generate size bytes of random data into the buffer. */
113 static inline krb5_error_code
randomize(krb5_context ctx,void * buffer,unsigned int size)114 randomize(krb5_context ctx, void *buffer, unsigned int size)
115 {
116     krb5_data rdata = make_data(buffer, size);
117     return krb5_c_random_make_octets(ctx, &rdata);
118 }
119 
120 /* Generate a radius packet id. */
121 static krb5_error_code
id_generate(krb5_context ctx,krad_packet_iter_cb cb,void * data,uchar * id)122 id_generate(krb5_context ctx, krad_packet_iter_cb cb, void *data, uchar *id)
123 {
124     krb5_error_code retval;
125     const krad_packet *tmp;
126     idmap used;
127     uchar i;
128 
129     retval = randomize(ctx, &i, sizeof(i));
130     if (retval != 0) {
131         if (cb != NULL)
132             (*cb)(data, TRUE);
133         return retval;
134     }
135 
136     if (cb != NULL) {
137         idmap_init(&used);
138         for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE))
139             idmap_set(&used, tmp->pkt.data[1]);
140 
141         retval = idmap_find(&used, &i);
142         if (retval != 0)
143             return retval;
144     }
145 
146     *id = i;
147     return 0;
148 }
149 
150 /* Generate a random authenticator field. */
151 static krb5_error_code
auth_generate_random(krb5_context ctx,uchar * rauth)152 auth_generate_random(krb5_context ctx, uchar *rauth)
153 {
154     krb5_ui_4 trunctime;
155     time_t currtime;
156 
157     /* Get the least-significant four bytes of the current time. */
158     currtime = time(NULL);
159     if (currtime == (time_t)-1)
160         return errno;
161     trunctime = (krb5_ui_4)currtime;
162     memcpy(rauth, &trunctime, sizeof(trunctime));
163 
164     /* Randomize the rest of the buffer. */
165     return randomize(ctx, rauth + sizeof(trunctime),
166                      AUTH_FIELD_SIZE - sizeof(trunctime));
167 }
168 
169 /* Generate a response authenticator field. */
170 static krb5_error_code
auth_generate_response(krb5_context ctx,const char * secret,const krad_packet * response,const uchar * auth,uchar * rauth)171 auth_generate_response(krb5_context ctx, const char *secret,
172                        const krad_packet *response, const uchar *auth,
173                        uchar *rauth)
174 {
175     krb5_error_code retval;
176     krb5_checksum hash;
177     krb5_data data;
178 
179     /* Allocate the temporary buffer. */
180     retval = alloc_data(&data, response->pkt.length + strlen(secret));
181     if (retval != 0)
182         return retval;
183 
184     /* Encoded RADIUS packet with the request's
185      * authenticator and the secret at the end. */
186     memcpy(data.data, response->pkt.data, response->pkt.length);
187     memcpy(data.data + OFFSET_AUTH, auth, AUTH_FIELD_SIZE);
188     memcpy(data.data + response->pkt.length, secret, strlen(secret));
189 
190     /* Hash it. */
191     retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
192                                   &hash);
193     free(data.data);
194     if (retval != 0)
195         return retval;
196 
197     memcpy(rauth, hash.contents, AUTH_FIELD_SIZE);
198     krb5_free_checksum_contents(ctx, &hash);
199     return 0;
200 }
201 
202 /* Create a new packet. */
203 static krad_packet *
packet_new(void)204 packet_new(void)
205 {
206     krad_packet *pkt;
207 
208     pkt = calloc(1, sizeof(krad_packet));
209     if (pkt == NULL)
210         return NULL;
211     pkt->pkt = make_data(pkt->buffer, sizeof(pkt->buffer));
212 
213     return pkt;
214 }
215 
216 /* Set the attrset object by decoding the packet. */
217 static krb5_error_code
packet_set_attrset(krb5_context ctx,const char * secret,krad_packet * pkt)218 packet_set_attrset(krb5_context ctx, const char *secret, krad_packet *pkt)
219 {
220     krb5_data tmp;
221 
222     tmp = make_data(pkt_attr(pkt), pkt->pkt.length - OFFSET_ATTR);
223     return kr_attrset_decode(ctx, &tmp, secret, pkt_auth(pkt), &pkt->attrset);
224 }
225 
226 /* Determine if a packet requires a Message-Authenticator attribute. */
227 static inline krb5_boolean
requires_msgauth(const char * secret,krad_code code)228 requires_msgauth(const char *secret, krad_code code)
229 {
230     /* If no secret is provided, assume that the transport is a UNIX socket.
231      * Message-Authenticator is required only on UDP and TCP connections. */
232     if (*secret == '\0')
233         return FALSE;
234 
235     /*
236      * Per draft-ietf-radext-deprecating-radius-03 sections 5.2.1 and 5.2.4,
237      * Message-Authenticator is required in Access-Request packets and all
238      * potential responses when UDP or TCP transport is used.
239      */
240     return code == KRAD_CODE_ACCESS_REQUEST ||
241         code == KRAD_CODE_ACCESS_ACCEPT || code == KRAD_CODE_ACCESS_REJECT ||
242         code == KRAD_CODE_ACCESS_CHALLENGE;
243 }
244 
245 /* Check if the packet has a Message-Authenticator attribute. */
246 static inline krb5_boolean
has_pkt_msgauth(const krad_packet * pkt)247 has_pkt_msgauth(const krad_packet *pkt)
248 {
249     return krad_attrset_get(pkt->attrset, KRAD_ATTR_MESSAGE_AUTHENTICATOR,
250                             0) != NULL;
251 }
252 
253 /* Return the beginning of the Message-Authenticator attribute in pkt, or NULL
254  * if no such attribute is present. */
255 static const uint8_t *
lookup_msgauth_addr(const krad_packet * pkt)256 lookup_msgauth_addr(const krad_packet *pkt)
257 {
258     size_t i;
259     uint8_t *p;
260 
261     i = OFFSET_ATTR;
262     while (i + 2 < pkt->pkt.length) {
263         p = (uint8_t *)offset(&pkt->pkt, i);
264         if (*p == KRAD_ATTR_MESSAGE_AUTHENTICATOR)
265             return p;
266         i += p[1];
267     }
268 
269     return NULL;
270 }
271 
272 /*
273  * Calculate the message authenticator MAC for pkt as specified in RFC 2869
274  * section 5.14, placing the result in mac_out.  Use the provided authenticator
275  * auth, which may be from pkt or from a corresponding request.
276  */
277 static krb5_error_code
calculate_mac(const char * secret,const krad_packet * pkt,const uint8_t auth[AUTH_FIELD_SIZE],uint8_t mac_out[MD5_DIGEST_SIZE])278 calculate_mac(const char *secret, const krad_packet *pkt,
279               const uint8_t auth[AUTH_FIELD_SIZE],
280               uint8_t mac_out[MD5_DIGEST_SIZE])
281 {
282     const uint8_t *msgauth_attr, *msgauth_end, *pkt_end;
283     krb5_crypto_iov input[5];
284     krb5_data ksecr, mac;
285     static const uint8_t zeroed_msgauth[MSGAUTH_SIZE] = {
286         KRAD_ATTR_MESSAGE_AUTHENTICATOR, MSGAUTH_SIZE
287     };
288 
289     msgauth_attr = lookup_msgauth_addr(pkt);
290     if (msgauth_attr == NULL)
291         return EINVAL;
292     msgauth_end = msgauth_attr + MSGAUTH_SIZE;
293     pkt_end = (const uint8_t *)pkt->pkt.data + pkt->pkt.length;
294 
295     /* Read code, id, and length from the packet. */
296     input[0].flags = KRB5_CRYPTO_TYPE_DATA;
297     input[0].data = make_data(pkt->pkt.data, OFFSET_AUTH);
298 
299     /* Read the provided authenticator. */
300     input[1].flags = KRB5_CRYPTO_TYPE_DATA;
301     input[1].data = make_data((uint8_t *)auth, AUTH_FIELD_SIZE);
302 
303     /* Read any attributes before Message-Authenticator. */
304     input[2].flags = KRB5_CRYPTO_TYPE_DATA;
305     input[2].data = make_data(pkt_attr(pkt), msgauth_attr - pkt_attr(pkt));
306 
307     /* Read Message-Authenticator with the data bytes all set to zero, per RFC
308      * 2869 section 5.14. */
309     input[3].flags = KRB5_CRYPTO_TYPE_DATA;
310     input[3].data = make_data((uint8_t *)zeroed_msgauth, MSGAUTH_SIZE);
311 
312     /* Read any attributes after Message-Authenticator. */
313     input[4].flags = KRB5_CRYPTO_TYPE_DATA;
314     input[4].data = make_data((uint8_t *)msgauth_end, pkt_end - msgauth_end);
315 
316     mac = make_data(mac_out, MD5_DIGEST_SIZE);
317     ksecr = string2data((char *)secret);
318     return k5_hmac_md5(&ksecr, input, 5, &mac);
319 }
320 
321 ssize_t
krad_packet_bytes_needed(const krb5_data * buffer)322 krad_packet_bytes_needed(const krb5_data *buffer)
323 {
324     size_t len;
325 
326     if (buffer->length < OFFSET_AUTH)
327         return OFFSET_AUTH - buffer->length;
328 
329     len = load_16_be(offset(buffer, OFFSET_LENGTH));
330     if (len > KRAD_PACKET_SIZE_MAX)
331         return -1;
332 
333     return (buffer->length > len) ? 0 : len - buffer->length;
334 }
335 
336 void
krad_packet_free(krad_packet * pkt)337 krad_packet_free(krad_packet *pkt)
338 {
339     if (pkt)
340         krad_attrset_free(pkt->attrset);
341     free(pkt);
342 }
343 
344 /* Create a new request packet. */
345 krb5_error_code
krad_packet_new_request(krb5_context ctx,const char * secret,krad_code code,const krad_attrset * set,krad_packet_iter_cb cb,void * data,krad_packet ** request)346 krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
347                         const krad_attrset *set, krad_packet_iter_cb cb,
348                         void *data, krad_packet **request)
349 {
350     krb5_error_code retval;
351     krad_packet *pkt;
352     uchar id;
353     size_t attrset_len;
354     krb5_boolean msgauth_required;
355 
356     pkt = packet_new();
357     if (pkt == NULL) {
358         if (cb != NULL)
359             (*cb)(data, TRUE);
360         return ENOMEM;
361     }
362 
363     /* Generate the ID. */
364     retval = id_generate(ctx, cb, data, &id);
365     if (retval != 0)
366         goto error;
367     pkt_id_set(pkt, id);
368 
369     /* Generate the authenticator. */
370     retval = auth_generate_random(ctx, pkt_auth(pkt));
371     if (retval != 0)
372         goto error;
373 
374     /* Determine if Message-Authenticator is required. */
375     msgauth_required = (*secret != '\0' && code == KRAD_CODE_ACCESS_REQUEST);
376 
377     /* Encode the attributes. */
378     retval = kr_attrset_encode(set, secret, pkt_auth(pkt), msgauth_required,
379                                pkt_attr(pkt), &attrset_len);
380     if (retval != 0)
381         goto error;
382 
383     /* Set the code, ID and length. */
384     pkt->pkt.length = attrset_len + OFFSET_ATTR;
385     pkt_code_set(pkt, code);
386     pkt_len_set(pkt, pkt->pkt.length);
387 
388     if (msgauth_required) {
389         /* Calculate and set the Message-Authenticator MAC. */
390         retval = calculate_mac(secret, pkt, pkt_auth(pkt), pkt_attr(pkt) + 2);
391         if (retval != 0)
392             goto error;
393     }
394 
395     /* Copy the attrset for future use. */
396     retval = packet_set_attrset(ctx, secret, pkt);
397     if (retval != 0)
398         goto error;
399 
400     *request = pkt;
401     return 0;
402 
403 error:
404     free(pkt);
405     return retval;
406 }
407 
408 /* Create a new request packet. */
409 krb5_error_code
krad_packet_new_response(krb5_context ctx,const char * secret,krad_code code,const krad_attrset * set,const krad_packet * request,krad_packet ** response)410 krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
411                          const krad_attrset *set, const krad_packet *request,
412                          krad_packet **response)
413 {
414     krb5_error_code retval;
415     krad_packet *pkt;
416     size_t attrset_len;
417     krb5_boolean msgauth_required;
418 
419     pkt = packet_new();
420     if (pkt == NULL)
421         return ENOMEM;
422 
423     /* Determine if Message-Authenticator is required. */
424     msgauth_required = requires_msgauth(secret, code);
425 
426     /* Encode the attributes. */
427     retval = kr_attrset_encode(set, secret, pkt_auth(request),
428                                msgauth_required, pkt_attr(pkt), &attrset_len);
429     if (retval != 0)
430         goto error;
431 
432     /* Set the code, ID and length. */
433     pkt->pkt.length = attrset_len + OFFSET_ATTR;
434     pkt_code_set(pkt, code);
435     pkt_id_set(pkt, pkt_id_get(request));
436     pkt_len_set(pkt, pkt->pkt.length);
437 
438     /* Generate the authenticator. */
439     retval = auth_generate_response(ctx, secret, pkt, pkt_auth(request),
440                                     pkt_auth(pkt));
441     if (retval != 0)
442         goto error;
443 
444     if (msgauth_required) {
445         /*
446          * Calculate and replace the Message-Authenticator MAC.  Per RFC 2869
447          * section 5.14, use the authenticator from the request, not from the
448          * response.
449          */
450         retval = calculate_mac(secret, pkt, pkt_auth(request),
451                                pkt_attr(pkt) + 2);
452         if (retval != 0)
453             goto error;
454     }
455 
456     /* Copy the attrset for future use. */
457     retval = packet_set_attrset(ctx, secret, pkt);
458     if (retval != 0)
459         goto error;
460 
461     *response = pkt;
462     return 0;
463 
464 error:
465     free(pkt);
466     return retval;
467 }
468 
469 /* Verify the Message-Authenticator value in pkt, using the provided
470  * authenticator (which may be from pkt or from a corresponding request). */
471 static krb5_error_code
verify_msgauth(const char * secret,const krad_packet * pkt,const uint8_t auth[AUTH_FIELD_SIZE])472 verify_msgauth(const char *secret, const krad_packet *pkt,
473                const uint8_t auth[AUTH_FIELD_SIZE])
474 {
475     uint8_t mac[MD5_DIGEST_SIZE];
476     const krb5_data *msgauth;
477     krb5_error_code retval;
478 
479     msgauth = krad_packet_get_attr(pkt, KRAD_ATTR_MESSAGE_AUTHENTICATOR, 0);
480 /* XXX ENODATA does not exist in FreeBSD. The closest thing we have to */
481 /* XXX ENODATA is ENOATTR. We use that instead. */
482 #define ENODATA ENOATTR
483     if (msgauth == NULL)
484         return ENODATA;
485 
486     retval = calculate_mac(secret, pkt, auth, mac);
487     if (retval)
488         return retval;
489 
490     if (msgauth->length != MD5_DIGEST_SIZE)
491         return EMSGSIZE;
492 
493     if (k5_bcmp(mac, msgauth->data, MD5_DIGEST_SIZE) != 0)
494         return EBADMSG;
495 
496     return 0;
497 }
498 
499 /* Decode a packet. */
500 static krb5_error_code
decode_packet(krb5_context ctx,const char * secret,const krb5_data * buffer,krad_packet ** pkt)501 decode_packet(krb5_context ctx, const char *secret, const krb5_data *buffer,
502               krad_packet **pkt)
503 {
504     krb5_error_code retval;
505     krad_packet *tmp;
506     krb5_ui_2 len;
507 
508     tmp = packet_new();
509     if (tmp == NULL) {
510         retval = ENOMEM;
511         goto error;
512     }
513 
514     /* Ensure a proper message length. */
515     retval = (buffer->length < OFFSET_ATTR) ? EMSGSIZE : 0;
516     if (retval != 0)
517         goto error;
518     len = load_16_be(offset(buffer, OFFSET_LENGTH));
519     retval = (len < OFFSET_ATTR) ? EBADMSG : 0;
520     if (retval != 0)
521         goto error;
522     retval = (len > buffer->length || len > tmp->pkt.length) ? EBADMSG : 0;
523     if (retval != 0)
524         goto error;
525 
526     /* Copy over the buffer. */
527     tmp->pkt.length = len;
528     memcpy(tmp->pkt.data, buffer->data, len);
529 
530     /* Parse the packet to ensure it is well-formed. */
531     retval = packet_set_attrset(ctx, secret, tmp);
532     if (retval != 0)
533         goto error;
534 
535     *pkt = tmp;
536     return 0;
537 
538 error:
539     krad_packet_free(tmp);
540     return retval;
541 }
542 
543 krb5_error_code
krad_packet_decode_request(krb5_context ctx,const char * secret,const krb5_data * buffer,krad_packet_iter_cb cb,void * data,const krad_packet ** duppkt,krad_packet ** reqpkt)544 krad_packet_decode_request(krb5_context ctx, const char *secret,
545                            const krb5_data *buffer, krad_packet_iter_cb cb,
546                            void *data, const krad_packet **duppkt,
547                            krad_packet **reqpkt)
548 {
549     const krad_packet *tmp = NULL;
550     krad_packet *req;
551     krb5_error_code retval;
552 
553     retval = decode_packet(ctx, secret, buffer, &req);
554     if (retval)
555         return retval;
556 
557     /* Verify Message-Authenticator if present. */
558     if (has_pkt_msgauth(req)) {
559         retval = verify_msgauth(secret, req, pkt_auth(req));
560         if (retval) {
561             krad_packet_free(req);
562             return retval;
563         }
564     }
565 
566     if (cb != NULL) {
567         for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) {
568             if (pkt_id_get(*reqpkt) == pkt_id_get(tmp))
569                 break;
570         }
571 
572         if (tmp != NULL)
573             (*cb)(data, TRUE);
574     }
575 
576     *reqpkt = req;
577     *duppkt = tmp;
578     return 0;
579 }
580 
581 krb5_error_code
krad_packet_decode_response(krb5_context ctx,const char * secret,const krb5_data * buffer,krad_packet_iter_cb cb,void * data,const krad_packet ** reqpkt,krad_packet ** rsppkt)582 krad_packet_decode_response(krb5_context ctx, const char *secret,
583                             const krb5_data *buffer, krad_packet_iter_cb cb,
584                             void *data, const krad_packet **reqpkt,
585                             krad_packet **rsppkt)
586 {
587     uchar auth[AUTH_FIELD_SIZE];
588     const krad_packet *tmp = NULL;
589     krb5_error_code retval;
590 
591     retval = decode_packet(ctx, secret, buffer, rsppkt);
592     if (cb != NULL && retval == 0) {
593         for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) {
594             if (pkt_id_get(*rsppkt) != pkt_id_get(tmp))
595                 continue;
596 
597             /* Response */
598             retval = auth_generate_response(ctx, secret, *rsppkt,
599                                             pkt_auth(tmp), auth);
600             if (retval != 0) {
601                 krad_packet_free(*rsppkt);
602                 break;
603             }
604 
605             /* Verify the response authenticator. */
606             if (k5_bcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) != 0)
607                 continue;
608 
609             /* Verify Message-Authenticator if present. */
610             if (has_pkt_msgauth(*rsppkt)) {
611                 if (verify_msgauth(secret, *rsppkt, pkt_auth(tmp)) != 0)
612                     continue;
613             }
614 
615             break;
616         }
617     }
618 
619     if (cb != NULL && (retval != 0 || tmp != NULL))
620         (*cb)(data, TRUE);
621 
622     *reqpkt = tmp;
623     return retval;
624 }
625 
626 const krb5_data *
krad_packet_encode(const krad_packet * pkt)627 krad_packet_encode(const krad_packet *pkt)
628 {
629     return &pkt->pkt;
630 }
631 
632 krad_code
krad_packet_get_code(const krad_packet * pkt)633 krad_packet_get_code(const krad_packet *pkt)
634 {
635     if (pkt == NULL)
636         return 0;
637 
638     return pkt_code_get(pkt);
639 }
640 
641 const krb5_data *
krad_packet_get_attr(const krad_packet * pkt,krad_attr type,size_t indx)642 krad_packet_get_attr(const krad_packet *pkt, krad_attr type, size_t indx)
643 {
644     return krad_attrset_get(pkt->attrset, type, indx);
645 }
646