Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: atchops_rsa_generate #409

Merged
merged 9 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/atchops/include/atchops/rsa_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ int atchops_rsa_key_public_key_clone(const atchops_rsa_key_public_key *src, atch
*/
int atchops_rsa_key_private_key_clone(const atchops_rsa_key_private_key *src, atchops_rsa_key_private_key *dst);

/**
* @brief Generate a new RSA 2048 key pair (public and private)
*
* @param public_key the public key struct to populate, assumed to be allocated and initialized. initialized via atchops_rsa_key_public_key_init
* @param private_key the private key struct to populate, assumed to be allocated and initialized. initialized via atchops_rsa_key_private_key_init
*/
int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa_key_private_key *private_key);

/**
* @brief Populate a public key struct from a base64 string
*
Expand Down
6 changes: 0 additions & 6 deletions packages/atchops/src/rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,9 +407,3 @@ exit: {
return ret;
}
}

int atchops_rsa_generate(atchops_rsa_key_public_key *public_key, atchops_rsa_key_private_key *private_key,
const unsigned int key_size) {
// TODO maybe also introduce `enum atchops_rsa_key_size` ?
return 1; // TODO: implement
}
241 changes: 234 additions & 7 deletions packages/atchops/src/rsa_key.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "atchops/rsa_key.h"
#include "atchops/base64.h"
#include "atchops/constants.h"
#include "atchops/mbedtls.h"
#include <atlogger/atlogger.h>
#include <stddef.h>
Expand All @@ -8,8 +9,6 @@

#define TAG "rsa_key"

#define BASE64_DECODED_KEY_BUFFER_SIZE 8192 // the max buffer size of a decoded RSA key

void atchops_rsa_key_public_key_init(atchops_rsa_key_public_key *public_key) {
/*
* 1. Validate arguments
Expand Down Expand Up @@ -177,6 +176,232 @@ int atchops_rsa_key_private_key_clone(const atchops_rsa_key_private_key *src, at
exit: { return ret; }
}

int atchops_rsa_key_generate(atchops_rsa_key_public_key *public_key, atchops_rsa_key_private_key *private_key) {
int ret = 1;

/*
* 1. Validate arguments
*/
if (public_key == NULL) {
ret = 1;
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "public_key is null\n");
return ret;
}

if (private_key == NULL) {
ret = 1;
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "private_key is null\n");
return ret;
}

/*
* 2. Variables
*/
mbedtls_entropy_context entropy;
mbedtls_entropy_init(&entropy);

mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ctr_drbg_init(&ctr_drbg);

mbedtls_pk_context pk;
mbedtls_pk_init(&pk);

const size_t public_key_base64_size = 1024; // 1024 bytes is sufficient size for a 2048 bit RSA key base64 encoded
char public_key_base64[public_key_base64_size];
memset(public_key_base64, 0, sizeof(char) * public_key_base64_size);

const size_t private_key_base64_size = 2048; // 2048 bytes is sufficient size for a 2048 bit RSA key base64 encoded
char private_key_base64[private_key_base64_size];
memset(private_key_base64, 0, sizeof(char) * private_key_base64_size);

unsigned char *private_key_non_base64 =
NULL; // holds the raw bytes of the 9 element SEQUENCE of the numbers (0, N, E, D, P, Q, DP, DQ, QP), free later

unsigned char *private_key_pkcs8 = NULL; // buffer for building the pkcs_8 formatted private key, free later
char *private_key_pkcs8_base64 = NULL; // to hold the base64-encoded pkcs 8 formatted private key, free later

const size_t temp_buf_size = 4096; // sufficient to hold a private RSA Key in format ----BEGIN ....
unsigned char temp_buf[temp_buf_size];

/*
* 3. Seed RNG
*/
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *)ATCHOPS_RNG_PERSONALIZATION,
strlen(ATCHOPS_RNG_PERSONALIZATION))) != 0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to seed random number generator\n");
goto exit;
}

/*
* 4. Use MbedTLS to generate RSA key pair
*/
if ((ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA))) != 0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to setup RSA key\n");
goto exit;
}

if ((ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(pk), mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537)) != 0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to generate RSA key\n");
goto exit;
}

/*
* 5. Write to public_key_base64 buffer
*/
memset(temp_buf, 0, sizeof(temp_buf));
if ((ret = mbedtls_pk_write_pubkey_pem(&pk, temp_buf, temp_buf_size)) != 0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to write public key\n");
goto exit;
}

size_t public_key_base64_len = 0;
char *begin = strstr((char *)temp_buf, "-----BEGIN PUBLIC KEY-----");
char *end = strstr((char *)temp_buf, "-----END PUBLIC KEY-----");
if (begin != NULL && end != NULL) {

begin += strlen("-----BEGIN PUBLIC KEY-----");
while (*begin == '\n' || *begin == '\r' || *begin == ' ')
begin++;

for (char *src = begin, *dest = public_key_base64; src < end; ++src) {
if (*src != '\n' && *src != '\r') {
*dest++ = *src;
public_key_base64_len++;
}
}
}

/*
* 6. Write to private_key_base64 buffer (PKCS#8 format)
*/
memset(temp_buf, 0, sizeof(unsigned char) * temp_buf_size);
if ((ret = mbedtls_pk_write_key_pem(&pk, temp_buf, temp_buf_size)) != 0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to write private key (PKCS#8 format)\n");
goto exit;
}

size_t private_key_base64_len = 0;
begin = strstr((char *)temp_buf, "-----BEGIN RSA PRIVATE KEY-----");
end = strstr((char *)temp_buf, "-----END RSA PRIVATE KEY-----");
if (begin != NULL && end != NULL) {
begin += strlen("-----BEGIN RSA PRIVATE KEY-----");
while (*begin == '\n' || *begin == '\r' || *begin == ' ')
begin++;

for (char *src = begin, *dest = private_key_base64; src < end; ++src) {
if (*src != '\n' && *src != '\r') {
*dest++ = *src;
private_key_base64_len++;
}
}
}

const size_t private_key_non_base64_size = atchops_base64_decoded_size(private_key_base64_len);
private_key_non_base64 = (unsigned char *)malloc(private_key_non_base64_size);
if (private_key_non_base64 == NULL) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for private_key_non_base64\n");
goto exit;
}

size_t private_key_non_base64_len = 0;
if ((ret = atchops_base64_decode((const unsigned char *)private_key_base64, private_key_base64_len,
private_key_non_base64, private_key_non_base64_size, &private_key_non_base64_len)) !=
0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to decode private key\n");
goto exit;
}

const size_t private_key_pkcs8_size = private_key_non_base64_len + 22;
private_key_pkcs8 = (unsigned char *)malloc(private_key_pkcs8_size);
if (private_key_pkcs8 == NULL) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for private_key_pkcs8\n");
goto exit;
}
memset(private_key_pkcs8, 0, sizeof(unsigned char) * private_key_pkcs8_size);


// https://lapo.it/asn1js/ use this to debug
// PrivateKeyInfo SEQUENCE (3 elements)
private_key_pkcs8[0] = 0x30; // constructed sequence tag
private_key_pkcs8[1] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2
// bytes are the length of data)
private_key_pkcs8[2] = (unsigned char)((private_key_pkcs8_size >> 8) & 0xFF);
private_key_pkcs8[3] = (unsigned char)(private_key_pkcs8_size & 0xFF);

// version INTEGER 0
private_key_pkcs8[4] = 0x02; // integer tag
private_key_pkcs8[5] = 0x01; // length of data
private_key_pkcs8[6] = 0x00; // data

// private key algorithm identifier
private_key_pkcs8[7] = 0x30; // constructed sequence tag
private_key_pkcs8[8] = 0x0D; // there are 2 elements in the sequence
private_key_pkcs8[9] = 0x06;
private_key_pkcs8[10] = 0x09;
private_key_pkcs8[11] = 0x2A;
private_key_pkcs8[12] = 0x86;
private_key_pkcs8[13] = 0x48;
private_key_pkcs8[14] = 0x86;
private_key_pkcs8[15] = 0xF7;
private_key_pkcs8[16] = 0x0D;
private_key_pkcs8[17] = 0x01;
private_key_pkcs8[18] = 0x01;
private_key_pkcs8[19] = 0x01;
private_key_pkcs8[20] = 0x05;
private_key_pkcs8[21] = 0x00;

// PrivateKey OCTET STRING
private_key_pkcs8[22] = 0x04; // octet string tag
private_key_pkcs8[23] = 0x82; // 8 --> 1000 0000 (1 in MSB means that it is long form) and 2 --> 0010 0000 (the next 2
// bytes are the length of data)
private_key_pkcs8[24] = (unsigned char)((private_key_non_base64_len >> 8) & 0xFF); // length of data
private_key_pkcs8[25] = (unsigned char)(private_key_non_base64_len & 0xFF); // length of data

memcpy(private_key_pkcs8 + 26, private_key_non_base64, private_key_non_base64_len);

const size_t private_key_base64_pkcs8_size = atchops_base64_encoded_size(private_key_non_base64_len);
private_key_pkcs8_base64 = (char *)malloc(private_key_base64_pkcs8_size);
if (private_key_pkcs8_base64 == NULL) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to allocate memory for private_key_pkcs8_base64\n");
goto exit;
}
memset(private_key_pkcs8_base64, 0, sizeof(char) * private_key_base64_pkcs8_size);

size_t private_key_base64_pkcs8_len = 0;
if ((ret = atchops_base64_encode(private_key_pkcs8, 26 + private_key_non_base64_len, private_key_pkcs8_base64,
private_key_base64_pkcs8_size, &private_key_base64_pkcs8_len)) != 0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to encode private key\n");
goto exit;
}

/*
* 7. Populate the atchops_rsa_key_public_key and atchops_rsa_key_private_key structs
*/

if ((ret = atchops_rsa_key_populate_public_key(public_key, (const char *)public_key_base64, public_key_base64_len)) !=
0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to populate public key\n");
goto exit;
}

if ((ret = atchops_rsa_key_populate_private_key(private_key, (const char *)private_key_pkcs8_base64,
private_key_base64_pkcs8_len)) != 0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Failed to populate private key\n");
goto exit;
}

exit: {
mbedtls_pk_free(&pk);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
free(private_key_non_base64);
free(private_key_pkcs8_base64);
free(private_key_pkcs8);
return ret;
}
}

int atchops_rsa_key_populate_public_key(atchops_rsa_key_public_key *public_key, const char *public_key_base64,
const size_t public_key_base64_len) {
int ret = 1;
Expand Down Expand Up @@ -207,7 +432,7 @@ int atchops_rsa_key_populate_public_key(atchops_rsa_key_public_key *public_key,
*/
mbedtls_asn1_sequence *seq = NULL; // free later

const size_t dst_size = BASE64_DECODED_KEY_BUFFER_SIZE;
const size_t dst_size = 2048; // sufficient size for a 2048 bit RSA key
unsigned char dst[dst_size];
memset(dst, 0, sizeof(unsigned char) * dst_size);
size_t dst_len = 0;
Expand Down Expand Up @@ -305,7 +530,7 @@ int atchops_rsa_key_populate_private_key(atchops_rsa_key_private_key *private_ke
*/
mbedtls_asn1_sequence *seq = NULL; // free later

const size_t dst_size = BASE64_DECODED_KEY_BUFFER_SIZE;
const size_t dst_size = 4096; // sufficient size for a 2048 bit RSA private key
unsigned char dst[dst_size];
memset(dst, 0, sizeof(unsigned char) * dst_size);
size_t dst_len = 0;
Expand Down Expand Up @@ -395,7 +620,8 @@ exit: {
}

bool atchops_rsa_key_is_public_key_populated(const atchops_rsa_key_public_key *public_key) {
return atchops_rsa_key_public_key_is_n_initialized(public_key) && atchops_rsa_key_public_key_is_e_initialized(public_key);
return atchops_rsa_key_public_key_is_n_initialized(public_key) &&
atchops_rsa_key_public_key_is_e_initialized(public_key);
}

bool atchops_rsa_key_is_private_key_populated(const atchops_rsa_key_private_key *private_key) {
Expand Down Expand Up @@ -1058,7 +1284,8 @@ bool atchops_rsa_key_private_key_is_q_initialized(const atchops_rsa_key_private_
return private_key->q._is_value_initialized;
}

void atchops_rsa_key_private_key_set_q_initialized(atchops_rsa_key_private_key *private_key, const bool is_initialized) {
void atchops_rsa_key_private_key_set_q_initialized(atchops_rsa_key_private_key *private_key,
const bool is_initialized) {
/*
* 1. Validate arguments
*/
Expand All @@ -1074,7 +1301,7 @@ void atchops_rsa_key_private_key_set_q_initialized(atchops_rsa_key_private_key *
}

int atchops_rsa_key_private_key_set_q(atchops_rsa_key_private_key *private_key, const unsigned char *q,
const size_t q_len) {
const size_t q_len) {
int ret = 1;

/*
Expand Down
Loading