More progress on secio

This commit is contained in:
John Jones 2017-02-09 03:34:12 -05:00
parent 773c980f1f
commit c1620d1d8b
9 changed files with 151 additions and 52 deletions

View file

@ -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);

View file

@ -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

View file

@ -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 != 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;
}

View file

@ -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);
/**

View file

@ -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

View file

@ -1,5 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#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;
}

View file

@ -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,14 +130,14 @@ int libp2p_secio_propose_protobuf_decode(unsigned char* buffer, size_t buffer_le
pos += bytes_read;
got_something = 1;
break;
case (3): // ciphers
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->ciphers), &((*out)->ciphers_size), &bytes_read) == 0)
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): // exchanges
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->exchanges), &((*out)->exchanges_size), &bytes_read) == 0)
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;

View file

@ -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);

View file

@ -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;
}