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
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.
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.
41 #include "stunmessage.h"
42 #include "stunagent.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
)
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
;
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
);
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
;
106 uint8_t *username
= NULL
;
107 uint16_t username_len
;
113 int sent_id_idx
= -1;
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
;
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
);
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
;
183 if (sent_id_idx
== STUN_AGENT_MAX_SAVED_IDS
) {
184 return STUN_VALIDATION_UNMATCHED_RESPONSE
;
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
));
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
))) {
220 username
= (uint8_t *) stun_message_find (msg
, STUN_ATTRIBUTE_USERNAME
,
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
);
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
;
240 uint16_t username_len
;
243 if (long_term_key_valid
) {
244 memcpy (md5
, long_term_key
, sizeof (md5
));
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
,
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
);
267 stun_sha1 (msg
->buffer
, hash
+ 20 - msg
->buffer
,
268 hash
- msg
->buffer
, sha
, md5
, sizeof(md5
), FALSE
);
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
);
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
));
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");
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
;
318 return STUN_VALIDATION_UNKNOWN_ATTRIBUTE
;
320 return STUN_VALIDATION_SUCCESS
;
324 bool stun_agent_forget_transaction (StunAgent
*agent
, StunTransactionId id
)
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
;
340 bool stun_agent_init_request (StunAgent
*agent
, StunMessage
*msg
,
341 uint8_t *buffer
, size_t buffer_len
, StunMethod m
)
344 StunTransactionId id
;
346 msg
->buffer
= buffer
;
347 msg
->buffer_len
= buffer_len
;
351 msg
->long_term_valid
= FALSE
;
353 stun_make_transid (id
);
355 ret
= stun_message_init (msg
, STUN_REQUEST
, m
, id
);
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
);
375 bool stun_agent_init_indication (StunAgent
*agent
, StunMessage
*msg
,
376 uint8_t *buffer
, size_t buffer_len
, StunMethod m
)
379 StunTransactionId id
;
381 msg
->buffer
= buffer
;
382 msg
->buffer_len
= buffer_len
;
386 msg
->long_term_valid
= FALSE
;
388 stun_make_transid (id
);
389 ret
= stun_message_init (msg
, STUN_INDICATION
, m
, id
);
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
));
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
) {
413 msg
->buffer
= buffer
;
414 msg
->buffer_len
= buffer_len
;
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
);
439 bool stun_agent_init_error (StunAgent
*agent
, StunMessage
*msg
,
440 uint8_t *buffer
, size_t buffer_len
, const StunMessage
*request
,
443 StunTransactionId id
;
445 if (stun_message_get_class (request
) != STUN_REQUEST
) {
449 msg
->buffer
= buffer
;
450 msg
->buffer_len
= buffer_len
;
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
) {
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
)
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
) {
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
);
508 size_t stun_agent_finish_message (StunAgent
*agent
, StunMessage
*msg
,
509 const uint8_t *key
, size_t key_len
)
513 int saved_id_idx
= 0;
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
) {
523 if (saved_id_idx
== STUN_AGENT_MAX_SAVED_IDS
) {
524 stun_debug ("Saved ids full");
528 if (msg
->key
!= NULL
) {
530 key_len
= msg
->key_len
;
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
;
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
) {
551 stun_hash_creds (realm
, realm_len
,
552 username
, username_len
,
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 */
562 ptr
= stun_message_append (msg
, STUN_ATTRIBUTE_MESSAGE_INTEGRITY
, 20);
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
) {
572 if (agent
->usage_flags
& STUN_AGENT_USAGE_USE_FINGERPRINT
)
575 stun_sha1 (msg
->buffer
, stun_message_length (msg
),
576 stun_message_length (msg
) - minus
, ptr
, md5
, sizeof(md5
), TRUE
);
578 stun_sha1 (msg
->buffer
, stun_message_length (msg
),
579 stun_message_length (msg
) - 20, ptr
, md5
, sizeof(md5
), FALSE
);
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
) {
587 if (agent
->usage_flags
& STUN_AGENT_USAGE_USE_FINGERPRINT
)
590 stun_sha1 (msg
->buffer
, stun_message_length (msg
),
591 stun_message_length (msg
) - minus
, ptr
, key
, key_len
, TRUE
);
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:"
600 stun_debug_bytes (key
, key_len
);
601 stun_debug ("\n sent : ");
602 stun_debug_bytes (ptr
, 20);
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);
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);
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
) {
660 stun_agent_find_unknowns (StunAgent
*agent
, const StunMessage
* msg
,
661 uint16_t *list
, unsigned max
)
664 uint16_t len
= stun_message_length (msg
);
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
);
688 void stun_agent_set_software (StunAgent
*agent
, const char *software
)
690 agent
->software_attribute
= software
;