conncheck: Remove useless checks from priv_add_new_turn_refresh
[sipe-libnice.git] / stun / stunagent.c
blobbe2a9cf07a092e2d4fe8770e1aa08533ad2f40e4
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2008-2009 Collabora Ltd.
5 * Contact: Youness Alaoui
6 * (C) 2008-2009 Nokia Corporation. All rights reserved.
8 * The contents of this file are subject to the Mozilla Public License Version
9 * 1.1 (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS" basis,
14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15 * for the specific language governing rights and limitations under the
16 * License.
18 * The Original Code is the Nice GLib ICE library.
20 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
21 * Corporation. All Rights Reserved.
23 * Contributors:
24 * Youness Alaoui, Collabora Ltd.
26 * Alternatively, the contents of this file may be used under the terms of the
27 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
28 * case the provisions of LGPL are applicable instead of those above. If you
29 * wish to allow use of your version of this file only under the terms of the
30 * LGPL and not to allow others to use your version of this file under the
31 * MPL, indicate your decision by deleting the provisions above and replace
32 * them with the notice and other provisions required by the LGPL. If you do
33 * not delete the provisions above, a recipient may use your version of this
34 * file under either the MPL or the LGPL.
37 #ifdef HAVE_CONFIG_H
38 # include <config.h>
39 #endif
41 #include "stunmessage.h"
42 #include "stunagent.h"
43 #include "stunhmac.h"
44 #include "stun5389.h"
45 #include "utils.h"
47 #include <string.h>
48 #include <stdlib.h>
51 static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type);
52 static unsigned stun_agent_find_unknowns (StunAgent *agent,
53 const StunMessage * msg, uint16_t *list, unsigned max);
55 void stun_agent_init (StunAgent *agent, const uint16_t *known_attributes,
56 StunCompatibility compatibility, StunAgentUsageFlags usage_flags)
58 int i;
60 agent->known_attributes = (uint16_t *) known_attributes;
61 agent->compatibility = compatibility;
62 agent->usage_flags = usage_flags;
63 agent->software_attribute = NULL;
65 for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) {
66 agent->sent_ids[i].valid = FALSE;
71 bool stun_agent_default_validater (StunAgent *agent,
72 StunMessage *message, uint8_t *username, uint16_t username_len,
73 uint8_t **password, size_t *password_len, void *user_data)
75 StunDefaultValidaterData* val = (StunDefaultValidaterData *) user_data;
76 int i;
78 for (i = 0; val && val[i].username ; i++) {
79 stun_debug ("Comparing username '");
80 stun_debug_bytes (username, username_len);
81 stun_debug ("' (%d) with '", username_len);
82 stun_debug_bytes (val[i].username, val[i].username_len);
83 stun_debug ("' (%d) : %d\n",
84 val[i].username_len, memcmp (username, val[i].username, username_len));
85 if (username_len == val[i].username_len &&
86 memcmp (username, val[i].username, username_len) == 0) {
87 *password = (uint8_t *) val[i].password;
88 *password_len = val[i].password_len;
89 stun_debug ("Found valid username, returning password : '%s'\n", *password);
90 return TRUE;
94 return FALSE;
98 StunValidationStatus stun_agent_validate (StunAgent *agent, StunMessage *msg,
99 const uint8_t *buffer, size_t buffer_len,
100 StunMessageIntegrityValidate validater, void * validater_data)
102 StunTransactionId msg_id;
103 uint32_t fpr;
104 uint32_t crc32;
105 int len;
106 uint8_t *username = NULL;
107 uint16_t username_len;
108 uint8_t *key = NULL;
109 size_t key_len;
110 uint8_t *hash;
111 uint8_t sha[20];
112 uint16_t hlen;
113 int sent_id_idx = -1;
114 uint16_t unknown;
115 int error_code;
116 int ignore_credentials = 0;
117 uint8_t long_term_key[16];
118 bool long_term_key_valid = FALSE;
120 len = stun_message_validate_buffer_length (buffer, buffer_len);
121 if (len == STUN_MESSAGE_BUFFER_INVALID) {
122 return STUN_VALIDATION_NOT_STUN;
123 } else if (len == STUN_MESSAGE_BUFFER_INCOMPLETE) {
124 return STUN_VALIDATION_INCOMPLETE_STUN;
125 } else if (len != (int) buffer_len) {
126 return STUN_VALIDATION_NOT_STUN;
129 msg->buffer = (uint8_t *) buffer;
130 msg->buffer_len = buffer_len;
131 msg->agent = agent;
132 msg->key = NULL;
133 msg->key_len = 0;
134 msg->long_term_valid = FALSE;
136 /* TODO: reject it or not ? */
137 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
138 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
139 !stun_message_has_cookie (msg)) {
140 stun_debug ("STUN demux error: no cookie!\n");
141 return STUN_VALIDATION_BAD_REQUEST;
144 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
145 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
146 agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
147 /* Looks for FINGERPRINT */
148 if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) !=
149 STUN_MESSAGE_RETURN_SUCCESS) {
150 stun_debug ("STUN demux error: no FINGERPRINT attribute!\n");
151 return STUN_VALIDATION_BAD_REQUEST;
153 /* Checks FINGERPRINT */
154 crc32 = stun_fingerprint (msg->buffer, stun_message_length (msg),
155 agent->compatibility == STUN_COMPATIBILITY_WLM2009);
156 fpr = ntohl (fpr);
157 if (fpr != crc32) {
158 stun_debug ("STUN demux error: bad fingerprint: 0x%08x,"
159 " expected: 0x%08x!\n", fpr, crc32);
160 return STUN_VALIDATION_BAD_REQUEST;
163 stun_debug ("STUN demux: OK!\n");
166 if (stun_message_get_class (msg) == STUN_RESPONSE ||
167 stun_message_get_class (msg) == STUN_ERROR) {
168 stun_message_id (msg, msg_id);
169 for (sent_id_idx = 0; sent_id_idx < STUN_AGENT_MAX_SAVED_IDS; sent_id_idx++) {
170 if (agent->sent_ids[sent_id_idx].valid == TRUE &&
171 agent->sent_ids[sent_id_idx].method == stun_message_get_method (msg) &&
172 memcmp (msg_id, agent->sent_ids[sent_id_idx].id,
173 sizeof(StunTransactionId)) == 0) {
175 key = agent->sent_ids[sent_id_idx].key;
176 key_len = agent->sent_ids[sent_id_idx].key_len;
177 memcpy (long_term_key, agent->sent_ids[sent_id_idx].long_term_key,
178 sizeof(long_term_key));
179 long_term_key_valid = agent->sent_ids[sent_id_idx].long_term_valid;
180 break;
183 if (sent_id_idx == STUN_AGENT_MAX_SAVED_IDS) {
184 return STUN_VALIDATION_UNMATCHED_RESPONSE;
188 ignore_credentials =
189 (agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) ||
190 (stun_message_get_class (msg) == STUN_ERROR &&
191 stun_message_find_error (msg, &error_code) ==
192 STUN_MESSAGE_RETURN_SUCCESS &&
193 (error_code == 400 || error_code == 401)) ||
194 (stun_message_get_class (msg) == STUN_INDICATION &&
195 (agent->usage_flags & STUN_AGENT_USAGE_NO_INDICATION_AUTH));
197 if (key == NULL &&
198 ignore_credentials == 0 &&
199 (stun_message_get_class (msg) == STUN_REQUEST ||
200 stun_message_get_class (msg) == STUN_INDICATION) &&
201 (((agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS) &&
202 (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
203 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY))) ||
204 ((agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) &&
205 stun_message_get_class (msg) == STUN_REQUEST &&
206 (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
207 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) ||
208 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_NONCE) ||
209 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_REALM))) ||
210 ((agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) == 0 &&
211 stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) &&
212 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY)))) {
213 return STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST;
216 if (stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) &&
217 ((key == NULL && ignore_credentials == 0) ||
218 (agent->usage_flags & STUN_AGENT_USAGE_FORCE_VALIDATER))) {
219 username_len = 0;
220 username = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_USERNAME,
221 &username_len);
222 if (validater == NULL ||
223 validater (agent, msg, username, username_len,
224 &key, &key_len, validater_data) == FALSE) {
225 return STUN_VALIDATION_UNAUTHORIZED;
229 if (ignore_credentials == 0 && key != NULL && key_len > 0) {
230 hash = (uint8_t *) stun_message_find (msg,
231 STUN_ATTRIBUTE_MESSAGE_INTEGRITY, &hlen);
233 if (hash) {
234 /* We must give the size from start to the end of the attribute
235 because you might have a FINGERPRINT attribute after it... */
236 if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
237 uint8_t *realm = NULL;
238 uint8_t *username = NULL;
239 uint16_t realm_len;
240 uint16_t username_len;
241 uint8_t md5[16];
243 if (long_term_key_valid) {
244 memcpy (md5, long_term_key, sizeof (md5));
245 } else {
246 realm = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_REALM, &realm_len);
247 username = (uint8_t *) stun_message_find (msg,
248 STUN_ATTRIBUTE_USERNAME, &username_len);
249 if (username == NULL || realm == NULL) {
250 return STUN_VALIDATION_UNAUTHORIZED;
252 stun_hash_creds (realm, realm_len,
253 username, username_len,
254 key, key_len, md5);
257 memcpy (msg->long_term_key, md5, sizeof(md5));
258 msg->long_term_valid = TRUE;
260 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
261 stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
262 sha, md5, sizeof(md5), TRUE);
263 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
264 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
265 stun_message_length (msg) - 20, sha, md5, sizeof(md5), TRUE);
266 } else {
267 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
268 hash - msg->buffer, sha, md5, sizeof(md5), FALSE);
270 } else {
271 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
272 stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
273 sha, key, key_len, TRUE);
274 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
275 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
276 stun_message_length (msg) - 20, sha, key, key_len, TRUE);
277 } else {
278 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
279 hash - msg->buffer, sha, key, key_len, FALSE);
283 stun_debug (" Message HMAC-SHA1 fingerprint:");
284 stun_debug ("\nkey : ");
285 stun_debug_bytes (key, key_len);
286 stun_debug ("\n expected: ");
287 stun_debug_bytes (sha, sizeof (sha));
288 stun_debug ("\n received: ");
289 stun_debug_bytes (hash, sizeof (sha));
290 stun_debug ("\n");
292 if (memcmp (sha, hash, sizeof (sha))) {
293 stun_debug ("STUN auth error: SHA1 fingerprint mismatch!\n");
294 return STUN_VALIDATION_UNAUTHORIZED;
297 stun_debug ("STUN auth: OK!\n");
298 msg->key = key;
299 msg->key_len = key_len;
300 } else if (!(stun_message_get_class (msg) == STUN_ERROR &&
301 stun_message_find_error (msg, &error_code) ==
302 STUN_MESSAGE_RETURN_SUCCESS &&
303 (error_code == 400 || error_code == 401))) {
304 stun_debug ("STUN auth error: No message integrity attribute!\n");
305 return STUN_VALIDATION_UNAUTHORIZED;
310 if (sent_id_idx != -1 && sent_id_idx < STUN_AGENT_MAX_SAVED_IDS) {
311 agent->sent_ids[sent_id_idx].valid = FALSE;
314 if (stun_agent_find_unknowns (agent, msg, &unknown, 1) > 0) {
315 if (stun_message_get_class (msg) == STUN_REQUEST)
316 return STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE;
317 else
318 return STUN_VALIDATION_UNKNOWN_ATTRIBUTE;
320 return STUN_VALIDATION_SUCCESS;
324 bool stun_agent_forget_transaction (StunAgent *agent, StunTransactionId id)
326 int i;
328 for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) {
329 if (agent->sent_ids[i].valid == TRUE &&
330 memcmp (id, agent->sent_ids[i].id,
331 sizeof(StunTransactionId)) == 0) {
332 agent->sent_ids[i].valid = FALSE;
333 return TRUE;
337 return FALSE;
340 bool stun_agent_init_request (StunAgent *agent, StunMessage *msg,
341 uint8_t *buffer, size_t buffer_len, StunMethod m)
343 bool ret;
344 StunTransactionId id;
346 msg->buffer = buffer;
347 msg->buffer_len = buffer_len;
348 msg->agent = agent;
349 msg->key = NULL;
350 msg->key_len = 0;
351 msg->long_term_valid = FALSE;
353 stun_make_transid (id);
355 ret = stun_message_init (msg, STUN_REQUEST, m, id);
357 if (ret) {
358 if (agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
359 agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
360 uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
361 memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie));
363 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
364 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
365 (agent->software_attribute != NULL ||
366 agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE)) {
367 stun_message_append_software (msg, agent->software_attribute);
371 return ret;
375 bool stun_agent_init_indication (StunAgent *agent, StunMessage *msg,
376 uint8_t *buffer, size_t buffer_len, StunMethod m)
378 bool ret;
379 StunTransactionId id;
381 msg->buffer = buffer;
382 msg->buffer_len = buffer_len;
383 msg->agent = agent;
384 msg->key = NULL;
385 msg->key_len = 0;
386 msg->long_term_valid = FALSE;
388 stun_make_transid (id);
389 ret = stun_message_init (msg, STUN_INDICATION, m, id);
391 if (ret) {
392 if (agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
393 agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
394 uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
395 memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie));
399 return ret;
403 bool stun_agent_init_response (StunAgent *agent, StunMessage *msg,
404 uint8_t *buffer, size_t buffer_len, const StunMessage *request)
407 StunTransactionId id;
409 if (stun_message_get_class (request) != STUN_REQUEST) {
410 return FALSE;
413 msg->buffer = buffer;
414 msg->buffer_len = buffer_len;
415 msg->agent = agent;
416 msg->key = request->key;
417 msg->key_len = request->key_len;
418 memmove (msg->long_term_key, request->long_term_key,
419 sizeof(msg->long_term_key));
420 msg->long_term_valid = request->long_term_valid;
422 stun_message_id (request, id);
424 if (stun_message_init (msg, STUN_RESPONSE,
425 stun_message_get_method (request), id)) {
427 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
428 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
429 (agent->software_attribute != NULL ||
430 agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE)) {
431 stun_message_append_software (msg, agent->software_attribute);
433 return TRUE;
435 return FALSE;
439 bool stun_agent_init_error (StunAgent *agent, StunMessage *msg,
440 uint8_t *buffer, size_t buffer_len, const StunMessage *request,
441 StunError err)
443 StunTransactionId id;
445 if (stun_message_get_class (request) != STUN_REQUEST) {
446 return FALSE;
449 msg->buffer = buffer;
450 msg->buffer_len = buffer_len;
451 msg->agent = agent;
452 msg->key = request->key;
453 msg->key_len = request->key_len;
454 memmove (msg->long_term_key, request->long_term_key,
455 sizeof(msg->long_term_key));
456 msg->long_term_valid = request->long_term_valid;
458 stun_message_id (request, id);
461 if (stun_message_init (msg, STUN_ERROR,
462 stun_message_get_method (request), id)) {
464 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
465 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
466 (agent->software_attribute != NULL ||
467 agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE)) {
468 stun_message_append_software (msg, agent->software_attribute);
470 if (stun_message_append_error (msg, err) == STUN_MESSAGE_RETURN_SUCCESS) {
471 return TRUE;
474 return FALSE;
478 size_t stun_agent_build_unknown_attributes_error (StunAgent *agent,
479 StunMessage *msg, uint8_t *buffer, size_t buffer_len,
480 const StunMessage *request)
483 unsigned counter;
484 uint16_t ids[STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES];
486 counter = stun_agent_find_unknowns (agent, request,
487 ids, STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES);
489 if (stun_agent_init_error (agent, msg, buffer, buffer_len,
490 request, STUN_ERROR_UNKNOWN_ATTRIBUTE) == FALSE) {
491 return 0;
494 /* NOTE: Old RFC3489 compatibility:
495 * When counter is odd, duplicate one value for 32-bits padding. */
496 if (!stun_message_has_cookie (request) && (counter & 1))
497 ids[counter++] = ids[0];
499 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES,
500 ids, counter * 2) == STUN_MESSAGE_RETURN_SUCCESS) {
501 return stun_agent_finish_message (agent, msg, request->key, request->key_len);
504 return 0;
508 size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
509 const uint8_t *key, size_t key_len)
511 uint8_t *ptr;
512 uint32_t fpr;
513 int saved_id_idx = 0;
514 uint8_t md5[16];
516 if (stun_message_get_class (msg) == STUN_REQUEST) {
517 for (saved_id_idx = 0; saved_id_idx < STUN_AGENT_MAX_SAVED_IDS; saved_id_idx++) {
518 if (agent->sent_ids[saved_id_idx].valid == FALSE) {
519 break;
523 if (saved_id_idx == STUN_AGENT_MAX_SAVED_IDS) {
524 stun_debug ("Saved ids full");
525 return 0;
528 if (msg->key != NULL) {
529 key = msg->key;
530 key_len = msg->key_len;
533 if (key != NULL) {
534 bool skip = FALSE;
536 if (msg->long_term_valid) {
537 memcpy (md5, msg->long_term_key, sizeof(msg->long_term_key));
538 } else if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
539 uint8_t *realm = NULL;
540 uint8_t *username = NULL;
541 uint16_t realm_len;
542 uint16_t username_len;
544 realm = (uint8_t *) stun_message_find (msg,
545 STUN_ATTRIBUTE_REALM, &realm_len);
546 username = (uint8_t *) stun_message_find (msg,
547 STUN_ATTRIBUTE_USERNAME, &username_len);
548 if (username == NULL || realm == NULL) {
549 skip = TRUE;
550 } else {
551 stun_hash_creds (realm, realm_len,
552 username, username_len,
553 key, key_len, md5);
555 memcpy (msg->long_term_key, md5, sizeof(msg->long_term_key));
556 msg->long_term_valid = TRUE;
559 /* If no realm/username and long term credentials,
560 then don't send the message integrity */
561 if (skip == FALSE) {
562 ptr = stun_message_append (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, 20);
563 if (ptr == NULL) {
564 return 0;
566 if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
567 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
568 stun_sha1 (msg->buffer, stun_message_length (msg),
569 stun_message_length (msg) - 20, ptr, md5, sizeof(md5), TRUE);
570 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
571 size_t minus = 20;
572 if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
573 minus -= 8;
575 stun_sha1 (msg->buffer, stun_message_length (msg),
576 stun_message_length (msg) - minus, ptr, md5, sizeof(md5), TRUE);
577 } else {
578 stun_sha1 (msg->buffer, stun_message_length (msg),
579 stun_message_length (msg) - 20, ptr, md5, sizeof(md5), FALSE);
581 } else {
582 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489) {
583 stun_sha1 (msg->buffer, stun_message_length (msg),
584 stun_message_length (msg) - 20, ptr, key, key_len, TRUE);
585 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
586 size_t minus = 20;
587 if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
588 minus -= 8;
590 stun_sha1 (msg->buffer, stun_message_length (msg),
591 stun_message_length (msg) - minus, ptr, key, key_len, TRUE);
592 } else {
593 stun_sha1 (msg->buffer, stun_message_length (msg),
594 stun_message_length (msg) - 20, ptr, key, key_len, FALSE);
598 stun_debug (" Message HMAC-SHA1 message integrity:"
599 "\n key : ");
600 stun_debug_bytes (key, key_len);
601 stun_debug ("\n sent : ");
602 stun_debug_bytes (ptr, 20);
603 stun_debug ("\n");
607 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
608 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
609 agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
610 ptr = stun_message_append (msg, STUN_ATTRIBUTE_FINGERPRINT, 4);
611 if (ptr == NULL) {
612 return 0;
615 fpr = stun_fingerprint (msg->buffer, stun_message_length (msg),
616 agent->compatibility == STUN_COMPATIBILITY_WLM2009);
617 memcpy (ptr, &fpr, sizeof (fpr));
619 stun_debug (" Message HMAC-SHA1 fingerprint: ");
620 stun_debug_bytes (ptr, 4);
621 stun_debug ("\n");
625 if (stun_message_get_class (msg) == STUN_REQUEST) {
626 stun_message_id (msg, agent->sent_ids[saved_id_idx].id);
627 agent->sent_ids[saved_id_idx].method = stun_message_get_method (msg);
628 agent->sent_ids[saved_id_idx].key = (uint8_t *) key;
629 agent->sent_ids[saved_id_idx].key_len = key_len;
630 memcpy (agent->sent_ids[saved_id_idx].long_term_key, msg->long_term_key,
631 sizeof(msg->long_term_key));
632 agent->sent_ids[saved_id_idx].long_term_valid = msg->long_term_valid;
633 agent->sent_ids[saved_id_idx].valid = TRUE;
636 msg->key = (uint8_t *) key;
637 msg->key_len = key_len;
638 return stun_message_length (msg);
642 static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type)
645 uint16_t *known_attr = agent->known_attributes;
647 while(*known_attr != 0) {
648 if (*known_attr == type) {
649 return FALSE;
651 known_attr++;
654 return TRUE;
659 static unsigned
660 stun_agent_find_unknowns (StunAgent *agent, const StunMessage * msg,
661 uint16_t *list, unsigned max)
663 unsigned count = 0;
664 uint16_t len = stun_message_length (msg);
665 size_t offset = 0;
667 offset = STUN_MESSAGE_ATTRIBUTES_POS;
669 while ((offset < len) && (count < max))
671 size_t alen = stun_getw (msg->buffer + offset + STUN_ATTRIBUTE_TYPE_LEN);
672 uint16_t atype = stun_getw (msg->buffer + offset);
674 offset += STUN_ATTRIBUTE_VALUE_POS + stun_align (alen);
676 if (!stun_optional (atype) && stun_agent_is_unknown (agent, atype))
678 stun_debug ("STUN unknown: attribute 0x%04x(%u bytes)\n",
679 (unsigned)atype, (unsigned)alen);
680 list[count++] = htons (atype);
684 stun_debug ("STUN unknown: %u mandatory attribute(s)!\n", count);
685 return count;
688 void stun_agent_set_software (StunAgent *agent, const char *software)
690 agent->software_attribute = software;