Beginning of the buildout of secio

This commit is contained in:
John Jones 2017-02-01 07:52:09 -05:00
parent f54eab6824
commit 6d9a9e0e70
4 changed files with 268 additions and 0 deletions

View file

@ -0,0 +1,40 @@
#pragma once
struct Propose {
unsigned char* rand;
size_t rand_size;
unsigned char* public_key;
size_t public_key_size;
char* exchanges;
size_t exchanges_size;
char* ciphers;
size_t ciphers_size;
char* hashes;
size_t hashes_size;
};
/**
* retrieves the approximate size of an encoded version of the passed in struct
* @param in the struct to look at
* @reutrns the size of buffer needed
*/
size_t libp2p_secio_propose_protobuf_encode_size(struct Propose* in);
/**
* Encode the struct Propose in protobuf format
* @param in the struct to be encoded
* @param buffer where to put the results
* @param max_buffer_length the max to write
* @param bytes_written how many bytes were written to the buffer
* @returns true(1) on success, otherwise false(0)
*/
int libp2p_secio_propose_protobuf_encode(struct Propose* in, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written);
/**
* Turns a protobuf array into a Propose struct
* @param buffer the protobuf array
* @param max_buffer_length the length of the buffer
* @param out a pointer to the new struct Propose NOTE: this method allocates memory
* @returns true(1) on success, otherwise false(0)
*/
int libp2p_secio_propose_protobuf_decode(unsigned char* buffer, size_t max_buffer_length, struct Propose** out);

View file

@ -0,0 +1,10 @@
#pragma once
/**
* A secure connection
*/
struct SecureSession {
int socket_descriptor;
};

147
secio/propose.c Normal file
View file

@ -0,0 +1,147 @@
#include <stdio.h>
#include "libp2p/secio/propose.h"
// rand pubkey exchanges ciphers hashes
enum WireType secio_propose_message_fields[] = { WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED };
// epubkey signature
enum WireType secio_exchange_message_fields[] = { WIRETYPE_LENGTH_DELIMITED, WIRETYPE_LENGTH_DELIMITED };
struct Propose* libp2p_secio_propose_new() {
struct Propose* retVal = (struct Propose*)malloc(sizeof(struct propose));
if (retVal == NULL)
return NULL;
memset((void*)retVal, 0, sizeof(struct Propose));
return retVal;
}
void libp2p_secio_propose_free( struct Propose* in) {
if (in != NULL) {
if (in->rand != NULL)
free(in->rand);
if (in->public_key != NULL)
free(in->public_key);
if (in->ciphers != NULL)
free(in->ciphers);
if (in->exchanges != NULL)
free(in->exchanges);
if (in->hashes != NULL)
free(in->hashes);
free(in);
}
}
/**
* retrieves the approximate size of an encoded version of the passed in struct
* @param in the struct to look at
* @reutrns the size of buffer needed
*/
size_t libp2p_secio_propose_protobuf_encode_size(struct Propose* in) {
size_t retVal = 0;
retVal += 11 + in->rand_size;
retVal += 11 + in->public_key_size;
retVal += 11 + in->ciphers_size;
retVal += 11 + in->exchanges_size;
retVal += 11 + in->hashes_size;
return retVal;
}
/**
* Encode the struct Propose in protobuf format
* @param in the struct to be encoded
* @param buffer where to put the results
* @param max_buffer_length the max to write
* @param bytes_written how many bytes were written to the buffer
* @returns true(1) on success, otherwise false(0)
*/
int libp2p_secio_propose_protobuf_encode(struct Propose* in, unsigned char* buffer, size_t max_buffer_length, size_t* bytes_written) {
*bytes_written = 0;
int retVal;
size_t bytes_used;
// rand
if (!protobuf_encode_length_delimited(1, secio_propose_message_fields[0], in->rand, in->rand_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used))
return -1;
*bytes_written += bytes_used;
// public key
if (!protobuf_encode_length_delimited(2, secio_propose_message_fields[1], in->public_key, in->public_key_size, &buffer[*bytes_written], max_buffer_length - *bytes_written, &bytes_used))
return -1;
*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 -1;
*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 -1;
*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 -1;
*bytes_written += bytes_used;
return 1;
}
/**
* Turns a protobuf array into a Propose struct
* @param buffer the protobuf array
* @param buffer_length the length of the buffer
* @param out a pointer to the new struct Propose NOTE: this method allocates memory
* @returns true(1) on success, otherwise false(0)
*/
int libp2p_secio_propose_protobuf_decode(unsigned char* buffer, size_t buffer_length, struct Propose** out) {
size_t pos = 0;
int retVal = 0;
unsigned char* temp_buffer = NULL;
size_t temp_size;
if (libp2p_secio_propose_new(out) == 0)
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): // rand
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->rand), &((*out)->rand_size), &bytes_read) == 0)
goto exit;
pos += bytes_read;
break;
case (2): // public key
if (protobuf_decode_length_delimited(&buffer[pos], buffer_length - pos, (char**)&((*out)->public_key), &((*out)->public_key_size), &bytes_read) == 0)
goto exit;
pos += bytes_read;
break;
case (3): // 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;
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;
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;
pos += bytes_read;
break;
}
}
retVal = 1;
exit:
if (retVal == 0) {
libp2p_secio_propose_free(*out);
}
if (temp_buffer != NULL)
free(temp_buffer);
return retVal;
}

71
secio/secio.c Normal file
View file

@ -0,0 +1,71 @@
#include <stdio.h>
#include "libp2p/secio/secio.h"
const char* SupportedExchanges = "P-256,P-384,P-521";
const char* SupportedCiphers = "AES-256,AES-128,Blowfish";
const char* SupportedHashes = "SHA256,SHA512";
/***
* Create a new SecureSession struct
* @returns a pointer to a new SecureSession object
*/
struct SecureSession* libp2p_secio_secure_session_new() {
struct SecureSession* ss = (struct SecureSession*) malloc(sizeof(struct SecureSession));
if (ss == NULL)
return NULL;
ss->socket_descriptor = -1;
return ss;
}
/***
* Clean up resources from a SecureSession struct
* @param in the SecureSession to be deallocated
*/
void libp2p_secio_secure_session_free(struct SecureSession* in) {
//TODO: should we close the socket?
free(in);
}
/***
* 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) {
// generate 16 byte nonce
char nonceOut[16];
if (!generateNonce(nonceOut, 16))
return 0;
// will need:
// public key
// supported exchanges
// supported ciphers
// supported hashes
// send request
// receive response
// get public key
// generate their peer id
// negotiate encryption parameters NOTE: SelectBest must match, otherwise this won't work
// curve
// cipher
// hash
// prepare exchange of encryption parameters
// send
// receive
// parse and verify
// generate keys for mac and encryption
// send expected message (local nonce) to verify encryption works
}