/** * Read the modulus and public exponent of a certificate. */ int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx) { int ret = X509_NOT_OK, mod_len, pub_len; uint8_t *modulus = NULL, *pub_exp = NULL; if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || asn1_skip_obj(cert, offset, ASN1_SEQUENCE) || asn1_next_obj(cert, offset, ASN1_BIT_STRING) < 0) goto end_pub_key; (*offset)++; /* ignore the padding bit field */ if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) goto end_pub_key; mod_len = asn1_get_int(cert, offset, &modulus); pub_len = asn1_get_int(cert, offset, &pub_exp); RSA_pub_key_new(&x509_ctx->rsa_ctx, modulus, mod_len, pub_exp, pub_len); SSL_FREE(modulus); SSL_FREE(pub_exp); ret = X509_OK; end_pub_key: return ret; }
/** * Perform HMAC-SHA1 * NOTE: does not handle keys larger than the block size. */ void ssl_hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, int key_len, uint8_t *digest) { SHA1_CTX context; uint8_t *k_ipad = (uint8_t *)SSL_ZALLOC(64); uint8_t *k_opad = (uint8_t *)SSL_ZALLOC(64); int i; // memset(k_ipad, 0, sizeof k_ipad); // memset(k_opad, 0, sizeof k_opad); memcpy(k_ipad, key, key_len); memcpy(k_opad, key, key_len); for (i = 0; i < 64; i++) { k_ipad[i] ^= 0x36; k_opad[i] ^= 0x5c; } SHA1_Init(&context); SHA1_Update(&context, k_ipad, 64); SHA1_Update(&context, msg, length); SHA1_Final(digest, &context); SHA1_Init(&context); SHA1_Update(&context, k_opad, 64); SHA1_Update(&context, digest, SHA1_SIZE); SHA1_Final(digest, &context); SSL_FREE(k_ipad); SSL_FREE(k_opad); }
/** * Get the subject name (or the issuer) of a certificate. */ int asn1_name(const uint8_t *cert, int *offset, char *dn[]) { int ret = X509_NOT_OK; int dn_type; char *tmp; if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0) goto end_name; while (asn1_next_obj(cert, offset, ASN1_SET) >= 0) { int i, found = 0; if (asn1_next_obj(cert, offset, ASN1_SEQUENCE) < 0 || (dn_type = asn1_get_oid_x520(cert, offset)) < 0) goto end_name; tmp = NULL; if (asn1_get_printable_str(cert, offset, &tmp) < 0) { SSL_FREE(tmp); goto end_name; } /* find the distinguished named type */ for (i = 0; i < X509_NUM_DN_TYPES; i++) { if (dn_type == g_dn_types[i]) { if (dn[i] == NULL) { dn[i] = tmp; found = 1; break; } } } if (found == 0) /* not found so get rid of it */ { SSL_FREE(tmp); } } ret = X509_OK; end_name: return ret; }
/** * Get all the RSA private key specifics from an ASN.1 encoded file */ int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx) { int offset = 7; uint8_t *modulus = NULL, *priv_exp = NULL, *pub_exp = NULL; int mod_len, priv_len, pub_len; #ifdef CONFIG_BIGINT_CRT uint8_t *p = NULL, *q = NULL, *dP = NULL, *dQ = NULL, *qInv = NULL; int p_len, q_len, dP_len, dQ_len, qInv_len; #endif /* not in der format */ if (buf[0] != ASN1_SEQUENCE) /* basic sanity check */ { #ifdef CONFIG_SSL_FULL_MODE ssl_printf("Error: This is not a valid ASN.1 file\n"); #endif return X509_INVALID_PRIV_KEY; } /* Use the private key to mix up the RNG if possible. */ RNG_custom_init(buf, len); mod_len = asn1_get_int(buf, &offset, &modulus); pub_len = asn1_get_int(buf, &offset, &pub_exp); priv_len = asn1_get_int(buf, &offset, &priv_exp); if (mod_len <= 0 || pub_len <= 0 || priv_len <= 0) return X509_INVALID_PRIV_KEY; #ifdef CONFIG_BIGINT_CRT p_len = asn1_get_int(buf, &offset, &p); q_len = asn1_get_int(buf, &offset, &q); dP_len = asn1_get_int(buf, &offset, &dP); dQ_len = asn1_get_int(buf, &offset, &dQ); qInv_len = asn1_get_int(buf, &offset, &qInv); if (p_len <= 0 || q_len <= 0 || dP_len <= 0 || dQ_len <= 0 || qInv_len <= 0) return X509_INVALID_PRIV_KEY; RSA_priv_key_new(rsa_ctx, modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len, p, p_len, q, p_len, dP, dP_len, dQ, dQ_len, qInv, qInv_len); SSL_FREE(p); SSL_FREE(q); SSL_FREE(dP); SSL_FREE(dQ); SSL_FREE(qInv); #else RSA_priv_key_new(rsa_ctx, modulus, mod_len, pub_exp, pub_len, priv_exp, priv_len); #endif SSL_FREE(modulus); SSL_FREE(priv_exp); SSL_FREE(pub_exp); return X509_OK; }
/** * Free up any RSA context resources. */ void RSA_free(RSA_CTX *rsa_ctx) { BI_CTX *bi_ctx; if (rsa_ctx == NULL) /* deal with ptrs that are null */ return; bi_ctx = rsa_ctx->bi_ctx; bi_depermanent(rsa_ctx->e); bi_free(bi_ctx, rsa_ctx->e); bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET); if (rsa_ctx->d) { bi_depermanent(rsa_ctx->d); bi_free(bi_ctx, rsa_ctx->d); #ifdef CONFIG_BIGINT_CRT bi_depermanent(rsa_ctx->dP); bi_depermanent(rsa_ctx->dQ); bi_depermanent(rsa_ctx->qInv); bi_free(bi_ctx, rsa_ctx->dP); bi_free(bi_ctx, rsa_ctx->dQ); bi_free(bi_ctx, rsa_ctx->qInv); bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET); bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET); #endif } bi_terminate(bi_ctx); SSL_FREE(rsa_ctx); }
/** * @brief Use PKCS1.5 for decryption/verification. * @param ctx [in] The context * @param in_data [in] The data to decrypt (must be < modulus size-11) * @param out_data [out] The decrypted data. * @param out_len [int] The size of the decrypted buffer in bytes * @param is_decryption [in] Decryption or verify operation. * @return The number of bytes that were originally encrypted. -1 on error. * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 */ int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, int out_len, int is_decryption) { const int byte_size = ctx->num_octets; int i = 0, size; bigint *decrypted_bi, *dat_bi; uint8_t *block = (uint8_t *)SSL_MALLOC(byte_size); int pad_count = 0; if (out_len < byte_size) /* check output has enough size */ return -1; memset(out_data, 0, out_len); /* initialise */ /* decrypt */ dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size); #ifdef CONFIG_SSL_CERT_VERIFICATION decrypted_bi = is_decryption ? /* decrypt or verify? */ RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi); #else /* always a decryption */ decrypted_bi = RSA_private(ctx, dat_bi); #endif /* convert to a normal block */ bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size); if (block[i++] != 0) /* leading 0? */ return -1; #ifdef CONFIG_SSL_CERT_VERIFICATION if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */ { if (block[i++] != 0x01) /* BT correct? */ return -1; while (block[i++] == 0xff && i < byte_size) pad_count++; } else /* PKCS1.5 encryption padding is random */ #endif { if (block[i++] != 0x02) /* BT correct? */ return -1; while (block[i++] && i < byte_size) pad_count++; } /* check separator byte 0x00 - and padding must be 8 or more bytes */ if (i == byte_size || pad_count < 8) return -1; size = byte_size - i; /* get only the bit we want */ if (size > 0) memcpy(out_data, &block[i], size); SSL_FREE(block); return size ? size : -1; }
static ioa_socket_handle dtls_server_input_handler(dtls_listener_relay_server_type* server, ioa_socket_handle s, ioa_network_buffer_handle nbh) { FUNCSTART; if (!server || !nbh) { return NULL; } SSL* connecting_ssl = NULL; BIO *wbio = NULL; struct timeval timeout; /* Create BIO */ wbio = BIO_new_dgram(s->fd, BIO_NOCLOSE); (void)BIO_dgram_set_peer(wbio, (struct sockaddr*) &(server->sm.m.sm.nd.src_addr)); /* Set and activate timeouts */ timeout.tv_sec = DTLS_MAX_RECV_TIMEOUT; timeout.tv_usec = 0; BIO_ctrl(wbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); #if DTLSv1_2_SUPPORTED if(get_dtls_version(ioa_network_buffer_data(nbh), (int)ioa_network_buffer_get_size(nbh)) == 1) { connecting_ssl = SSL_NEW(server->dtls_ctx_v1_2); } else { connecting_ssl = SSL_NEW(server->dtls_ctx); } #else { connecting_ssl = SSL_NEW(server->dtls_ctx); } #endif SSL_set_accept_state(connecting_ssl); SSL_set_bio(connecting_ssl, NULL, wbio); SSL_set_options(connecting_ssl, SSL_OP_COOKIE_EXCHANGE); SSL_set_max_cert_list(connecting_ssl, 655350); ioa_socket_handle rc = dtls_accept_client_connection(server, s, connecting_ssl, &(server->sm.m.sm.nd.src_addr), &(server->addr), nbh); if (!rc) { if (!(SSL_get_shutdown(connecting_ssl) & SSL_SENT_SHUTDOWN)) { SSL_set_shutdown(connecting_ssl, SSL_RECEIVED_SHUTDOWN); SSL_shutdown(connecting_ssl); } SSL_FREE(connecting_ssl); } return rc; }
/** *@brief Clear the memory cache. */ void ICACHE_FLASH_ATTR bi_clear_cache(BI_CTX *ctx) { bigint *p, *pn; if (ctx->free_list == NULL) return; for (p = ctx->free_list; p != NULL; p = pn) { pn = p->next; SSL_FREE(p->comps); SSL_FREE(p); } ctx->free_count = 0; ctx->free_list = NULL; }
/** * Clean up all of the CA certificates. */ void remove_ca_certs(CA_CERT_CTX *ca_cert_ctx) { int i = 0; if (ca_cert_ctx == NULL) return; while (i < CONFIG_X509_MAX_CA_CERTS && ca_cert_ctx->cert[i]) { x509_free(ca_cert_ctx->cert[i]); ca_cert_ctx->cert[i++] = NULL; } SSL_FREE(ca_cert_ctx); }
/** * @brief Close the bigint context and free any resources. * * Free up any used memory - a check is done if all objects were not * properly freed. * @param ctx [in] The bigint session context. */ void ICACHE_FLASH_ATTR bi_terminate(BI_CTX *ctx) { bi_depermanent(ctx->bi_radix); bi_free(ctx, ctx->bi_radix); if (ctx->active_count != 0) { #ifdef CONFIG_SSL_FULL_MODE ssl_printf("bi_terminate: there were %d un-freed bigints\n", ctx->active_count); #endif return; /* wujg : org ---> abort(); */ } bi_clear_cache(ctx); SSL_FREE(ctx); }
/* * Allocate and zero more components. Does not consume bi. */ static void ICACHE_FLASH_ATTR more_comps(bigint *bi, int n) { comp * bi_backs = NULL; if (n > bi->max_comps) { bi->max_comps = max(bi->max_comps * 2, n); if(bi->comps) { //bi->comps = (comp*)SSL_REALLOC(bi->comps, bi->max_comps * COMP_BYTE_SIZE); bi_backs = (comp*)SSL_ZALLOC(bi->max_comps * COMP_BYTE_SIZE); if(bi_backs) { memcpy(bi_backs,bi->comps,bi->max_comps * COMP_BYTE_SIZE); SSL_FREE(bi->comps); bi->comps = bi_backs; } } } if (n > bi->size) { memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE); } bi->size = n; }
/** * @brief Perform a modular exponentiation. * * This function requires bi_set_mod() to have been called previously. This is * one of the optimisations used for performance. * @param ctx [in] The bigint session context. * @param bi [in] The bigint on which to perform the mod power operation. * @param biexp [in] The bigint exponent. * @return The result of the mod exponentiation operation * @see bi_set_mod(). */ bigint * ICACHE_FLASH_ATTR bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) { int i = find_max_exp_index(biexp), j, window_size = 1; bigint *biR = int_to_bi(ctx, 1); #if defined(CONFIG_BIGINT_MONTGOMERY) uint8_t mod_offset = ctx->mod_offset; if (!ctx->use_classical) { /* preconvert */ bi = bi_mont(ctx, bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */ bi_free(ctx, biR); biR = ctx->bi_R_mod_m[mod_offset]; /* A */ } #endif check(bi); check(biexp); #ifdef CONFIG_BIGINT_SLIDING_WINDOW for (j = i; j > 32; j /= 5) /* work out an optimum size */ window_size++; /* work out the slide constants */ precompute_slide_window(ctx, window_size, bi); #else /* just one constant */ ctx->g = (bigint **)SSL_MALLOC(sizeof(bigint *)); ctx->g[0] = bi_clone(ctx, bi); ctx->window = 1; bi_permanent(ctx->g[0]); #endif /* if sliding-window is off, then only one bit will be done at a time and * will reduce to standard left-to-right exponentiation */ do { if (exp_bit_is_one(biexp, i)) { int l = i-window_size+1; int part_exp = 0; if (l < 0) /* LSB of exponent will always be 1 */ l = 0; else { while (exp_bit_is_one(biexp, l) == 0) l++; /* go back up */ } /* build up the section of the exponent */ for (j = i; j >= l; j--) { biR = bi_residue(ctx, bi_square(ctx, biR)); if (exp_bit_is_one(biexp, j)) part_exp++; if (j != l) part_exp <<= 1; } part_exp = (part_exp-1)/2; /* adjust for array */ biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp])); i = l-1; } else /* square it */ { biR = bi_residue(ctx, bi_square(ctx, biR)); i--; } } while (i >= 0); /* cleanup */ for (i = 0; i < ctx->window; i++) { bi_depermanent(ctx->g[i]); bi_free(ctx, ctx->g[i]); } SSL_FREE(ctx->g); bi_free(ctx, bi); bi_free(ctx, biexp); #if defined CONFIG_BIGINT_MONTGOMERY return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */ #else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */ return biR; #endif }
static int create_new_connected_udp_socket( dtls_listener_relay_server_type* server, ioa_socket_handle s) { evutil_socket_t udp_fd = socket(s->local_addr.ss.sa_family, CLIENT_DGRAM_SOCKET_TYPE, CLIENT_DGRAM_SOCKET_PROTOCOL); if (udp_fd < 0) { perror("socket"); TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Cannot allocate new socket\n", __FUNCTION__); return -1; } if (sock_bind_to_device(udp_fd, (unsigned char*) (s->e->relay_ifname)) < 0) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot bind udp server socket to device %s\n", (char*) (s->e->relay_ifname)); } ioa_socket_handle ret = (ioa_socket*) turn_malloc(sizeof(ioa_socket)); if (!ret) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Cannot allocate new socket structure\n", __FUNCTION__); close(udp_fd); return -1; } ns_bzero(ret, sizeof(ioa_socket)); ret->magic = SOCKET_MAGIC; ret->fd = udp_fd; ret->family = s->family; ret->st = s->st; ret->sat = CLIENT_SOCKET; ret->local_addr_known = 1; addr_cpy(&(ret->local_addr), &(s->local_addr)); if (addr_bind(udp_fd,&(s->local_addr),1,1,UDP_SOCKET) < 0) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot bind new detached udp server socket to local addr\n"); IOA_CLOSE_SOCKET(ret); return -1; } ret->bound = 1; { int connect_err = 0; if (addr_connect(udp_fd, &(server->sm.m.sm.nd.src_addr), &connect_err) < 0) { char sl[129]; char sr[129]; addr_to_string(&(ret->local_addr),(u08bits*)sl); addr_to_string(&(server->sm.m.sm.nd.src_addr),(u08bits*)sr); TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot connect new detached udp client socket from local addr %s to remote addr %s\n",sl,sr); IOA_CLOSE_SOCKET(ret); return -1; } } ret->connected = 1; addr_cpy(&(ret->remote_addr), &(server->sm.m.sm.nd.src_addr)); set_socket_options(ret); ret->current_ttl = s->current_ttl; ret->default_ttl = s->default_ttl; ret->current_tos = s->current_tos; ret->default_tos = s->default_tos; #if DTLS_SUPPORTED if (!turn_params.no_dtls && is_dtls_handshake_message( ioa_network_buffer_data(server->sm.m.sm.nd.nbh), (int) ioa_network_buffer_get_size( server->sm.m.sm.nd.nbh))) { SSL* connecting_ssl = NULL; BIO *wbio = NULL; struct timeval timeout; /* Create BIO */ wbio = BIO_new_dgram(ret->fd, BIO_NOCLOSE); (void) BIO_dgram_set_peer(wbio, (struct sockaddr*) &(server->sm.m.sm.nd.src_addr)); BIO_ctrl(wbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &(server->sm.m.sm.nd.src_addr)); /* Set and activate timeouts */ timeout.tv_sec = DTLS_MAX_RECV_TIMEOUT; timeout.tv_usec = 0; BIO_ctrl(wbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); #if DTLSv1_2_SUPPORTED if(get_dtls_version(ioa_network_buffer_data(server->sm.m.sm.nd.nbh), (int)ioa_network_buffer_get_size(server->sm.m.sm.nd.nbh)) == 1) { connecting_ssl = SSL_NEW(server->dtls_ctx_v1_2); } else { connecting_ssl = SSL_NEW(server->dtls_ctx); } #else { connecting_ssl = SSL_NEW(server->dtls_ctx); } #endif SSL_set_accept_state(connecting_ssl); SSL_set_bio(connecting_ssl, NULL, wbio); SSL_set_options(connecting_ssl, SSL_OP_COOKIE_EXCHANGE); SSL_set_max_cert_list(connecting_ssl, 655350); int rc = ssl_read(ret->fd, connecting_ssl, server->sm.m.sm.nd.nbh, server->verbose); if (rc < 0) { if (!(SSL_get_shutdown(connecting_ssl) & SSL_SENT_SHUTDOWN)) { SSL_set_shutdown(connecting_ssl, SSL_RECEIVED_SHUTDOWN); SSL_shutdown(connecting_ssl); } SSL_FREE(connecting_ssl); IOA_CLOSE_SOCKET(ret); return -1; } addr_debug_print(server->verbose, &(server->sm.m.sm.nd.src_addr), "Accepted DTLS connection from"); ret->ssl = connecting_ssl; ioa_network_buffer_delete(server->e, server->sm.m.sm.nd.nbh); server->sm.m.sm.nd.nbh = NULL; ret->st = DTLS_SOCKET; } #endif server->sm.m.sm.s = ret; return server->connect_cb(server->e, &(server->sm)); }
static SSL* tls_connect(ioa_socket_raw fd, ioa_addr *remote_addr, int *try_again, int connect_cycle) { int ctxtype = (int)(((unsigned long)random())%root_tls_ctx_num); SSL *ssl; ssl = SSL_NEW(root_tls_ctx[ctxtype]); #if ALPN_SUPPORTED SSL_set_alpn_protos(ssl, kALPNProtos, kALPNProtosLen); #endif if(use_tcp) { SSL_set_fd(ssl, fd); } else { #if !DTLS_SUPPORTED UNUSED_ARG(remote_addr); fprintf(stderr,"ERROR: DTLS is not supported.\n"); exit(-1); #else /* Create BIO, connect and set to already connected */ BIO *bio = BIO_new_dgram(fd, BIO_CLOSE); //bio = BIO_new_socket(fd, BIO_CLOSE); BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &remote_addr->ss); SSL_set_bio(ssl, bio, bio); { struct timeval timeout; /* Set and activate timeouts */ timeout.tv_sec = DTLS_MAX_CONNECT_TIMEOUT; timeout.tv_usec = 0; BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); } set_mtu_df(ssl, fd, remote_addr->ss.sa_family, SOSO_MTU, !use_tcp, clnet_verbose); #endif } SSL_set_max_cert_list(ssl, 655350); if (clnet_verbose) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "call SSL_connect...\n"); int rc = 0; do { do { rc = SSL_connect(ssl); } while (rc < 0 && errno == EINTR); int orig_errno = errno; if (rc > 0) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,"%s: client session connected with cipher %s, method=%s\n",__FUNCTION__, SSL_get_cipher(ssl),turn_get_ssl_method(ssl,NULL)); if(clnet_verbose && SSL_get_peer_certificate(ssl)) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "------------------------------------------------------------\n"); X509_NAME_print_ex_fp(stdout, X509_get_subject_name(SSL_get_peer_certificate(ssl)), 1, XN_FLAG_MULTILINE); TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\n\n Cipher: %s\n", SSL_CIPHER_get_name(SSL_get_current_cipher(ssl))); TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\n------------------------------------------------------------\n\n"); } break; } else { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: cannot connect: rc=%d, ctx=%d\n", __FUNCTION__,rc,ctxtype); switch (SSL_get_error(ssl, rc)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: if(!dos) usleep(1000); continue; default: { char buf[1025]; TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "errno=%d, err=%d, %s (%d)\n",orig_errno, (int)ERR_get_error(), ERR_error_string(ERR_get_error(), buf), (int)SSL_get_error(ssl, rc)); if(connect_cycle<MAX_TLS_CYCLES) { if(try_again) { SSL_FREE(ssl); *try_again = 1; return NULL; } } exit(-1); } }; } } while (1); if (clnet_verbose && SSL_get_peer_certificate(ssl)) { if(use_tcp) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "------TLS---------------------------------------------------\n"); } else { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "------DTLS---------------------------------------------------\n"); } X509_NAME_print_ex_fp(stdout, X509_get_subject_name( SSL_get_peer_certificate(ssl)), 1, XN_FLAG_MULTILINE); TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\n\n Cipher: %s\n", SSL_CIPHER_get_name(SSL_get_current_cipher(ssl))); TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "\n------------------------------------------------------------\n\n"); } return ssl; }
static int clnet_allocate(int verbose, app_ur_conn_info *clnet_info, ioa_addr *relay_addr, int af, char *turn_addr, u16bits *turn_port) { int af_cycle = 0; int reopen_socket = 0; int allocate_finished; stun_buffer request_message, response_message; beg_allocate: allocate_finished=0; while (!allocate_finished && af_cycle++ < 32) { int allocate_sent = 0; if(reopen_socket && !use_tcp) { socket_closesocket(clnet_info->fd); clnet_info->fd = -1; if (clnet_connect(addr_get_port(&(clnet_info->remote_addr)), clnet_info->rsaddr, (u08bits*)clnet_info->ifname, clnet_info->lsaddr, verbose, clnet_info) < 0) { exit(-1); } reopen_socket = 0; } int af4 = dual_allocation || (af == STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV4); int af6 = dual_allocation || (af == STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6); uint64_t reservation_token = 0; char* rt = NULL; int ep = !no_rtcp && !dual_allocation; if(!no_rtcp) { if (!never_allocate_rtcp && allocate_rtcp) { reservation_token = ioa_ntoh64(current_reservation_token); rt = (char*) (&reservation_token); } } if(is_TCP_relay()) { ep = -1; } else if(rt) { ep = -1; } else if(!ep) { ep = (((u08bits)random()) % 2); ep = ep-1; } if(!dos) stun_set_allocate_request(&request_message, UCLIENT_SESSION_LIFETIME, af4, af6, relay_transport, mobility, rt, ep); else stun_set_allocate_request(&request_message, UCLIENT_SESSION_LIFETIME/3, af4, af6, relay_transport, mobility, rt, ep); if(bps) stun_attr_add_bandwidth_str(request_message.buf, (size_t*)(&(request_message.len)), bps); if(dont_fragment) stun_attr_add(&request_message, STUN_ATTRIBUTE_DONT_FRAGMENT, NULL, 0); add_origin(&request_message); if(add_integrity(clnet_info, &request_message)<0) return -1; stun_attr_add_fingerprint_str(request_message.buf,(size_t*)&(request_message.len)); while (!allocate_sent) { int len = send_buffer(clnet_info, &request_message,0,0); if (len > 0) { if (verbose) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "allocate sent\n"); } allocate_sent = 1; } else { perror("send"); exit(1); } } ////////////<<==allocate send if(not_rare_event()) return 0; ////////allocate response==>> { int allocate_received = 0; while (!allocate_received) { int len = recv_buffer(clnet_info, &response_message, 1, 0, NULL, &request_message); if (len > 0) { if (verbose) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "allocate response received: \n"); } response_message.len = len; int err_code = 0; u08bits err_msg[129]; if (stun_is_success_response(&response_message)) { allocate_received = 1; allocate_finished = 1; if(clnet_info->nonce[0]) { if(check_integrity(clnet_info, &response_message)<0) return -1; } if (verbose) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "success\n"); } { int found = 0; stun_attr_ref sar = stun_attr_get_first(&response_message); while (sar) { int attr_type = stun_attr_get_type(sar); if(attr_type == STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS) { if (stun_attr_get_addr(&response_message, sar, relay_addr, NULL) < 0) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: !!!: relay addr cannot be received (1)\n", __FUNCTION__); return -1; } else { if (verbose) { ioa_addr raddr; memcpy(&raddr, relay_addr,sizeof(ioa_addr)); addr_debug_print(verbose, &raddr,"Received relay addr"); } if(!addr_any(relay_addr)) { if(relay_addr->ss.sa_family == AF_INET) { if(default_address_family != STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6) { found = 1; addr_cpy(&(clnet_info->relay_addr),relay_addr); break; } } if(relay_addr->ss.sa_family == AF_INET6) { if(default_address_family == STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6) { found = 1; addr_cpy(&(clnet_info->relay_addr),relay_addr); break; } } } } } sar = stun_attr_get_next(&response_message,sar); } if(!found) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: !!!: relay addr cannot be received (2)\n", __FUNCTION__); return -1; } } stun_attr_ref rt_sar = stun_attr_get_first_by_type( &response_message, STUN_ATTRIBUTE_RESERVATION_TOKEN); uint64_t rtv = stun_attr_get_reservation_token_value(rt_sar); current_reservation_token = rtv; if (verbose) TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "%s: rtv=%llu\n", __FUNCTION__, (long long unsigned int)rtv); read_mobility_ticket(clnet_info, &response_message); } else if (stun_is_challenge_response_str(response_message.buf, (size_t)response_message.len, &err_code,err_msg,sizeof(err_msg), clnet_info->realm,clnet_info->nonce, clnet_info->server_name, &(clnet_info->oauth))) { goto beg_allocate; } else if (stun_is_error_response(&response_message, &err_code,err_msg,sizeof(err_msg))) { allocate_received = 1; if(err_code == 300) { if(clnet_info->nonce[0]) { if(check_integrity(clnet_info, &response_message)<0) return -1; } ioa_addr alternate_server; if(stun_attr_get_first_addr(&response_message, STUN_ATTRIBUTE_ALTERNATE_SERVER, &alternate_server, NULL)==-1) { //error } else if(turn_addr && turn_port){ addr_to_string_no_port(&alternate_server, (u08bits*)turn_addr); *turn_port = (u16bits)addr_get_port(&alternate_server); } } TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "error %d (%s)\n", err_code,(char*)err_msg); if (err_code != 437) { allocate_finished = 1; current_reservation_token = 0; return -1; } else { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "trying allocate again %d...\n", err_code); sleep(1); reopen_socket = 1; } } else { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "unknown allocate response\n"); /* Try again ? */ } } else { perror("recv"); exit(-1); break; } } } } ////////////<<== allocate response received if(rare_event()) return 0; if(!allocate_finished) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot complete Allocation\n"); exit(-1); } allocate_rtcp = !allocate_rtcp; if (1) { af_cycle = 0; if(clnet_info->s_mobile_id[0]) { int fd = clnet_info->fd; SSL* ssl = clnet_info->ssl; int close_now = (int)(random()%2); if(close_now) { int close_socket = (int)(random()%2); if(ssl && !close_socket) { SSL_shutdown(ssl); SSL_FREE(ssl); fd = -1; } else if(fd>=0) { close(fd); fd = -1; ssl = NULL; } } app_ur_conn_info ci; ns_bcopy(clnet_info,&ci,sizeof(ci)); ci.fd = -1; ci.ssl = NULL; clnet_info->fd = -1; clnet_info->ssl = NULL; //Reopen: if(clnet_connect(addr_get_port(&(ci.remote_addr)), ci.rsaddr, (unsigned char*)ci.ifname, ci.lsaddr, clnet_verbose, clnet_info)<0) { exit(-1); } if(ssl) { SSL_shutdown(ssl); SSL_FREE(ssl); } else if(fd>=0) { close(fd); } } beg_refresh: if(af_cycle++>32) { TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot complete Refresh\n"); exit(-1); } //==>>refresh request, for an example only: { int refresh_sent = 0; stun_init_request(STUN_METHOD_REFRESH, &request_message); uint32_t lt = htonl(UCLIENT_SESSION_LIFETIME); stun_attr_add(&request_message, STUN_ATTRIBUTE_LIFETIME, (const char*) <, 4); if(clnet_info->s_mobile_id[0]) { stun_attr_add(&request_message, STUN_ATTRIBUTE_MOBILITY_TICKET, (const char*)clnet_info->s_mobile_id, strlen(clnet_info->s_mobile_id)); } if(dual_allocation && !mobility) { int t = ((u08bits)random())%3; if(t) { u08bits field[4]; field[0] = (t==1) ? (u08bits)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV4 : (u08bits)STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY_VALUE_IPV6; field[1]=0; field[2]=0; field[3]=0; stun_attr_add(&request_message, STUN_ATTRIBUTE_REQUESTED_ADDRESS_FAMILY, (const char*) field, 4); } } add_origin(&request_message); if(add_integrity(clnet_info, &request_message)<0) return -1; stun_attr_add_fingerprint_str(request_message.buf,(size_t*)&(request_message.len)); while (!refresh_sent) { int len = send_buffer(clnet_info, &request_message, 0,0); if (len > 0) { if (verbose) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "refresh sent\n"); } refresh_sent = 1; if(clnet_info->s_mobile_id[0]) { usleep(10000); send_buffer(clnet_info, &request_message, 0,0); } } else { perror("send"); exit(1); } } } if(not_rare_event()) return 0; ////////refresh response==>> { int refresh_received = 0; while (!refresh_received) { int len = recv_buffer(clnet_info, &response_message, 1, 0, NULL, &request_message); if(clnet_info->s_mobile_id[0]) { len = recv_buffer(clnet_info, &response_message, 1, 0, NULL, &request_message); } if (len > 0) { if (verbose) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "refresh response received: \n"); } response_message.len = len; int err_code = 0; u08bits err_msg[129]; if (stun_is_success_response(&response_message)) { read_mobility_ticket(clnet_info, &response_message); refresh_received = 1; if (verbose) { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "success\n"); } } else if (stun_is_challenge_response_str(response_message.buf, (size_t)response_message.len, &err_code,err_msg,sizeof(err_msg), clnet_info->realm,clnet_info->nonce, clnet_info->server_name, &(clnet_info->oauth))) { goto beg_refresh; } else if (stun_is_error_response(&response_message, &err_code,err_msg,sizeof(err_msg))) { refresh_received = 1; TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "error %d (%s)\n", err_code,(char*)err_msg); return -1; } else { TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "unknown refresh response\n"); /* Try again ? */ } } else { perror("recv"); exit(-1); break; } } } } return 0; }