From d091a29b193a654f3b18e44da7b11139f3b4fa26 Mon Sep 17 00:00:00 2001 From: John Jones Date: Thu, 2 Feb 2017 14:10:12 -0500 Subject: [PATCH] Added multistream protocol to communicate with GO version --- .cproject | 1 + Makefile | 15 ++- crypto/Makefile | 4 +- crypto/key.c | 127 ++++++++++++++++++++---- crypto/peerutils.c | 66 ++++++++++++ crypto/sha1.c | 2 +- include/libp2p/crypto/key.h | 14 ++- include/libp2p/{ => crypto}/peerutils.h | 44 ++------ include/libp2p/net/multistream.h | 30 ++++++ include/libp2p/net/p2pnet.h | 37 +++++++ include/libp2p/secio/propose.h | 2 +- include/libp2p/secio/secio.h | 18 +++- net/Makefile | 18 ++++ net/multistream.c | 117 ++++++++++++++++++++++ net/p2pnet.h | 18 ---- net/sctp.c | 2 +- net/socket.c | 92 ++++++++++++++++- net/tcp.c | 2 +- net/udp.c | 2 +- secio/propose.c | 2 +- secio/secio.c | 89 +++++++++++++---- test/Makefile | 2 +- test/crypto/test_key.h | 24 ++--- test/crypto/test_rsa.h | 8 +- test/test_multistream.h | 35 +++++++ test/test_secio.h | 55 ++++++++++ test/testit.c | 19 ++-- 27 files changed, 714 insertions(+), 131 deletions(-) create mode 100644 crypto/peerutils.c rename include/libp2p/{ => crypto}/peerutils.h (86%) create mode 100644 include/libp2p/net/multistream.h create mode 100644 include/libp2p/net/p2pnet.h create mode 100644 net/Makefile create mode 100644 net/multistream.c delete mode 100644 net/p2pnet.h create mode 100644 test/test_multistream.h create mode 100644 test/test_secio.h diff --git a/.cproject b/.cproject index bd43fbf..542ec82 100644 --- a/.cproject +++ b/.cproject @@ -26,6 +26,7 @@ diff --git a/Makefile b/Makefile index 224d126..a147db5 100644 --- a/Makefile +++ b/Makefile @@ -2,19 +2,27 @@ DEBUG = true export DEBUG -OBJS = crypto/*.o crypto/encoding/*.o thirdparty/mbedtls/*.o hashmap/hashmap.o record/*.o routing/*.o +OBJS = crypto/*.o crypto/encoding/*.o \ + thirdparty/mbedtls/*.o \ + hashmap/hashmap.o \ + net/*.o \ + record/*.o \ + routing/*.o \ + secio/*.o +link: $(OBJS) + ar rcs libp2p.a $(OBJS) compile: cd crypto; make all; cd thirdparty; make all; cd hashmap; make all; + cd net; make all; cd record; make all; cd routing; make all; cd secio; make all; - ar rcs libp2p.a $(OBJS) -test: compile +test: compile link cd test; make all; rebuild: clean all @@ -24,6 +32,7 @@ all: test clean: cd crypto; make clean; cd hashmap; make clean; + cd net; make clean; cd thirdparty; make clean cd test; make clean; cd record; make clean; diff --git a/crypto/Makefile b/crypto/Makefile index e0ea3ac..825d6d9 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -1,8 +1,8 @@ CC = gcc -CFLAGS = -O0 -I../include -g3 +CFLAGS = -O0 -I../include -I../../c-protobuf -I../../c-multihash/include -g3 LFLAGS = DEPS = -OBJS = rsa.o sha256.o sha512.o sha1.o +OBJS = rsa.o sha256.o sha512.o sha1.o key.o peerutils.o %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/crypto/key.c b/crypto/key.c index 8d91484..83ec18a 100644 --- a/crypto/key.c +++ b/crypto/key.c @@ -1,31 +1,29 @@ -#include +#include +#include + +#include "libp2p/crypto/key.h" +#include "libp2p/crypto/sha256.h" +#include "libp2p/crypto/peerutils.h" +#include "protobuf.h" /** - * Utilities for public keys + * Utilities for public and private keys */ -enum KeyType { KEYTYPE_RSA, KEYTYPE_ED25519, KEYTYPE_INVALID }; - -struct PublicKey { - enum KeyType key_type; - char* raw_key; - size_t raw_key_size; -}; - struct PublicKey* libp2p_crypto_public_key_new() { struct PublicKey* retVal = malloc(sizeof(struct PublicKey)); if (retVal == NULL) return NULL; - retVal->key_type = KEYTYPE_INVALID; - retVal->raw_key = NULL; - retVal->raw_key_size = 0; + retVal->type = KEYTYPE_INVALID; + retVal->data = NULL; + retVal->data_size = 0; return retVal; } void libp2p_crypto_public_key_free(struct PublicKey* in) { if (in != NULL) { - if (in->raw_key != NULL) - free(in->raw_key); + if (in->data != NULL) + free(in->data); free(in); in = NULL; } @@ -33,6 +31,10 @@ void libp2p_crypto_public_key_free(struct PublicKey* in) { /** * Unmarshal a public key from a protobuf + * @param buffer the protobuf + * @param buffer_length the length of the protobuf + * @param out the pointer to the struct PublicKey that will be allocated + * @returns true(1) on success, otherwise false(0) */ int libp2p_crypto_public_key_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct PublicKey** out) { @@ -55,12 +57,12 @@ int libp2p_crypto_public_key_protobuf_decode(unsigned char* buffer, size_t buffe pos += bytes_read; switch(field_no) { case (1): // type - if (protobuf_decode_varint(&buffer[pos], buffer_length - pos, &((*out)->key_type), &bytes_read) == 0) + if (protobuf_decode_varint(&buffer[pos], buffer_length - pos, (long long unsigned int*)&((*out)->type), &bytes_read) == 0) goto exit; pos += bytes_read; break; case (2): // key - if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->raw_key), &((*out)->raw_key_size), &bytes_read) == 0) + if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->data), &((*out)->data_size), &bytes_read) == 0) goto exit; pos += bytes_read; break; @@ -75,3 +77,94 @@ exit: } return retVal; } + +struct PrivateKey* libp2p_crypto_private_key_new() { + struct PrivateKey* retVal = malloc(sizeof(struct PrivateKey)); + if (retVal == NULL) + return NULL; + retVal->type = KEYTYPE_INVALID; + retVal->data = NULL; + retVal->data_size = 0; + return retVal; +} + +void libp2p_crypto_private_key_free(struct PrivateKey* in) { + if (in != NULL) { + if (in->data != NULL) + free(in->data); + free(in); + in = NULL; + } +} + +/** + * Unmarshal a private key from a protobuf + * @param buffer the protobuf + * @param buffer_length the length of the protobuf + * @param out the pointer to the struct PrivateKey that will be allocated + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_crypto_private_key_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct PrivateKey** out) { + + // first field is type (RSA vs ED25519) + // second field is the public key + + size_t pos = 0; + int retVal = 0; + + if ( (*out = libp2p_crypto_private_key_new()) == NULL) + goto exit; + + while(pos < buffer_length) { + size_t bytes_read = 0; + int field_no; + enum WireType field_type; + if (protobuf_decode_field_and_type(&buffer[pos], buffer_length, &field_no, &field_type, &bytes_read) == 0) { + goto exit; + } + pos += bytes_read; + switch(field_no) { + case (1): // type + if (protobuf_decode_varint(&buffer[pos], buffer_length - pos, (long long unsigned int*)&((*out)->type), &bytes_read) == 0) + goto exit; + pos += bytes_read; + break; + case (2): // key + if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->data), &((*out)->data_size), &bytes_read) == 0) + goto exit; + pos += bytes_read; + break; + } + } + + retVal = 1; + +exit: + if (retVal == 0) { + libp2p_crypto_private_key_free(*out); + } + return retVal; +} + +/** + * convert a public key into a peer id + * @param public_key the public key struct + * @param peer_id the results, in a null-terminated string + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_crypto_public_key_to_peer_id(struct PublicKey* public_key, char** peer_id) { + unsigned char hashed[32]; + libp2p_crypto_hashing_sha256(public_key->data, public_key->data_size, hashed); + size_t final_id_size = 100; + unsigned char final_id[final_id_size]; + memset(final_id, 0, final_id_size); + if (!PrettyID(final_id, &final_id_size, hashed, 32)) + return 0; + *peer_id = (char*)malloc(final_id_size + 1); + if (*peer_id == NULL) + return 0; + memset(*peer_id, 0, final_id_size + 1); + memcpy(*peer_id, final_id, final_id_size); + return 1; +} + diff --git a/crypto/peerutils.c b/crypto/peerutils.c new file mode 100644 index 0000000..5952d0a --- /dev/null +++ b/crypto/peerutils.c @@ -0,0 +1,66 @@ +#include +#include + +#include "mh/multihash.h" +#include "mh/hashes.h" +#include "libp2p/crypto/encoding/base58.h" +#include "libp2p/crypto/sha256.h" + +/** + * base58 encode a string NOTE: this also puts the prefix 'Qm' in front as the ID is a multihash + * @param pointyaddr where the results will go + * @param rezbuflen the length of the results buffer. It will also put how much was used here + * @param ID_BUF the input text (usually a SHA256 hash) + * @param ID_BUF_SIZE the input size (normally a SHA256, therefore 32 bytes) + * @returns true(1) on success + */ +int PrettyID(unsigned char * pointyaddr, size_t* rezbuflen,unsigned char * ID_BUF, size_t ID_BUF_SIZE)//b58 encoded ID buf +{ + int returnstatus = 0; + + unsigned char temp_buffer[*rezbuflen]; + + memset(temp_buffer, 0, *rezbuflen); + + // wrap the base58 into a multihash + int retVal = mh_new(temp_buffer, MH_H_SHA2_256, ID_BUF, ID_BUF_SIZE); + if (retVal < 0) + return 0; + + // base58 the multihash + returnstatus = libp2p_crypto_encoding_base58_encode(temp_buffer, strlen((char*)temp_buffer), &pointyaddr, rezbuflen); + if(returnstatus == 0) + return 0; + + return 1; +} + +/**** + * Make a SHA256 hash of what is usually the DER formatted private key. + * @param result where to store the result. Should be 32 chars long + * @param texttohash the text to hash + * @param text_size the size of the text + */ +void ID_FromPK_non_null_terminated(char * result,unsigned char * texttohash, size_t text_size) +{ + /* old way + unsigned char hash[32]; + bzero(hash,32); + SHA256_CTX ctx; + sha256_init(&ctx); + sha256_update(&ctx,texttohash,text_size); + sha256_final(&ctx,hash); + a_store_hash(result,hash); + */ + libp2p_crypto_hashing_sha256(texttohash, text_size, (unsigned char*)result); +} + +/**** + * Make a SHA256 hash of what is usually the DER formatted private key. + * @param result where to store the result. Should be 32 chars long + * @param texttohash a null terminated string of the text to hash + */ +void ID_FromPK(char * result,unsigned char * texttohash) +{ + ID_FromPK_non_null_terminated(result,texttohash,strlen((char*)texttohash)); +} diff --git a/crypto/sha1.c b/crypto/sha1.c index d2ed6b4..5bf90ec 100644 --- a/crypto/sha1.c +++ b/crypto/sha1.c @@ -92,7 +92,7 @@ A million repetitions of "a" #include #include -#include +#include "libp2p/crypto/sha1.h" void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); diff --git a/include/libp2p/crypto/key.h b/include/libp2p/crypto/key.h index f201970..12355b7 100644 --- a/include/libp2p/crypto/key.h +++ b/include/libp2p/crypto/key.h @@ -19,11 +19,21 @@ struct PrivateKey { }; struct PublicKey* libp2p_crypto_public_key_new(); - void libp2p_crypto_public_key_free(struct PublicKey* in); +struct PrivateKey* libp2p_crypto_private_key_new(); +void libp2p_crypto_private_key_free(struct PrivateKey* in); + /** * Unmarshal a public key from a protobuf */ int libp2p_crypto_public_key_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct PublicKey** out); -int libp2p_crypto_private_key_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct PublicKey** out); +int libp2p_crypto_private_key_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct PrivateKey** out); + +/** + * convert a public key into a peer id + * @param public_key the public key struct + * @param peer_id the results, in a null-terminated string + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_crypto_public_key_to_peer_id(struct PublicKey* public_key, char** peer_id); diff --git a/include/libp2p/peerutils.h b/include/libp2p/crypto/peerutils.h similarity index 86% rename from include/libp2p/peerutils.h rename to include/libp2p/crypto/peerutils.h index 17b12a5..48ecd76 100644 --- a/include/libp2p/peerutils.h +++ b/include/libp2p/crypto/peerutils.h @@ -9,6 +9,8 @@ #include "mh/multihash.h" #include "mh/hashes.h" +/* + #define uchar unsigned char // 8-bit byte #define juint unsigned int // 32-bit word // DBL_INT_ADD treats two unsigned ints a and b as one 64-bit integer and adds c to it @@ -170,6 +172,8 @@ void a_store_hash(unsigned char * result,unsigned char hash[]) } } +*/ + /** * base58 encode a string NOTE: this also puts the prefix 'Qm' in front as the ID is a multihash * @param pointyaddr where the results will go @@ -178,26 +182,7 @@ void a_store_hash(unsigned char * result,unsigned char hash[]) * @param ID_BUF_SIZE the input size (normally a SHA256, therefore 32 bytes) * @returns true(1) on success */ -int PrettyID(unsigned char * pointyaddr, size_t* rezbuflen,unsigned char * ID_BUF, size_t ID_BUF_SIZE)//b58 encoded ID buf -{ - int returnstatus = 0; - - unsigned char temp_buffer[*rezbuflen]; - - memset(temp_buffer, 0, *rezbuflen); - - // wrap the base58 into a multihash - int retVal = mh_new(temp_buffer, MH_H_SHA2_256, ID_BUF, ID_BUF_SIZE); - if (retVal < 0) - return 0; - - // base58 the multihash - returnstatus = libp2p_crypto_encoding_base58_encode(temp_buffer, strlen((char*)temp_buffer), &pointyaddr, rezbuflen); - if(returnstatus == 0) - return 0; - - return 1; -} +int PrettyID(unsigned char * pointyaddr, size_t* rezbuflen,unsigned char * ID_BUF, size_t ID_BUF_SIZE);//b58 encoded ID buf /**** * Make a SHA256 hash of what is usually the DER formatted private key. @@ -205,28 +190,13 @@ int PrettyID(unsigned char * pointyaddr, size_t* rezbuflen,unsigned char * ID_BU * @param texttohash the text to hash * @param text_size the size of the text */ -void ID_FromPK_non_null_terminated(char * result,unsigned char * texttohash, size_t text_size) -{ - /* old way - unsigned char hash[32]; - bzero(hash,32); - SHA256_CTX ctx; - sha256_init(&ctx); - sha256_update(&ctx,texttohash,text_size); - sha256_final(&ctx,hash); - a_store_hash(result,hash); - */ - libp2p_crypto_hashing_sha256(texttohash, text_size, (unsigned char*)result); -} +void ID_FromPK_non_null_terminated(char * result,unsigned char * texttohash, size_t text_size); /**** * Make a SHA256 hash of what is usually the DER formatted private key. * @param result where to store the result. Should be 32 chars long * @param texttohash a null terminated string of the text to hash */ -void ID_FromPK(char * result,unsigned char * texttohash) -{ - ID_FromPK_non_null_terminated(result,texttohash,strlen((char*)texttohash)); -} +void ID_FromPK(char * result,unsigned char * texttohash); #endif diff --git a/include/libp2p/net/multistream.h b/include/libp2p/net/multistream.h new file mode 100644 index 0000000..2c03bae --- /dev/null +++ b/include/libp2p/net/multistream.h @@ -0,0 +1,30 @@ +#pragma once + +/*** + * An implementation of the libp2p multistream + */ + +/** + * Write to an open multistream host + * @param socket_fd the socket file descriptor + * @param data the data to send + * @param data_length the length of the data + * @returns the number of bytes written + */ +int libp2p_net_multistream_send(int socket_fd, const unsigned char* data, size_t data_length); +/** + * Read from a multistream socket + * @param socket_fd the socket file descriptor + * @param results where to put the results. NOTE: this memory is allocated + * @param results_size the size of the results in bytes + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_net_multistream_receive(int socket_fd, char** results, size_t* results_size); + +/** + * 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/net/p2pnet.h b/include/libp2p/net/p2pnet.h new file mode 100644 index 0000000..57b0646 --- /dev/null +++ b/include/libp2p/net/p2pnet.h @@ -0,0 +1,37 @@ +#ifndef P2PNET_H +#define P2PNET_H + +#include + + int socket_open4(); + int socket_bind4(int s, uint32_t ip, uint16_t port); + int socket_bind4_reuse(int s, uint32_t ip, uint16_t port); + int socket_accept4(int s, uint32_t *ip, uint16_t *port); + int socket_local4(int s, uint32_t *ip, uint16_t *port); + int socket_connect4(int s, uint32_t ip, uint16_t port); + int socket_listen(int s, uint32_t *localip, uint16_t *localport); + ssize_t socket_read(int s, char *buf, size_t len, int flags); + ssize_t socket_write(int s, char *buf, size_t len, int flags); + /** + * Used to send the size of the next transmission for "framed" transmissions. NOTE: This will send in big endian format + * @param s the socket descriptor + * @param size the size to send + * @param flags socket flags + * @returns number of bytes sent + */ + ssize_t socket_write_size(int s, unsigned long size, int flags); + + int socket_tcp4(void); + + int socket_stream_sctp4(void); + + int socket_udp4(void); + + /** + * convert a hostname into an ip address + * @param hostname the name of the host. i.e. www.jmjatlanta.com + * @returns the ip address as an uint32_t + */ + uint32_t hostname_to_ip(const char* hostname); + +#endif // P2PNET_H diff --git a/include/libp2p/secio/propose.h b/include/libp2p/secio/propose.h index ca31180..3762c4d 100644 --- a/include/libp2p/secio/propose.h +++ b/include/libp2p/secio/propose.h @@ -23,7 +23,7 @@ void libp2p_secio_propose_free(struct Propose* in); * @param from_size the size of from * @returns true(1) on success, otherwise false(0) */ -int libp2p_secio_propose_set_property(void** to, size_t* to_size, void* from, size_t from_size); +int libp2p_secio_propose_set_property(void** to, size_t* to_size, const void* from, size_t from_size); /** * retrieves the approximate size of an encoded version of the passed in struct diff --git a/include/libp2p/secio/secio.h b/include/libp2p/secio/secio.h index 6dc669e..878e1fc 100644 --- a/include/libp2p/secio/secio.h +++ b/include/libp2p/secio/secio.h @@ -1,13 +1,29 @@ #pragma once #include "libp2p/crypto/key.h" +#include "libp2p/crypto/rsa.h" /** * A secure connection */ +enum IPTrafficType { TCP, UDP }; + struct SecureSession { + // to get the connection started + char* host; + int port; + enum IPTrafficType traffic_type; + // once the connection is established int socket_descriptor; struct PublicKey remote_key; - int remote_peer_id; + char* remote_peer_id; }; + +/*** + * performs initial communication over an insecure channel to share + * keys, IDs, and initiate connection. This is a framed messaging system + * @param session the secure session to be filled + * @returns true(1) on success, false(0) otherwise + */ +int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey* private_key); diff --git a/net/Makefile b/net/Makefile new file mode 100644 index 0000000..5e9e63e --- /dev/null +++ b/net/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CFLAGS = -O0 -Wall -I../include -I../../c-protobuf + +ifdef DEBUG +CFLAGS += -g3 +endif + +LFLAGS = +DEPS = +OBJS = sctp.o socket.o tcp.o udp.o multistream.o + +%.o: %.c $(DEPS) + $(CC) -c -o $@ $< $(CFLAGS) + +all: $(OBJS) + +clean: + rm -f *.o diff --git a/net/multistream.c b/net/multistream.c new file mode 100644 index 0000000..2214763 --- /dev/null +++ b/net/multistream.c @@ -0,0 +1,117 @@ +#include +#include + +#include "libp2p/net/p2pnet.h" +#include "varint.h" + +/*** + * An implementation of the libp2p multistream + */ + +/** + * Write to an open multistream host + * @param socket_fd the socket file descriptor + * @param data the data to send + * @param data_length the length of the data + * @returns the number of bytes written + */ +int libp2p_net_multistream_send(int socket_fd, const unsigned char* data, size_t data_length) { + int num_bytes = 0; + + if (data_length > 0) { // only do this is if there is something to send + // first send the size + unsigned char varint[12]; + size_t varint_size = 0; + varint_encode(data_length, &varint[0], 12, &varint_size); + num_bytes = socket_write(socket_fd, (char*)varint, varint_size, 0); + if (num_bytes == 0) + return 0; + // then send the actual data + num_bytes += socket_write(socket_fd, (char*)data, data_length, 0); + } + + return num_bytes; +} + +/*** + * Parse the incoming data, removing the size indicator at the front of the array + * @param incoming the incoming data + * @param incoming_size the size of the incoming data + * @param outgoing the buffer to hold the outgoing data, allocated within this function + * @param outgoing_size the outgoing size + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_net_multistream_parse_results(char* incoming, size_t incoming_size, char** outgoing, size_t* outgoing_size) { + int retVal = 0; + if (incoming_size > 0) { + // TODO: handle this differently + // read the varint + // allocate memory + *outgoing = (char*)malloc(incoming_size - 1); + if (*outgoing == NULL) + return 0; + // copy in the data + memcpy(*outgoing, &incoming[1], incoming_size - 1); + *outgoing_size = incoming_size - 1; + retVal = 1; + } + return retVal; +} + +/** + * Read from a multistream socket + * @param socket_fd the socket file descriptor + * @param results where to put the results. NOTE: this memory is allocated + * @param results_size the size of the results in bytes + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_net_multistream_receive(int socket_fd, char** results, size_t* results_size) { + int bytes = 0; + size_t buffer_size = 65535; + char buffer[buffer_size]; + + bytes = socket_read(socket_fd, buffer, buffer_size, 0); + if (bytes == 0) + return 0; + + // parse the results, removing the leading size indicator + return libp2p_net_multistream_parse_results(buffer, bytes, results, results_size); +} + + +/** + * 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) { + int retVal = -1, socket = -1; + char* results = NULL; + size_t results_size; + size_t num_bytes = 0; + + uint32_t ip = hostname_to_ip(hostname); + socket = socket_open4(); + + // connect + if (socket_connect4(socket, ip, port) != 0) + goto exit; + + // try to receive the protocol id + retVal = libp2p_net_multistream_receive(socket, &results, &results_size); + + // send the multistream handshake + const char* protocol_buffer = "/multistream/1.0.0\n"; + + num_bytes = libp2p_net_multistream_send(socket, (const unsigned char*)protocol_buffer, strlen(protocol_buffer)); + if (num_bytes <= 0) + goto exit; + + retVal = socket; + exit: + if (results != NULL) + free(results); + return retVal; +} + diff --git a/net/p2pnet.h b/net/p2pnet.h deleted file mode 100644 index a11e025..0000000 --- a/net/p2pnet.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef P2PNET_H - #define P2PNET_H - - int socket_bind4(int s, uint32_t ip, uint16_t port); - int socket_bind4_reuse(int s, uint32_t ip, uint16_t port); - int socket_accept4(int s, uint32_t *ip, uint16_t *port); - int socket_local4(int s, uint32_t *ip, uint16_t *port); - int socket_connect4(int s, uint32_t ip, uint16_t port); - int socket_listen(int s, uint32_t *localip, uint16_t *localport); - ssize_t socket_read(int s, char *buf, size_t len, int flags); - ssize_t socket_write(int s, char *buf, size_t len, int flags); - - int socket_tcp4(void); - - int socket_stream_sctp4(void); - - int socket_udp4(void); -#endif // P2PNET_H diff --git a/net/sctp.c b/net/sctp.c index 0ebbe7a..827ded8 100644 --- a/net/sctp.c +++ b/net/sctp.c @@ -1,7 +1,7 @@ #include #include #include -#include "p2pnet.h" +#include "libp2p/net/p2pnet.h" /* Create a SCTP socket. */ diff --git a/net/socket.c b/net/socket.c index 7c7f476..c22ad7a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -3,8 +3,11 @@ #include #include #include +#include #include -#include "p2pnet.h" +#include + +#include "libp2p/net/p2pnet.h" /* associate an IP address with an port to a socket. * first param is the socket file description @@ -64,7 +67,12 @@ int socket_local4(int s, uint32_t *ip, uint16_t *port) return 0; } -/* start a client connection. +/*** + * start a client connection. + * @param s the socket number + * @param ip the ip address + * @param port the port number + * @return 0 on success, otherwise -1 */ int socket_connect4(int s, uint32_t ip, uint16_t port) { @@ -112,3 +120,83 @@ ssize_t socket_write(int s, char *buf, size_t len, int flags) { return send(s, buf, len, flags); } + +int socket_open4() { + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + + return sockfd; +} + +/** + * Used to send the size of the next transmission for "framed" transmissions. NOTE: This will send in big endian format + * @param s the socket descriptor + * @param size the size to send + * @param flags socket flags + * @returns number of bytes sent + */ +ssize_t socket_write_size(int s, unsigned long size, int flags) { + // determine if we're big or little endian + int big_endian = 1; + if (*(char*)&big_endian == 1) { + big_endian = 0; + } + // convert to int32_t + int32_t conv = htonl(size); + // swap bytes if this machine is little endian + if (!big_endian) { + uint32_t b0, b1, b2, b3; + b0 = (conv & 0x000000ff) << 24u; + b1 = (conv & 0x0000ff00) << 8u; + b2 = (conv & 0x00ff0000) >> 8u; + b3 = (conv & 0xff000000) >> 24u; + conv = b0 | b1 | b2 | b3; + } + + // send to socket + char* data = (char*)&conv; + int left = sizeof(conv); + ssize_t rc; + int retries_left = 100; + do { + rc = send(s, data, left, flags); + if (rc < 0) { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { + retries_left--; + if (retries_left <= 0) + break; + } else { + return -1; + } + } else { + data += rc; + left -= rc; + } + } while (left > 0); + return sizeof(conv) - left; + //return send(s, size, 4, flags); +} + + +/** + * convert a hostname into an ip address + * @param hostname the name of the host. i.e. www.jmjatlanta.com + * @returns the ip address as an uint32_t + */ +uint32_t hostname_to_ip(const char* hostname) +{ + struct hostent *he; + struct in_addr **addr_list; + + if ( (he = gethostbyname( hostname ) ) == NULL) + { + // get the host info + herror("gethostbyname"); + return 1; + } + + addr_list = (struct in_addr **) he->h_addr_list; + if ((*addr_list) == NULL) + return 0; + + return addr_list[0]->s_addr; +} diff --git a/net/tcp.c b/net/tcp.c index 7ab51a9..3206ceb 100644 --- a/net/tcp.c +++ b/net/tcp.c @@ -1,7 +1,7 @@ #include #include #include -#include "p2pnet.h" +#include "libp2p/net/p2pnet.h" /* Create a TCP socket. */ diff --git a/net/udp.c b/net/udp.c index 08dab8d..4985196 100644 --- a/net/udp.c +++ b/net/udp.c @@ -1,7 +1,7 @@ #include #include #include -#include "p2pnet.h" +#include "libp2p/net/p2pnet.h" /* Create a UDP socket. */ diff --git a/secio/propose.c b/secio/propose.c index d95c342..ef7ee8d 100644 --- a/secio/propose.c +++ b/secio/propose.c @@ -32,7 +32,7 @@ void libp2p_secio_propose_free( struct Propose* in) { } } -int libp2p_secio_propose_set_property(void** to, size_t* to_size, void* from, size_t from_size) { +int libp2p_secio_propose_set_property(void** to, size_t* to_size, const void* from, size_t from_size) { if (*to != NULL) free(*to); *to = (void*)malloc(from_size); diff --git a/secio/secio.c b/secio/secio.c index 8d794d2..387e2ed 100644 --- a/secio/secio.c +++ b/secio/secio.c @@ -1,8 +1,10 @@ #include #include +#include #include "libp2p/secio/secio.h" #include "libp2p/secio/propose.h" +#include "libp2p/net/p2pnet.h" const char* SupportedExchanges = "P-256,P-384,P-521"; const char* SupportedCiphers = "AES-256,AES-128,Blowfish"; @@ -29,56 +31,104 @@ void libp2p_secio_secure_session_free(struct SecureSession* in) { free(in); } +/** + * Generate a random nonce + * @param results where to put the results + * @param length the length of the nonce + * @returns true(1) on success, otherwise false(0) + */ +int libp2p_secio_generate_nonce(char* results, int length) { + results = "abcdefghijklmno"; + return 1; +} + /*** * performs initial communication over an insecure channel to share * keys, IDs, and initiate connection. This is a framed messaging system * @param session the secure session to be filled * @returns true(1) on success, false(0) otherwise */ -int libp2p_secio_secure_session_handshake(struct SecureSession* session, struct RsaPrivateKey* private_key) { - int retVal = 0, protobuf_size = 0, results_size = 0; - unsigned char* protobuf = 0;; - unsigned char* results; - struct Propose* propose = NULL; - struct SocketMuxer* socketMuxer; +int libp2p_secio_handshake(struct SecureSession* session, struct RsaPrivateKey* private_key) { + int retVal = 0, results_size = 65535, bytes_written = 0; + size_t protobuf_size = 0; + unsigned char* protobuf = 0; + unsigned char results[results_size]; + struct Propose* propose_out = NULL; + struct Propose* propose_in = NULL; + struct PublicKey* public_key = NULL; + uint32_t ip; + int socket; // generate 16 byte nonce char nonceOut[16]; - if (!generateNonce(&nonceOut, 16)) { + if (!libp2p_secio_generate_nonce(&nonceOut[0], 16)) { goto exit; } - propose = libp2p_secio_propose_new(); - libp2p_secio_propose_set_property(&propose->rand, &propose->rand_size, nonceOut, 16); + propose_out = libp2p_secio_propose_new(); + libp2p_secio_propose_set_property((void**)&propose_out->rand, &propose_out->rand_size, nonceOut, 16); // will need: // TODO: public key // supported exchanges - libp2p_secio_propose_set_property(&propose->exchanges, &propose->exchanges_size, SupportedExchanges, strlen(SupportedExchanges)); + libp2p_secio_propose_set_property((void**)&propose_out->exchanges, &propose_out->exchanges_size, SupportedExchanges, strlen(SupportedExchanges)); // supported ciphers - libp2p_secio_propose_set_property(&propose->ciphers, &propose->ciphers_size, SupportedCiphers, strlen(SupportedCiphers)); + libp2p_secio_propose_set_property((void**)&propose_out->ciphers, &propose_out->ciphers_size, SupportedCiphers, strlen(SupportedCiphers)); // supported hashes - libp2p_secio_propose_set_property(&propose->hashes, &propose->exchanges_size, SupportedHashes, strlen(SupportedHashes)); + libp2p_secio_propose_set_property((void**)&propose_out->hashes, &propose_out->exchanges_size, SupportedHashes, strlen(SupportedHashes)); // send request (protobuf, then send) - protobuf_size = libp2p_secio_propose_protobuf_encode_size(propose); + protobuf_size = libp2p_secio_propose_protobuf_encode_size(propose_out); protobuf = (unsigned char*) malloc(protobuf_size); if (protobuf == NULL) goto exit; - if (!libp2p_secio_propose_protobuf_encode(propose, protobuf, protobuf_size, &protobuf_size)) + if (!libp2p_secio_propose_protobuf_encode(propose_out, protobuf, protobuf_size, &protobuf_size)) goto exit; - libp2p_secio_propose_free(propose); - if (!libp2p_net_socket_muxer_send(socketMuxer, protobuf, protobuf_size)) + ip = hostname_to_ip(session->host); + socket = socket_open4(); + // connect + if (socket_connect4(socket, ip, session->port) != 0) + goto exit; + + // try 1 + // first try to send mulitstream line + char buf[21]; + buf[0] = 23; + strcpy(&buf[1], "/multistream/1.0.0\n"); + bytes_written = socket_write_size(socket, 20, sizeof(uint32_t)); + if (bytes_written != 4) + goto exit; + bytes_written = socket_write(socket, buf, 20, 0); + if (bytes_written != 20) + goto exit; + // check to see what was written back... + bytes_written = socket_read(socket, (char*)&results[0], results_size, 0); + if (bytes_written == 65535) + goto exit; + // end of try 1 + + // send struct Propose in protobuf format + bytes_written = socket_write_size(socket, protobuf_size, sizeof(uint32_t)); + if (bytes_written != 4) + goto exit; + bytes_written = socket_write(socket, (char*)protobuf, protobuf_size, 0); + if (bytes_written != protobuf_size) goto exit; // receive response (turn back into a Propose struct) - if (!libp2p_net_socket_muxer_receive(socketMuxer, &results, &results_size)) + bytes_written = socket_read(socket, (char*)&results[0], results_size, 0); + if (bytes_written == 65535) goto exit; - if (!libp2p_secio_propose_protobuf_decode(results, results_size, &propose)) + + if (!libp2p_secio_propose_protobuf_decode(results, results_size, &propose_in)) goto exit; // get public key + if (!libp2p_crypto_public_key_protobuf_decode(propose_in->public_key, propose_in->public_key_size, &public_key)) + goto exit; // generate their peer id + char* remote_peer_id; + libp2p_crypto_public_key_to_peer_id(public_key, &remote_peer_id); // negotiate encryption parameters NOTE: SelectBest must match, otherwise this won't work // curve @@ -101,7 +151,8 @@ int libp2p_secio_secure_session_handshake(struct SecureSession* session, struct exit: - ipfs_secio_propose_free(propose); + libp2p_secio_propose_free(propose_out); + libp2p_secio_propose_free(propose_in); if (protobuf != NULL) free(protobuf); diff --git a/test/Makefile b/test/Makefile index 37300d6..52d6cde 100644 --- a/test/Makefile +++ b/test/Makefile @@ -7,7 +7,7 @@ endif LFLAGS = -L../ -L../../c-multihash DEPS = crypto/test_base58.h crypto/test_rsa.h test_mbedtls.h -OBJS = testit.o +OBJS = testit.o ../../c-protobuf/protobuf.o ../../c-protobuf/varint.o ../libp2p.a %.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) diff --git a/test/crypto/test_key.h b/test/crypto/test_key.h index 65b72be..2657865 100644 --- a/test/crypto/test_key.h +++ b/test/crypto/test_key.h @@ -8,31 +8,30 @@ int test_protobuf_private_key() { size_t decode_base64_size = 0; unsigned char* decode_base64; // this is a base64 encoded private key. It makes it easier to test if it is in base64 form - char* orig_priv_key = "CAASpwkwggSjAgEAAoIBAQDTDJBWjDzS/HxDNOHazvzH2bu9CPMVHUrrvKRdBUM5ansL6/CC3MVZ6HVm4O6QHRapN6EF2CbrTgI4KBOXIL125Xo8MlROnyfXYk3O5q2tgwL/MbW8kXjtkyCfBak7MUoLOdLU7Svg0gkl3l+uDAiDcCLnwJVcFfq9ch6z4wMOhYJqE5dtx0uXxn6IuKWl1B69FTvBXCc0thw8Rw54b941FDcsBH5ttV9mRNCJym3poZ5qalNgXlxoIIB+PUx5QD+aq7KMJdpAX8HkapBntCOahP/QUceRmma0grlZLeYkH6/oi/hIrM6se3KUZ+F6tBuDFys8UAZy/X2BCUbKjbxtAgMBAAECggEANWfQfpYuLhXGPBt9q6kFPm1SnJtPJ+CpvM2XqhJS2IyhZnrl+bd0GTRBwS7aL42s1lVFYf04nAK5fQxnKK8YQqX/MIxr2RldM5ukpN6qxGWKtJkXrAgD2dqJPrRoBpqKahzPxSHfIJ0Fw5dqDtjsrpYJvyt0oEDPmnDuZAbmFx4sJqnesPNhKxtRMBx1+yxGVuRVJjHcqAgqPqwNiuoMEaYMY+G9yzT6vza8ovCpbX7BBIgM5fAT9PD8TBG//Vu9THvj/ZomiVG2qv6RL0qQyVb+DUzPZz1amBsSvahtXCl72jA3JwAZ943RxSR66P934S0ashkVwLUi46z/EAbJ4QKBgQDojGIO07BEVL2+7VxlGL9XGZQp4Y3qlhh2zDDQGwkCq/KQ+BdNYWitPwqRl9GqFLgpmeQIhyHTOa/IThx+AXGKVQ24ROH+skUs4IbO6R3qY7BKtb5lkZE/Yln09x70BBngUYAzh/rtnsXO3cl1x2XDDqUbCwlGcDAs8Jh/6UnvQwKBgQDoVSQs7Uq9MJCGIUM2bixX89tHzSxq5mn9wMD3/XRVfT5Ua8YkYBuzcmlcT39N7L5BwuyFqX3Vi7lv/Ya/qaQP6XkrZ8W1OAaTlYewfE5ZgknJqSpXcNWhABKeNmqndvqyQ/8HNCv/j8AdraGB2DGO57Xso5J0CQ43W/U9+QIyjwKBgHLL2hw3o+wXaRO3WMUPUmVM2zdRgR0suybp5a7Vqb0H5NZrohUw4NulIzJ8H6Q2VjMzJL6Q9sGu2HepF6ecTtBa7ErqtiVlG4Dr1aCOs5XhYEWBMlwxX+JKSt4Cn+UVoTB7Cy5lEhn7JurX0Xuy0ylXMWoIKKv89cs5eg6quzTBAoGAaq9eEztLjKCWXOE9SetBdYnG8aunb9cqaJlwgu/h0bfXPVDYBbAUSEyLURY4MQI7Q1tM3Pu9iqfEmUZj7/LoIV5mg6X9RX/alT6etk3+dF+9nlqN1OU9U9cCtZ/rTcb2y5EptJcidRH/eCFY/pTV/PcttOJPx/S4kHcroC+N8MUCgYEA6DA5QHxHfNN6Nxv+pEzy2DIxFe9RrBxS+KPBsra1C8jgdeMf4EmfU0Nox92V0q0bRrD5ztqQwSONI0hSRb1iiMWR6MuFnAFajUJfASjjIlZ6nIQjQslI7vjlvYyyHS/p/Codxap+yJlTLWwVEOXp2D9pWwiMq1xEyf0TH1BosvM="; + // these were pulled from the GO version of ipfs + char* orig_priv_key = "CAASqgkwggSmAgEAAoIBAQD0a4RI+bF/ov7IVOGSJ8dQfnK1DwM0gwVuJAd+3LXxIZEPZzsKIKia0TojDbTdLvOJ23wsaojTF/4bSzBK5otdAz8YSgez4vTRUV5pUqvCkK0dSJJ1DHTdrFUwvzlXuKbwNbvWyzjmKfeaE9a9YLzhrUIUTRvKyqhZXr++vMy3hw4fdtGUTJWeiqmoIuJWIZ1748Ff6LjcP7TdG7OvY4q+U9ilEJYdF4aM+TJY193zKp0GNWohunuVrtOUnL9VQaSSDbvGdFS1Mg9iCN6kRBQTHVQvFzvuEw/Y2LvoPH3yFG1zj6bDLWfOBhegy/6Zi6fi4E1UfgJNFN1sjWF+gZoHAgMBAAECggEBALTqBD9zuoMsJYQo99IT6X7WKZeE5i1vMYzF1Fp9iZpS6ylIkrW7WLFHXs3lblMtVoxazn2d2WrOXoLbU4KNROhy57fVy//FZMqufMBetc3NAqYjOmyy7KnLzj7Hu+0HO2GflEq3n4UV2TTNrGv+d7BfawLV1FV1TcjgzfKjkq/gMDCTPMgfT7lcF4TGSqv6Pgudp8RRn/R7EKOx+I8/XkJsZWP3XJ0zj4ciqDmKrX2j7wZMT8CH/8wfyg4NGk1+TN4xBB2CXgulIWJg5yhzu+JgbGnHEL/Ga+i40XJe+RnlKDpjQ+ZFyrOkmHpIldasjWNGFeKwLjzrDQfyDRwex5ECgYEA+fFGJ+zbi2YJwHDO/44PmvcoCWpho0ah7y+O5/LEVROTYEoNRqodLet+z+LMKDq/o2qTNaYJLiDGMBZzhqyJIFR5ZJ5MhgLloY1gL8s0a7KMWDbh7giiWSu5zqhB3Du8Tom+8bYZUxOL4zhzCGrFitRqiEIIjy1/c5qyRQZaZx8CgYEA+lf6tdO6kKiAOxm7sdZ3rEl4UGFY+tEqgivKwurLRIor0XDfhCKr1hCfsZggpR8SMLfjCuNEgKbceofcKMa8OtyDbMPRz0mYNkCELTUYA+r8Ib/LvleQApMcLn+TDNwEnGlglSrrF33RVAUK+i/WfSXUvZRVpLQpRmdAqHjJeBkCgYEA0+Zz/iFXOGW32slJFWxRWqYz8VeZk52saGY/l/I/9Yj1J2tgugo7VtUS3BiB0ZGNK3SNfaxYmBz9KYO/Sew5DYnQqTdz1SHboQ2FAMAcnznutlNBVFdJnKPvkX8g5yBV05gApFgoPECUFn2jOP2coMjZ0M97Bjgil9YNUWvDdS0CgYEA4beFs3+tzVRAGgl/tD7dNBgiRMchBTSmkSuO6+PrVmcGTxboUSk5qg7fDa9Ob9LuAcMrENwNHbpVPJ1WoeVePewpC14bxDxk4zWUd3ZRquaqYnud5obor4mYdUxNd+DAv447qQNDaLDmlkzdsuqDB9+eSzh9Z72RIYtjPwN5E7ECgYEAsbqkMZXfK1tTRfduX+7KOlPMfcSr29X6nuDglcna4dHec6FAOzp3xL2722nnFt6gygc7pErrm0m0Wd/6BMTb4T3+GYwkDiMjM2CsTZYjpzrUri/VfRR509rScxHVR0/1PTFWN0K0+VZbEAyXDbbs4opq40tW0dWtcKxaNlimMw8="; struct PrivateKey* private_key = libp2p_crypto_private_key_new(); struct RsaPrivateKey rsa_private_key = {0}; + char* orig_peer_id = "QmbTyKkUuv6yaSpTuCFq1Ft6Q3g4wTtFJk1BLGMPRdAEP8"; + size_t orig_peer_id_size = strlen(orig_peer_id); + unsigned char hashed[32]; + size_t final_id_size = 1600; + unsigned char final_id[final_id_size]; - // convert from base64 // 1) take the private key and turn it back into bytes (decode base 64) decode_base64_size = libp2p_crypto_encoding_base64_decode_size(strlen(orig_priv_key)); decode_base64 = (unsigned char*)malloc(decode_base64_size); memset(decode_base64, 0, decode_base64_size); - int retVal = libp2p_crypto_encoding_base64_decode((unsigned char*)orig_priv_key, strlen(orig_priv_key), &decode_base64[0], decode_base64_size, &decode_base64_size); - if (retVal == 0) + if (!libp2p_crypto_encoding_base64_decode((unsigned char*)orig_priv_key, strlen(orig_priv_key), &decode_base64[0], decode_base64_size, &decode_base64_size)) goto exit; - // the first 5 bytes [0-4] are protobuf metadata before the DER encoded private key - // byte 0 is "Tag 1 which is a varint" - // byte 1 is the value of the varint - // byte 2 is "Tag 2 which is a type 2, length delimited field" - // bytes 3 & 4 is a varint with the value of 1191, which is the number of bytes that follow - if (!libp2p_crypto_private_key_protobuf_decode(decode_base64, decode_base64_size, &private_key)) goto exit; - // 2) take the bytes of the private key and turn it back into a private key struct + // 2) take the bytes of the private key and turn it back into an RSA private key struct + //TODO: should verify that this key is RSA if (!libp2p_crypto_encoding_x509_der_to_private_key(private_key->data, private_key->data_size, &rsa_private_key)) goto exit; @@ -41,10 +40,7 @@ int test_protobuf_private_key() { goto exit; // 3) grab the public key, hash it, then base58 it - unsigned char hashed[32]; ID_FromPK_non_null_terminated((char*)hashed, (unsigned char*)rsa_private_key.public_key_der, rsa_private_key.public_key_length); - size_t final_id_size = 1600; - unsigned char final_id[final_id_size]; memset(final_id, 0, final_id_size); if (!PrettyID(final_id, &final_id_size, hashed, 32)) goto exit; diff --git a/test/crypto/test_rsa.h b/test/crypto/test_rsa.h index e8098af..8b9054b 100644 --- a/test/crypto/test_rsa.h +++ b/test/crypto/test_rsa.h @@ -8,7 +8,7 @@ #include "libp2p/crypto/rsa.h" #include "libp2p/crypto/encoding/base64.h" #include "libp2p/crypto/encoding/x509.h" -#include "libp2p/peerutils.h" +#include "libp2p/crypto/peerutils.h" /** @@ -123,9 +123,11 @@ int test_public_der_to_private_der() { int test_crypto_rsa_public_key_to_peer_id() { // this is the base64 encoded private key from the config file - char* orig_priv_key = "CAASpwkwggSjAgEAAoIBAQDTDJBWjDzS/HxDNOHazvzH2bu9CPMVHUrrvKRdBUM5ansL6/CC3MVZ6HVm4O6QHRapN6EF2CbrTgI4KBOXIL125Xo8MlROnyfXYk3O5q2tgwL/MbW8kXjtkyCfBak7MUoLOdLU7Svg0gkl3l+uDAiDcCLnwJVcFfq9ch6z4wMOhYJqE5dtx0uXxn6IuKWl1B69FTvBXCc0thw8Rw54b941FDcsBH5ttV9mRNCJym3poZ5qalNgXlxoIIB+PUx5QD+aq7KMJdpAX8HkapBntCOahP/QUceRmma0grlZLeYkH6/oi/hIrM6se3KUZ+F6tBuDFys8UAZy/X2BCUbKjbxtAgMBAAECggEANWfQfpYuLhXGPBt9q6kFPm1SnJtPJ+CpvM2XqhJS2IyhZnrl+bd0GTRBwS7aL42s1lVFYf04nAK5fQxnKK8YQqX/MIxr2RldM5ukpN6qxGWKtJkXrAgD2dqJPrRoBpqKahzPxSHfIJ0Fw5dqDtjsrpYJvyt0oEDPmnDuZAbmFx4sJqnesPNhKxtRMBx1+yxGVuRVJjHcqAgqPqwNiuoMEaYMY+G9yzT6vza8ovCpbX7BBIgM5fAT9PD8TBG//Vu9THvj/ZomiVG2qv6RL0qQyVb+DUzPZz1amBsSvahtXCl72jA3JwAZ943RxSR66P934S0ashkVwLUi46z/EAbJ4QKBgQDojGIO07BEVL2+7VxlGL9XGZQp4Y3qlhh2zDDQGwkCq/KQ+BdNYWitPwqRl9GqFLgpmeQIhyHTOa/IThx+AXGKVQ24ROH+skUs4IbO6R3qY7BKtb5lkZE/Yln09x70BBngUYAzh/rtnsXO3cl1x2XDDqUbCwlGcDAs8Jh/6UnvQwKBgQDoVSQs7Uq9MJCGIUM2bixX89tHzSxq5mn9wMD3/XRVfT5Ua8YkYBuzcmlcT39N7L5BwuyFqX3Vi7lv/Ya/qaQP6XkrZ8W1OAaTlYewfE5ZgknJqSpXcNWhABKeNmqndvqyQ/8HNCv/j8AdraGB2DGO57Xso5J0CQ43W/U9+QIyjwKBgHLL2hw3o+wXaRO3WMUPUmVM2zdRgR0suybp5a7Vqb0H5NZrohUw4NulIzJ8H6Q2VjMzJL6Q9sGu2HepF6ecTtBa7ErqtiVlG4Dr1aCOs5XhYEWBMlwxX+JKSt4Cn+UVoTB7Cy5lEhn7JurX0Xuy0ylXMWoIKKv89cs5eg6quzTBAoGAaq9eEztLjKCWXOE9SetBdYnG8aunb9cqaJlwgu/h0bfXPVDYBbAUSEyLURY4MQI7Q1tM3Pu9iqfEmUZj7/LoIV5mg6X9RX/alT6etk3+dF+9nlqN1OU9U9cCtZ/rTcb2y5EptJcidRH/eCFY/pTV/PcttOJPx/S4kHcroC+N8MUCgYEA6DA5QHxHfNN6Nxv+pEzy2DIxFe9RrBxS+KPBsra1C8jgdeMf4EmfU0Nox92V0q0bRrD5ztqQwSONI0hSRb1iiMWR6MuFnAFajUJfASjjIlZ6nIQjQslI7vjlvYyyHS/p/Codxap+yJlTLWwVEOXp2D9pWwiMq1xEyf0TH1BosvM="; + //char* orig_priv_key = "CAASpwkwggSjAgEAAoIBAQDTDJBWjDzS/HxDNOHazvzH2bu9CPMVHUrrvKRdBUM5ansL6/CC3MVZ6HVm4O6QHRapN6EF2CbrTgI4KBOXIL125Xo8MlROnyfXYk3O5q2tgwL/MbW8kXjtkyCfBak7MUoLOdLU7Svg0gkl3l+uDAiDcCLnwJVcFfq9ch6z4wMOhYJqE5dtx0uXxn6IuKWl1B69FTvBXCc0thw8Rw54b941FDcsBH5ttV9mRNCJym3poZ5qalNgXlxoIIB+PUx5QD+aq7KMJdpAX8HkapBntCOahP/QUceRmma0grlZLeYkH6/oi/hIrM6se3KUZ+F6tBuDFys8UAZy/X2BCUbKjbxtAgMBAAECggEANWfQfpYuLhXGPBt9q6kFPm1SnJtPJ+CpvM2XqhJS2IyhZnrl+bd0GTRBwS7aL42s1lVFYf04nAK5fQxnKK8YQqX/MIxr2RldM5ukpN6qxGWKtJkXrAgD2dqJPrRoBpqKahzPxSHfIJ0Fw5dqDtjsrpYJvyt0oEDPmnDuZAbmFx4sJqnesPNhKxtRMBx1+yxGVuRVJjHcqAgqPqwNiuoMEaYMY+G9yzT6vza8ovCpbX7BBIgM5fAT9PD8TBG//Vu9THvj/ZomiVG2qv6RL0qQyVb+DUzPZz1amBsSvahtXCl72jA3JwAZ943RxSR66P934S0ashkVwLUi46z/EAbJ4QKBgQDojGIO07BEVL2+7VxlGL9XGZQp4Y3qlhh2zDDQGwkCq/KQ+BdNYWitPwqRl9GqFLgpmeQIhyHTOa/IThx+AXGKVQ24ROH+skUs4IbO6R3qY7BKtb5lkZE/Yln09x70BBngUYAzh/rtnsXO3cl1x2XDDqUbCwlGcDAs8Jh/6UnvQwKBgQDoVSQs7Uq9MJCGIUM2bixX89tHzSxq5mn9wMD3/XRVfT5Ua8YkYBuzcmlcT39N7L5BwuyFqX3Vi7lv/Ya/qaQP6XkrZ8W1OAaTlYewfE5ZgknJqSpXcNWhABKeNmqndvqyQ/8HNCv/j8AdraGB2DGO57Xso5J0CQ43W/U9+QIyjwKBgHLL2hw3o+wXaRO3WMUPUmVM2zdRgR0suybp5a7Vqb0H5NZrohUw4NulIzJ8H6Q2VjMzJL6Q9sGu2HepF6ecTtBa7ErqtiVlG4Dr1aCOs5XhYEWBMlwxX+JKSt4Cn+UVoTB7Cy5lEhn7JurX0Xuy0ylXMWoIKKv89cs5eg6quzTBAoGAaq9eEztLjKCWXOE9SetBdYnG8aunb9cqaJlwgu/h0bfXPVDYBbAUSEyLURY4MQI7Q1tM3Pu9iqfEmUZj7/LoIV5mg6X9RX/alT6etk3+dF+9nlqN1OU9U9cCtZ/rTcb2y5EptJcidRH/eCFY/pTV/PcttOJPx/S4kHcroC+N8MUCgYEA6DA5QHxHfNN6Nxv+pEzy2DIxFe9RrBxS+KPBsra1C8jgdeMf4EmfU0Nox92V0q0bRrD5ztqQwSONI0hSRb1iiMWR6MuFnAFajUJfASjjIlZ6nIQjQslI7vjlvYyyHS/p/Codxap+yJlTLWwVEOXp2D9pWwiMq1xEyf0TH1BosvM="; + char* orig_priv_key = "CAASqgkwggSmAgEAAoIBAQD0a4RI+bF/ov7IVOGSJ8dQfnK1DwM0gwVuJAd+3LXxIZEPZzsKIKia0TojDbTdLvOJ23wsaojTF/4bSzBK5otdAz8YSgez4vTRUV5pUqvCkK0dSJJ1DHTdrFUwvzlXuKbwNbvWyzjmKfeaE9a9YLzhrUIUTRvKyqhZXr++vMy3hw4fdtGUTJWeiqmoIuJWIZ1748Ff6LjcP7TdG7OvY4q+U9ilEJYdF4aM+TJY193zKp0GNWohunuVrtOUnL9VQaSSDbvGdFS1Mg9iCN6kRBQTHVQvFzvuEw/Y2LvoPH3yFG1zj6bDLWfOBhegy/6Zi6fi4E1UfgJNFN1sjWF+gZoHAgMBAAECggEBALTqBD9zuoMsJYQo99IT6X7WKZeE5i1vMYzF1Fp9iZpS6ylIkrW7WLFHXs3lblMtVoxazn2d2WrOXoLbU4KNROhy57fVy//FZMqufMBetc3NAqYjOmyy7KnLzj7Hu+0HO2GflEq3n4UV2TTNrGv+d7BfawLV1FV1TcjgzfKjkq/gMDCTPMgfT7lcF4TGSqv6Pgudp8RRn/R7EKOx+I8/XkJsZWP3XJ0zj4ciqDmKrX2j7wZMT8CH/8wfyg4NGk1+TN4xBB2CXgulIWJg5yhzu+JgbGnHEL/Ga+i40XJe+RnlKDpjQ+ZFyrOkmHpIldasjWNGFeKwLjzrDQfyDRwex5ECgYEA+fFGJ+zbi2YJwHDO/44PmvcoCWpho0ah7y+O5/LEVROTYEoNRqodLet+z+LMKDq/o2qTNaYJLiDGMBZzhqyJIFR5ZJ5MhgLloY1gL8s0a7KMWDbh7giiWSu5zqhB3Du8Tom+8bYZUxOL4zhzCGrFitRqiEIIjy1/c5qyRQZaZx8CgYEA+lf6tdO6kKiAOxm7sdZ3rEl4UGFY+tEqgivKwurLRIor0XDfhCKr1hCfsZggpR8SMLfjCuNEgKbceofcKMa8OtyDbMPRz0mYNkCELTUYA+r8Ib/LvleQApMcLn+TDNwEnGlglSrrF33RVAUK+i/WfSXUvZRVpLQpRmdAqHjJeBkCgYEA0+Zz/iFXOGW32slJFWxRWqYz8VeZk52saGY/l/I/9Yj1J2tgugo7VtUS3BiB0ZGNK3SNfaxYmBz9KYO/Sew5DYnQqTdz1SHboQ2FAMAcnznutlNBVFdJnKPvkX8g5yBV05gApFgoPECUFn2jOP2coMjZ0M97Bjgil9YNUWvDdS0CgYEA4beFs3+tzVRAGgl/tD7dNBgiRMchBTSmkSuO6+PrVmcGTxboUSk5qg7fDa9Ob9LuAcMrENwNHbpVPJ1WoeVePewpC14bxDxk4zWUd3ZRquaqYnud5obor4mYdUxNd+DAv447qQNDaLDmlkzdsuqDB9+eSzh9Z72RIYtjPwN5E7ECgYEAsbqkMZXfK1tTRfduX+7KOlPMfcSr29X6nuDglcna4dHec6FAOzp3xL2722nnFt6gygc7pErrm0m0Wd/6BMTb4T3+GYwkDiMjM2CsTZYjpzrUri/VfRR509rScxHVR0/1PTFWN0K0+VZbEAyXDbbs4opq40tW0dWtcKxaNlimMw8="; // this is the peer id from the config file - char* orig_peer_id = "QmRskXriTSRjAftYX7QG1i1jAhouz5AHaLYZKNhEWRu5Fq"; + //char* orig_peer_id = "QmRskXriTSRjAftYX7QG1i1jAhouz5AHaLYZKNhEWRu5Fq"; + char* orig_peer_id = "QmbTyKkUuv6yaSpTuCFq1Ft6Q3g4wTtFJk1BLGMPRdAEP8"; size_t orig_peer_id_size = strlen(orig_peer_id); // if we take the private key, retrieve the public key, hash it, we should come up with the peer id diff --git a/test/test_multistream.h b/test/test_multistream.h new file mode 100644 index 0000000..82a086e --- /dev/null +++ b/test/test_multistream.h @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + +#include "libp2p/net/multistream.h" + +int test_multistream_connect() { + int retVal = 0, socket_fd = -1; + char* response; + size_t response_size; + + socket_fd = libp2p_net_multistream_connect("www.jmjatlanta.com", 4001); + if (socket_fd < 0) + goto exit; + + // try to respond something, perhaps either the protocol id or the ls command + //const unsigned char* out = "/multistream/1.0.0\n"; + const unsigned char* out = "ls"; + + if (libp2p_net_multistream_send(socket_fd, out, strlen((char*)out)) <= 0) + goto exit; + + // retrieve response + retVal = libp2p_net_multistream_receive(socket_fd, &response, &response_size); + if (retVal <= 0) + goto exit; + + retVal = 1; + + exit: + + return retVal > 0; +} diff --git a/test/test_secio.h b/test/test_secio.h new file mode 100644 index 0000000..66e4701 --- /dev/null +++ b/test/test_secio.h @@ -0,0 +1,55 @@ +#include + +#include "libp2p/secio/secio.h" + + +int test_secio_handshake() { + int retVal = 0; + size_t decode_base64_size = 0; + unsigned char* decode_base64; + // 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 + char* orig_priv_key = "CAASqgkwggSmAgEAAoIBAQD0a4RI+bF/ov7IVOGSJ8dQfnK1DwM0gwVuJAd+3LXxIZEPZzsKIKia0TojDbTdLvOJ23wsaojTF/4bSzBK5otdAz8YSgez4vTRUV5pUqvCkK0dSJJ1DHTdrFUwvzlXuKbwNbvWyzjmKfeaE9a9YLzhrUIUTRvKyqhZXr++vMy3hw4fdtGUTJWeiqmoIuJWIZ1748Ff6LjcP7TdG7OvY4q+U9ilEJYdF4aM+TJY193zKp0GNWohunuVrtOUnL9VQaSSDbvGdFS1Mg9iCN6kRBQTHVQvFzvuEw/Y2LvoPH3yFG1zj6bDLWfOBhegy/6Zi6fi4E1UfgJNFN1sjWF+gZoHAgMBAAECggEBALTqBD9zuoMsJYQo99IT6X7WKZeE5i1vMYzF1Fp9iZpS6ylIkrW7WLFHXs3lblMtVoxazn2d2WrOXoLbU4KNROhy57fVy//FZMqufMBetc3NAqYjOmyy7KnLzj7Hu+0HO2GflEq3n4UV2TTNrGv+d7BfawLV1FV1TcjgzfKjkq/gMDCTPMgfT7lcF4TGSqv6Pgudp8RRn/R7EKOx+I8/XkJsZWP3XJ0zj4ciqDmKrX2j7wZMT8CH/8wfyg4NGk1+TN4xBB2CXgulIWJg5yhzu+JgbGnHEL/Ga+i40XJe+RnlKDpjQ+ZFyrOkmHpIldasjWNGFeKwLjzrDQfyDRwex5ECgYEA+fFGJ+zbi2YJwHDO/44PmvcoCWpho0ah7y+O5/LEVROTYEoNRqodLet+z+LMKDq/o2qTNaYJLiDGMBZzhqyJIFR5ZJ5MhgLloY1gL8s0a7KMWDbh7giiWSu5zqhB3Du8Tom+8bYZUxOL4zhzCGrFitRqiEIIjy1/c5qyRQZaZx8CgYEA+lf6tdO6kKiAOxm7sdZ3rEl4UGFY+tEqgivKwurLRIor0XDfhCKr1hCfsZggpR8SMLfjCuNEgKbceofcKMa8OtyDbMPRz0mYNkCELTUYA+r8Ib/LvleQApMcLn+TDNwEnGlglSrrF33RVAUK+i/WfSXUvZRVpLQpRmdAqHjJeBkCgYEA0+Zz/iFXOGW32slJFWxRWqYz8VeZk52saGY/l/I/9Yj1J2tgugo7VtUS3BiB0ZGNK3SNfaxYmBz9KYO/Sew5DYnQqTdz1SHboQ2FAMAcnznutlNBVFdJnKPvkX8g5yBV05gApFgoPECUFn2jOP2coMjZ0M97Bjgil9YNUWvDdS0CgYEA4beFs3+tzVRAGgl/tD7dNBgiRMchBTSmkSuO6+PrVmcGTxboUSk5qg7fDa9Ob9LuAcMrENwNHbpVPJ1WoeVePewpC14bxDxk4zWUd3ZRquaqYnud5obor4mYdUxNd+DAv447qQNDaLDmlkzdsuqDB9+eSzh9Z72RIYtjPwN5E7ECgYEAsbqkMZXfK1tTRfduX+7KOlPMfcSr29X6nuDglcna4dHec6FAOzp3xL2722nnFt6gygc7pErrm0m0Wd/6BMTb4T3+GYwkDiMjM2CsTZYjpzrUri/VfRR509rScxHVR0/1PTFWN0K0+VZbEAyXDbbs4opq40tW0dWtcKxaNlimMw8="; + struct PrivateKey* private_key = libp2p_crypto_private_key_new(); + struct RsaPrivateKey rsa_private_key = {0}; + char* orig_peer_id = "QmbTyKkUuv6yaSpTuCFq1Ft6Q3g4wTtFJk1BLGMPRdAEP8"; + size_t orig_peer_id_size = strlen(orig_peer_id); + unsigned char hashed[32]; + size_t final_id_size = 1600; + unsigned char final_id[final_id_size]; + + // 1) take the private key and turn it back into bytes (decode base 64) + decode_base64_size = libp2p_crypto_encoding_base64_decode_size(strlen(orig_priv_key)); + decode_base64 = (unsigned char*)malloc(decode_base64_size); + memset(decode_base64, 0, decode_base64_size); + + if (!libp2p_crypto_encoding_base64_decode((unsigned char*)orig_priv_key, strlen(orig_priv_key), &decode_base64[0], decode_base64_size, &decode_base64_size)) + goto exit; + + if (!libp2p_crypto_private_key_protobuf_decode(decode_base64, decode_base64_size, &private_key)) + goto exit; + + // 2) take the bytes of the private key and turn it back into an RSA private key struct + //TODO: should verify that this key is RSA + if (!libp2p_crypto_encoding_x509_der_to_private_key(private_key->data, private_key->data_size, &rsa_private_key)) + goto exit; + + // 2b) take the private key and fill in the public key DER + if (!libp2p_crypto_rsa_private_key_fill_public_key(&rsa_private_key)) + goto exit; + + + struct SecureSession secure_session; + + secure_session.host = "www.jmjatlanta.com"; + secure_session.port = 4001; + secure_session.traffic_type = TCP; + + if (!libp2p_secio_handshake(&secure_session, &rsa_private_key)) + goto exit; + + retVal = 1; + exit: + + return retVal; +} diff --git a/test/testit.c b/test/testit.c index d46faa2..cbf7568 100644 --- a/test/testit.c +++ b/test/testit.c @@ -1,11 +1,12 @@ - #include - #include "crypto/test_rsa.h" #include "crypto/test_base58.h" #include "crypto/test_base32.h" +#include "crypto/test_key.h" +#include "test_secio.h" #include "test_mbedtls.h" +#include "test_multistream.h" const char* names[] = { "test_public_der_to_private_der", @@ -26,7 +27,10 @@ const char* names[] = { "test_base58_peer_address", //"test_mbedtls_pk_write_key_der", //"test_crypto_rsa_sign", - "test_crypto_encoding_base32_encode" + "test_crypto_encoding_base32_encode", + "test_protobuf_private_key", + "test_secio_handshake", + "test_multistream_connect" }; int (*funcs[])(void) = { @@ -48,7 +52,10 @@ int (*funcs[])(void) = { test_base58_peer_address, //test_mbedtls_pk_write_key_der, //test_crypto_rsa_sign, - test_crypto_encoding_base32_encode + test_crypto_encoding_base32_encode, + test_protobuf_private_key, + test_secio_handshake, + test_multistream_connect }; int testit(const char* name, int (*func)(void)) { @@ -98,8 +105,8 @@ int main(int argc, char** argv) { if (tests_ran == 0) printf("***** No tests found *****\n"); else { - if (counter > 0) { - printf("***** There were %d failed test(s) *****\n", counter); + if (tests_ran - counter > 0) { + printf("***** There were %d failed test(s) (%d successful) *****\n", tests_ran - counter, counter); } else { printf("All %d tests passed\n", tests_ran); }