Google puts the STUN cookie, but doesn't follow RFC 5389
[sipe-libnice.git] / stun / stunagent.c
blobd143599f641e1555af639d11dcb9b88c8fe3ce00
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 !(agent->usage_flags & STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES));
122 if (len == STUN_MESSAGE_BUFFER_INVALID) {
123 return STUN_VALIDATION_NOT_STUN;
124 } else if (len == STUN_MESSAGE_BUFFER_INCOMPLETE) {
125 return STUN_VALIDATION_INCOMPLETE_STUN;
126 } else if (len != (int) buffer_len) {
127 return STUN_VALIDATION_NOT_STUN;
130 msg->buffer = (uint8_t *) buffer;
131 msg->buffer_len = buffer_len;
132 msg->agent = agent;
133 msg->key = NULL;
134 msg->key_len = 0;
135 msg->long_term_valid = FALSE;
137 /* TODO: reject it or not ? */
138 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
139 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
140 !stun_message_has_cookie (msg)) {
141 stun_debug ("STUN demux error: no cookie!\n");
142 return STUN_VALIDATION_BAD_REQUEST;
145 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
146 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
147 agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
148 /* Looks for FINGERPRINT */
149 if (stun_message_find32 (msg, STUN_ATTRIBUTE_FINGERPRINT, &fpr) !=
150 STUN_MESSAGE_RETURN_SUCCESS) {
151 stun_debug ("STUN demux error: no FINGERPRINT attribute!\n");
152 return STUN_VALIDATION_BAD_REQUEST;
154 /* Checks FINGERPRINT */
155 crc32 = stun_fingerprint (msg->buffer, stun_message_length (msg),
156 agent->compatibility == STUN_COMPATIBILITY_WLM2009);
157 fpr = ntohl (fpr);
158 if (fpr != crc32) {
159 stun_debug ("STUN demux error: bad fingerprint: 0x%08x,"
160 " expected: 0x%08x!\n", fpr, crc32);
161 return STUN_VALIDATION_BAD_REQUEST;
164 stun_debug ("STUN demux: OK!\n");
167 if (stun_message_get_class (msg) == STUN_RESPONSE ||
168 stun_message_get_class (msg) == STUN_ERROR) {
169 stun_message_id (msg, msg_id);
170 for (sent_id_idx = 0; sent_id_idx < STUN_AGENT_MAX_SAVED_IDS; sent_id_idx++) {
171 if (agent->sent_ids[sent_id_idx].valid == TRUE &&
172 agent->sent_ids[sent_id_idx].method == stun_message_get_method (msg) &&
173 memcmp (msg_id, agent->sent_ids[sent_id_idx].id,
174 sizeof(StunTransactionId)) == 0) {
176 key = agent->sent_ids[sent_id_idx].key;
177 key_len = agent->sent_ids[sent_id_idx].key_len;
178 memcpy (long_term_key, agent->sent_ids[sent_id_idx].long_term_key,
179 sizeof(long_term_key));
180 long_term_key_valid = agent->sent_ids[sent_id_idx].long_term_valid;
181 break;
184 if (sent_id_idx == STUN_AGENT_MAX_SAVED_IDS) {
185 return STUN_VALIDATION_UNMATCHED_RESPONSE;
189 ignore_credentials =
190 (agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) ||
191 (stun_message_get_class (msg) == STUN_ERROR &&
192 stun_message_find_error (msg, &error_code) ==
193 STUN_MESSAGE_RETURN_SUCCESS &&
194 (error_code == 400 || error_code == 401)) ||
195 (stun_message_get_class (msg) == STUN_INDICATION &&
196 (agent->usage_flags & STUN_AGENT_USAGE_NO_INDICATION_AUTH));
198 if (key == NULL &&
199 ignore_credentials == 0 &&
200 (stun_message_get_class (msg) == STUN_REQUEST ||
201 stun_message_get_class (msg) == STUN_INDICATION) &&
202 (((agent->usage_flags & STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS) &&
203 (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
204 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY))) ||
205 ((agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) &&
206 stun_message_get_class (msg) == STUN_REQUEST &&
207 (!stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) ||
208 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) ||
209 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_NONCE) ||
210 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_REALM))) ||
211 ((agent->usage_flags & STUN_AGENT_USAGE_IGNORE_CREDENTIALS) == 0 &&
212 stun_message_has_attribute (msg, STUN_ATTRIBUTE_USERNAME) &&
213 !stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY)))) {
214 return STUN_VALIDATION_UNAUTHORIZED_BAD_REQUEST;
217 if (stun_message_has_attribute (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY) &&
218 ((key == NULL && ignore_credentials == 0) ||
219 (agent->usage_flags & STUN_AGENT_USAGE_FORCE_VALIDATER))) {
220 username_len = 0;
221 username = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_USERNAME,
222 &username_len);
223 if (validater == NULL ||
224 validater (agent, msg, username, username_len,
225 &key, &key_len, validater_data) == FALSE) {
226 return STUN_VALIDATION_UNAUTHORIZED;
230 if (ignore_credentials == 0 && key != NULL && key_len > 0) {
231 hash = (uint8_t *) stun_message_find (msg,
232 STUN_ATTRIBUTE_MESSAGE_INTEGRITY, &hlen);
234 if (hash) {
235 /* We must give the size from start to the end of the attribute
236 because you might have a FINGERPRINT attribute after it... */
237 if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
238 uint8_t *realm = NULL;
239 uint8_t *username = NULL;
240 uint16_t realm_len;
241 uint16_t username_len;
242 uint8_t md5[16];
244 if (long_term_key_valid) {
245 memcpy (md5, long_term_key, sizeof (md5));
246 } else {
247 realm = (uint8_t *) stun_message_find (msg, STUN_ATTRIBUTE_REALM, &realm_len);
248 username = (uint8_t *) stun_message_find (msg,
249 STUN_ATTRIBUTE_USERNAME, &username_len);
250 if (username == NULL || realm == NULL) {
251 return STUN_VALIDATION_UNAUTHORIZED;
253 stun_hash_creds (realm, realm_len,
254 username, username_len,
255 key, key_len, md5);
258 memcpy (msg->long_term_key, md5, sizeof(md5));
259 msg->long_term_valid = TRUE;
261 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 ||
262 agent->compatibility == STUN_COMPATIBILITY_OC2007) {
263 stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
264 sha, md5, sizeof(md5), TRUE);
265 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
266 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
267 stun_message_length (msg) - 20, sha, md5, sizeof(md5), TRUE);
268 } else {
269 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
270 hash - msg->buffer, sha, md5, sizeof(md5), FALSE);
272 } else {
273 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 ||
274 agent->compatibility == STUN_COMPATIBILITY_OC2007) {
275 stun_sha1 (msg->buffer, hash + 20 - msg->buffer, hash - msg->buffer,
276 sha, key, key_len, TRUE);
277 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
278 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
279 stun_message_length (msg) - 20, sha, key, key_len, TRUE);
280 } else {
281 stun_sha1 (msg->buffer, hash + 20 - msg->buffer,
282 hash - msg->buffer, sha, key, key_len, FALSE);
286 stun_debug (" Message HMAC-SHA1 fingerprint:");
287 stun_debug ("\nkey : ");
288 stun_debug_bytes (key, key_len);
289 stun_debug ("\n expected: ");
290 stun_debug_bytes (sha, sizeof (sha));
291 stun_debug ("\n received: ");
292 stun_debug_bytes (hash, sizeof (sha));
293 stun_debug ("\n");
295 if (memcmp (sha, hash, sizeof (sha))) {
296 stun_debug ("STUN auth error: SHA1 fingerprint mismatch!\n");
297 return STUN_VALIDATION_UNAUTHORIZED;
300 stun_debug ("STUN auth: OK!\n");
301 msg->key = key;
302 msg->key_len = key_len;
303 } else if (!(stun_message_get_class (msg) == STUN_ERROR &&
304 stun_message_find_error (msg, &error_code) ==
305 STUN_MESSAGE_RETURN_SUCCESS &&
306 (error_code == 400 || error_code == 401))) {
307 stun_debug ("STUN auth error: No message integrity attribute!\n");
308 return STUN_VALIDATION_UNAUTHORIZED;
313 if (sent_id_idx != -1 && sent_id_idx < STUN_AGENT_MAX_SAVED_IDS) {
314 agent->sent_ids[sent_id_idx].valid = FALSE;
317 if (stun_agent_find_unknowns (agent, msg, &unknown, 1) > 0) {
318 if (stun_message_get_class (msg) == STUN_REQUEST)
319 return STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE;
320 else
321 return STUN_VALIDATION_UNKNOWN_ATTRIBUTE;
323 return STUN_VALIDATION_SUCCESS;
327 bool stun_agent_forget_transaction (StunAgent *agent, StunTransactionId id)
329 int i;
331 for (i = 0; i < STUN_AGENT_MAX_SAVED_IDS; i++) {
332 if (agent->sent_ids[i].valid == TRUE &&
333 memcmp (id, agent->sent_ids[i].id,
334 sizeof(StunTransactionId)) == 0) {
335 agent->sent_ids[i].valid = FALSE;
336 return TRUE;
340 return FALSE;
343 bool stun_agent_init_request (StunAgent *agent, StunMessage *msg,
344 uint8_t *buffer, size_t buffer_len, StunMethod m)
346 bool ret;
347 StunTransactionId id;
349 msg->buffer = buffer;
350 msg->buffer_len = buffer_len;
351 msg->agent = agent;
352 msg->key = NULL;
353 msg->key_len = 0;
354 msg->long_term_valid = FALSE;
356 stun_make_transid (id);
358 ret = stun_message_init (msg, STUN_REQUEST, m, id);
360 if (ret) {
361 if (agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
362 agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
363 uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
364 memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie));
366 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
367 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
368 (agent->software_attribute != NULL ||
369 agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE)) {
370 stun_message_append_software (msg, agent->software_attribute);
374 return ret;
378 bool stun_agent_init_indication (StunAgent *agent, StunMessage *msg,
379 uint8_t *buffer, size_t buffer_len, StunMethod m)
381 bool ret;
382 StunTransactionId id;
384 msg->buffer = buffer;
385 msg->buffer_len = buffer_len;
386 msg->agent = agent;
387 msg->key = NULL;
388 msg->key_len = 0;
389 msg->long_term_valid = FALSE;
391 stun_make_transid (id);
392 ret = stun_message_init (msg, STUN_INDICATION, m, id);
394 if (ret) {
395 if (agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
396 agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
397 uint32_t cookie = htonl (STUN_MAGIC_COOKIE);
398 memcpy (msg->buffer + STUN_MESSAGE_TRANS_ID_POS, &cookie, sizeof (cookie));
402 return ret;
406 bool stun_agent_init_response (StunAgent *agent, StunMessage *msg,
407 uint8_t *buffer, size_t buffer_len, const StunMessage *request)
410 StunTransactionId id;
412 if (stun_message_get_class (request) != STUN_REQUEST) {
413 return FALSE;
416 msg->buffer = buffer;
417 msg->buffer_len = buffer_len;
418 msg->agent = agent;
419 msg->key = request->key;
420 msg->key_len = request->key_len;
421 memmove (msg->long_term_key, request->long_term_key,
422 sizeof(msg->long_term_key));
423 msg->long_term_valid = request->long_term_valid;
425 stun_message_id (request, id);
427 if (stun_message_init (msg, STUN_RESPONSE,
428 stun_message_get_method (request), id)) {
430 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
431 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
432 (agent->software_attribute != NULL ||
433 agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE)) {
434 stun_message_append_software (msg, agent->software_attribute);
436 return TRUE;
438 return FALSE;
442 bool stun_agent_init_error (StunAgent *agent, StunMessage *msg,
443 uint8_t *buffer, size_t buffer_len, const StunMessage *request,
444 StunError err)
446 StunTransactionId id;
448 if (stun_message_get_class (request) != STUN_REQUEST) {
449 return FALSE;
452 msg->buffer = buffer;
453 msg->buffer_len = buffer_len;
454 msg->agent = agent;
455 msg->key = request->key;
456 msg->key_len = request->key_len;
457 memmove (msg->long_term_key, request->long_term_key,
458 sizeof(msg->long_term_key));
459 msg->long_term_valid = request->long_term_valid;
461 stun_message_id (request, id);
464 if (stun_message_init (msg, STUN_ERROR,
465 stun_message_get_method (request), id)) {
467 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
468 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
469 (agent->software_attribute != NULL ||
470 agent->usage_flags & STUN_AGENT_USAGE_ADD_SOFTWARE)) {
471 stun_message_append_software (msg, agent->software_attribute);
473 if (stun_message_append_error (msg, err) == STUN_MESSAGE_RETURN_SUCCESS) {
474 return TRUE;
477 return FALSE;
481 size_t stun_agent_build_unknown_attributes_error (StunAgent *agent,
482 StunMessage *msg, uint8_t *buffer, size_t buffer_len,
483 const StunMessage *request)
486 unsigned counter;
487 uint16_t ids[STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES];
489 counter = stun_agent_find_unknowns (agent, request,
490 ids, STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES);
492 if (stun_agent_init_error (agent, msg, buffer, buffer_len,
493 request, STUN_ERROR_UNKNOWN_ATTRIBUTE) == FALSE) {
494 return 0;
497 /* NOTE: Old RFC3489 compatibility:
498 * When counter is odd, duplicate one value for 32-bits padding. */
499 if (!stun_message_has_cookie (request) && (counter & 1))
500 ids[counter++] = ids[0];
502 if (stun_message_append_bytes (msg, STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES,
503 ids, counter * 2) == STUN_MESSAGE_RETURN_SUCCESS) {
504 return stun_agent_finish_message (agent, msg, request->key, request->key_len);
507 return 0;
511 size_t stun_agent_finish_message (StunAgent *agent, StunMessage *msg,
512 const uint8_t *key, size_t key_len)
514 uint8_t *ptr;
515 uint32_t fpr;
516 int saved_id_idx = 0;
517 uint8_t md5[16];
519 if (stun_message_get_class (msg) == STUN_REQUEST) {
520 for (saved_id_idx = 0; saved_id_idx < STUN_AGENT_MAX_SAVED_IDS; saved_id_idx++) {
521 if (agent->sent_ids[saved_id_idx].valid == FALSE) {
522 break;
526 if (saved_id_idx == STUN_AGENT_MAX_SAVED_IDS) {
527 stun_debug ("Saved ids full");
528 return 0;
531 if (msg->key != NULL) {
532 key = msg->key;
533 key_len = msg->key_len;
536 if (key != NULL) {
537 bool skip = FALSE;
539 if (msg->long_term_valid) {
540 memcpy (md5, msg->long_term_key, sizeof(msg->long_term_key));
541 } else if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
542 uint8_t *realm = NULL;
543 uint8_t *username = NULL;
544 uint16_t realm_len;
545 uint16_t username_len;
547 realm = (uint8_t *) stun_message_find (msg,
548 STUN_ATTRIBUTE_REALM, &realm_len);
549 username = (uint8_t *) stun_message_find (msg,
550 STUN_ATTRIBUTE_USERNAME, &username_len);
551 if (username == NULL || realm == NULL) {
552 skip = TRUE;
553 } else {
554 stun_hash_creds (realm, realm_len,
555 username, username_len,
556 key, key_len, md5);
558 memcpy (msg->long_term_key, md5, sizeof(msg->long_term_key));
559 msg->long_term_valid = TRUE;
562 /* If no realm/username and long term credentials,
563 then don't send the message integrity */
564 if (skip == FALSE) {
565 ptr = stun_message_append (msg, STUN_ATTRIBUTE_MESSAGE_INTEGRITY, 20);
566 if (ptr == NULL) {
567 return 0;
569 if (agent->usage_flags & STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS) {
570 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 ||
571 agent->compatibility == STUN_COMPATIBILITY_OC2007) {
572 stun_sha1 (msg->buffer, stun_message_length (msg),
573 stun_message_length (msg) - 20, ptr, md5, sizeof(md5), TRUE);
574 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
575 size_t minus = 20;
576 if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
577 minus -= 8;
579 stun_sha1 (msg->buffer, stun_message_length (msg),
580 stun_message_length (msg) - minus, ptr, md5, sizeof(md5), TRUE);
581 } else {
582 stun_sha1 (msg->buffer, stun_message_length (msg),
583 stun_message_length (msg) - 20, ptr, md5, sizeof(md5), FALSE);
585 } else {
586 if (agent->compatibility == STUN_COMPATIBILITY_RFC3489 ||
587 agent->compatibility == STUN_COMPATIBILITY_OC2007) {
588 stun_sha1 (msg->buffer, stun_message_length (msg),
589 stun_message_length (msg) - 20, ptr, key, key_len, TRUE);
590 } else if (agent->compatibility == STUN_COMPATIBILITY_WLM2009) {
591 size_t minus = 20;
592 if (agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT)
593 minus -= 8;
595 stun_sha1 (msg->buffer, stun_message_length (msg),
596 stun_message_length (msg) - minus, ptr, key, key_len, TRUE);
597 } else {
598 stun_sha1 (msg->buffer, stun_message_length (msg),
599 stun_message_length (msg) - 20, ptr, key, key_len, FALSE);
603 stun_debug (" Message HMAC-SHA1 message integrity:"
604 "\n key : ");
605 stun_debug_bytes (key, key_len);
606 stun_debug ("\n sent : ");
607 stun_debug_bytes (ptr, 20);
608 stun_debug ("\n");
612 if ((agent->compatibility == STUN_COMPATIBILITY_RFC5389 ||
613 agent->compatibility == STUN_COMPATIBILITY_WLM2009) &&
614 agent->usage_flags & STUN_AGENT_USAGE_USE_FINGERPRINT) {
615 ptr = stun_message_append (msg, STUN_ATTRIBUTE_FINGERPRINT, 4);
616 if (ptr == NULL) {
617 return 0;
620 fpr = stun_fingerprint (msg->buffer, stun_message_length (msg),
621 agent->compatibility == STUN_COMPATIBILITY_WLM2009);
622 memcpy (ptr, &fpr, sizeof (fpr));
624 stun_debug (" Message HMAC-SHA1 fingerprint: ");
625 stun_debug_bytes (ptr, 4);
626 stun_debug ("\n");
630 if (stun_message_get_class (msg) == STUN_REQUEST) {
631 stun_message_id (msg, agent->sent_ids[saved_id_idx].id);
632 agent->sent_ids[saved_id_idx].method = stun_message_get_method (msg);
633 agent->sent_ids[saved_id_idx].key = (uint8_t *) key;
634 agent->sent_ids[saved_id_idx].key_len = key_len;
635 memcpy (agent->sent_ids[saved_id_idx].long_term_key, msg->long_term_key,
636 sizeof(msg->long_term_key));
637 agent->sent_ids[saved_id_idx].long_term_valid = msg->long_term_valid;
638 agent->sent_ids[saved_id_idx].valid = TRUE;
641 msg->key = (uint8_t *) key;
642 msg->key_len = key_len;
643 return stun_message_length (msg);
647 static bool stun_agent_is_unknown (StunAgent *agent, uint16_t type)
650 uint16_t *known_attr = agent->known_attributes;
652 while(*known_attr != 0) {
653 if (*known_attr == type) {
654 return FALSE;
656 known_attr++;
659 return TRUE;
664 static unsigned
665 stun_agent_find_unknowns (StunAgent *agent, const StunMessage * msg,
666 uint16_t *list, unsigned max)
668 unsigned count = 0;
669 uint16_t len = stun_message_length (msg);
670 size_t offset = 0;
672 offset = STUN_MESSAGE_ATTRIBUTES_POS;
674 while ((offset < len) && (count < max))
676 size_t alen = stun_getw (msg->buffer + offset + STUN_ATTRIBUTE_TYPE_LEN);
677 uint16_t atype = stun_getw (msg->buffer + offset);
679 if (!stun_optional (atype) && stun_agent_is_unknown (agent, atype))
681 stun_debug ("STUN unknown: attribute 0x%04x(%u bytes)\n",
682 (unsigned)atype, (unsigned)alen);
683 list[count++] = htons (atype);
686 if (!(agent->usage_flags & STUN_AGENT_USAGE_NO_ALIGNED_ATTRIBUTES))
687 alen = stun_align (alen);
689 offset += STUN_ATTRIBUTE_VALUE_POS + alen;
692 stun_debug ("STUN unknown: %u mandatory attribute(s)!\n", count);
693 return count;
696 void stun_agent_set_software (StunAgent *agent, const char *software)
698 agent->software_attribute = software;