Many fixes around secio

This commit is contained in:
John Jones 2017-03-02 16:14:52 -05:00
parent c5fa775534
commit 6d9473069b
22 changed files with 317 additions and 137 deletions

View file

@ -8,6 +8,8 @@
#include "libp2p/conn/transport_dialer.h" #include "libp2p/conn/transport_dialer.h"
#include "libp2p/crypto/key.h" #include "libp2p/crypto/key.h"
#include "libp2p/utils/linked_list.h" #include "libp2p/utils/linked_list.h"
#include "libp2p/utils/multiaddress.h"
#include "libp2p/net/multistream.h"
struct TransportDialer* libp2p_conn_tcp_transport_dialer_new(); struct TransportDialer* libp2p_conn_tcp_transport_dialer_new();
@ -60,14 +62,38 @@ void libp2p_conn_dialer_free(struct Dialer* in) {
/** /**
* Retrieve a Connection struct from the dialer * Retrieve a Connection struct from the dialer
* NOTE: This should no longer be used. _get_stream should
* be used instead (which calls this method internally).
* @param dialer the dialer to use * @param dialer the dialer to use
* @param muiltiaddress who to connect to * @param muiltiaddress who to connect to
* @returns a Connection, or NULL * @returns a Connection, or NULL
*/ */
struct Connection* libp2p_conn_dialer_get_connection(struct Dialer* dialer, struct MultiAddress* multiaddress) { struct Connection* libp2p_conn_dialer_get_connection(const struct Dialer* dialer, const struct MultiAddress* multiaddress) {
struct Connection* conn = libp2p_conn_transport_dialer_get(dialer->transport_dialers, multiaddress); struct Connection* conn = libp2p_conn_transport_dialer_get(dialer->transport_dialers, multiaddress);
if (conn == NULL) { if (conn == NULL) {
conn = dialer->fallback_dialer->dial(dialer->fallback_dialer, multiaddress); conn = dialer->fallback_dialer->dial(dialer->fallback_dialer, multiaddress);
} }
return conn; return conn;
} }
/**
* return a Stream that is already set up to use the passed in protocol
* @param dialer the dialer to use
* @param multiaddress the host to dial
* @param protocol the protocol to use (right now only 'multistream' is supported)
* @returns the ready-to-use stream
*/
struct Stream* libp2p_conn_dialer_get_stream(const struct Dialer* dialer, const struct MultiAddress* multiaddress, const char* protocol) {
// this is a shortcut for now. Other protocols will soon be implemented
if (strcmp(protocol, "multistream") != 0)
return NULL;
char* ip;
int port;
if (!libp2p_utils_multiaddress_parse_ip4_tcp(multiaddress, &ip, &port)) {
free(ip);
return NULL;
}
struct Stream* stream = libp2p_net_multistream_connect(ip, port);
free(ip);
return stream;
}

View file

@ -6,43 +6,13 @@
#include "libp2p/net/p2pnet.h" #include "libp2p/net/p2pnet.h"
#include "libp2p/conn/connection.h" #include "libp2p/conn/connection.h"
#include "libp2p/conn/transport_dialer.h" #include "libp2p/conn/transport_dialer.h"
#include "libp2p/utils/multiaddress.h"
/** /**
* An implementation of a tcp transport dialer * An implementation of a tcp transport dialer
*/ */
int libp2p_conn_tcp_can_handle(const struct MultiAddress* addr) {
struct TcpIp {
char* ip;
int port;
};
struct TcpIp* libp2p_conn_parse_ip_multiaddress(struct MultiAddress* addr) {
struct TcpIp* out = (struct TcpIp*)malloc(sizeof(struct TcpIp));
char* address = malloc(strlen(addr->string) + 1);
strcpy(address, addr->string);
char* tok = strtok(address, "/");
int pos = 0;
while (tok != NULL) {
switch (pos) {
case 1: {
out->ip = malloc(strlen(tok) + 1);
strcpy(out->ip, tok);
break;
}
case 3: {
out->port = strtol(tok, NULL, 10);
break;
}
}
tok = strtok(NULL, "/");
pos++;
}
//TODO: do a better job of parsing the results
return out;
}
int libp2p_conn_tcp_can_handle(struct MultiAddress* addr) {
return 1; return 1;
} }
@ -59,13 +29,15 @@ int libp2p_conn_tcp_write(const struct Connection* connection, const char* in, s
return bytes == num_bytes; return bytes == num_bytes;
} }
struct Connection* libp2p_conn_tcp_dial(struct TransportDialer* transport_dialer, struct MultiAddress* addr) { struct Connection* libp2p_conn_tcp_dial(const struct TransportDialer* transport_dialer, const struct MultiAddress* addr) {
struct Connection* conn = (struct Connection*) malloc(sizeof(struct Connection*)); struct Connection* conn = (struct Connection*) malloc(sizeof(struct Connection*));
conn->socket_handle = socket_open4(); conn->socket_handle = socket_open4();
struct TcpIp* results = libp2p_conn_parse_ip_multiaddress(addr); char* ip;
struct hostent* host = gethostbyname(results->ip); int port;
libp2p_utils_multiaddress_parse_ip4_tcp(addr, &ip, &port);
struct hostent* host = gethostbyname(ip);
struct in_addr** addr_list = (struct in_addr**)host->h_addr_list; struct in_addr** addr_list = (struct in_addr**)host->h_addr_list;
socket_connect4(conn->socket_handle, (*addr_list[0]).s_addr, results->port); socket_connect4(conn->socket_handle, (*addr_list[0]).s_addr, port);
conn->read = libp2p_conn_tcp_read; conn->read = libp2p_conn_tcp_read;
conn->write = libp2p_conn_tcp_write; conn->write = libp2p_conn_tcp_write;
return conn; return conn;

View file

@ -33,8 +33,8 @@ void libp2p_conn_transport_dialer_free(struct TransportDialer* in) {
* @param multiaddr the address * @param multiaddr the address
* @returns a connection, or NULL if no appropriate dialer was found * @returns a connection, or NULL if no appropriate dialer was found
*/ */
struct Connection* libp2p_conn_transport_dialer_get(struct Libp2pLinkedList* transport_dialers, struct MultiAddress* multiaddr) { struct Connection* libp2p_conn_transport_dialer_get(const struct Libp2pLinkedList* transport_dialers, const struct MultiAddress* multiaddr) {
struct Libp2pLinkedList* current = transport_dialers; const struct Libp2pLinkedList* current = transport_dialers;
struct TransportDialer* t_dialer = NULL; struct TransportDialer* t_dialer = NULL;
while (current != NULL) { while (current != NULL) {
t_dialer = (struct TransportDialer*)current->item; t_dialer = (struct TransportDialer*)current->item;

20
crypto/aes.c Normal file
View file

@ -0,0 +1,20 @@
#include "mbedtls/aes.h"
/**
* Encrypt a block of text
* @param key the aes key
* @param iv the random part of encryption
* @param input the text to encrypt
* @param input_size the length of the array
* @param output where the output will be placed
* @param output_size the length of the memory allocated for output
* @returns true(1) on success, otherwise false(0)
*/
int libp2p_crypto_aes_encrypt(char* key, char* iv, char* input, size_t input_size, unsigned char* output, size_t* output_size) {
mbedtls_aes_context ctx;
mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, key, 256);
mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, 24, iv, input, output);
//TODO Implement this method
return 0;
}

View file

@ -1,7 +1,12 @@
/*** /***
* A local dialer. Uses MultiAddr to figure out the best way to * A local dialer. Uses MultiAddr to figure out the best way to
* connect to a client, then returns an open Connection that can be * connect to a client, then returns an open Connection that can be
* closed, read from and written to. * closed, read from and written to. The normal procedure is as follows:
* 1) Create a Dialer struct, with the required information about the local host
* 2) Call _get_connection to create the connection with a specific host
* NOTE: 1 Dialer could be used to create all connections, saving time and resources
* if it is not too difficult to pass it around. The struct has enough information to
* build connections that negotiate many protocols
*/ */
#include "libp2p/crypto/key.h" #include "libp2p/crypto/key.h"
@ -29,11 +34,16 @@ struct Dialer {
/** /**
* Create a Dialer with the specified local information * Create a Dialer with the specified local information
* NOTE: This fills in the fallback_dialer too
* @param peer_id the local PeerID
* @param private_key the local private key
* @returns a new Dialer struct
*/ */
struct Dialer* libp2p_conn_dialer_new(char* peer_id, struct PrivateKey* private_key); struct Dialer* libp2p_conn_dialer_new(char* peer_id, struct PrivateKey* private_key);
/** /**
* free resources from the Dialer * free resources from the Dialer struct
* @param in the Dialer struct to relieve of their resources
*/ */
void libp2p_conn_dialer_free(struct Dialer* in); void libp2p_conn_dialer_free(struct Dialer* in);
@ -43,4 +53,14 @@ void libp2p_conn_dialer_free(struct Dialer* in);
* @param muiltiaddress who to connect to * @param muiltiaddress who to connect to
* @returns a Connection, or NULL * @returns a Connection, or NULL
*/ */
struct Connection* libp2p_conn_dialer_get_connection(struct Dialer* dialer, struct MultiAddress* multiaddress); struct Connection* libp2p_conn_dialer_get_connection(const struct Dialer* dialer, const struct MultiAddress* multiaddress);
/**
* return a Stream that is already set up to use the passed in protocol
* @param dialer the dialer to use
* @param multiaddress the host to dial
* @param protocol the protocol to use (right now only 'multistream' is supported)
* @returns the ready-to-use stream
*/
struct Stream* libp2p_conn_dialer_get_stream(const struct Dialer* dialer, const struct MultiAddress* multiaddress, const char* protocol);

View file

@ -6,11 +6,11 @@
struct TransportDialer { struct TransportDialer {
char* peer_id; char* peer_id;
struct PrivateKey* private_key; struct PrivateKey* private_key;
int (*can_handle)(struct MultiAddress* multiaddr); int (*can_handle)(const struct MultiAddress* multiaddr);
struct Connection* (*dial)(struct TransportDialer* transport_dialer, struct MultiAddress* multiaddr); struct Connection* (*dial)(const struct TransportDialer* transport_dialer, const struct MultiAddress* multiaddr);
}; };
struct TransportDialer* libp2p_conn_transport_dialer_new(char* peer_id, struct PrivateKey* private_key); struct TransportDialer* libp2p_conn_transport_dialer_new(char* peer_id, struct PrivateKey* private_key);
void libp2p_conn_transport_dialer_free(struct TransportDialer* in); void libp2p_conn_transport_dialer_free(struct TransportDialer* in);
struct Connection* libp2p_conn_transport_dialer_get(struct Libp2pLinkedList* transport_dialers, struct MultiAddress* multiaddr); struct Connection* libp2p_conn_transport_dialer_get(const struct Libp2pLinkedList* transport_dialers, const struct MultiAddress* multiaddr);

View file

@ -0,0 +1,11 @@
#pragma once
/**
* Encrypt a block of text
* @param input the text to encrypt
* @param input_size the length of the array
* @param output where the output will be placed
* @param output_size the length of the memory allocated for output
* @returns true(1) on success, otherwise false(0)
*/
int libp2p_crypto_aes_encrypt(char* input, size_t input_size, unsigned char* output, size_t& output_size);

View file

@ -11,7 +11,7 @@ struct StretchedKey {
size_t iv_size; size_t iv_size;
char* cipher_key; char* cipher_key;
size_t cipher_size; size_t cipher_size;
char* mac_key; unsigned char* mac_key;
size_t mac_size; size_t mac_size;
}; };

View file

@ -14,8 +14,8 @@ enum ConnectionType {
}; };
struct Libp2pPeer { struct Libp2pPeer {
char* id; // protobuf field 1 char* id; // protobuf field 1; the ID (aka peer id) of the peer
size_t id_size; size_t id_size; // the length of id
struct Libp2pLinkedList* addr_head; // protobuf field 2 of multiaddr bytes (repeatable) (stored here as a struct MultiAddr) struct Libp2pLinkedList* addr_head; // protobuf field 2 of multiaddr bytes (repeatable) (stored here as a struct MultiAddr)
enum ConnectionType connection_type; // protobuf field 3 (a varint) enum ConnectionType connection_type; // protobuf field 3 (a varint)
}; };

View file

@ -15,7 +15,7 @@ struct SecureSession {
int port; int port;
enum IPTrafficType traffic_type; enum IPTrafficType traffic_type;
// once the connection is established // once the connection is established
int socket_descriptor; struct Stream* stream;
struct PublicKey remote_key; struct PublicKey remote_key;
char* remote_peer_id; char* remote_peer_id;
// filled in during negotiations // filled in during negotiations
@ -28,6 +28,8 @@ struct SecureSession {
size_t shared_key_size; size_t shared_key_size;
char nonce[16]; char nonce[16];
struct StretchedKey* stretched_key; struct StretchedKey* stretched_key;
unsigned char* mac;
size_t mac_size;
}; };
/*** /***

View file

@ -0,0 +1,13 @@
#pragma once
#include "multiaddr/multiaddr.h"
/**
* This is a hack to get ip4/tcp working
* TODO: this should be moved further down in the networking stack and generified for different multiaddresses
* This makes too many assumptions
* @param address the multiaddress to parse
* @param ip the first IP address in the multiaddress
* @param port the first port in the multiaddress
* @returns true(1) on success, false(0) on failure
*/
int libp2p_utils_multiaddress_parse_ip4_tcp(const struct MultiAddress* address, char** ip, int* port);

View file

@ -128,15 +128,15 @@ struct Stream* libp2p_net_multistream_connect(const char* hostname, int port) {
if (stream == NULL) if (stream == NULL)
goto exit; goto exit;
num_bytes = libp2p_net_multistream_write(stream, (unsigned char*)protocol_buffer, strlen(protocol_buffer));
if (num_bytes <= 0)
goto exit;
// try to receive the protocol id // try to receive the protocol id
return_result = libp2p_net_multistream_read(stream, &results, &results_size); return_result = libp2p_net_multistream_read(stream, &results, &results_size);
if (return_result == 0 || results_size < 1) if (return_result == 0 || results_size < 1)
goto exit; goto exit;
num_bytes = libp2p_net_multistream_write(stream, (unsigned char*)protocol_buffer, strlen(protocol_buffer));
if (num_bytes <= 0)
goto exit;
if (strstr((char*)results, "multistream") == NULL) if (strstr((char*)results, "multistream") == NULL)
goto exit; goto exit;

View file

@ -184,19 +184,27 @@ ssize_t socket_write_size(int s, unsigned long size, int flags) {
*/ */
uint32_t hostname_to_ip(const char* hostname) uint32_t hostname_to_ip(const char* hostname)
{ {
struct hostent *he; struct sockaddr_in sa;
struct in_addr **addr_list; int result = inet_pton(AF_INET, hostname, &(sa.sin_addr));
if (result != 0) {
// an ip address was passed in instead of a hostname
return sa.sin_addr.s_addr;
} else {
// it is probably an actual host name and not just an ip address
struct hostent *he;
struct in_addr **addr_list;
if ( (he = gethostbyname( hostname ) ) == NULL) if ( (he = gethostbyname( hostname ) ) == NULL)
{ {
// get the host info // get the host info
herror("gethostbyname"); herror("gethostbyname");
return 1; return 1;
} }
addr_list = (struct in_addr **) he->h_addr_list; addr_list = (struct in_addr **) he->h_addr_list;
if ((*addr_list) == NULL) if ((*addr_list) == NULL)
return 0; return 0;
return addr_list[0]->s_addr; return addr_list[0]->s_addr;
}
} }

View file

@ -71,7 +71,7 @@ int libp2p_secio_exchange_protobuf_decode(unsigned char* buffer, size_t buffer_l
size_t pos = 0; size_t pos = 0;
int retVal = 0; int retVal = 0;
if (libp2p_secio_exchange_new(out) == 0) if ( (*out = libp2p_secio_exchange_new()) == NULL)
goto exit; goto exit;
while(pos < buffer_length) { while(pos < buffer_length) {

View file

@ -78,11 +78,11 @@ int libp2p_secio_propose_protobuf_encode(struct Propose* in, unsigned char* buff
return 0; return 0;
*bytes_written += bytes_used; *bytes_written += bytes_used;
// exchanges // exchanges
if (!protobuf_encode_length_delimited(4, secio_propose_message_fields[3], in->exchanges, in->exchanges_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used)) if (!protobuf_encode_length_delimited(3, secio_propose_message_fields[2], in->exchanges, in->exchanges_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used))
return 0; return 0;
*bytes_written += bytes_used; *bytes_written += bytes_used;
// ciphers // ciphers
if (!protobuf_encode_length_delimited(3, secio_propose_message_fields[2], in->ciphers, in->ciphers_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used)) if (!protobuf_encode_length_delimited(4, secio_propose_message_fields[3], in->ciphers, in->ciphers_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used))
return 0; return 0;
*bytes_written += bytes_used; *bytes_written += bytes_used;
// hashes // hashes
@ -131,11 +131,11 @@ int libp2p_secio_propose_protobuf_decode(unsigned char* buffer, size_t buffer_le
got_something = 1; got_something = 1;
break; break;
case (3): // exchanges case (3): // exchanges
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->exchanges), &((*out)->exchanges_size), &bytes_read) == 0) if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->exchanges), &((*out)->exchanges_size), &bytes_read) == 0)
goto exit; goto exit;
pos += bytes_read; pos += bytes_read;
got_something = 1; got_something = 1;
break; break;
case (4): // ciphers case (4): // ciphers
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->ciphers), &((*out)->ciphers_size), &bytes_read) == 0) if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->ciphers), &((*out)->ciphers_size), &bytes_read) == 0)
goto exit; goto exit;

View file

@ -29,7 +29,7 @@ struct SecureSession* libp2p_secio_secure_session_new() {
struct SecureSession* ss = (struct SecureSession*) malloc(sizeof(struct SecureSession)); struct SecureSession* ss = (struct SecureSession*) malloc(sizeof(struct SecureSession));
if (ss == NULL) if (ss == NULL)
return NULL; return NULL;
ss->socket_descriptor = -1; ss->stream = NULL;
return ss; return ss;
} }
@ -291,8 +291,10 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s
if (num_needed > hash_size) if (num_needed > hash_size)
num_needed = hash_size; num_needed = hash_size;
// combine current_hash with first_seed // combine current_hash with first_seed
if (temp != NULL) if (temp != NULL) {
free(temp); free(temp);
temp = NULL;
}
seed_size = secret_size + strlen(first_seed) + hash_size; seed_size = secret_size + strlen(first_seed) + hash_size;
temp = malloc(seed_size); temp = malloc(seed_size);
memcpy(temp, secret, secret_size); memcpy(temp, secret, secret_size);
@ -305,6 +307,7 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s
num_filled += num_needed; num_filled += num_needed;
// redo the hashes by adding the secret to the current hash // redo the hashes by adding the secret to the current hash
free(temp); free(temp);
temp = NULL;
seed_size = secret_size + hash_size; seed_size = secret_size + hash_size;
temp = malloc(seed_size); temp = malloc(seed_size);
memcpy(temp, secret, secret_size); memcpy(temp, secret, secret_size);
@ -336,6 +339,8 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s
memcpy(k2->mac_key, temp, k2->mac_size); memcpy(k2->mac_key, temp, k2->mac_size);
temp += k2->mac_size; temp += k2->mac_size;
temp = NULL;
retVal = 1; retVal = 1;
// cleanup // cleanup
@ -362,8 +367,35 @@ int libp2p_secio_stretch_keys(char* cipherType, char* hashType, unsigned char* s
} }
int libp2p_secio_make_mac_and_cipher(struct SecureSession* session) { int libp2p_secio_make_mac_and_cipher(struct SecureSession* session) {
// TODO: Implement this method // mac
return 0; int (*mac_func)(const char*, size_t, unsigned char*);
if (strcmp(session->chosen_hash, "SHA1") == 0) {
session->stretched_key->mac_size = 40;
mac_func = libp2p_crypto_hashing_sha1;
} else if (strcmp(session->chosen_hash, "SHA512") == 0) {
session->stretched_key->mac_size = 32;
mac_func = libp2p_crypto_hashing_sha512;
} else if (strcmp(session->chosen_hash, "SHA256") == 0) {
session->stretched_key->mac_size = 16;
mac_func = libp2p_crypto_hashing_sha256;
} else {
return 0;
}
session->stretched_key->mac_key = malloc(session->stretched_key->mac_size);
mac_func(session->stretched_key->cipher_key, session->stretched_key->cipher_size, session->stretched_key->mac_key);
// block cipher
if (strcmp(session->chosen_cipher, "AES-128") == 0) {
} else if (strcmp(session->chosen_cipher, "AES-256") == 0) {
} else if (strcmp(session->chosen_cipher, "Blowfish") == 0) {
} else {
return 0;
}
return 1;
} }
int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size_t data_length) { int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size_t data_length) {
@ -377,7 +409,7 @@ int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size
int written = 0; int written = 0;
int written_this_time = 0; int written_this_time = 0;
do { do {
written_this_time = socket_write(session->socket_descriptor, &size_as_char[written], left, 0); written_this_time = socket_write(*((int*)session->stream->socket_descriptor), &size_as_char[written], left, 0);
if (written_this_time < 0) { if (written_this_time < 0) {
written_this_time = 0; written_this_time = 0;
if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) {
@ -393,7 +425,7 @@ int libp2p_secio_write(struct SecureSession* session, unsigned char* bytes, size
left = data_length; left = data_length;
written = 0; written = 0;
do { do {
written_this_time = socket_write(session->socket_descriptor, (char*)&bytes[written], left, 0); written_this_time = socket_write(*((int*)session->stream->socket_descriptor), (char*)&bytes[written], left, 0);
if (written_this_time < 0) { if (written_this_time < 0) {
written_this_time = 0; written_this_time = 0;
if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) {
@ -420,7 +452,7 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si
int read = 0; int read = 0;
int read_this_time = 0; int read_this_time = 0;
do { do {
read_this_time = socket_read(session->socket_descriptor, &size[read], 1, 0); read_this_time = socket_read(*((int*)session->stream->socket_descriptor), &size[read], 1, 0);
if (read_this_time < 0) { if (read_this_time < 0) {
read_this_time = 0; read_this_time = 0;
if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) {
@ -449,7 +481,7 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si
*results = malloc(left); *results = malloc(left);
unsigned char* ptr = *results; unsigned char* ptr = *results;
do { do {
read_this_time = socket_read(session->socket_descriptor, (char*)&ptr[read], left, 0); read_this_time = socket_read(*((int*)session->stream->socket_descriptor), (char*)&ptr[read], left, 0);
if (read_this_time < 0) { if (read_this_time < 0) {
read_this_time = 0; read_this_time = 0;
if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) {
@ -474,9 +506,6 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si
* @returns true(1) on success, false(0) otherwise * @returns true(1) on success, false(0) otherwise
*/ */
int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivateKey* private_key) { int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivateKey* private_key) {
// this needs to be redone
return 0;
/*
int retVal = 0; int retVal = 0;
size_t results_size = 0, bytes_written = 0; size_t results_size = 0, bytes_written = 0;
unsigned char* propose_in_bytes = NULL; // the remote protobuf unsigned char* propose_in_bytes = NULL; // the remote protobuf
@ -504,6 +533,27 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
//TODO: make sure we're not talking to ourself //TODO: make sure we're not talking to ourself
// prepare the multistream send of the protocol ID
const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n";
int protocol_len = strlen((char*)protocol);
unsigned char* total = malloc(protocol_len + propose_out_size);
memcpy(total, protocol, protocol_len);
memcpy(&total[protocol_len], propose_out_bytes, propose_out_size);
bytes_written = libp2p_net_multistream_write(local_session->stream, total, protocol_len + propose_out_size);
free(total);
if (bytes_written <= 0)
goto exit;
// we should get back the secio confirmation
bytes_written = libp2p_net_multistream_read(local_session->stream, &results, &results_size);
if (bytes_written < 5 || strstr((char*)results, "secio") == NULL)
goto exit;
free(results);
results = NULL;
results_size = 0;
// generate 16 byte nonce // generate 16 byte nonce
if (!libp2p_secio_generate_nonce(&local_session->nonce[0], 16)) { if (!libp2p_secio_generate_nonce(&local_session->nonce[0], 16)) {
goto exit; goto exit;
@ -549,30 +599,11 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
if (libp2p_secio_propose_protobuf_encode(propose_out, propose_out_bytes, propose_out_size, &propose_out_size) == 0) if (libp2p_secio_propose_protobuf_encode(propose_out, propose_out_bytes, propose_out_size, &propose_out_size) == 0)
goto exit; goto exit;
// prepare the multistream send
const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n";
int protocol_len = strlen((char*)protocol);
unsigned char* total = malloc(protocol_len + propose_out_size);
memcpy(total, protocol, protocol_len);
memcpy(&total[protocol_len], propose_out_bytes, propose_out_size);
bytes_written = libp2p_net_multistream_write(local_session->socket_descriptor, total, protocol_len + propose_out_size); bytes_written = libp2p_secio_write(local_session, propose_out_bytes, propose_out_size);
free(total); if (bytes_written < propose_out_size)
if (bytes_written <= 0)
goto exit; goto exit;
//bytes_written = libp2p_secio_write(local_session, propose_out_bytes, propose_out_size);
//if (bytes_written < propose_out_size)
// goto exit;
// we should get back the secio confirmation
bytes_written = libp2p_net_multistream_receive(local_session->socket_descriptor, (char**)&results, &results_size);
if (bytes_written < 5 || strstr((char*)results, "secio") == NULL)
goto exit;
free(results);
results = NULL;
results_size = 0;
// now receive the proposal from the new connection // now receive the proposal from the new connection
bytes_written = libp2p_secio_read(local_session, &propose_in_bytes, &propose_in_size); bytes_written = libp2p_secio_read(local_session, &propose_in_bytes, &propose_in_size);
if (bytes_written <= 0) if (bytes_written <= 0)
@ -587,6 +618,11 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
// generate their peer id // generate their peer id
libp2p_crypto_public_key_to_peer_id(public_key, &remote_peer_id); libp2p_crypto_public_key_to_peer_id(public_key, &remote_peer_id);
// receive Exchange packet
bytes_written = libp2p_secio_read(local_session, &results, &results_size);
if (bytes_written == 0)
goto exit;
libp2p_secio_exchange_protobuf_decode(results, results_size, &exchange_in);
// negotiate encryption parameters NOTE: SelectBest must match, otherwise this won't work // negotiate encryption parameters NOTE: SelectBest must match, otherwise this won't work
// first determine order // first determine order
@ -653,12 +689,6 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
free(exchange_out_protobuf); free(exchange_out_protobuf);
exchange_out_protobuf = NULL; exchange_out_protobuf = NULL;
// receive Exchange packet
bytes_written = libp2p_secio_read(local_session, &results, &results_size);
if (bytes_written == 0)
goto exit;
libp2p_secio_exchange_protobuf_decode(results, results_size, &exchange_in);
// parse and verify // parse and verify
remote_session.ephemeral_public_key = exchange_in->epubkey; remote_session.ephemeral_public_key = exchange_in->epubkey;
remote_session.ephemeral_public_key_size = exchange_in->epubkey_size; remote_session.ephemeral_public_key_size = exchange_in->epubkey_size;
@ -669,8 +699,9 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
libp2p_utils_vector_add(char_buffer, propose_in_bytes, propose_in_size); libp2p_utils_vector_add(char_buffer, propose_in_bytes, propose_in_size);
libp2p_utils_vector_add(char_buffer, propose_out_bytes, propose_out_size); libp2p_utils_vector_add(char_buffer, propose_out_bytes, propose_out_size);
libp2p_utils_vector_add(char_buffer, remote_session.ephemeral_public_key, remote_session.ephemeral_public_key_size); libp2p_utils_vector_add(char_buffer, remote_session.ephemeral_public_key, remote_session.ephemeral_public_key_size);
if (!libp2p_secio_verify_signature(public_key, char_buffer->buffer, char_buffer->buffer_size, exchange_in->signature)) // TODO: signature verification
goto exit; //if (!libp2p_secio_verify_signature(public_key, char_buffer->buffer, char_buffer->buffer_size, exchange_in->signature))
// goto exit;
libp2p_utils_vector_free(char_buffer); libp2p_utils_vector_free(char_buffer);
char_buffer = NULL; char_buffer = NULL;
@ -727,5 +758,4 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat
libp2p_secio_propose_free(propose_in); libp2p_secio_propose_free(propose_in);
return retVal; return retVal;
*/
} }

View file

@ -1,6 +1,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "libp2p/conn/dialer.h" #include "libp2p/conn/dialer.h"
#include "libp2p/net/stream.h"
#include "test_helper.h" #include "test_helper.h"
int test_dialer_new() { int test_dialer_new() {
@ -42,15 +43,6 @@ int test_dialer_dial() {
if (conn == NULL) if (conn == NULL)
goto exit; goto exit;
if (conn->write(conn, "ping", 4) == 0)
goto exit;
if (conn->read(conn, &result, &result_size) == 0)
goto exit;
if (result_size < 4 || strncmp(result, "pong", 4) != 0)
goto exit;
// clean up resources // clean up resources
retVal = 1; retVal = 1;
exit: exit:
@ -63,3 +55,47 @@ int test_dialer_dial() {
libp2p_conn_connection_free(conn); libp2p_conn_connection_free(conn);
return retVal; return retVal;
} }
int test_dialer_dial_multistream() {
int retVal = 0;
char* config_dir = "/home/parallels/.ipfs/config";
char* destination_string = "/ip4/192.210.179.217/tcp/4001/";
char* peer_id = NULL;
struct PrivateKey* private_key = NULL;
struct Dialer* dialer = NULL;
struct MultiAddress* destination_address = NULL;
struct Stream* stream = NULL;
char* result = NULL;
size_t result_size = 0;
test_helper_get_id_from_config(config_dir, &private_key, &peer_id);
if (private_key == NULL)
goto exit;
dialer = libp2p_conn_dialer_new(peer_id, private_key);
if (dialer == NULL)
goto exit;
destination_address = multiaddress_new_from_string(destination_string);
if (destination_address == NULL)
goto exit;
// now try to dial
stream = libp2p_conn_dialer_get_stream(dialer, destination_address, "multistream");
if (stream == NULL)
goto exit;
// now ping
// clean up resources
retVal = 1;
exit:
if (result != NULL)
free(result);
free(peer_id);
multiaddress_free(destination_address);
libp2p_conn_dialer_free(dialer);
libp2p_crypto_private_key_free(private_key);
stream->close(stream);
return retVal;
}

View file

@ -23,12 +23,13 @@ int test_multistream_connect() {
} }
int test_multistream_get_list() { int test_multistream_get_list() {
int retVal = 0, socket_fd = -1; int retVal = 0;
unsigned char* response; unsigned char* response;
size_t response_size; size_t response_size;
char* filtered = NULL;
struct Stream* stream = libp2p_net_multistream_connect("www.jmjatlanta.com", 4001); struct Stream* stream = libp2p_net_multistream_connect("www.jmjatlanta.com", 4001);
if (socket_fd < 0) if (*((int*)stream->socket_descriptor) < 0)
goto exit; goto exit;
// try to respond something, ls command // try to respond something, ls command
@ -42,7 +43,12 @@ int test_multistream_get_list() {
if (retVal <= 0) if (retVal <= 0)
goto exit; goto exit;
fprintf(stdout, "Response from multistream ls: %s", (char*)response); filtered = malloc(response_size + 1);
strncpy(filtered, response, response_size);
filtered[response_size] = 0;
fprintf(stdout, "Response from multistream ls: %s", (char*)filtered);
free(filtered);
retVal = 1; retVal = 1;

View file

@ -5,16 +5,13 @@
#include "libp2p/net/p2pnet.h" #include "libp2p/net/p2pnet.h"
int test_secio_handshake() { int test_secio_handshake() {
return 0;
/*
* this needs to be redone
int retVal = 0; int retVal = 0;
size_t decode_base64_size = 0; size_t decode_base64_size = 0;
unsigned char* decode_base64 = NULL; unsigned char* decode_base64 = NULL;
// this is a base64 encoded private key. It makes it easier to test if it is in base64 form // this is a base64 encoded private key. It makes it easier to test if it is in base64 form
// these were pulled from the GO version of ipfs // these were pulled from the GO version of ipfs
char* orig_priv_key = "CAASpwkwggSjAgEAAoIBAQCwfp3DpbTP/nD1R+1PcP7nDOV9MEDiLUoNf9cBVhWGefJT0ES81do1COwLXiD/k7gAHJu197F7AfFYKt+NQu6jpCDC/uRtK0M0MpeDGI0LV1oz0rKLTN79zQwKDHFimWCmNyOZRLfR3PF5TgLc0qiFOZw9WwYNJkohu6k6yVMDJiy3l/+K5Vdw9VVyz7mRulXdDvEMxccraKaTvjLAUNFjiqm5Zs3hrcZszuuP2RhcpZU40kuWDtyN9TAEge0NfhS5Fj7GtgQsHWJ4RxTdebHkQmX49ltI/nIw9TxGIVcA50g7eF/3a3zZtkh48JadbHiT2Mfr6SPXl0328gyg7v7tAgMBAAECggEABGlFvCwaFtC/NgI0NjYWyOOToMth88U6AphdYVUreI73tYyRCz81EvpEHAygOoMQqEAOzD+CmhZ0V8XKjJdNq51gjD8eqnPYXCefjdFBRTVLtdvgRocHU8SaNm4VL2ex+LWMGDqVdZNWHbgLbkV9nMbR1t69ifqZA7rTAfsiLgPtneu4kGjrO1nr+uFC0srch2o0stmiqxmcGOrkD9x2kXkw33O8wTSyBp3+STlTOehePuUqEho9BXdT7b2nXC8MNdTCekG9f3oUeKsK9pxH7ZlG3yUOBoM0mEm/N7BrPfJnQbogomUapWOpssWKSz0LCpKuy4El3mFpua0jmd3nAQKBgQDWvVHj44gSecjsrWH/QpMIn8W/ISXfJRxJKrdVBRC5Ey0h3wdLnF6Olz4kuD7KurPOWNR+IKaLzOWxZdX79aQn+oY8lB+UCM+0w1TWJeSWBUYATPtUU4xpKdD6YZ8ksOdgZ4hbn9VD49uu/SJUPVNGV+eHibnvdR+/sFJuHTAb4QKBgQDSaBd1V7z5R6NK8373QNMDHZnSa2qH8uAGvoSuajYGgcpAzDY3aueQFpQS66scrZK6zLQyOQgtyrIg/hKbeP+vV5LGBirzOtAH7Kko5BYeY/SCXOkHBsHhuPGyghqWl6KR2Vj8cjJZFCAiUvoqf3Ws0vW58kp/KgDCnlKGmgQkjQKBgDPYi7/4vG6xhqhWCDYIDdXkNWs7BpjErfqgXJkjWvFERv5Jicpgm5fTvkZBUa/CugzU96DoIy3Xr5FQJATsPtEENIrFvIYSRou/KWl2xqTN6yPBcmDetyTg2rrI/RJvv71P4eU1RtlYVz79kN9D2yo9qQHZZ9H/tkWivZQmaeohAoGAIafa0L9HEAzAdvW6AmzRE/eBKmJaOQLFiO6ipI+CssnCA1lm9rhX7/lcmCYwSbcN+GlUDZCH2WNJ2PMrIMlbBL4aUSidaCipLAtUB6FsVFIiw1N/Rsty6ds+dhJPlHUO4QuGK2NM4GjStwrUz0VyGkHoYmT6O5sJYhgXFUa/kOUCgYEAv1VGeX6EPsFgp+FKM1Q/8MYi7PPpSUI2fqMhnwe36u7UdNYa3Ismmo/ipfCw7DdX5qRcUh44PodTp4Zwp67Bd2KRzEAZmMvIurzclQB7VWUT7pB7yfbO9bjBUVbPTagjiqb30zq9A4kt+B/0MSPxa/Kh8EkgI02Jqh2Q97Ij4sc="; char* orig_priv_key = "CAASpwkwggSjAgEAAoIBAQCo+BYd213u8PNHNcnXZ6TcUc7oXEoCtWL12XJEFqAiC7emadkp+WtujmuR993L6uCRPU/+mNXIvetodMQ5GORq0MxsPlKFNuVuqHS4PCdWYYFKeel4QsG17T3XMo72Kxm7/pQ1Dbs6tzWD4Ie4Zsa7ziyffjeak1/EExkFf0AKtj4UdXErNRI5gZhkDnWp6Si117Z2VVTslE+kKXWpLK0RYZ4w8DhhZa+ykt2tleOOJt8ocJ3s3yVZQxOafL1lwA8f10VEEeJLPGKJ1Y7mmW7OJhLmrq9tvdTLhum1H5kdYu/pheCm5b6/NSGKS+XbQztu5zedsKSPHsOlYhxYu3GJAgMBAAECggEAZIz93Fam14Jbw4ymyKDM4q9sSapiAKqgcV0tOoecU6ZVa5qhuPDMlcX7DapLOwZTDRtHd2LMFeGvLUIPY0sE4uvOOrv7r3qznd5xVxG09xqfLgrOfNp9HB5KJr3XhXawocclu0yolpBgMFJ1ca73pNtUgrVBsaLx4mTbBwJqwfQpQb/Xdkrdgc663bwXkSl4vApwhZGzi5CFJ6SFC6l6fMKoteWM1ay5e2VCfxi/1g41EINkrqm+QPWhy11bo21ScozxiFiywcxQ8Huo+I5GDHI5EUfIHP97NSRG24/IDSebxsGTukMdpLmiiwizV7hHP2eDlikHAhxBBAF2GkbkAQKBgQDg69jPHrETvHGlKjlEDE8sYQUrwpmGLHfsfZYqBxcz65jPYFAypG4icIU6f8Uhz9c42jLEBssNPT8LyLl2uY467hZZA2SkeWKS66Vi5wBGTN5qOBWUejhzTx8UzasYroWl/0RqFZhU9Xhwg4YqT9X8jYw5mXyOMLatp/d/Y96p0QKBgQDAUQodQZc9yc7olsmNvbuHZtBA+VndKCokFOuJ6YLRK69AL7y6n6eUjne6JqcEIKDC7vr33ryuOdFI+zNzMsdYykE8xcg2c5itWRqG7EdMxgR1dYLUqGC5ustRM/mmhmRzW8DXy88sS+vM4U84yPKv/rfeKAoYgE722R0kkpQCOQKBgQCKfm63yiw6/NP1YXR1hCbUKsFmWqLxzTvisMngAxG0dKNZPfLj2/+80RAYH0ihMztQ1Hph3dT1x/qkJOqeQk9j1eqI0OANrniWAueJaLfwkbB6MyKGlGNiDRwUUTfDMOM2fWIA+F8eITASB8p7D0GyCu6HIQ1i+HfjogNxu2sFoQKBgE4ZGthiqH6JE6NUiKks4ZjM4clg+WNcSjC45iXtVBiJevO/7w6Cg1VKvcg0piKA9Yfz8Kr0Iv9Fr33JtU0U0+t0xyVc1D94lgnfY2xjS1kcGPdyLx0Y+56xApwJVVqQvP4zxo5bz9gXRLzAyqEuyY87C4QGEoN8p5SK+tC9TanRAoGAbC+uVaBtqRqv3LY16+H58BW8lVfN+8dqtBOWluM2uImB1qL2EbKk0X/OChz3Dgzef5VTox6nHcMyYPwXLirS9aIYPggjdpDTjfbWPxUcwYmIB1U++F/mRk1IeDgl9g7t/OlPMg4snxQGEzMPPDVrj/KeLEKv5x+T5yFZ/y+8xNo=";
char* orig_peer_id = "QmYm3WdMQqqQuEyCWmRVNEjtXjhGhyRRNshdvqV7YLGvpA"; char* orig_peer_id = "QmZigcoDKaAafGSwot2tchJarCafxKapoRmnYTrZ69ckjb";
size_t orig_peer_id_size = strlen(orig_peer_id); size_t orig_peer_id_size = strlen(orig_peer_id);
struct RsaPrivateKey* rsa_private_key = NULL; struct RsaPrivateKey* rsa_private_key = NULL;
unsigned char hashed[32] = {0}; unsigned char hashed[32] = {0};
@ -45,12 +42,12 @@ int test_secio_handshake() {
if (!libp2p_crypto_rsa_private_key_fill_public_key(rsa_private_key)) if (!libp2p_crypto_rsa_private_key_fill_public_key(rsa_private_key))
goto exit; goto exit;
secure_session.host = "192.210.179.217"; secure_session.host = "www.jmjatlanta.com";
secure_session.port = 4001; secure_session.port = 4001;
secure_session.traffic_type = TCP; secure_session.traffic_type = TCP;
// connect to host // connect to host
secure_session.socket_descriptor = libp2p_net_multistream_connect(secure_session.host, secure_session.port); secure_session.stream = libp2p_net_multistream_connect(secure_session.host, secure_session.port);
if (secure_session.socket_descriptor == -1) { if (*((int*)secure_session.stream->socket_descriptor) == -1) {
fprintf(stderr, "test_secio_handshake: Unable to get socket descriptor\n"); fprintf(stderr, "test_secio_handshake: Unable to get socket descriptor\n");
goto exit; goto exit;
} }
@ -77,5 +74,4 @@ int test_secio_handshake() {
if (rsa_private_key != NULL) if (rsa_private_key != NULL)
libp2p_crypto_rsa_rsa_private_key_free(rsa_private_key); libp2p_crypto_rsa_rsa_private_key_free(rsa_private_key);
return retVal; return retVal;
*/
} }

View file

@ -40,6 +40,7 @@ const char* names[] = {
"test_ephemeral_key_generate", "test_ephemeral_key_generate",
"test_dialer_new", "test_dialer_new",
"test_dialer_dial", "test_dialer_dial",
"test_dialer_dial_multistream",
"test_record_protobuf", "test_record_protobuf",
"test_record_make_put_record", "test_record_make_put_record",
"test_record_peer_protobuf", "test_record_peer_protobuf",
@ -76,6 +77,7 @@ int (*funcs[])(void) = {
test_ephemeral_key_generate, test_ephemeral_key_generate,
test_dialer_new, test_dialer_new,
test_dialer_dial, test_dialer_dial,
test_dialer_dial_multistream,
test_record_protobuf, test_record_protobuf,
test_record_make_put_record, test_record_make_put_record,
test_record_peer_protobuf, test_record_peer_protobuf,

View file

@ -1,5 +1,5 @@
CC = gcc CC = gcc
CFLAGS = -O0 -Wall -I../include CFLAGS = -O0 -Wall -I../include -I../../c-multiaddr/include
ifdef DEBUG ifdef DEBUG
CFLAGS += -g3 CFLAGS += -g3
@ -7,7 +7,7 @@ endif
LFLAGS = LFLAGS =
DEPS = DEPS =
OBJS = string_list.o vector.o linked_list.o OBJS = string_list.o vector.o linked_list.o multiaddress.o
%.o: %.c $(DEPS) %.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS) $(CC) -c -o $@ $< $(CFLAGS)

38
utils/multiaddress.c Normal file
View file

@ -0,0 +1,38 @@
#include <stdlib.h>
/**
* A central repository for parsing Multiaddress structs
*/
#include "libp2p/utils/multiaddress.h"
/**
* This is a hack to get ip4/tcp working
* TODO: this should be moved further down in the networking stack and generified for different multiaddresses
* This makes too many assumptions
* @param address the multiaddress to parse
* @param ip the first IP address in the multiaddress
* @param port the first port in the multiaddress
* @returns true(1) on success, false(0) on failure
*/
int libp2p_utils_multiaddress_parse_ip4_tcp(const struct MultiAddress* address, char** ip, int* port) {
// the incoming address is not what was expected
if (strncmp(address->string, "/ip4/", 5) != 0)
return 0;
if (strstr(address->string, "/tcp/") == NULL)
return 0;
// ip
char* str = malloc(strlen(address->string));
if (str == NULL)
return 0;
strcpy(str, &address->string[5]); // gets rid of /ip4/
char* pos = strchr(str, '/');
pos[0] = 0;
*ip = malloc(strlen(str) + 1);
strcpy(*ip, str);
free(str);
// port
str = strstr(address->string, "/tcp/");
str += 5;
*port = atoi(str);
return 1;
}