Skip to content
Snippets Groups Projects
Commit 74a20cda authored by Maarten de Waard's avatar Maarten de Waard :angel:
Browse files

Merge branch '1-make-a-decryption-api-endpoint' into 'master'

Resolve "Make a decryption API endpoint"

See merge request !1
parents fdab54da 8b02b98e
No related branches found
No related tags found
No related merge requests found
Showing with 1836 additions and 0 deletions
/.vagrant
*.swp
*.o
cryptops-api
Makefile 0 → 100644
TARGET=cryptops-api
CFLAGS=-O0 -g -Wall -D_GNU_SOURCE -Iincludes -Isrc
LFLAGS=-L./libraries -lcryptsetup -lc -lulfius -lyder -lorcania -ljansson
CC=gcc
LINKER=gcc
SRCDIR = src
OBJDIR = obj
BINDIR = bin
SOURCES := $(SRCDIR)/$(TARGET).c
INCLUDES := $(wildcard $(SRCDIR)/*.h)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
$(BINDIR)/$(TARGET): $(BINDIR)
$(BINDIR):
mkdir -p $(BINDIR)
$(BINDIR)/$(TARGET): $(OBJECTS)
@$(LINKER) $(OBJECTS) $(LFLAGS) -o $@
@echo "Linking complete."
$(OBJECTS): | $(OBJDIR)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
@$(CC) $(CFLAGS) -c $< -o $@
@echo "Compiled "$<" successfully."
.PHONY: clean
clean:
@rm -f $(OBJECTS)
@echo "Cleanup complete."
.PHONY: remove
remove: clean
@rm -f $(BINDIR)/$(TARGET)
@echo "Executable removed."
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "debian/jessie64"
config.vm.synced_folder ".", "/test", type: 'virtualbox'
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y libmicrohttpd-dev libjansson-dev libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev libcryptsetup-dev
SHELL
end
/**
*
* Orcania library
*
* Different functions for different purposes but that can be shared between
* other projects
*
*/
#ifndef __ORCANIA_H__
#define __ORCANIA_H__
#ifndef U_DISABLE_JANSSON
#include <jansson.h>
#endif
#define ORCANIA_VERSION 1.1
/**
* char * str_replace(const char * source, char * old, char * new)
* replace all occurences of old by new in the string source
* return a char * with the new value
* return NULL on error
* returned value must be free'd after use
*/
char * str_replace(const char * source, const char * str_old, const char * str_new);
/**
* o_strdup
* a modified strdup function that don't crash when source is NULL, instead return NULL
* Returned value must be free'd after use
*/
char * o_strdup(const char * source);
/**
* o_strndup
* a modified strndup function that don't crash when source is NULL, instead return NULL
* Returned value must be free'd after use
*/
char * o_strndup(const char * source, size_t len);
/**
* o_strcmp
* a modified strcmp function that don't crash when p1 is NULL or p2 us NULL
*/
int o_strcmp(const char * p1, const char * p2);
/**
* o_strncmp
* a modified strncmp function that don't crash when p1 is NULL or p2 us NULL
*/
int o_strncmp(const char * p1, const char * p2, size_t n);
/**
* o_strcpy
* a modified strcpy function that don't crash when p1 is NULL or p2 us NULL
*/
char * o_strcpy(char * p1, const char * p2);
/**
* o_strncpy
* a modified strncpy function that don't crash when p1 is NULL or p2 us NULL
*/
char * o_strncpy(char * p1, const char * p2, size_t n);
/**
* o_strcasecmp
* a modified strcasecmp function that don't crash when p1 is NULL or p2 us NULL
*/
int o_strcasecmp(const char * p1, const char * p2);
/**
* o_strncasecmp
* a modified strncasecmp function that don't crash when p1 is NULL or p2 us NULL
*/
int o_strncasecmp(const char * p1, const char * p2, size_t n);
/**
* o_strstr
* a modified strstr function that don't crash when haystack is NULL or needle us NULL
*/
char * o_strstr(const char * haystack, const char * needle);
/**
* o_strnstr
* a modified strnstr function that don't crash when haystack is NULL or needle us NULL
*/
char * o_strnstr(const char * haystack, const char * needle, size_t len);
/**
* o_strcasestr
* a modified strcasestr function that don't crash when haystack is NULL or needle us NULL
*/
char * o_strcasestr(const char * haystack, const char * needle);
/**
* o_strchr
* a modified strchr function that don't crash when haystack is NULL
*/
char * o_strchr(const char * haystack, int c);
/**
* o_strrchr
* a modified strrchr function that don't crash when haystack is NULL
*/
char * o_strrchr(const char * haystack, int c);
/**
* o_strlen
* a modified version of strlen that don't crash when s is NULL
*/
size_t o_strlen(const char * s);
/**
* char * msprintf(const char * message, ...)
* Implementation of sprintf that return a malloc'd char * with the string construction
* because life is too short to use 3 lines instead of 1
* but don't forget to free the returned value after use!
*/
char * msprintf(const char * message, ...);
/**
* Split a string into an array of strings using separator string
* return the number of elements to be returned, 0 on error
* if return_array is not NULL, set the returned array in it
* return_array is an array of char * ending with a NULL value
* return_array must be free'd after use
* you can use free_string_array to free return_array
*/
int split_string(const char * string, const char * separator, char *** return_array);
/**
* Clean an array of strings
*/
void free_string_array(char ** array);
/**
* Check if an array of string has a specified value
*/
int string_array_has_value(const char ** array, const char * needle);
/**
* Check if an array of string has a specified trimmed value
*/
int string_array_has_trimmed_value(const char ** array, const char * needle);
/**
* Remove string of beginning and ending whitespaces
*/
char * trimwhitespace(char * str);
#ifndef U_DISABLE_JANSSON
/**
* json_t * json_search(json_t * haystack, json_t * needle)
* jansson library addon
* This function could be removed if y pull request is accepted in jansson official repository:
* https://github.com/akheron/jansson/pull/265
* Look for an occurence of needle within haystack
* If needle is present in haystack, return the reference to the json_t * that is equal to needle
* If needle is not found, return NULL
*/
json_t * json_search(json_t * haystack, json_t * needle);
/**
* Check if the result json object has a "result" element that is equal to value
*/
int check_result_value(json_t * result, const int value);
#endif
/**
* Memory functions
*/
/* C89 allows these to be macros */
#undef malloc
#undef realloc
#undef free
typedef void *(*o_malloc_t)(size_t);
typedef void *(*o_realloc_t)(void *, size_t);
typedef void (*o_free_t)(void *);
void * o_malloc(size_t size);
void * o_realloc(void * ptr, size_t size);
void o_free(void * ptr);
void o_set_alloc_funcs(o_malloc_t malloc_fn, o_realloc_t realloc_fn, o_free_t free_fn);
void o_get_alloc_funcs(o_malloc_t * malloc_fn, o_realloc_t * realloc_fn, o_free_t * free_fn);
/**
* Base64 encode and decode functions
*/
/**
* o_base64_encode - Base64 encode
* @src: Data to be encoded
* @len: Length of the data to be encoded
* @out: Pointer to output variable
* @out_len: Pointer to output length variable
* Returns: 1 on success, 0 on failure
*
* The nul terminator is not included in out_len.
*/
int o_base64_encode(const unsigned char * src, size_t len, unsigned char * out, size_t * out_len);
/**
* o_base64_decode - Base64 decode
* @src: Data to be decoded
* @len: Length of the data to be decoded
* @out: Pointer to output variable
* @out_len: Pointer to output length variable
* Returns: 1 on success, 0 on failure
*
* The nul terminator is not included in out_len.
*/
int o_base64_decode(const unsigned char *src, size_t len, unsigned char * out, size_t * out_len);
#endif
This diff is collapsed.
/**
*
* Yder Framework
*
* Logging framework library
*
* yder.h: structures and functions declarations
*
* Copyright 2015-2017 Nicolas Mora <mail@babelouest.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library 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 GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __YDER_H__
#define __YDER_H__
#define YDER_VERSION 2.0
#define Y_LOG_MODE_NONE 0x0000
#define Y_LOG_MODE_CONSOLE 0x00F0
#define Y_LOG_MODE_SYSLOG 0x0F00
#define Y_LOG_MODE_FILE 0xF000
#define Y_LOG_MODE_CURRENT 0xFFFF
#define Y_LOG_LEVEL_NONE 0x0000
#define Y_LOG_LEVEL_ERROR 0x000F
#define Y_LOG_LEVEL_WARNING 0x00F0
#define Y_LOG_LEVEL_INFO 0x0F00
#define Y_LOG_LEVEL_DEBUG 0xF000
#define Y_LOG_LEVEL_CURRENT 0xFFFF
/**
* Initialize logging with mode and level parameters, specify a log file if needed
* Return true on success, false on error
*/
int y_init_logs(const char * app, const unsigned long init_mode, const unsigned long init_level, const char * init_log_file, const char * message);
/**
* Close the logs
*/
int y_close_logs();
/**
* Log a message using current parameters
*/
void y_log_message(const unsigned long type, const char * message, ...);
#endif // __YDER_H__
File added
File added
File added
File added
File added
File added
/**
* Default callback function, returning a 404 response.
* @param[in] request incoming HTTP request
* @param[out] response HTTP response to the request
* @param[in] user_data extra data to pass between main thread and callbacks
* @return internal status code
*/
int callback_default(const struct _u_request * request,
struct _u_response * response, void * user_data)
{
ulfius_set_string_body_response(response, 404, "Unknown endpoint");
return U_CALLBACK_CONTINUE;
}
/**
* Callback function that uses the password passed in the request to open the
* luks volume.
* @param[in] request incoming HTTP request
* @param[out] response HTTP response to the request
* @param[in] user_data extra data to pass between main thread and callbacks
* @return internal status code
*/
int callback_encryption_unlock(const struct _u_request * request,
struct _u_response * response, void * user_data)
{
json_t * json_input = ulfius_get_json_body_request(request, NULL);
const char * password;
password = json_string_value(json_object_get(json_input, "password"));
if (password == NULL)
{
return send_simple_response(response, 400, "error", "missing password");
}
int unlock_status = encryption_unlock(CONTAINER_DEVICE, MAPPED_DEVICE_NAME,
password);
if (unlock_status == -1)
{
// Experience learns that -1 is returned when the password is wrong.
return send_simple_response(response, 403, "error",
"incorrect password");
}
if (unlock_status != 0)
{
// Something else went wrong with unlocking.
printf("encryption_unlock failed with status %d\n", unlock_status);
return send_simple_response(response, 500, "error",
"error during unlocking");
}
// If we reach this point, apparently everything went well.
int r = send_simple_response(response, 200, "status", "ok");
stop_server();
return r;
}
/**
* Use a fifo to signal that we want to stop the api server.
*/
void stop_server()
{
printf("Stopping cryptops-api server...\n");
int fifo;
char fifo_path[] = FIFO_PATH;
fifo = open(fifo_path, O_WRONLY);
char * msg = "stop";
write(fifo, msg, strlen(msg) + 1);
}
/**
* Read a file completely into a string.
* @param filename Path to the file to read.
* @return Contents of the file.
*/
char * read_file(const char * filename)
{
char * buffer = NULL;
long length;
FILE * file = fopen(filename, "rb");
if (filename != NULL)
{
if (file)
{
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
buffer = o_malloc(length + 1);
if (buffer)
{
fread(buffer, 1, length, file);
}
buffer[length] = '\0';
fclose (file);
}
return buffer;
}
else
{
return NULL;
}
}
/**
* Respond to the request with a simple json structure '{$field: $value}'.
* @param response response struct to use
* @param http_status HTTP status code to return
* @param field name of the json field to return
* @param value json value to return
*/
int send_simple_response(struct _u_response * response, int http_status,
const char * field, const char * value)
{
json_t * json_body = NULL;
json_body = json_object();
json_object_set_new(json_body, field, json_string(value));
ulfius_set_json_body_response(response, http_status, json_body);
json_decref(json_body);
return U_CALLBACK_CONTINUE;
}
#include <includes/common-includes.h>
#include <includes/settings.h>
#define FIFO_PATH "/tmp/cryptops-api-stop"
#include <auxiliary.c>
#include <encryption_functions.c>
#include <api/default.c>
#include <api/encryption_unlock.c>
int main(int argc, char ** argv)
{
y_init_logs("cryptops-api", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG,
NULL, "Starting cryptops-api");
struct _u_instance instance;
if (ulfius_init_instance(&instance, PORT, NULL, NULL) != U_OK)
{
y_log_message(Y_LOG_LEVEL_ERROR, "Error ulfius_init_instance, abort");
return(1);
}
u_map_put(instance.default_headers, "Access-Control-Allow-Origin", "*");
// Maximum body size sent by the client is 1 Kb.
instance.max_post_body_size = 1024;
// Add api endpoints.
ulfius_add_endpoint_by_val(&instance, "POST", PREFIX, "/encryption/unlock",
0, &callback_encryption_unlock, NULL);
// Add default endpoint.
ulfius_set_default_endpoint(&instance, &callback_default, NULL);
// Start the framework.
int ret;
if (argc == 4 && strcmp("-secure", argv[1]) == 0)
{
// If command-line options are -secure <key_file> <cert_file>,
// then listen for https connections.
char * key_pem = read_file(argv[2]);
char * cert_pem = read_file(argv[3]);
ret = ulfius_start_secure_framework(&instance, key_pem, cert_pem);
o_free(key_pem);
o_free(cert_pem);
}
else
{
// Listen for http connections.
ret = ulfius_start_framework(&instance);
}
if (ret == U_OK)
{
y_log_message(Y_LOG_LEVEL_DEBUG, "Start %sframework on port %d",
((argc == 4 && strcmp("-secure", argv[1]) == 0) ? "secure " : ""),
instance.port);
// Wait for signal from fifo to quit.
y_init_logs("cryptops-api", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG,
NULL, "Waiting for fifo signal to quit");
int fifo = 0;
char buf[4];
char fifo_path[] = FIFO_PATH;
mkfifo(fifo_path, 0600);
fifo = open(fifo_path, O_RDONLY);
// This will block until the fifo is written to.
read(fifo, &buf, 4);
}
else
{
y_log_message(Y_LOG_LEVEL_DEBUG, "Error starting framework");
}
y_log_message(Y_LOG_LEVEL_DEBUG, "End framework");
y_close_logs();
ulfius_stop_framework(&instance);
ulfius_clean_instance(&instance);
return 0;
}
/**
* Use cryptsetup to initialise the luks container.
* It will not be opened (decrypted) yet, but it does check if the container
* seems usable.
* @param crypt_device struct to store crypt device context
* @param crypt_device path to the encrypted container
* @return status code
*/
static int container_initialise(struct crypt_device **cd, const char *path)
{
// Let LUKS initialise the encrypted device.
int r = crypt_init(cd, path);
if (r < 0)
{
printf("crypt_init() failed for %s.\n", path);
printf("status: %d.\n", r);
return r;
}
// Load the LUKS header from the block device into the crypt device context.
r = crypt_load(*cd, CRYPT_LUKS1, NULL);
if (r < 0)
{
printf("crypt_load() failed on device %s.\n",
crypt_get_device_name(*cd));
}
return r;
}
/**
* Use cryptsetup to unlock the luks container.
* This will create `/dev/mapper/$device_name`.
* @param path path to the encrypted container
* @param device_name name of the mapping
* @param password encryption password of the container
* @return status code
*/
static int encryption_unlock(const char *path, const char *device_name,
const char *password)
{
// Let LUKS initialise the encrypted device.
struct crypt_device *cd;
int r = container_initialise(&cd, path);
if (r < 0)
{
printf("crypt_load() failed on device %s.\n",
crypt_get_device_name(cd));
crypt_free(cd);
return r;
}
// Create device mapping with name device_name.
r = crypt_activate_by_passphrase(cd, device_name, CRYPT_ANY_SLOT,
password, strlen(password), 0);
if (r < 0)
{
printf("Device %s activation failed.\n", device_name);
crypt_free(cd);
return r;
}
printf("LUKS device %s/%s is active.\n", crypt_get_dir(), device_name);
printf("\tcipher used: %s\n", crypt_get_cipher(cd));
printf("\tcipher mode: %s\n", crypt_get_cipher_mode(cd));
printf("\tdevice UUID: %s\n", crypt_get_uuid(cd));
crypt_free(cd);
return 0;
}
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define U_DISABLE_CURL
#define U_DISABLE_WEBSOCKET
#include <ulfius.h>
#include <jansson.h>
#include <libcryptsetup.h>
#define PREFIX "/cryptops/v0"
#define PORT 8000
#define CONTAINER_DEVICE "/dev/xvda1"
#define MAPPED_DEVICE_NAME "xvda1_crypt"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment