diff --git a/crypto/rsa.c b/crypto/rsa.c index 1f3fb67..c8ef695 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -1,6 +1,7 @@ #include #include +#include "libp2p/crypto/key.h" #include "libp2p/crypto/rsa.h" #include "libp2p/crypto/sha256.h" @@ -16,6 +17,21 @@ #include "mbedtls/oid.h" #include "mbedtls/pk.h" +struct PrivateKey* libp2p_crypto_rsa_to_private_key(struct RsaPrivateKey* in) { + struct PrivateKey* out = libp2p_crypto_private_key_new(); + if (out != NULL) { + out->data = (unsigned char*)malloc(in->der_length); + if (out->data == NULL) { + libp2p_crypto_private_key_free(out); + return NULL; + } + memcpy(out->data, in->der, in->der_length); + out->data_size = in->der_length; + out->type = KEYTYPE_RSA; + } + return out; +} + /** * Take an rsa context and turn it into a der formatted byte stream. * NOTE: the stream starts from the right. So there could be a lot of padding in front. diff --git a/include/libp2p/crypto/rsa.h b/include/libp2p/crypto/rsa.h index 2012897..f2074c7 100644 --- a/include/libp2p/crypto/rsa.h +++ b/include/libp2p/crypto/rsa.h @@ -27,6 +27,13 @@ struct RsaPrivateKey { size_t public_key_length; }; +/** + * Convert a struct RsaPrivateKey to a struct PrivateKey + * @param in the RsaPrivateKey + * @returns a struct PrivateKey + */ +struct PrivateKey* libp2p_crypto_rsa_to_private_key(struct RsaPrivateKey* in); + /** * generate a new private key * @param private_key the new private key diff --git a/include/libp2p/net/multistream.h b/include/libp2p/net/multistream.h index 2c03bae..50582d6 100644 --- a/include/libp2p/net/multistream.h +++ b/include/libp2p/net/multistream.h @@ -28,3 +28,27 @@ int libp2p_net_multistream_receive(int socket_fd, char** results, size_t* result * @returns the socket file descriptor of the connection, or -1 on error */ int libp2p_net_multistream_connect(const char* hostname, int port); + +/** + * Negotiate the multistream protocol by sending and receiving the protocol id. This is a server side function. + * Servers should send the protocol ID, and then expect it back. + * @param fd the socket file descriptor + * @returns true(1) if the negotiation was successful. + */ +int libp2p_net_multistream_negotiate(int fd); + +/** + * Expect to read a message, and follow its instructions + * @param fd the socket file descriptor + * @returns true(1) on success, false(0) if not + */ +int libp2p_net_multistream_handle_message(int fd); + +/** + * Connect to a multistream host, and this includes the multistream handshaking. + * @param hostname the host + * @param port the port + * @returns the socket file descriptor of the connection, or -1 on error + */ +int libp2p_net_multistream_connect(const char* hostname, int port); + diff --git a/include/libp2p/record/message.h b/include/libp2p/record/message.h index 03ac58f..29cf99b 100644 --- a/include/libp2p/record/message.h +++ b/include/libp2p/record/message.h @@ -64,3 +64,4 @@ int libp2p_message_protobuf_encode(struct Libp2pMessage* in, unsigned char* buff * @returns true(1) on success, otherwise false(0) */ int libp2p_message_protobuf_decode(unsigned char* buffer, size_t buffer_size, struct Libp2pMessage** out); + diff --git a/net/multistream.c b/net/multistream.c index a9f2e24..68b524a 100644 --- a/net/multistream.c +++ b/net/multistream.c @@ -2,8 +2,10 @@ #include #include #include - +#include +#include #include "libp2p/net/p2pnet.h" +#include "libp2p/record/message.h" #include "varint.h" /*** @@ -135,3 +137,67 @@ int libp2p_net_multistream_connect(const char* hostname, int port) { return retVal; } +int libp2p_net_multistream_negotiate(int fd) { + const char* protocolID = "/multistream/1.0.0\n"; + char* results; + size_t results_length = 0; + // send the protocol id + if (!libp2p_net_multistream_send(fd, (unsigned char*)protocolID, strlen(protocolID))) + return 0; + // expect the same back + libp2p_net_multistream_receive(fd, &results, &results_length); + if (results_length == 0) + return 0; + if (strncmp(results, protocolID, strlen(protocolID)) != 0) + return 0; + return 1; +} + +/** + * The remote client requested a ping + * @param fd the socket file descriptor + * @param msg the incoming ping message + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_net_multistream_handle_ping(int fd, struct Libp2pMessage* msg) { + // protobuf the message + size_t protobuf_size = libp2p_message_protobuf_encode_size(msg); + unsigned char protobuf[protobuf_size]; + libp2p_message_protobuf_encode(msg, &protobuf[0], protobuf_size, &protobuf_size); + libp2p_net_multistream_send(fd, protobuf, protobuf_size); + return 1; +} + +/** + * Expect to read a message, and follow its instructions + * @param fd the socket file descriptor + * @returns true(1) on success, false(0) if not + */ +int libp2p_net_multistream_handle_message(int fd) { + int retVal = 0; + unsigned char* results = NULL; + size_t results_size = 0; + struct Libp2pMessage* msg = NULL; + // read what they sent + libp2p_net_multistream_receive(fd, (char**)&results, &results_size); + // unprotobuf it + if (!libp2p_message_protobuf_decode(results, results_size, &msg)) + goto exit; + // do what they ask + switch (msg->message_type) { + case (MESSAGE_TYPE_PING): + libp2p_net_multistream_handle_ping(fd, msg); + break; + default: + break; + } + // clean up + retVal = 1; + exit: + if (results != NULL) + free(results); + if (msg != NULL) + libp2p_message_free(msg); + + return retVal; +} diff --git a/peer/peer.c b/peer/peer.c index 78c0df0..7fda1a8 100644 --- a/peer/peer.c +++ b/peer/peer.c @@ -71,15 +71,18 @@ struct Libp2pPeer* libp2p_peer_copy(struct Libp2pPeer* in) { } size_t libp2p_peer_protobuf_encode_size(struct Libp2pPeer* in) { - // id + connection_type - int sz = 11 + in->id_size + 11; - // loop through the multiaddresses - struct Libp2pLinkedList* current = in->addr_head; - while (current != NULL) { - // find the length of the MultiAddress converted into bytes - struct MultiAddress* data = (struct MultiAddress*)current->item; - sz += 11 + data->bsize; - current = current->next; + int sz = 0; + if (in != NULL) { + // id + connection_type + sz = 11 + in->id_size + 11; + // loop through the multiaddresses + struct Libp2pLinkedList* current = in->addr_head; + while (current != NULL) { + // find the length of the MultiAddress converted into bytes + struct MultiAddress* data = (struct MultiAddress*)current->item; + sz += 11 + data->bsize; + current = current->next; + } } return sz; } diff --git a/record/message.c b/record/message.c index ff754e6..8276675 100644 --- a/record/message.c +++ b/record/message.c @@ -82,25 +82,34 @@ int libp2p_message_protobuf_encode(struct Libp2pMessage* in, unsigned char* buff size_t bytes_used = 0; *bytes_written = 0; int retVal = 0; + size_t protobuf_size = 0; + unsigned char* protobuf = NULL; // field 1 retVal = protobuf_encode_varint(1, WIRETYPE_VARINT, in->message_type, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used); if (retVal == 0) return 0; *bytes_written += bytes_used; // field 2 - retVal = protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, in->key, in->key_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used); - if (retVal == 0) - return 0; - *bytes_written += bytes_used; + if (in->key != NULL) { + retVal = protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, in->key, in->key_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used); + if (retVal == 0) + return 0; + *bytes_written += bytes_used; + } // field 3 - size_t protobuf_size = libp2p_record_protobuf_encode_size(in->record); - unsigned char protobuf[protobuf_size]; - if (!libp2p_record_protobuf_encode(in->record, protobuf, protobuf_size, &protobuf_size)) - return 0; - retVal = protobuf_encode_length_delimited(3, WIRETYPE_LENGTH_DELIMITED, protobuf, protobuf_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used); - if (retVal == 0) - return 0; - *bytes_written += bytes_used; + if (in->record != NULL) { + protobuf_size = libp2p_record_protobuf_encode_size(in->record); + protobuf = (unsigned char*) malloc(protobuf_size); + if (!libp2p_record_protobuf_encode(in->record, protobuf, protobuf_size, &protobuf_size)) { + free(protobuf); + return 0; + } + retVal = protobuf_encode_length_delimited(3, WIRETYPE_LENGTH_DELIMITED, protobuf, protobuf_size, &buffer[*bytes_written], max_buffer_size - *bytes_written, &bytes_used); + free(protobuf); + if (retVal == 0) + return 0; + *bytes_written += bytes_used; + } // field 8 (repeated) struct Libp2pLinkedList* current = in->closer_peer_head; while (current != NULL) { diff --git a/record/record.c b/record/record.c index 8dea9b8..2675d53 100644 --- a/record/record.c +++ b/record/record.c @@ -97,11 +97,14 @@ int libp2p_record_protobuf_encode(const struct Libp2pRecord* in, unsigned char* * @returns the approximate number of bytes required */ size_t libp2p_record_protobuf_encode_size(const struct Libp2pRecord* in) { - size_t retVal = 11 + in->key_size; - retVal += 11 + in->value_size; - retVal += 11 + in->author_size; - retVal += 11 + in->signature_size; - retVal += 11 + in->time_received_size; + size_t retVal = 0; + if (in != NULL) { + retVal = 11 + in->key_size; + retVal += 11 + in->value_size; + retVal += 11 + in->author_size; + retVal += 11 + in->signature_size; + retVal += 11 + in->time_received_size; + } return retVal; } diff --git a/secio/secio.c b/secio/secio.c index 4c00ecc..77f48e5 100644 --- a/secio/secio.c +++ b/secio/secio.c @@ -499,21 +499,6 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat char* remote_peer_id = NULL; struct EphemeralPrivateKey* e_private_key = NULL; - const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n"; - - bytes_written = libp2p_net_multistream_send(local_session->socket_descriptor, protocol, strlen((char*)protocol)); - if (bytes_written <= 0) - 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; - //TODO: make sure we're not talking to ourself // generate 16 byte nonce @@ -561,9 +546,31 @@ 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) 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_send(local_session->socket_descriptor, total, protocol_len + propose_out_size); + free(total); + if (bytes_written <= 0) + 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 bytes_written = libp2p_secio_read(local_session, &propose_in_bytes, &propose_in_size); diff --git a/test/test_secio.h b/test/test_secio.h index e1d7b11..ddc7eb0 100644 --- a/test/test_secio.h +++ b/test/test_secio.h @@ -42,7 +42,7 @@ int test_secio_handshake() { if (!libp2p_crypto_rsa_private_key_fill_public_key(rsa_private_key)) goto exit; - secure_session.host = "10.0.1.9"; + secure_session.host = "192.210.179.217"; secure_session.port = 4001; secure_session.traffic_type = TCP; // connect to host diff --git a/test/testit.c b/test/testit.c index bdd5451..915ddc6 100644 --- a/test/testit.c +++ b/test/testit.c @@ -34,7 +34,7 @@ const char* names[] = { //"test_crypto_rsa_sign", "test_crypto_encoding_base32_encode", "test_protobuf_private_key", - //"test_secio_handshake", + "test_secio_handshake", "test_multistream_connect", "test_multistream_get_list", "test_ephemeral_key_generate", @@ -70,7 +70,7 @@ int (*funcs[])(void) = { //test_crypto_rsa_sign, test_crypto_encoding_base32_encode, test_protobuf_private_key, - //test_secio_handshake, + test_secio_handshake, test_multistream_connect, test_multistream_get_list, test_ephemeral_key_generate,