fw: Add lots of comments to source
This commit is contained in:
parent
8f28367b2d
commit
de4e34992c
10 changed files with 191 additions and 79 deletions
|
|
@ -1,3 +1,22 @@
|
||||||
|
/* cage - a minimal (partial) C implementation of the age asymmetric file encryption format.
|
||||||
|
* Copyright (c) 2021 Jan Götte <cage.code@jaseg.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
* You can find a usage example at the end of this file.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
@ -35,7 +54,7 @@
|
||||||
#define MBEDTLS_CHECK(fun_call) MBEDTLS_CHECK_VAL(fun_call, CA_ERR_MBEDTLS_ERROR)
|
#define MBEDTLS_CHECK(fun_call) MBEDTLS_CHECK_VAL(fun_call, CA_ERR_MBEDTLS_ERROR)
|
||||||
|
|
||||||
|
|
||||||
/* Constant-time memcmp because inexplicably mbedtls doesn't have one.
|
/* Constant-time memcmp because mbedtls inexplicably doesn't have one.
|
||||||
* See https://github.com/ARMmbed/mbedtls/issues/3040
|
* See https://github.com/ARMmbed/mbedtls/issues/3040
|
||||||
*/
|
*/
|
||||||
static inline int constant_time_memcmp( const void *a, const void *b, size_t n )
|
static inline int constant_time_memcmp( const void *a, const void *b, size_t n )
|
||||||
|
|
@ -53,18 +72,24 @@ static inline int constant_time_memcmp( const void *a, const void *b, size_t n )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse a single stanza (decryption key line). Invokes specialized parsers depending on asmmmetric crypto used. */
|
||||||
static enum ca_error parse_stanza(struct ca_keystore *ks, const char *stanza_head, size_t len, unsigned char file_key[16]);
|
static enum ca_error parse_stanza(struct ca_keystore *ks, const char *stanza_head, size_t len, unsigned char file_key[16]);
|
||||||
|
/* Decrypt file encryption key from stanza, X25519 variant. */
|
||||||
static enum ca_error parse_stanza_x25519(struct ca_keystore *ks, size_t nargs, const char **args, size_t body_len, const unsigned char *body, unsigned char file_key[16]);
|
static enum ca_error parse_stanza_x25519(struct ca_keystore *ks, size_t nargs, const char **args, size_t body_len, const unsigned char *body, unsigned char file_key[16]);
|
||||||
|
/* Check symmetric file key by checking decrypted header MAC */
|
||||||
static enum ca_error check_file_key(const unsigned char *buf, size_t buflen, const unsigned char file_key[16]);
|
static enum ca_error check_file_key(const unsigned char *buf, size_t buflen, const unsigned char file_key[16]);
|
||||||
|
|
||||||
|
/* Initialize keystore struct */
|
||||||
void ca_keystore_init(struct ca_keystore *ks) {
|
void ca_keystore_init(struct ca_keystore *ks) {
|
||||||
mbedtls_ecp_keypair_init(&(ks->x25519_kp));
|
mbedtls_ecp_keypair_init(&(ks->x25519_kp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Free keystore struct */
|
||||||
void ca_keystore_free(struct ca_keystore *ks) {
|
void ca_keystore_free(struct ca_keystore *ks) {
|
||||||
mbedtls_ecp_keypair_free(&(ks->x25519_kp));
|
mbedtls_ecp_keypair_free(&(ks->x25519_kp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert error code to human-readable string */
|
||||||
const char *ca_errstr(enum ca_error err) {
|
const char *ca_errstr(enum ca_error err) {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case CA_ERR_SUCCESS: return "success";
|
case CA_ERR_SUCCESS: return "success";
|
||||||
|
|
@ -85,6 +110,7 @@ const char *ca_errstr(enum ca_error err) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load X25519 private key into keystore */
|
||||||
enum ca_error ca_keystore_load_x25519_private_key(struct ca_keystore *ks, const unsigned char buf[32]) {
|
enum ca_error ca_keystore_load_x25519_private_key(struct ca_keystore *ks, const unsigned char buf[32]) {
|
||||||
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
||||||
/*
|
/*
|
||||||
|
|
@ -108,19 +134,27 @@ cleanup:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t buflen, unsigned char file_key[16]) {
|
/* Public API: Read encrypted age file from given buffer and try to decrypt file key using private keys in the given
|
||||||
|
* keystore. Returns 0 on success, error code on failure. If the file key cannot be decrypted using any of the private
|
||||||
|
* keys in the keystore, CA_ERR_KEY_NOT_FOUND is returned.
|
||||||
|
*/
|
||||||
|
enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t buflen, /* output */ unsigned char file_key[16]) {
|
||||||
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
||||||
|
|
||||||
|
/* Check that the input buffer is well-formed. */
|
||||||
if (buflen <= 0) {
|
if (buflen <= 0) {
|
||||||
LOG_PRINTF("Error: parse_age_buf: (buflen == %d) <= 0\r\n", buflen);
|
LOG_PRINTF("Error: parse_age_buf: (buflen == %d) <= 0\r\n", buflen);
|
||||||
return CA_ERR_INVALID_HEADER;
|
return CA_ERR_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strnlen(buf, buflen) >= buflen) {
|
if (strnlen(buf, buflen) >= buflen) {
|
||||||
LOG_PRINTF("Error: parse_age_buf: Buffer is not null-terminated\r\n");
|
LOG_PRINTF("Error: parse_age_buf: Buffer is not null-terminated\r\n");
|
||||||
return CA_ERR_INVALID_HEADER; /* buffer is not null-terminated */
|
return CA_ERR_INVALID_HEADER; /* buffer is not null-terminated */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* First character of line currently being processed */
|
||||||
const char *current_line = buf;
|
const char *current_line = buf;
|
||||||
|
/* Newline character or null byte at the end of line currently being processed */
|
||||||
const char *line_end = strchr(buf, '\n');
|
const char *line_end = strchr(buf, '\n');
|
||||||
|
|
||||||
if (!line_end) {
|
if (!line_end) {
|
||||||
|
|
@ -128,12 +162,14 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
||||||
return CA_ERR_INVALID_HEADER; /* header has to contain at least magic string, one stanza and payload separator line */
|
return CA_ERR_INVALID_HEADER; /* header has to contain at least magic string, one stanza and payload separator line */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check header prefix */
|
||||||
const char *header_start = "age-encryption.org/v";
|
const char *header_start = "age-encryption.org/v";
|
||||||
if (strncmp(current_line, header_start, strlen(header_start))) {
|
if (strncmp(current_line, header_start, strlen(header_start))) {
|
||||||
LOG_PRINTF("Error: parse_age_buf: header magic string corrupt or missing\r\n");
|
LOG_PRINTF("Error: parse_age_buf: header magic string corrupt or missing\r\n");
|
||||||
return CA_ERR_INVALID_HEADER; /* header magic string corrupt or missing */
|
return CA_ERR_INVALID_HEADER; /* header magic string corrupt or missing */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse and validate header version number */
|
||||||
char *endptr = NULL;
|
char *endptr = NULL;
|
||||||
unsigned long header_version = strtoul(current_line + strlen(header_start), &endptr, 10);
|
unsigned long header_version = strtoul(current_line + strlen(header_start), &endptr, 10);
|
||||||
|
|
||||||
|
|
@ -147,7 +183,13 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
||||||
return CA_ERR_FILE_FORMAT_TOO_NEW;
|
return CA_ERR_FILE_FORMAT_TOO_NEW;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *stanza_head = NULL;
|
/* Stanza parse loop.
|
||||||
|
*
|
||||||
|
* In age, a stanza is one line containing an encryption of the symmetric file key under one asymmetric public key.
|
||||||
|
* Stanzas can be validated by decrypting the header and checking a MAC. To decrypt the file key, iterate through
|
||||||
|
* all stanzas and try to decrypt each one in turn.
|
||||||
|
*/
|
||||||
|
const char *stanza_head = NULL; /* Start of current stanza */
|
||||||
size_t stanza_num = 0;
|
size_t stanza_num = 0;
|
||||||
for (size_t i=0; i<buflen; i++) {
|
for (size_t i=0; i<buflen; i++) {
|
||||||
/* we forced buf above to be nul-terminated and we know line_end is \n (!= \0), so line_end+1 must be valid. */
|
/* we forced buf above to be nul-terminated and we know line_end is \n (!= \0), so line_end+1 must be valid. */
|
||||||
|
|
@ -159,34 +201,31 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
||||||
return CA_ERR_INVALID_HEADER; /* the header must always end with '\n' after the --- separator line */
|
return CA_ERR_INVALID_HEADER; /* the header must always end with '\n' after the --- separator line */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stanza_head) {
|
||||||
|
err = parse_stanza(ks, stanza_head, current_line - stanza_head, file_key);
|
||||||
|
if (err != CA_ERR_SUCCESS)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!check_file_key((const unsigned char *)buf, buflen, file_key)) {
|
||||||
|
/* LOG_PRINTF("Found file key in stanza %d\n", stanza_num); */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} /* else { LOG_PRINTF("stanza %d does not match\n", stanza_num); } */
|
||||||
|
}
|
||||||
|
|
||||||
if (!strncmp(current_line, "-> ", 3)) { /* stanza start */
|
if (!strncmp(current_line, "-> ", 3)) { /* stanza start */
|
||||||
|
/* Next line contains a stanza */
|
||||||
|
|
||||||
stanza_num += 1;
|
stanza_num += 1;
|
||||||
if (stanza_num > CA_ERR_TOO_MANY_STANZAS) {
|
if (stanza_num > CA_MAX_STANZAS) {
|
||||||
return CA_ERR_TOO_MANY_STANZAS;
|
return CA_ERR_TOO_MANY_STANZAS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stanza_head) {
|
|
||||||
err = parse_stanza(ks, stanza_head, current_line - stanza_head, file_key);
|
|
||||||
if (err != CA_ERR_SUCCESS)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (!check_file_key((const unsigned char *)buf, buflen, file_key)) {
|
|
||||||
/*
|
|
||||||
LOG_PRINTF("Found file key in stanza %d\n", stanza_num);
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
LOG_PRINTF("stanza %d does not match\n", stanza_num);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stanza_head = current_line;
|
stanza_head = current_line;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
} else if (!strncmp(current_line, "---", 3)) { /* Payload separator line */
|
} else if (!strncmp(current_line, "---", 3)) {
|
||||||
|
/* Next line contains the payload separator, this is the last stanza. */
|
||||||
|
|
||||||
if (stanza_head) {
|
if (stanza_head) {
|
||||||
err = parse_stanza(ks, stanza_head, current_line - stanza_head, file_key);
|
err = parse_stanza(ks, stanza_head, current_line - stanza_head, file_key);
|
||||||
|
|
@ -194,16 +233,11 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!check_file_key((const unsigned char *)buf, buflen, file_key)) {
|
if (!check_file_key((const unsigned char *)buf, buflen, file_key)) {
|
||||||
/*
|
/* LOG_PRINTF("Found file key in stanza %d\n", stanza_num); */
|
||||||
LOG_PRINTF("Found file key in stanza %d\n", stanza_num);
|
|
||||||
*/
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} else {
|
} /* else { LOG_PRINTF("stanza %d does not match\n", stanza_num); } */
|
||||||
/*
|
|
||||||
LOG_PRINTF("stanza %d does not match\n", stanza_num);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
LOG_PRINTF("Error: parse_age_buf: header does not contain any stanzas\r\n");
|
LOG_PRINTF("Error: parse_age_buf: header does not contain any stanzas\r\n");
|
||||||
return CA_ERR_INVALID_HEADER; /* the header must contain at least one stanza */
|
return CA_ERR_INVALID_HEADER; /* the header must contain at least one stanza */
|
||||||
|
|
@ -226,6 +260,7 @@ enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t bufl
|
||||||
return CA_ERR_KEY_NOT_FOUND;
|
return CA_ERR_KEY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Internal: parse single stanza */
|
||||||
enum ca_error parse_stanza(struct ca_keystore *ks, const char *stanza_head, size_t len, unsigned char file_key[16]) {
|
enum ca_error parse_stanza(struct ca_keystore *ks, const char *stanza_head, size_t len, unsigned char file_key[16]) {
|
||||||
const char *stanza_x25519 = "X25519";
|
const char *stanza_x25519 = "X25519";
|
||||||
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
||||||
|
|
@ -471,6 +506,7 @@ cleanup:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Public API: Decrypt file contents given file key */
|
||||||
enum ca_error stream_decrypt(unsigned char *out, size_t outlen, size_t *out_written, const unsigned char *in, size_t inlen, const unsigned char file_key[16]) {
|
enum ca_error stream_decrypt(unsigned char *out, size_t outlen, size_t *out_written, const unsigned char *in, size_t inlen, const unsigned char file_key[16]) {
|
||||||
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
enum ca_error err = CA_ERR_CORRUPTED_STATE;
|
||||||
|
|
||||||
|
|
@ -479,7 +515,7 @@ enum ca_error stream_decrypt(unsigned char *out, size_t outlen, size_t *out_writ
|
||||||
return CA_ERR_INVALID_HEADER;
|
return CA_ERR_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char *endl = (const unsigned char *)strchr(found+1, '\n');
|
const unsigned char *endl = (const unsigned char *)memchr(found+1, '\n', inlen-((const unsigned char *)(found+1)-in));
|
||||||
if (!endl) {
|
if (!endl) {
|
||||||
return CA_ERR_INVALID_HEADER;
|
return CA_ERR_INVALID_HEADER;
|
||||||
}
|
}
|
||||||
|
|
@ -608,6 +644,7 @@ int main(int argc, char **argv) {
|
||||||
char hrp[64];
|
char hrp[64];
|
||||||
char private_key[64];
|
char private_key[64];
|
||||||
size_t bech32_key_len;
|
size_t bech32_key_len;
|
||||||
|
/* the age design doc says that keys use the slightly obscure "bech32" format for storage. */
|
||||||
enum bech32_err b32_err = bech32_decode(hrp, sizeof(hrp), private_key, sizeof(private_key), &bech32_key_len, argv[1], NULL);
|
enum bech32_err b32_err = bech32_decode(hrp, sizeof(hrp), private_key, sizeof(private_key), &bech32_key_len, argv[1], NULL);
|
||||||
if (b32_err) {
|
if (b32_err) {
|
||||||
fprintf(stderr, "Error: bech32_decode: rc=%d\n", b32_err);
|
fprintf(stderr, "Error: bech32_decode: rc=%d\n", b32_err);
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@ enum ca_error {
|
||||||
CA_ERR_TOO_MANY_STANZAS = 13,
|
CA_ERR_TOO_MANY_STANZAS = 13,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Maximum number of stanzas that are checked before returning CA_ERR_TOO_MANY_STANZAS.
|
||||||
|
* This is a compile-time constant to set an upper bound for stanza decryption. For very large values, a bad age file
|
||||||
|
* that contains many stanzas could take very long to decrypt. */
|
||||||
#ifndef CA_MAX_STANZAS
|
#ifndef CA_MAX_STANZAS
|
||||||
#define CA_MAX_STANZAS 8
|
#define CA_MAX_STANZAS 8
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -36,6 +39,7 @@ struct ca_keystore {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Public API */
|
||||||
enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t buflen, unsigned char file_key[16]);
|
enum ca_error parse_age_buf(struct ca_keystore *ks, const char *buf, size_t buflen, unsigned char file_key[16]);
|
||||||
void ca_keystore_init(struct ca_keystore *ks);
|
void ca_keystore_init(struct ca_keystore *ks);
|
||||||
void ca_keystore_free(struct ca_keystore *ks);
|
void ca_keystore_free(struct ca_keystore *ks);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,22 @@
|
||||||
|
/* cage - a minimal (partial) C implementation of the age asymmetric file encryption format.
|
||||||
|
* Copyright (c) 2021 Jan Götte <cage.code@jaseg.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* ---
|
||||||
|
* This file contains a minimal base64 decoder for use in cage's stanza parsing.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,18 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
||||||
*
|
*
|
||||||
*
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* libusbhost is free software: you can redistribute it and/or modify
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Lesser General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the tachibana project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,22 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the tachibana project
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#include "gpio_helpers.h"
|
#include "gpio_helpers.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,21 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
||||||
*
|
*
|
||||||
*
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* tachibana is free software: you can redistribute it and/or modify
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Lesser General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
@ -37,6 +35,7 @@
|
||||||
#include "cage.h"
|
#include "cage.h"
|
||||||
#include "bech32.h"
|
#include "bech32.h"
|
||||||
|
|
||||||
|
/* Calculated system clock speeds */
|
||||||
unsigned int sysclk_speed = 0;
|
unsigned int sysclk_speed = 0;
|
||||||
unsigned int apb1_speed = 0;
|
unsigned int apb1_speed = 0;
|
||||||
unsigned int apb2_speed = 0;
|
unsigned int apb2_speed = 0;
|
||||||
|
|
@ -44,9 +43,11 @@ unsigned int auxclk_speed = 0;
|
||||||
unsigned int apb1_timer_speed = 0;
|
unsigned int apb1_timer_speed = 0;
|
||||||
unsigned int apb2_timer_speed = 0;
|
unsigned int apb2_timer_speed = 0;
|
||||||
|
|
||||||
|
/* Device driver handles */
|
||||||
struct leds leds;
|
struct leds leds;
|
||||||
struct spi_fpga_if spif;
|
struct spi_fpga_if spif;
|
||||||
|
|
||||||
|
/* Test age payload */
|
||||||
uint8_t cage_startup_test_data[] = {
|
uint8_t cage_startup_test_data[] = {
|
||||||
0x61, 0x67, 0x65, 0x2d, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6f,
|
0x61, 0x67, 0x65, 0x2d, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x6f,
|
||||||
0x72, 0x67, 0x2f, 0x76, 0x31, 0x0a, 0x2d, 0x3e, 0x20, 0x58, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20,
|
0x72, 0x67, 0x2f, 0x76, 0x31, 0x0a, 0x2d, 0x3e, 0x20, 0x58, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20,
|
||||||
|
|
@ -66,12 +67,14 @@ uint8_t cage_startup_test_data[] = {
|
||||||
0x5d, 0x66, 0x00
|
0x5d, 0x66, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* libc support */
|
||||||
void __libc_init_array(void) { /* we don't need this. */ }
|
void __libc_init_array(void) { /* we don't need this. */ }
|
||||||
void __assert_func (unused_a const char *file, unused_a int line, unused_a const char *function, unused_a const char *expr) {
|
void __assert_func (unused_a const char *file, unused_a int line, unused_a const char *function, unused_a const char *expr) {
|
||||||
asm volatile ("bkpt");
|
asm volatile ("bkpt");
|
||||||
while(1) {}
|
while(1) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set all clocks to max, sysclk = 84 MHz */
|
||||||
static void clock_setup(void)
|
static void clock_setup(void)
|
||||||
{
|
{
|
||||||
/* 8MHz HSE clock as PLL source. */
|
/* 8MHz HSE clock as PLL source. */
|
||||||
|
|
@ -163,6 +166,7 @@ static void led_setup(void)
|
||||||
GPIOB->BSRR = 0xf << 11;
|
GPIOB->BSRR = 0xf << 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Support code for SPI interface */
|
||||||
static void spi_fpga_if_set_cs(bool val) {
|
static void spi_fpga_if_set_cs(bool val) {
|
||||||
if (val)
|
if (val)
|
||||||
GPIOA->BSRR = 1<<4;
|
GPIOA->BSRR = 1<<4;
|
||||||
|
|
@ -198,6 +202,7 @@ static void spi_fpga_setup(void)
|
||||||
spif_init(&spif, SPI1, &spi_fpga_if_set_cs);
|
spif_init(&spif, SPI1, &spi_fpga_if_set_cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* libc replacement functions */
|
||||||
unsigned long strtoul(const char *nptr, char **endptr, int base) {
|
unsigned long strtoul(const char *nptr, char **endptr, int base) {
|
||||||
if (endptr)
|
if (endptr)
|
||||||
*endptr = NULL;
|
*endptr = NULL;
|
||||||
|
|
@ -226,6 +231,8 @@ unsigned long strtoul(const char *nptr, char **endptr, int base) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Analogous to same transformation done on FPGA: Sometimes we receive pixel data with lsb corrupted (maybe a graphics
|
||||||
|
* stack bug?). Fix this corruption before displaying values. */
|
||||||
static uint8_t unfuck_channel_val(uint8_t val) {
|
static uint8_t unfuck_channel_val(uint8_t val) {
|
||||||
if ((val & 0xf) == 0xf)
|
if ((val & 0xf) == 0xf)
|
||||||
return val + 1;
|
return val + 1;
|
||||||
|
|
@ -240,16 +247,21 @@ static void unpack_px_data(uint8_t *buf, size_t size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hooks for mbedtls to use tinyalloc. */
|
||||||
void *malloc(size_t size) { return ta_alloc(size); }
|
void *malloc(size_t size) { return ta_alloc(size); }
|
||||||
void free(void *ptr) { ta_free(ptr); }
|
void free(void *ptr) { ta_free(ptr); }
|
||||||
void *calloc(size_t nmemb, size_t size) { return ta_calloc(nmemb, size); }
|
void *calloc(size_t nmemb, size_t size) { return ta_calloc(nmemb, size); }
|
||||||
|
|
||||||
unsigned char ta_heap[0x10000];
|
unsigned char ta_heap[0x10000];
|
||||||
|
|
||||||
|
/* buffers for FPGA-facing SPI protocol */
|
||||||
uint8_t payload_buf[16384];
|
uint8_t payload_buf[16384];
|
||||||
uint8_t dec_buf[16384];
|
uint8_t dec_buf[16384];
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/* Check if FPU is enabled */
|
||||||
if (((SCB->CPACR>>20) & 0xf) != 0xf) {
|
if (((SCB->CPACR>>20) & 0xf) != 0xf) {
|
||||||
asm volatile ("bkpt");
|
asm volatile ("bkpt");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,22 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
||||||
*
|
*
|
||||||
*
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* tachibana is free software: you can redistribute it and/or modify
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Lesser General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* ---
|
||||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
*
|
||||||
|
* This file contains driver code for hooking up mbedtls to the STM32's hardware RNG.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
@ -33,9 +35,11 @@
|
||||||
|
|
||||||
|
|
||||||
struct rng_state {
|
struct rng_state {
|
||||||
|
/* Error flags */
|
||||||
bool seed_error;
|
bool seed_error;
|
||||||
bool clock_error;
|
bool clock_error;
|
||||||
|
|
||||||
|
/* Hardware RNG status */
|
||||||
size_t data_available;
|
size_t data_available;
|
||||||
uint32_t data[MBEDTLS_CTR_DRBG_ENTROPY_LEN];
|
uint32_t data[MBEDTLS_CTR_DRBG_ENTROPY_LEN];
|
||||||
};
|
};
|
||||||
|
|
@ -44,9 +48,8 @@ static volatile struct rng_state rng_state;
|
||||||
static mbedtls_ctr_drbg_context drbg_ctx;
|
static mbedtls_ctr_drbg_context drbg_ctx;
|
||||||
void *g_drbg_ctx = &drbg_ctx;
|
void *g_drbg_ctx = &drbg_ctx;
|
||||||
|
|
||||||
|
/* RNG callback for mbedtls, registered below in rng_init. */
|
||||||
static int drbg_f_entropy(void *p, unsigned char *buf, size_t len);
|
static int drbg_f_entropy(void *p, unsigned char *buf, size_t len);
|
||||||
|
|
||||||
|
|
||||||
int drbg_f_entropy(void *p, unsigned char *buf, size_t len) {
|
int drbg_f_entropy(void *p, unsigned char *buf, size_t len) {
|
||||||
(void) p;
|
(void) p;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,21 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
||||||
*
|
*
|
||||||
*
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* libusbhost is free software: you can redistribute it and/or modify
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Lesser General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
|
* ---
|
||||||
|
* This file contains an USART driver with DMA-accelerated nonblocking transmission.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,18 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
* Copyright (C) 2021 jaseg <code@jaseg.de>
|
||||||
*
|
*
|
||||||
*
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* tachibana is free software: you can redistribute it and/or modify
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Lesser General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue