Use sourcecode for libjuice

This commit is contained in:
dijunkun
2023-07-13 16:58:20 +08:00
parent ef6a04dc97
commit 8cd87a2646
76 changed files with 14877 additions and 179 deletions

376
thirdparty/libjuice/src/stun.h vendored Normal file
View File

@@ -0,0 +1,376 @@
/**
* Copyright (c) 2020 Paul-Louis Ageneau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#ifndef JUICE_STUN_H
#define JUICE_STUN_H
#include "juice.h"
#include "addr.h"
#include "hash.h"
#include "hmac.h"
#include <stdbool.h>
#include <stdint.h>
#pragma pack(push, 1)
/*
* STUN message header (20 bytes)
* See https://www.rfc-editor.org/rfc/rfc8489.html#section-5
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |0 0| STUN Message Type | Message Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Magic Cookie = 0x2112A442 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | |
* | Transaction ID (96 bits) |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
#define STUN_TRANSACTION_ID_SIZE 12
struct stun_header {
uint16_t type;
uint16_t length;
uint32_t magic;
uint8_t transaction_id[STUN_TRANSACTION_ID_SIZE];
};
/*
* Format of STUN Message Type Field
*
* 0 1
* 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
* |M |M |M|M|M|C|M|M|M|C|M|M|M|M|
* |11|10|9|8|7|1|6|5|4|0|3|2|1|0|
* +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
* Request: C=b00
* Indication: C=b01
* Response: C=b10 (success)
* C=b11 (error)
*/
#define STUN_CLASS_MASK 0x0110
typedef enum stun_class {
STUN_CLASS_REQUEST = 0x0000,
STUN_CLASS_INDICATION = 0x0010,
STUN_CLASS_RESP_SUCCESS = 0x0100,
STUN_CLASS_RESP_ERROR = 0x0110
} stun_class_t;
typedef enum stun_method {
STUN_METHOD_BINDING = 0x0001,
// Methods for TURN
// See https://www.rfc-editor.org/rfc/rfc8656.html#section-17
STUN_METHOD_ALLOCATE = 0x003,
STUN_METHOD_REFRESH = 0x004,
STUN_METHOD_SEND = 0x006,
STUN_METHOD_DATA = 0x007,
STUN_METHOD_CREATE_PERMISSION = 0x008,
STUN_METHOD_CHANNEL_BIND = 0x009
} stun_method_t;
#define STUN_IS_RESPONSE(msg_class) (msg_class & 0x0100)
/*
* STUN attribute header
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type | Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Value (variable) ...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct stun_attr {
uint16_t type;
uint16_t length;
uint8_t value[];
};
typedef enum stun_attr_type {
// Comprehension-required
STUN_ATTR_MAPPED_ADDRESS = 0x0001,
STUN_ATTR_USERNAME = 0x0006,
STUN_ATTR_MESSAGE_INTEGRITY = 0x0008,
STUN_ATTR_ERROR_CODE = 0x0009,
STUN_ATTR_UNKNOWN_ATTRIBUTES = 0x000A,
STUN_ATTR_REALM = 0x0014,
STUN_ATTR_NONCE = 0x0015,
STUN_ATTR_MESSAGE_INTEGRITY_SHA256 = 0x001C,
STUN_ATTR_PASSWORD_ALGORITHM = 0x001D,
STUN_ATTR_USERHASH = 0x001E,
STUN_ATTR_XOR_MAPPED_ADDRESS = 0x0020,
STUN_ATTR_PRIORITY = 0x0024,
STUN_ATTR_USE_CANDIDATE = 0x0025,
// Comprehension-optional
STUN_ATTR_PASSWORD_ALGORITHMS = 0x8002,
STUN_ATTR_ALTERNATE_DOMAIN = 0x8003,
STUN_ATTR_SOFTWARE = 0x8022,
STUN_ATTR_ALTERNATE_SERVER = 0x8023,
STUN_ATTR_FINGERPRINT = 0x8028,
STUN_ATTR_ICE_CONTROLLED = 0x8029,
STUN_ATTR_ICE_CONTROLLING = 0x802A,
// Attributes for TURN
// See https://www.rfc-editor.org/rfc/rfc8656.html#section-18
STUN_ATTR_CHANNEL_NUMBER = 0x000C,
STUN_ATTR_LIFETIME = 0x000D,
STUN_ATTR_XOR_PEER_ADDRESS = 0x0012,
STUN_ATTR_DATA = 0x0013,
STUN_ATTR_XOR_RELAYED_ADDRESS = 0x0016,
STUN_ATTR_EVEN_PORT = 0x0018,
STUN_ATTR_REQUESTED_TRANSPORT = 0x0019,
STUN_ATTR_DONT_FRAGMENT = 0x001A,
STUN_ATTR_RESERVATION_TOKEN = 0x0022
} stun_attr_type_t;
#define STUN_IS_OPTIONAL_ATTR(attr_type) (attr_type & 0x8000)
/*
* STUN attribute value for MAPPED-ADDRESS or XOR-MAPPED-ADDRESS
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |X X X X X X X X| Family | Port or X-Port |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | |
* | Address or X-Address (32 bits or 128 bits) |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct stun_value_mapped_address {
uint8_t padding;
uint8_t family;
uint16_t port;
uint8_t address[];
};
typedef enum stun_address_family {
STUN_ADDRESS_FAMILY_IPV4 = 0x01,
STUN_ADDRESS_FAMILY_IPV6 = 0x02,
} stun_address_family_t;
/*
* STUN attribute value for ERROR-CODE
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved, should be 0 |Class| Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reason Phrase (variable) ...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct stun_value_error_code {
uint16_t reserved;
uint8_t code_class; // lower 3 bits only, higher bits are reserved
uint8_t code_number;
uint8_t reason[];
};
#define STUN_ERROR_INTERNAL_VALIDATION_FAILED 599
/*
* STUN attribute for CHANNEL-NUMBER
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Channel Number | RFFU = 0 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct stun_value_channel_number {
uint16_t channel_number;
uint16_t reserved;
};
/*
* STUN attribute for EVEN-PORT
*
* 0
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
* |R| RFFU |
* +-+-+-+-+-+-+-+-+
*/
struct stun_value_even_port {
uint8_t r;
};
/*
* STUN attribute for REQUESTED-TRANSPORT
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Protocol | RFFU |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
struct stun_value_requested_transport {
uint8_t protocol;
uint8_t reserved1;
uint16_t reserved2;
};
/*
* STUN attribute value for PASSWORD-ALGORITHM and PASSWORD-ALGORITHMS
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Algorithm 1 | Algorithm 1 Parameters Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Algorithm 1 Parameters (variable)
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Algorithm 2 | Algorithm 2 Parameters Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Algorithm 2 Parameters (variable)
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ...
*/
struct stun_value_password_algorithm {
uint16_t algorithm;
uint16_t parameters_length;
uint8_t parameters[];
};
typedef enum stun_password_algorithm {
STUN_PASSWORD_ALGORITHM_UNSET = 0x0000,
STUN_PASSWORD_ALGORITHM_MD5 = 0x0001,
STUN_PASSWORD_ALGORITHM_SHA256 = 0x0002,
} stun_password_algorithm_t;
#pragma pack(pop)
// The value of USERNAME is a variable-length value. It MUST contain a UTF-8 [RFC3629] encoded
// sequence of less than 513 bytes [...]
#define STUN_MAX_USERNAME_LEN 513 + 1
// The REALM attribute [...] MUST be a UTF-8 [RFC3629] encoded sequence of less than 128 characters
// (which can be as long as 763 bytes)
#define STUN_MAX_REALM_LEN 763 + 1
// The NONCE attribute may be present in requests and responses. It [...] MUST be less than 128
// characters (which can be as long as 763 bytes)
#define STUN_MAX_NONCE_LEN 763 + 1
// The value of SOFTWARE is variable length. It MUST be a UTF-8 [RFC3629] encoded sequence of less
// than 128 characters (which can be as long as 763 bytes)
#define STUN_MAX_SOFTWARE_LEN 763 + 1
// The reason phrase MUST be a UTF-8-encoded [RFC3629] sequence of fewer than 128 characters (which
// can be as long as 509 bytes when encoding them or 763 bytes when decoding them).
#define STUN_MAX_ERROR_REASON_LEN 763 + 1
#define STUN_MAX_PASSWORD_LEN STUN_MAX_USERNAME_LEN
// Nonce cookie prefix as specified in https://www.rfc-editor.org/rfc/rfc8489.html#section-9.2
#define STUN_NONCE_COOKIE "obMatJos2"
#define STUN_NONCE_COOKIE_LEN 9
// USERHASH is a SHA256 digest
#define USERHASH_SIZE HASH_SHA256_SIZE
// STUN Security Feature bits as defined in https://www.rfc-editor.org/rfc/rfc8489.html#section-18.1
// See errata about bit order: https://www.rfc-editor.org/errata_search.php?rfc=8489
// Bits are assigned starting from the least significant side of the bit set, so Bit 0 is the rightmost bit, and Bit 23 is the leftmost bit.
// Bit 0: Password algorithms
// Bit 1: Username anonymity
// Bit 2-23: Unassigned
#define STUN_SECURITY_PASSWORD_ALGORITHMS_BIT 0x01
#define STUN_SECURITY_USERNAME_ANONYMITY_BIT 0x02
#define STUN_MAX_PASSWORD_ALGORITHMS_VALUE_SIZE 256
typedef struct stun_credentials {
char username[STUN_MAX_USERNAME_LEN];
char realm[STUN_MAX_REALM_LEN];
char nonce[STUN_MAX_NONCE_LEN];
uint8_t userhash[USERHASH_SIZE];
bool enable_userhash;
stun_password_algorithm_t password_algorithm;
uint8_t password_algorithms_value[STUN_MAX_PASSWORD_ALGORITHMS_VALUE_SIZE];
size_t password_algorithms_value_size;
} stun_credentials_t;
typedef struct stun_message {
stun_class_t msg_class;
stun_method_t msg_method;
uint8_t transaction_id[STUN_TRANSACTION_ID_SIZE];
unsigned int error_code;
uint32_t priority;
uint64_t ice_controlling;
uint64_t ice_controlled;
bool use_candidate;
addr_record_t mapped;
stun_credentials_t credentials;
// Only for reading
bool has_integrity;
bool has_fingerprint;
// TURN
addr_record_t peer;
addr_record_t relayed;
addr_record_t alternate_server;
const char *data;
size_t data_size;
uint32_t lifetime;
uint16_t channel_number;
bool lifetime_set;
bool even_port;
bool next_port;
bool dont_fragment;
bool requested_transport;
uint64_t reservation_token;
} stun_message_t;
int stun_write(void *buf, size_t size, const stun_message_t *msg,
const char *password); // password may be NULL
int stun_write_header(void *buf, size_t size, stun_class_t class, stun_method_t method,
const uint8_t *transaction_id);
size_t stun_update_header_length(void *buf, size_t length);
int stun_write_attr(void *buf, size_t size, uint16_t type, const void *value, size_t length);
int stun_write_value_mapped_address(void *buf, size_t size, const struct sockaddr *addr,
socklen_t addrlen, const uint8_t *mask);
bool is_stun_datagram(const void *data, size_t size);
int stun_read(void *data, size_t size, stun_message_t *msg);
int stun_read_attr(const void *data, size_t size, stun_message_t *msg, uint8_t *begin,
uint8_t *attr_begin, uint32_t *security_bits);
int stun_read_value_mapped_address(const void *data, size_t size, addr_record_t *mapped,
const uint8_t *mask);
bool stun_check_integrity(void *buf, size_t size, const stun_message_t *msg, const char *password);
void stun_compute_userhash(const char *username, const char *realm, uint8_t *out);
void stun_prepend_nonce_cookie(char *nonce);
void stun_process_credentials(const stun_credentials_t *credentials, stun_credentials_t *dst);
const char *stun_get_error_reason(unsigned int code);
// Export for tests
JUICE_EXPORT bool _juice_is_stun_datagram(const void *data, size_t size);
JUICE_EXPORT int _juice_stun_read(void *data, size_t size, stun_message_t *msg);
JUICE_EXPORT bool _juice_stun_check_integrity(void *buf, size_t size, const stun_message_t *msg,
const char *password);
#endif