diff --git a/crypto/ephemeral.c b/crypto/ephemeral.c index 6ffecb9..f7110c0 100644 --- a/crypto/ephemeral.c +++ b/crypto/ephemeral.c @@ -191,6 +191,7 @@ int libp2p_crypto_ephemeral_keypair_generate(char* curve, struct EphemeralPrivat exit: + mbedtls_ecp_point_free(&point); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); mbedtls_ecdsa_free(&ctx); diff --git a/crypto/key.c b/crypto/key.c index 4f5e188..bfd7dc7 100644 --- a/crypto/key.c +++ b/crypto/key.c @@ -34,7 +34,7 @@ void libp2p_crypto_public_key_free(struct PublicKey* in) { * @param in the public key to examine * @returns the size in bytes */ -size_t libp2p_crypto_public_key_protobuf_encode_size(struct PublicKey* in) { +size_t libp2p_crypto_public_key_protobuf_encode_size(const struct PublicKey* in) { return 11 + 11 + in->data_size; } @@ -46,7 +46,7 @@ size_t libp2p_crypto_public_key_protobuf_encode_size(struct PublicKey* in) { * @param bytes_written how many bytes were used in the buffer * @returns true(1) on success, otherwise false(0) */ -int libp2p_crypto_public_key_protobuf_encode(struct PublicKey* in, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) { +int libp2p_crypto_public_key_protobuf_encode(const struct PublicKey* in, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) { // data & data_size size_t bytes_used = 0; *bytes_written = 0; @@ -130,6 +130,24 @@ void libp2p_crypto_private_key_free(struct PrivateKey* in) { } } +int libp2p_crypto_private_key_protobuf_encode_size(struct PrivateKey* in) { + return 22 + in->data_size; +} + +int libp2p_crypto_private_key_protobuf_encode(struct PrivateKey* in, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) { + *bytes_written = 0; + size_t bytes_used; + // type (RSA vs ED25519) + if (!protobuf_encode_varint(1, WIRETYPE_VARINT, in->type, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used)) + return 0; + *bytes_written += bytes_used; + // private key + if (!protobuf_encode_length_delimited(2, WIRETYPE_LENGTH_DELIMITED, in->data, in->data_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used)) + return 0; + *bytes_written += bytes_used; + return 1; +} + /** * Unmarshal a private key from a protobuf * @param buffer the protobuf diff --git a/crypto/rsa.c b/crypto/rsa.c index d83ea38..d642192 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -215,16 +215,38 @@ int libp2p_crypto_rsa_private_key_fill_public_key(struct RsaPrivateKey* private_ return 1; } +struct RsaPrivateKey* libp2p_crypto_rsa_rsa_private_key_new() { + struct RsaPrivateKey* out = (struct RsaPrivateKey*)malloc(sizeof(struct RsaPrivateKey)); + if (out != NULL) { + out->D = 0; + out->DP = 0; + out->DQ = 0; + out->E = 0; + out->N = 0; + out->P = 0; + out->Q = 0; + out->QP = 0; + out->der = NULL; + out->public_key_length = 0; + out->public_key_der = NULL; + out->public_key_length = 0; + } + return out; +} + /*** * Free resources used by RsaPrivateKey * @param private_key the resources * @returns true(1) */ int libp2p_crypto_rsa_rsa_private_key_free(struct RsaPrivateKey* private_key) { - if (private_key->der != NULL) - free(private_key->der); - if (private_key->public_key_der != NULL) - free(private_key->public_key_der); + if (private_key != NULL) { + if (private_key->der != NULL) + free(private_key->der); + if (private_key->public_key_der != NULL) + free(private_key->public_key_der); + free(private_key); + } return 1; } diff --git a/include/libp2p/crypto/key.h b/include/libp2p/crypto/key.h index 12355b7..4ab75ac 100644 --- a/include/libp2p/crypto/key.h +++ b/include/libp2p/crypto/key.h @@ -28,6 +28,8 @@ 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); +size_t libp2p_crypto_public_key_protobuf_encode_size(const struct PublicKey* in); +int libp2p_crypto_public_key_protobuf_encode(const struct PublicKey* in, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written); int libp2p_crypto_private_key_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct PrivateKey** out); /** diff --git a/include/libp2p/crypto/rsa.h b/include/libp2p/crypto/rsa.h index ee44cf0..f7a513b 100644 --- a/include/libp2p/crypto/rsa.h +++ b/include/libp2p/crypto/rsa.h @@ -49,7 +49,7 @@ int libp2p_crypto_rsa_private_key_fill_public_key(struct RsaPrivateKey* private_ * @returns 0 */ int libp2p_crypto_rsa_rsa_private_key_free(struct RsaPrivateKey* private_key); - +struct RsaPrivateKey* libp2p_crypto_rsa_rsa_private_key_new(); /** * sign a message * @param private_key the private key diff --git a/net/multistream.c b/net/multistream.c index 8732727..a9f2e24 100644 --- a/net/multistream.c +++ b/net/multistream.c @@ -1,5 +1,7 @@ #include +#include #include +#include #include "libp2p/net/p2pnet.h" #include "varint.h" @@ -45,7 +47,7 @@ int libp2p_net_multistream_receive(int socket_fd, char** results, size_t* result size_t buffer_size = 65535; char buffer[buffer_size]; char* pos = buffer; - int num_bytes = 0; + size_t num_bytes_requested = 0, left = 0, already_read = 0; // first read the varint while(1) { @@ -54,25 +56,39 @@ int libp2p_net_multistream_receive(int socket_fd, char** results, size_t* result pos[0] = c; if (c >> 7 == 0) { pos[1] = 0; - num_bytes = varint_decode((unsigned char*)buffer, strlen(buffer), NULL); + num_bytes_requested = varint_decode((unsigned char*)buffer, strlen(buffer), NULL); break; } pos++; } - if (num_bytes <= 0) + if (num_bytes_requested <= 0) return 0; - // now read the number of bytes we've found - bytes = socket_read(socket_fd, buffer, num_bytes, 0); + left = num_bytes_requested; + do { + bytes = socket_read(socket_fd, &buffer[already_read], left, 0); + if (bytes < 0) { + bytes = 0; + if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { + // do something intelligent + } else { + return 0; + } + } + left = left - bytes; + already_read += bytes; + } while (left > 0); - if (bytes == 0) + if (already_read != num_bytes_requested) return 0; // parse the results, removing the leading size indicator - *results = malloc(bytes); - memcpy(*results, buffer, bytes); - *results_size = bytes; - return bytes; + *results = malloc(num_bytes_requested); + if (*results == NULL) + return 0; + memcpy(*results, buffer, num_bytes_requested); + *results_size = num_bytes_requested; + return num_bytes_requested; } diff --git a/secio/propose.c b/secio/propose.c index fce5c24..784e305 100644 --- a/secio/propose.c +++ b/secio/propose.c @@ -77,14 +77,14 @@ int libp2p_secio_propose_protobuf_encode(struct Propose* in, unsigned char* buff if (!protobuf_encode_length_delimited(2, secio_propose_message_fields[1], (char*)in->public_key, in->public_key_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used)) return 0; *bytes_written += bytes_used; - // 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)) - return 0; - *bytes_written += bytes_used; // 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)) return 0; *bytes_written += bytes_used; + // 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)) + return 0; + *bytes_written += bytes_used; // hashes if (!protobuf_encode_length_delimited(5, secio_propose_message_fields[4], in->hashes, in->hashes_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used)) return 0; @@ -130,18 +130,18 @@ int libp2p_secio_propose_protobuf_decode(unsigned char* buffer, size_t buffer_le pos += bytes_read; got_something = 1; break; - case (3): // ciphers + case (3): // exchanges + if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->exchanges), &((*out)->exchanges_size), &bytes_read) == 0) + goto exit; + pos += bytes_read; + got_something = 1; + break; + case (4): // ciphers if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->ciphers), &((*out)->ciphers_size), &bytes_read) == 0) goto exit; pos += bytes_read; got_something = 1; break; - case (4): // exchanges - if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->exchanges), &((*out)->exchanges_size), &bytes_read) == 0) - goto exit; - pos += bytes_read; - got_something = 1; - break; case (5): // hashes if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->hashes), &((*out)->hashes_size), &bytes_read) == 0) goto exit; diff --git a/secio/secio.c b/secio/secio.c index 66448a0..c446be4 100644 --- a/secio/secio.c +++ b/secio/secio.c @@ -140,8 +140,8 @@ int libp2p_secio_select_best(int order, const char* local_list, int local_list_s if (order == 0) { libp2p_secio_string_allocate(lead_head->string, results); - libp2p_utils_string_list_free(lead_head); - return 1; + match = 1; + goto exit; } // this list doesn't match. Do further investigation @@ -158,6 +158,7 @@ int libp2p_secio_select_best(int order, const char* local_list, int local_list_s while ( lead != NULL ) { while (follower != NULL) { if (strcmp(lead->string, follower->string) == 0) { + libp2p_secio_string_allocate(lead->string, results); match = 1; break; } @@ -168,9 +169,12 @@ int libp2p_secio_select_best(int order, const char* local_list, int local_list_s follower = follower_head; lead = lead->next; } - if (!match) - return 0; - return 1; + exit: + if (lead_head != NULL) + libp2p_utils_string_list_free(lead_head); + if (follower_head != NULL) + libp2p_utils_string_list_free(follower_head); + return match; } /** @@ -424,9 +428,14 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si if ( (errno == EAGAIN) || (errno == EWOULDBLOCK)) { // TODO: use epoll or select to wait for socket to be writable } else { + fprintf(stderr, "Error in libp2p_secio_read: %s\n", strerror(errno)); return 0; } } + if (read == 0) { + fprintf(stderr, "Reading numbers: [%02x]", size[read]); + } + fprintf(stderr, " [%02x]", size[read]); if (read == 0 && size[0] == 10) { // a spurious \n // write over this value by not adding it @@ -436,9 +445,9 @@ int libp2p_secio_read(struct SecureSession* session, unsigned char** results, si } } while (left > 0); // now read the number of bytes we've found, minus the 4 that we just read + fprintf(stderr, " Before ntohl: %u", buffer_size); buffer_size = ntohl(buffer_size); - // JMJ - fprintf(stderr, "which switching bits results in %u.\n", buffer_size); + fprintf(stderr, " After: %u\n", buffer_size); if (buffer_size == 0) return 0; @@ -490,8 +499,9 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat unsigned char* exchange_out_protobuf; size_t exchange_out_protobuf_size; struct Exchange* exchange_in; - struct Libp2pVector* char_buffer; + struct Libp2pVector* char_buffer = NULL; struct StretchedKey* k1 = NULL, *k2 = NULL; + char* remote_peer_id = NULL; const unsigned char* protocol = (unsigned char*)"/secio/1.0.0\n"; @@ -501,7 +511,7 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat // we should get back the secio confirmation bytes_written = libp2p_net_multistream_receive(local_session->socket_descriptor, (char**)&results, &results_size); - if (bytes_written < 1 || strstr((char*)results, "secio") == NULL) + if (bytes_written < 5 || strstr((char*)results, "secio") == NULL) goto exit; free(results); @@ -523,10 +533,19 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat pub_key.type = KEYTYPE_RSA; pub_key.data_size = private_key->public_key_length; pub_key.data = malloc(pub_key.data_size); + memcpy(pub_key.data, private_key->public_key_der, private_key->public_key_length); results_size = libp2p_crypto_public_key_protobuf_encode_size(&pub_key); results = malloc(results_size); - if (libp2p_crypto_public_key_protobuf_encode(&pub_key, results, result_size, &results_size) == 0) + if (results == NULL) { + free(pub_key.data); goto exit; + } + if (libp2p_crypto_public_key_protobuf_encode(&pub_key, results, results_size, &results_size) == 0) { + free(pub_key.data); + goto exit; + } + free(pub_key.data); + propose_out->public_key_size = results_size; propose_out->public_key = malloc(results_size); memcpy(propose_out->public_key, results, results_size); @@ -562,7 +581,6 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat 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); @@ -572,12 +590,14 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat libp2p_secio_hash(propose_out, order_hash_out); order = libp2p_secio_bytes_compare((char*)order_hash_in, (char*)order_hash_out, 32); // curve - libp2p_secio_select_best(order, propose_out->exchanges, propose_out->exchanges_size, propose_in->exchanges, propose_in->exchanges_size, &local_session->chosen_curve); + if (libp2p_secio_select_best(order, propose_out->exchanges, propose_out->exchanges_size, propose_in->exchanges, propose_in->exchanges_size, &local_session->chosen_curve) == 0) + goto exit; // cipher - libp2p_secio_select_best(order, propose_out->ciphers, propose_out->ciphers_size, propose_in->ciphers, propose_in->ciphers_size, &local_session->chosen_cipher); + if (libp2p_secio_select_best(order, propose_out->ciphers, propose_out->ciphers_size, propose_in->ciphers, propose_in->ciphers_size, &local_session->chosen_cipher) == 0) + goto exit; // hash - libp2p_secio_select_best(order, propose_out->hashes, propose_out->hashes_size, propose_in->hashes, propose_in->hashes_size, &local_session->chosen_hash); - + if (libp2p_secio_select_best(order, propose_out->hashes, propose_out->hashes_size, propose_in->hashes, propose_in->hashes_size, &local_session->chosen_hash) == 0) + goto exit; // prepare exchange of encryption parameters struct SecureSession remote_session; @@ -614,6 +634,7 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat priv.data_size = private_key->der_length; libp2p_secio_sign(&priv, (char*)char_buffer->buffer, char_buffer->buffer_size, &exchange_out->signature, &exchange_out->signature_size); libp2p_utils_vector_free(char_buffer); + char_buffer = NULL; exchange_out_protobuf_size = libp2p_secio_exchange_protobuf_encode_size(exchange_out); exchange_out_protobuf = (unsigned char*)malloc(exchange_out_protobuf_size); @@ -642,6 +663,7 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat 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); + char_buffer = NULL; // 2.2 generate shared key NOTE: this was done above @@ -679,6 +701,12 @@ int libp2p_secio_handshake(struct SecureSession* local_session, struct RsaPrivat free(propose_out_bytes); if (results != NULL) free(results); + if (char_buffer != NULL) + libp2p_utils_vector_free(char_buffer); + if (public_key != NULL) + libp2p_crypto_public_key_free(public_key); + if (remote_peer_id != NULL) + free(remote_peer_id); libp2p_secio_propose_free(propose_out); libp2p_secio_propose_free(propose_in); diff --git a/test/test_secio.h b/test/test_secio.h index 309fb01..be1557d 100644 --- a/test/test_secio.h +++ b/test/test_secio.h @@ -13,12 +13,13 @@ int test_secio_handshake() { 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="; char* orig_peer_id = "QmbTyKkUuv6yaSpTuCFq1Ft6Q3g4wTtFJk1BLGMPRdAEP8"; size_t orig_peer_id_size = strlen(orig_peer_id); - struct RsaPrivateKey rsa_private_key = {0}; + struct RsaPrivateKey* rsa_private_key = NULL; unsigned char hashed[32]; size_t final_id_size = 1600; unsigned char final_id[final_id_size]; - struct PrivateKey* private_key = libp2p_crypto_private_key_new(); + struct PrivateKey* private_key = NULL; + struct SecureSession secure_session = {0}; // 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)); @@ -33,16 +34,14 @@ int test_secio_handshake() { // 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)) + rsa_private_key = libp2p_crypto_rsa_rsa_private_key_new(); + 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)) + 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; @@ -53,13 +52,26 @@ int test_secio_handshake() { goto exit; } - if (!libp2p_secio_handshake(&secure_session, &rsa_private_key)) { + if (!libp2p_secio_handshake(&secure_session, rsa_private_key)) { fprintf(stderr, "test_secio_handshake: Unable to do handshake\n"); goto exit; } retVal = 1; exit: - + if (secure_session.ephemeral_public_key != NULL) + free(secure_session.ephemeral_public_key); + if (secure_session.chosen_cipher != NULL) + free(secure_session.chosen_cipher); + if (secure_session.chosen_curve != NULL) + free(secure_session.chosen_curve); + if (secure_session.chosen_hash != NULL) + free(secure_session.chosen_hash); + if (private_key != NULL) + libp2p_crypto_private_key_free(private_key); + if (decode_base64 != NULL) + free(decode_base64); + if (rsa_private_key != NULL) + libp2p_crypto_rsa_rsa_private_key_free(rsa_private_key); return retVal; }