Beginning of the buildout of secio
This commit is contained in:
parent
f54eab6824
commit
6d9a9e0e70
4 changed files with 268 additions and 0 deletions
40
include/libp2p/secio/propose.h
Normal file
40
include/libp2p/secio/propose.h
Normal 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);
|
10
include/libp2p/secio/secio.h
Normal file
10
include/libp2p/secio/secio.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A secure connection
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct SecureSession {
|
||||||
|
int socket_descriptor;
|
||||||
|
|
||||||
|
};
|
147
secio/propose.c
Normal file
147
secio/propose.c
Normal 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
71
secio/secio.c
Normal 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
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue