Move functions and prototypes from one file to another to avoid having to install...
[sipe-libnice.git] / stun / stunagent.c
blob1194b17c1390785990f2f6630ca2aba5eceb96db
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2007 Nokia Corporation. All rights reserved.
5 * Contact: Rémi Denis-Courmont
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is the Nice GLib ICE library.
19 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
20 * Corporation. All Rights Reserved.
22 * Contributors:
23 * Rémi Denis-Courmont, Nokia
25 * Alternatively, the contents of this file may be used under the terms of the
26 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
27 * case the provisions of LGPL are applicable instead of those above. If you
28 * wish to allow use of your version of this file only under the terms of the
29 * LGPL and not to allow others to use your version of this file under the
30 * MPL, indicate your decision by deleting the provisions above and replace
31 * them with the notice and other provisions required by the LGPL. If you do
32 * not delete the provisions above, a recipient may use your version of this
33 * file under either the MPL or the LGPL.
36 #ifdef HAVE_CONFIG_H
37 # include <config.h>
38 #endif
40 #include "stunmessage.h"
41 #include "stunagent.h"
42 #include "stunhmac.h"
43 #include "stun5389.h"
44 #include "utils.h"
46 #include <string.h>
47 #include <stdlib.h>
50 static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type);
51 static unsigned stun_agent_find_unknowns (StunAgent *agent,
52 const StunMessage * msg, uint16_t *list, unsigned max);
54 void stun_agent_init (StunAgent *agent, const uint16_t *known_attributes,
55 StunCompatibility compatibility, StunAgentUsageFlags usage_flags)
57 int i;
59 agent->known_attributes = (uint16_t *) known_attributes;
60 agent->compatibility = compatibility;
61 agent->usage_flags = usage_flags;
63 for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) {
64 agent->sent_ids[i].valid = FALSE;
69 bool stun_agent_default_validater (StunAgent *agent,
70 StunMessage *message, uint8_t *username, uint16_t username_len,
71 uint8_t **password, size_t *password_len, void *user_data)
73 StunDefaultValidaterData* val = (StunDefaultValidaterData *) user_data;
74 int i;
76 for (i = 0; val && val[i].username ; i++) {
77 stun_debug ("Comparing username '");
78 stun_debug_bytes (username, username_len);
79 stun_debug ("' (%d) with '", username_len);
80 stun_debug_bytes (val[i].username, val[i].username_len);
81 stun_debug ("' (%d) : %d\n",
82 val[i].username_len, memcmp (username, val[i].username, username_len));
83 if (username_len == val[i].username_len &&
84 memcmp (username, val[i].username, username_len) == 0) {
85 *password = (uint8_t *) val[i].password;
86 *password_len = val[i].password_len;
87 stun_debug ("Found valid username, returning password : '%s'\n", *password);
88 return TRUE;
92 return FALSE;
96 StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
97 const uint8_t *buffer, size_t buffer_len,
98 StunMessageIntegrityValidate validater, void * validater_data)
100 StunTransactionId msg_id;
101 uint32_t fpr;
102 uint32_t crc32;
103 int len;
104 uint8_t *username = NULL;
105 uint16_t username_len;
106 uint8_t *key = NULL;
107 size_t key_len;
108 uint8_t *hash;
109 uint8_t sha[20];
110 uint16_t hlen;
111 int sent_id_idx = -1;
112 uint16_t unknown;
113 int error_code;
114 int ignore_credentials = 0;
115 uint8_t long_term_key[16];
116 bool long_term_key_valid = FALSE;
118 len = stun_message_validate_buffer_length (buffer, buffer_len);
119 if (len == STUN_MESSAGE_BUFFER_INVALID) {
120 return STUN_VALIDATION_NOT_STUN;
121 } else if (len == STUN_MESSAGE_BUFFER_INCOMPLETE) {
122 return STUN_VALIDATION_INCOMPLETE_STUN;
123 } else if (len != (int) buffer_len) {
124 return STUN_VALIDATION_NOT_STUN;
127 msg->buffer = (uint8_t *) buffer;
128 msg->buffer_len = buffer_len;
129 msg->agent = agent;
130 msg->key = NULL;
131 msg->key_len = 0;
132 msg->long_term_valid = FALSE;
134 /* TODO: reject it or not ? */
135 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
136 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
137 !stun_message_has_cookie (msg)) {
138 stun_debug ("STUN demux error: no cookie!\n");
139 return STUN_VALIDATION_BAD_REQUEST;
142 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
143 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
144 agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
145 /* Looks for FINGERPRINT */
146 if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) !=
147 STUN_MESSAGE_RETURN_SUCCESS) {
148 stun_debug ("STUN demux error: no FINGERPRINT attribute!\n");
149 return STUN_VALIDATION_BAD_REQUEST;
151 /* Checks FINGERPRINT */
152 crc32 = stun_fingerprint (msg->buffer, stun_message_length (msg),
153 agent->compatibility == STUN_COMPATIBILITY_WLM2009);
154 fpr = ntohl (fpr);
155 if (fpr != crc32) {
156 stun_debug ("STUN demux error: bad fingerprint: 0x%08x,"
157 " expected: 0x%08x!\n", fpr, crc32);
158 return STUN_VALIDATION_BAD_REQUEST;
161 stun_debug ("STUN demux: OK!\n");
164 if (stun_message_get_class (msg) == STUN_RESPONSE ||
165 stun_message_get_class (msg) == STUN_ERROR) {
166 stun_message_id (msg, msg_id);
167 for (sent_id_idx = 0; sent_id_idx < STUN_AGENT_MAX_SAVED_IDS; sent_id_idx++) {
168 if (agent->sent_ids[sent_id_idx].valid == TRUE &&
169 agent->sent_ids[sent_id_idx].method == stun_message_get_method (msg) &&
170 memcmp (msg_id, agent->sent_ids[sent_id_idx].id,
171 sizeof(StunTransactionId)) == 0) {
173 key = agent->sent_ids[sent_id_idx].key;
174 key_len = agent->sent_ids[sent_id_idx].key_len;
175 memcpy (long_term_key, agent->sent_ids[sent_id_idx].long_term_key,
176 sizeof(long_term_key));
177 long_term_key_valid = agent->sent_ids[sent_id_idx].long_term_valid;
178 break;
181 if (sent_id_idx == STUN_AGENT_MAX_SAVED_IDS) {
182 return STUN_VALIDATION_UNMATCHED_RESPONSE;
186 ignore_credentials =
187 (agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) ||
188 (stun_message_get_class (msg) == STUN_ERROR &&
189 stun_message_find_error (msg, &error_code) ==
190 STUN_MESSAGE_RETURN_SUCCESS &&
191 (error_code == 400 || error_code == 401)) ||
192 (stun_message_get_class (msg) == STUN_INDICATION &&
193 (agent->usage_flags & STUN_AGENT_USAGE_NO_INDICATION_AUTH));
195 if (key == NULL &&
196 ignore_credentials == 0 &&
197 (stun_message_get_class (msg) == STUN_REQUEST ||
198 stun_message_get_class (msg) == STUN_INDICATION) &&
199 (((agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS) &&
200 (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
201 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY))) ||
202 ((agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) &&
203 stun_message_get_class (msg) == STUN_REQUEST &&
204 (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
205 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) ||
206 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_NONCE) ||
207 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_REALM))) ||
208 ((agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) == 0 &&
209 stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) &&
210 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY)))) {
211 return STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST;
214 if (stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) &&
215 ((key == NULL && ignore_credentials == 0) ||
216 (agent->usage_flags & STUN_AGENT_USAGE_FORCE_VALIDATER))) {
217 username_len = 0;
218 username = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_USERNAME,
219 &username_len);
220 if (validater == NULL ||
221 validater (agent, msg, username, username_len,
222 &key, &key_len, validater_data) == FALSE) {
223 return STUN_VALIDATION_UNAUTHORIZED;
227 if (ignore_credentials == 0 && key != NULL && key_len > 0) {
228 hash = (uint8_t *) stun_message_find (msg,
229 STUN_ATTRIBUTE_MESSAGE_INTEGRITY, &hlen);
231 if (hash) {
232 /* We must give the size from start to the end of the attribute
233 because you might have a FINGERPRINT attribute after it... */
234 if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
235 uint8_t *realm = NULL;
236 uint8_t *username = NULL;
237 uint16_t realm_len;
238 uint16_t username_len;
239 uint8_t md5[16];
241 if (long_term_key_valid) {
242 memcpy (md5, long_term_key, sizeof (md5));
243 } else {
244 realm = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_REALM, &realm_len);
245 username = (uint8_t *) stun_message_find (msg,
246 STUN_ATTRIBUTE_USERNAME, &username_len);
247 if (username == NULL || realm == NULL) {
248 return STUN_VALIDATION_UNAUTHORIZED;
250 stun_hash_creds (realm, realm_len,
251 username, username_len,
252 key, key_len, md5);
255 memcpy (msg->long_term_key, md5, sizeof(md5));
256 msg->long_term_valid = TRUE;
258 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
259 stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
260 sha, md5, sizeof(md5), TRUE);
261 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
262 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
263 stun_message_length (msg) - 20, sha, md5, sizeof(md5), TRUE);
264 } else {
265 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
266 hash - msg->buffer, sha, md5, sizeof(md5), FALSE);
268 } else {
269 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
270 stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
271 sha, key, key_len, TRUE);
272 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
273 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
274 stun_message_length (msg) - 20, sha, key, key_len, TRUE);
275 } else {
276 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
277 hash - msg->buffer, sha, key, key_len, FALSE);
281 stun_debug (" Message HMAC-SHA1 fingerprint:");
282 stun_debug ("\nkey : ");
283 stun_debug_bytes (key, key_len);
284 stun_debug ("\n expected: ");
285 stun_debug_bytes (sha, sizeof (sha));
286 stun_debug ("\n received: ");
287 stun_debug_bytes (hash, sizeof (sha));
288 stun_debug ("\n");
290 if (memcmp (sha, hash, sizeof (sha))) {
291 stun_debug ("STUN auth error: SHA1 fingerprint mismatch!\n");
292 return STUN_VALIDATION_UNAUTHORIZED;
295 stun_debug ("STUN auth: OK!\n");
296 msg->key = key;
297 msg->key_len = key_len;
298 } else if (!(stun_message_get_class (msg) == STUN_ERROR &&
299 stun_message_find_error (msg, &error_code) ==
300 STUN_MESSAGE_RETURN_SUCCESS &&
301 (error_code == 400 || error_code == 401))) {
302 stun_debug ("STUN auth error: No message integrity attribute!\n");
303 return STUN_VALIDATION_UNAUTHORIZED;
308 if (sent_id_idx != -1 && sent_id_idx < STUN_AGENT_MAX_SAVED_IDS) {
309 agent->sent_ids[sent_id_idx].valid = FALSE;
312 if (stun_agent_find_unknowns (agent, msg, &unknown, 1) > 0) {
313 if (stun_message_get_class (msg) == STUN_REQUEST)
314 return STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE;
315 else
316 return STUN_VALIDATION_UNKNOWN_ATTRIBUTE;
318 return STUN_VALIDATION_SUCCESS;
323 bool stun_agent_init_request (StunAgent *agent, StunMessage *msg,
324 uint8_t *buffer, size_t buffer_len, StunMethod m)
326 bool ret;
327 StunTransactionId id;
329 msg->buffer = buffer;
330 msg->buffer_len = buffer_len;
331 msg->agent = agent;
332 msg->key = NULL;
333 msg->key_len = 0;
334 msg->long_term_valid = FALSE;
336 stun_make_transid (id);
338 ret = stun_message_init (msg, STUN_REQUEST, m, id);
340 if (ret) {
341 if (agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
342 agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
343 uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
344 memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie));
348 return ret;
352 bool stun_agent_init_indication (StunAgent *agent, StunMessage *msg,
353 uint8_t *buffer, size_t buffer_len, StunMethod m)
355 bool ret;
356 StunTransactionId id;
358 msg->buffer = buffer;
359 msg->buffer_len = buffer_len;
360 msg->agent = agent;
361 msg->key = NULL;
362 msg->key_len = 0;
363 msg->long_term_valid = FALSE;
365 stun_make_transid (id);
366 ret = stun_message_init (msg, STUN_INDICATION, m, id);
368 if (ret) {
369 if (agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
370 agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
371 uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
372 memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie));
376 return ret;
380 bool stun_agent_init_response (StunAgent *agent, StunMessage *msg,
381 uint8_t *buffer, size_t buffer_len, const StunMessage *request)
384 StunTransactionId id;
386 if (stun_message_get_class (request) != STUN_REQUEST) {
387 return FALSE;
390 msg->buffer = buffer;
391 msg->buffer_len = buffer_len;
392 msg->agent = agent;
393 msg->key = request->key;
394 msg->key_len = request->key_len;
395 memmove (msg->long_term_key, request->long_term_key,
396 sizeof(msg->long_term_key));
397 msg->long_term_valid = request->long_term_valid;
399 stun_message_id (request, id);
401 if (stun_message_init (msg, STUN_RESPONSE,
402 stun_message_get_method (request), id)) {
404 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
405 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
406 agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE) {
407 stun_message_append_software (msg);
409 return TRUE;
411 return FALSE;
415 bool stun_agent_init_error (StunAgent *agent, StunMessage *msg,
416 uint8_t *buffer, size_t buffer_len, const StunMessage *request,
417 StunError err)
419 StunTransactionId id;
421 if (stun_message_get_class (request) != STUN_REQUEST) {
422 return FALSE;
425 msg->buffer = buffer;
426 msg->buffer_len = buffer_len;
427 msg->agent = agent;
428 msg->key = request->key;
429 msg->key_len = request->key_len;
430 memmove (msg->long_term_key, request->long_term_key,
431 sizeof(msg->long_term_key));
432 msg->long_term_valid = request->long_term_valid;
434 stun_message_id (request, id);
437 if (stun_message_init (msg, STUN_ERROR,
438 stun_message_get_method (request), id)) {
440 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
441 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
442 agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE) {
443 stun_message_append_software (msg);
445 if (stun_message_append_error (msg, err) == STUN_MESSAGE_RETURN_SUCCESS) {
446 return TRUE;
449 return FALSE;
453 size_t stun_agent_build_unknown_attributes_error (StunAgent *agent,
454 StunMessage *msg, uint8_t *buffer, size_t buffer_len,
455 const StunMessage *request)
458 unsigned counter;
459 uint16_t ids[STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES];
461 counter = stun_agent_find_unknowns (agent, request,
462 ids, STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES);
464 if (stun_agent_init_error (agent, msg, buffer, buffer_len,
465 request, STUN_ERROR_UNKNOWN_ATTRIBUTE) == FALSE) {
466 return 0;
469 /* NOTE: Old RFC3489 compatibility:
470 * When counter is odd, duplicate one value for 32-bits padding. */
471 if (!stun_message_has_cookie (request) && (counter & 1))
472 ids[counter++] = ids[0];
474 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES,
475 ids, counter * 2) == STUN_MESSAGE_RETURN_SUCCESS) {
476 return stun_agent_finish_message (agent, msg, request->key, request->key_len);
479 return 0;
483 size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
484 const uint8_t *key, size_t key_len)
486 uint8_t *ptr;
487 uint32_t fpr;
488 int i;
489 StunTransactionId id;
490 uint8_t md5[16];
492 if (msg->key != NULL) {
493 key = msg->key;
494 key_len = msg->key_len;
497 if (key != NULL) {
498 bool skip = FALSE;
500 if (msg->long_term_valid) {
501 memcpy (md5, msg->long_term_key, sizeof(msg->long_term_key));
502 } else if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
503 uint8_t *realm = NULL;
504 uint8_t *username = NULL;
505 uint16_t realm_len;
506 uint16_t username_len;
508 realm = (uint8_t *) stun_message_find (msg,
509 STUN_ATTRIBUTE_REALM, &realm_len);
510 username = (uint8_t *) stun_message_find (msg,
511 STUN_ATTRIBUTE_USERNAME, &username_len);
512 if (username == NULL || realm == NULL) {
513 skip = TRUE;
514 } else {
515 stun_hash_creds (realm, realm_len,
516 username, username_len,
517 key, key_len, md5);
519 memcpy (msg->long_term_key, md5, sizeof(msg->long_term_key));
520 msg->long_term_valid = TRUE;
523 /* If no realm/username and long term credentials,
524 then don't send the message integrity */
525 if (skip == FALSE) {
526 ptr = stun_message_append (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, 20);
527 if (ptr == NULL) {
528 return 0;
530 if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
531 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
532 stun_sha1 (msg->buffer, stun_message_length (msg),
533 stun_message_length (msg) - 20, ptr, md5, sizeof(md5), TRUE);
534 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
535 size_t minus = 20;
536 if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
537 minus -= 8;
539 stun_sha1 (msg->buffer, stun_message_length (msg),
540 stun_message_length (msg) - minus, ptr, md5, sizeof(md5), TRUE);
541 } else {
542 stun_sha1 (msg->buffer, stun_message_length (msg),
543 stun_message_length (msg) - 20, ptr, md5, sizeof(md5), FALSE);
545 } else {
546 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
547 stun_sha1 (msg->buffer, stun_message_length (msg),
548 stun_message_length (msg) - 20, ptr, key, key_len, TRUE);
549 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
550 size_t minus = 20;
551 if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
552 minus -= 8;
554 stun_sha1 (msg->buffer, stun_message_length (msg),
555 stun_message_length (msg) - minus, ptr, key, key_len, TRUE);
556 } else {
557 stun_sha1 (msg->buffer, stun_message_length (msg),
558 stun_message_length (msg) - 20, ptr, key, key_len, FALSE);
562 stun_debug (" Message HMAC-SHA1 message integrity:"
563 "\n key : ");
564 stun_debug_bytes (key, key_len);
565 stun_debug ("\n sent : ");
566 stun_debug_bytes (ptr, 20);
567 stun_debug ("\n");
571 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
572 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
573 agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
574 ptr = stun_message_append (msg, STUN_ATTRIBUTE_FINGERPRINT, 4);
575 if (ptr == NULL) {
576 return 0;
579 fpr = stun_fingerprint (msg->buffer, stun_message_length (msg),
580 agent->compatibility == STUN_COMPATIBILITY_WLM2009);
581 memcpy (ptr, &fpr, sizeof (fpr));
583 stun_debug (" Message HMAC-SHA1 fingerprint: ");
584 stun_debug_bytes (ptr, 4);
585 stun_debug ("\n");
589 if (stun_message_get_class (msg) == STUN_REQUEST) {
590 for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) {
591 if (agent->sent_ids[i].valid == FALSE) {
592 stun_message_id (msg, id);
593 memcpy (agent->sent_ids[i].id, id, sizeof(StunTransactionId));
594 agent->sent_ids[i].method = stun_message_get_method (msg);
595 agent->sent_ids[i].key = (uint8_t *) key;
596 agent->sent_ids[i].key_len = key_len;
597 memcpy (agent->sent_ids[i].long_term_key, msg->long_term_key,
598 sizeof(msg->long_term_key));
599 agent->sent_ids[i].long_term_valid = msg->long_term_valid;
600 agent->sent_ids[i].valid = TRUE;
601 break;
606 msg->key = (uint8_t *) key;
607 msg->key_len = key_len;
608 return stun_message_length (msg);
612 static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type)
615 uint16_t *known_attr = agent->known_attributes;
617 while(*known_attr != 0) {
618 if (*known_attr == type) {
619 return FALSE;
621 known_attr++;
624 return TRUE;
629 static unsigned
630 stun_agent_find_unknowns (StunAgent *agent, const StunMessage * msg,
631 uint16_t *list, unsigned max)
633 unsigned count = 0;
634 uint16_t len = stun_message_length (msg);
635 size_t offset = 0;
637 offset = STUN_MESSAGE_ATTRIBUTES_POS;
639 while ((offset < len) && (count < max))
641 size_t alen = stun_getw (msg->buffer + offset + STUN_ATTRIBUTE_TYPE_LEN);
642 uint16_t atype = stun_getw (msg->buffer + offset);
644 offset += STUN_ATTRIBUTE_VALUE_POS + stun_align (alen);
646 if (!stun_optional (atype) && stun_agent_is_unknown (agent, atype))
648 stun_debug ("STUN unknown: attribute 0x%04x(%u bytes)\n",
649 (unsigned)atype, (unsigned)alen);
650 list[count++] = htons (atype);
654 stun_debug ("STUN unknown: %u mandatory attribute(s)!\n", count);
655 return count;