Fixed signature verification, continuing with swarm connectivity
This commit is contained in:
parent
03a4b412dd
commit
746682ebef
6 changed files with 202 additions and 53 deletions
19
crypto/rsa.c
19
crypto/rsa.c
|
@ -32,6 +32,25 @@ struct PrivateKey* libp2p_crypto_rsa_to_private_key(struct RsaPrivateKey* in) {
|
|||
return out;
|
||||
}
|
||||
|
||||
/***
|
||||
* Convert a PrivateKey struct to an RsaPrivateKey struct
|
||||
* @param in the PrivateKey (NOTE: Must be of type KEYTYPE_RSA
|
||||
* @returns the RsaPrivateKey or NULL on error
|
||||
*/
|
||||
struct RsaPrivateKey* libp2p_crypto_private_key_to_rsa(struct PrivateKey* in) {
|
||||
struct RsaPrivateKey* out = NULL;
|
||||
if (in->type == KEYTYPE_RSA) {
|
||||
out = libp2p_crypto_rsa_rsa_private_key_new();
|
||||
out->der_length = in->data_size;
|
||||
out->der = in->data;
|
||||
if (!libp2p_crypto_rsa_private_key_fill_public_key(out)) {
|
||||
libp2p_crypto_rsa_rsa_private_key_free(out);
|
||||
out = NULL;
|
||||
}
|
||||
}
|
||||
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.
|
||||
|
|
|
@ -34,6 +34,13 @@ struct RsaPrivateKey {
|
|||
*/
|
||||
struct PrivateKey* libp2p_crypto_rsa_to_private_key(struct RsaPrivateKey* in);
|
||||
|
||||
/***
|
||||
* Convert a PrivateKey struct to an RsaPrivateKey struct
|
||||
* @param in the PrivateKey (NOTE: Must be of type KEYTYPE_RSA
|
||||
* @returns the RsaPrivateKey or NULL on error
|
||||
*/
|
||||
struct RsaPrivateKey* libp2p_crypto_private_key_to_rsa(struct PrivateKey* in);
|
||||
|
||||
/**
|
||||
* generate a new private key
|
||||
* @param private_key the new private key
|
||||
|
|
|
@ -10,3 +10,49 @@
|
|||
* @returns a Stream
|
||||
*/
|
||||
struct Stream* libp2p_net_connection_new(int fd, char* ip, int port);
|
||||
|
||||
/***
|
||||
* These are put here to allow implementations of struct Stream
|
||||
* to use them. They should not be called by external code
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Close a network connection
|
||||
* @param stream_context the ConnectionContext
|
||||
* @returns true(1) on success, false(0) otherwise
|
||||
*/
|
||||
int libp2p_net_connection_close(void* stream_context);
|
||||
|
||||
/***
|
||||
* Check and see if there is anything waiting on this network connection
|
||||
* @param stream_context the ConnectionContext
|
||||
* @returns number of bytes waiting, or -1 on error
|
||||
*/
|
||||
int libp2p_net_connection_peek(void* stream_context);
|
||||
|
||||
/**
|
||||
* Read from the network
|
||||
* @param stream_context the ConnectionContext
|
||||
* @param msg where to put the results
|
||||
* @returns true(1) on success, false(0) otherwise
|
||||
*/
|
||||
int libp2p_net_connection_read(void* stream_context, struct StreamMessage** msg, int timeout_secs);
|
||||
|
||||
/**
|
||||
* Reads a certain amount of bytes directly from the stream
|
||||
* @param stream_context the context
|
||||
* @param buffer where to put the results
|
||||
* @param buffer_size the number of bytes to read
|
||||
* @param timeout_secs number of seconds before a timeout
|
||||
* @returns number of bytes read, or -1 on error
|
||||
*/
|
||||
int libp2p_net_connection_read_raw(void* stream_context, uint8_t* buffer, int buffer_size, int timeout_secs);
|
||||
|
||||
/**
|
||||
* Writes to a stream
|
||||
* @param stream the stream context (usually a SessionContext pointer)
|
||||
* @param buffer what to write
|
||||
* @returns number of bytes written
|
||||
*/
|
||||
int libp2p_net_connection_write(void* stream_context, struct StreamMessage* msg);
|
||||
|
|
|
@ -220,6 +220,7 @@ int libp2p_net_multistream_write(void* stream_context, struct StreamMessage* inc
|
|||
memcpy(outgoing.data, varint, varint_size);
|
||||
memcpy(&outgoing.data[varint_size], incoming->data, incoming->data_size);
|
||||
// now ship it
|
||||
libp2p_logger_debug("multistream", "Attempting write %d bytes.\n", (int)outgoing.data_size);
|
||||
num_bytes = parent_stream->write(parent_stream->stream_context, &outgoing);
|
||||
// subtract the varint if all went well
|
||||
if (num_bytes == outgoing.data_size)
|
||||
|
|
170
secio/secio.c
170
secio/secio.c
|
@ -16,6 +16,7 @@
|
|||
#include "libp2p/secio/exchange.h"
|
||||
#include "libp2p/net/multistream.h"
|
||||
#include "libp2p/net/p2pnet.h"
|
||||
#include "libp2p/net/connectionstream.h"
|
||||
#include "libp2p/os/utils.h"
|
||||
#include "libp2p/crypto/ephemeral.h"
|
||||
#include "libp2p/crypto/sha1.h"
|
||||
|
@ -69,40 +70,6 @@ int libp2p_secio_shutdown(void* context) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
/***
|
||||
* Initiates a secio handshake. Use this method when you want to initiate a secio
|
||||
* session. This should not be used to respond to incoming secio requests
|
||||
* @param parent_stream the parent stream
|
||||
* @param remote_peer the remote peer
|
||||
* @param peerstore the peerstore
|
||||
* @param rsa_private_key the local private key
|
||||
* @returns a Secio Stream
|
||||
*/
|
||||
struct Stream* libp2p_secio_stream_new(struct Stream* parent_stream, struct Libp2pPeer* remote_peer, struct Peerstore* peerstore, struct RsaPrivateKey* rsa_private_key) {
|
||||
struct Stream* new_stream = libp2p_stream_new();
|
||||
if (new_stream != NULL) {
|
||||
struct SecioContext* ctx = (struct SecioContext*) malloc(sizeof(struct SecioContext));
|
||||
if (ctx == NULL) {
|
||||
libp2p_stream_free(new_stream);
|
||||
new_stream = NULL;
|
||||
return NULL;
|
||||
}
|
||||
new_stream->stream_context = ctx;
|
||||
ctx->stream = new_stream;
|
||||
ctx->session_context = remote_peer->sessionContext;
|
||||
ctx->peer_store = peerstore;
|
||||
ctx->private_key = rsa_private_key;
|
||||
new_stream->parent_stream = parent_stream;
|
||||
if (!libp2p_secio_send_protocol(ctx)
|
||||
|| !libp2p_secio_receive_protocol(ctx)
|
||||
|| !libp2p_secio_handshake(ctx)) {
|
||||
libp2p_stream_free(new_stream);
|
||||
new_stream = NULL;
|
||||
}
|
||||
}
|
||||
return new_stream;
|
||||
}
|
||||
|
||||
struct Libp2pProtocolHandler* libp2p_secio_build_protocol_handler(struct RsaPrivateKey* private_key, struct Peerstore* peer_store) {
|
||||
struct Libp2pProtocolHandler* handler = (struct Libp2pProtocolHandler*) malloc(sizeof(struct Libp2pProtocolHandler));
|
||||
if (handler != NULL) {
|
||||
|
@ -309,10 +276,19 @@ int libp2p_secio_select_best(int order, const char* local_list, int local_list_s
|
|||
* @param in the bytes that were signed
|
||||
* @param in_length the number of bytes
|
||||
* @param signature the signature that was given to us
|
||||
* @param signature_length the length of the signature
|
||||
* @returns true(1) if the signature is correct, false(0) otherwise
|
||||
*/
|
||||
int libp2p_secio_verify_signature(struct PublicKey* public_key, const unsigned char* in, size_t in_length, unsigned char* signature) {
|
||||
|
||||
// debugging:
|
||||
if (libp2p_logger_watching_class("secio")) {
|
||||
fprintf(stdout, "Verifying signature of %d bytes:", (int)in_length);
|
||||
for(int i = 0; i < 32; i++) {
|
||||
fprintf(stdout, " %02x", signature[i]);
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
if (public_key->type == KEYTYPE_RSA) {
|
||||
struct RsaPublicKey rsa_key = {0};
|
||||
rsa_key.der = (char*)public_key->data;
|
||||
|
@ -333,12 +309,24 @@ int libp2p_secio_verify_signature(struct PublicKey* public_key, const unsigned c
|
|||
* @returns true(1) on success, otherwise false(0)
|
||||
*/
|
||||
int libp2p_secio_sign(struct PrivateKey* private_key, const char* in, size_t in_length, unsigned char** signature, size_t* signature_size) {
|
||||
|
||||
if (private_key->type == KEYTYPE_RSA) {
|
||||
struct RsaPrivateKey rsa_key = {0};
|
||||
rsa_key.der = (char*)private_key->data;
|
||||
rsa_key.der_length = private_key->data_size;
|
||||
return libp2p_crypto_rsa_sign(&rsa_key, in, in_length, signature, signature_size);
|
||||
int retVal = libp2p_crypto_rsa_sign(&rsa_key, in, in_length, signature, signature_size);
|
||||
// debugging
|
||||
if (retVal && libp2p_logger_watching_class("secio")) {
|
||||
unsigned char* ptr = *signature;
|
||||
fprintf(stdout, "Signature generated from %d bytes:", (int)in_length);
|
||||
for(int i = 0; i < *signature_size; i++) {
|
||||
fprintf(stdout, " %02x", ptr[i]);
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// TODO: Implement this method for non-RSA
|
||||
return 0;
|
||||
}
|
||||
|
@ -722,6 +710,7 @@ int libp2p_secio_unencrypted_read(struct Stream* secio_stream, struct StreamMess
|
|||
return 0;
|
||||
}
|
||||
left = left - read_this_time;
|
||||
read += read_this_time;
|
||||
} while (left > 0);
|
||||
|
||||
m->data_size = buffer_size;
|
||||
|
@ -816,6 +805,7 @@ int libp2p_secio_encrypted_write(void* stream_context, struct StreamMessage* byt
|
|||
return 0;
|
||||
}
|
||||
|
||||
libp2p_logger_debug("secio", "About to write %d bytes.\n", (int)outgoing.data_size);
|
||||
int retVal = libp2p_secio_unencrypted_write(parent_stream, &outgoing);
|
||||
if (!retVal) {
|
||||
libp2p_logger_error("secio", "secio_unencrypted_write returned false\n");
|
||||
|
@ -1016,6 +1006,14 @@ int libp2p_secio_handshake(struct SecioContext* secio_context) {
|
|||
propose_out = libp2p_secio_propose_build(local_session->local_nonce, private_key,
|
||||
SupportedExchanges, SupportedCiphers, SupportedHashes);
|
||||
|
||||
if (libp2p_logger_watching_class("secio")) {
|
||||
fprintf(stdout, "Our public key: ");
|
||||
for(int i = 0; i < propose_out->public_key_size; i++) {
|
||||
fprintf(stdout, " %02x", propose_out->public_key[i]);
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
// protobuf the proposal
|
||||
propose_out_size = libp2p_secio_propose_protobuf_encode_size(propose_out);
|
||||
propose_out_bytes = (unsigned char*)malloc(propose_out_size);
|
||||
|
@ -1038,28 +1036,58 @@ int libp2p_secio_handshake(struct SecioContext* secio_context) {
|
|||
libp2p_logger_error("secio", "Unable to get the remote's Propose struct.\n");
|
||||
goto exit;
|
||||
} else {
|
||||
//libp2p_logger_debug("secio", "Received their propose struct.\n");
|
||||
libp2p_logger_debug("secio","Received their propose struct.\n");
|
||||
}
|
||||
|
||||
if (!libp2p_secio_propose_protobuf_decode(incoming->data, incoming->data_size, &propose_in)) {
|
||||
libp2p_logger_error("secio", "Unable to un-protobuf the remote's Propose struct\n");
|
||||
goto exit;
|
||||
}
|
||||
// we need the propose bytes for later, so saving them off
|
||||
propose_in_bytes = malloc(incoming->data_size);
|
||||
memcpy(propose_in_bytes, incoming->data, incoming->data_size);
|
||||
propose_in_size = incoming->data_size;
|
||||
|
||||
libp2p_stream_message_free(incoming);
|
||||
incoming = NULL;
|
||||
|
||||
// get their nonce
|
||||
if (propose_in->rand_size != 16)
|
||||
if (!libp2p_secio_propose_protobuf_decode(propose_in_bytes, propose_in_size, &propose_in)) {
|
||||
libp2p_logger_error("secio", "Unable to un-protobuf the remote's Propose struct\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// get their nonce
|
||||
if (propose_in->rand_size != 16) {
|
||||
libp2p_logger_error("secio", "Their nonce is not 16 bytes!\n");
|
||||
goto exit;
|
||||
}
|
||||
memcpy(local_session->remote_nonce, propose_in->rand, 16);
|
||||
|
||||
// get public key and put it in a struct PublicKey
|
||||
// debugging
|
||||
if (libp2p_logger_watching_class("secio")) {
|
||||
fprintf(stdout, "Our nonce:");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
fprintf(stdout, " %02x", local_session->local_nonce[i]);
|
||||
}
|
||||
fprintf(stdout, "\nTheir nonce:");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
fprintf(stdout, " %02x", local_session->remote_nonce[i]);
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
if (libp2p_logger_watching_class("secio")) {
|
||||
fprintf(stdout, "Their public key (length %d):", (int)propose_in->public_key_size);
|
||||
for(int i = 0; i < propose_in->public_key_size; i++) {
|
||||
fprintf(stdout, " %02x", propose_in->public_key[i]);
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
if (!libp2p_crypto_public_key_protobuf_decode(propose_in->public_key, propose_in->public_key_size, &public_key))
|
||||
goto exit;
|
||||
|
||||
// generate their peer id
|
||||
libp2p_crypto_public_key_to_peer_id(public_key, &local_session->remote_peer_id);
|
||||
|
||||
libp2p_logger_debug("secio", "Their Peer ID: %s.\n", local_session->remote_peer_id);
|
||||
|
||||
// pull the peer from the peerstore if it is there
|
||||
remote_peer = libp2p_secio_get_peer_or_add(peerstore, local_session);
|
||||
|
||||
|
@ -1082,6 +1110,12 @@ int libp2p_secio_handshake(struct SecioContext* secio_context) {
|
|||
|
||||
// build buffer to sign
|
||||
char_buffer_length = propose_in_size + propose_out_size + local_session->ephemeral_private_key->public_key->bytes_size - 1;
|
||||
if (libp2p_logger_watching_class("secio")) {
|
||||
fprintf(stdout, "Building buffer to sign.\n");
|
||||
fprintf(stdout, "Propose in size : %d\n", (int)propose_in_size);
|
||||
fprintf(stdout, "Propose out size : %d\n", (int)propose_out_size);
|
||||
fprintf(stdout, "Epemeral key size: %d\n", (int)local_session->ephemeral_private_key->public_key->bytes_size);
|
||||
}
|
||||
char_buffer = malloc(char_buffer_length);
|
||||
if (char_buffer == NULL)
|
||||
goto exit;
|
||||
|
@ -1108,7 +1142,7 @@ int libp2p_secio_handshake(struct SecioContext* secio_context) {
|
|||
libp2p_logger_error("secio", "Unable to write exchange_out\n");
|
||||
goto exit;
|
||||
} else {
|
||||
//libp2p_logger_debug("secio", "Sent exchange_out.\n");
|
||||
libp2p_logger_debug("secio", "Sent exchange_out. Size: %d.\n", bytes_written);
|
||||
}
|
||||
free(exchange_out_protobuf);
|
||||
exchange_out_protobuf = NULL;
|
||||
|
@ -1122,7 +1156,7 @@ int libp2p_secio_handshake(struct SecioContext* secio_context) {
|
|||
libp2p_peer_handle_connection_error(remote_peer);
|
||||
goto exit;
|
||||
} else {
|
||||
libp2p_logger_debug("secio", "Read exchange packet.\n");
|
||||
libp2p_logger_debug("secio", "Read exchange packet. Size: %d.\n", bytes_written);
|
||||
}
|
||||
libp2p_secio_exchange_protobuf_decode(incoming->data, incoming->data_size, &exchange_in);
|
||||
libp2p_stream_message_free(incoming);
|
||||
|
@ -1201,7 +1235,7 @@ int libp2p_secio_handshake(struct SecioContext* secio_context) {
|
|||
// send their nonce to verify encryption works
|
||||
outgoing.data = (uint8_t*)local_session->remote_nonce;
|
||||
outgoing.data_size = 16;
|
||||
if (libp2p_secio_encrypted_write(local_session, &outgoing) <= 0) {
|
||||
if (libp2p_secio_encrypted_write(secio_context, &outgoing) <= 0) {
|
||||
libp2p_logger_error("secio", "Encrytped write returned 0 or less.\n");
|
||||
goto exit;
|
||||
}
|
||||
|
@ -1209,7 +1243,7 @@ int libp2p_secio_handshake(struct SecioContext* secio_context) {
|
|||
// receive our nonce to verify encryption works
|
||||
libp2p_logger_log("secio", LOGLEVEL_DEBUG, "Receiving our nonce\n");
|
||||
results = NULL;
|
||||
int bytes_read = libp2p_secio_encrypted_read(secio_context->stream->stream_context, &incoming, 10);
|
||||
int bytes_read = libp2p_secio_encrypted_read(secio_context, &incoming, 10);
|
||||
if (bytes_read <= 0 || incoming == NULL) {
|
||||
libp2p_logger_error("secio", "Encrypted read returned %d\n", bytes_read);
|
||||
goto exit;
|
||||
|
@ -1263,3 +1297,43 @@ int libp2p_secio_handshake(struct SecioContext* secio_context) {
|
|||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/***
|
||||
* Initiates a secio handshake. Use this method when you want to initiate a secio
|
||||
* session. This should not be used to respond to incoming secio requests
|
||||
* @param parent_stream the parent stream
|
||||
* @param remote_peer the remote peer
|
||||
* @param peerstore the peerstore
|
||||
* @param rsa_private_key the local private key
|
||||
* @returns a Secio Stream
|
||||
*/
|
||||
struct Stream* libp2p_secio_stream_new(struct Stream* parent_stream, struct Libp2pPeer* remote_peer, struct Peerstore* peerstore, struct RsaPrivateKey* rsa_private_key) {
|
||||
struct Stream* new_stream = libp2p_stream_new();
|
||||
if (new_stream != NULL) {
|
||||
struct SecioContext* ctx = (struct SecioContext*) malloc(sizeof(struct SecioContext));
|
||||
if (ctx == NULL) {
|
||||
libp2p_stream_free(new_stream);
|
||||
new_stream = NULL;
|
||||
return NULL;
|
||||
}
|
||||
new_stream->stream_context = ctx;
|
||||
ctx->stream = new_stream;
|
||||
ctx->session_context = remote_peer->sessionContext;
|
||||
ctx->peer_store = peerstore;
|
||||
ctx->private_key = rsa_private_key;
|
||||
new_stream->parent_stream = parent_stream;
|
||||
new_stream->close = libp2p_secio_shutdown;
|
||||
new_stream->peek = libp2p_net_connection_peek;
|
||||
new_stream->read = libp2p_secio_encrypted_read;
|
||||
new_stream->read_raw = libp2p_net_connection_read_raw;
|
||||
new_stream->write = libp2p_secio_encrypted_write;
|
||||
if (!libp2p_secio_send_protocol(ctx)
|
||||
|| !libp2p_secio_receive_protocol(ctx)
|
||||
|| !libp2p_secio_handshake(ctx)) {
|
||||
libp2p_stream_free(new_stream);
|
||||
new_stream = NULL;
|
||||
}
|
||||
}
|
||||
return new_stream;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,8 @@ int test_dialer_dial() {
|
|||
int test_dialer_join_swarm() {
|
||||
int retVal = 0;
|
||||
|
||||
libp2p_logger_add_class("secio");
|
||||
libp2p_logger_add_class("multistream");
|
||||
// we need a dialer and a peer
|
||||
struct Dialer* dialer = NULL;
|
||||
// this is a base64 encoded private key. It makes it easier to test if it is in base64 form
|
||||
|
@ -97,7 +99,7 @@ int test_dialer_join_swarm() {
|
|||
if (!libp2p_crypto_private_key_protobuf_decode(decode_base64, decode_base64_size, &priv))
|
||||
goto exit;
|
||||
|
||||
//TODO turn PrivateKey into RsaPrivateKey
|
||||
rsa_private_key = libp2p_crypto_private_key_to_rsa(priv);
|
||||
|
||||
// 2) make the local peer
|
||||
local_peer = libp2p_peer_new();
|
||||
|
@ -126,10 +128,10 @@ int test_dialer_join_swarm() {
|
|||
exit:
|
||||
if (decode_base64 != NULL)
|
||||
free(decode_base64);
|
||||
libp2p_peer_free(local_peer);
|
||||
libp2p_peerstore_free(peerstore);
|
||||
libp2p_conn_dialer_free(dialer);
|
||||
libp2p_crypto_private_key_free(priv);
|
||||
//libp2p_peer_free(local_peer);
|
||||
//libp2p_peerstore_free(peerstore);
|
||||
//libp2p_conn_dialer_free(dialer);
|
||||
//libp2p_crypto_private_key_free(priv);
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue