2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Krzysztof Jackiewicz <k.jackiewicz@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
29 #include <openssl/crypto.h>
30 #include <openssl/evp.h>
31 #include <openssl/rand.h>
32 #include <openssl/err.h>
34 #include <yaca_crypto.h>
35 #include <yaca_error.h>
39 static pthread_mutex_t *mutexes = NULL;
41 static __thread bool current_thread_initialized = false;
42 static size_t threads_cnt = 0;
43 static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
45 static void locking_callback(int mode, int type, UNUSED const char *file, UNUSED int line)
47 /* Ignore NULL mutexes and lock/unlock error codes as we can't do anything
53 if (mode & CRYPTO_LOCK)
54 pthread_mutex_lock(&mutexes[type]);
55 else if (mode & CRYPTO_UNLOCK)
56 pthread_mutex_unlock(&mutexes[type]);
59 static unsigned long thread_id_callback()
61 return pthread_self();
64 static void destroy_mutexes(int count)
66 if (mutexes != NULL) {
67 for (int i = 0; i < count; i++) {
68 /* Ignore returned value as we can't do anything about it */
69 pthread_mutex_destroy(&mutexes[i]);
76 API int yaca_initialize(void)
78 int ret = YACA_ERROR_NONE;
80 /* no calling yaca_initalize() twice on the same thread */
81 if (current_thread_initialized)
82 return YACA_ERROR_INTERNAL;
84 pthread_mutex_lock(&init_mutex);
88 assert(mutexes == NULL);
92 /* This should never fail on a /dev/random equipped system. If it does it
93 * means we might need to figure out another way of a truly random seed.
94 * https://wiki.openssl.org/index.php/Random_Numbers
96 * Another things to maybe consider for the future:
97 * - entropy on a mobile device (no mouse/keyboard)
98 * - fork safety: https://wiki.openssl.org/index.php/Random_fork-safety
99 * - hardware random generator (RdRand on new Intels, Samsung hardware?)
101 if (RAND_status() != 1) {
102 ERROR_DUMP(YACA_ERROR_INTERNAL);
103 ret = YACA_ERROR_INTERNAL;
107 OpenSSL_add_all_digests();
108 OpenSSL_add_all_ciphers();
110 /* enable threads support */
111 if (CRYPTO_num_locks() > 0) {
112 ret = yaca_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t),
115 if (ret != YACA_ERROR_NONE)
118 for (int i = 0; i < CRYPTO_num_locks(); i++) {
119 if (pthread_mutex_init(&mutexes[i], NULL) != 0) {
120 ret = YACA_ERROR_NONE;
123 ret = YACA_ERROR_OUT_OF_MEMORY;
130 ret = YACA_ERROR_INTERNAL;
138 CRYPTO_set_id_callback(thread_id_callback);
139 CRYPTO_set_locking_callback(locking_callback);
144 * - We should also decide on Openssl config.
145 * - Here's a good tutorial for initalization and cleanup:
146 * https://wiki.openssl.org/index.php/Library_Initialization
147 * - We should also initialize the entropy for random number generator:
148 * https://wiki.openssl.org/index.php/Random_Numbers#Initialization
152 current_thread_initialized = true;
155 pthread_mutex_unlock(&init_mutex);
160 API int yaca_cleanup(void)
162 /* calling cleanup twice on the same thread is a NOP */
163 if (!current_thread_initialized)
164 return YACA_ERROR_NONE;
166 /* per thread cleanup */
167 ERR_remove_thread_state(NULL);
168 CRYPTO_cleanup_all_ex_data();
170 pthread_mutex_lock(&init_mutex);
172 /* last one turns off the light */
173 if (threads_cnt == 1) {
175 ERR_remove_thread_state(NULL);
178 CRYPTO_cleanup_all_ex_data();
180 /* threads support cleanup */
181 CRYPTO_set_id_callback(NULL);
182 CRYPTO_set_locking_callback(NULL);
184 destroy_mutexes(CRYPTO_num_locks());
187 assert(threads_cnt > 0);
190 current_thread_initialized = false;
192 pthread_mutex_unlock(&init_mutex);
194 return YACA_ERROR_NONE;
197 API int yaca_malloc(size_t size, void **memory)
199 if (size == 0 || memory == NULL)
200 return YACA_ERROR_INVALID_PARAMETER;
202 *memory = OPENSSL_malloc(size);
203 if (*memory == NULL) {
204 ERROR_DUMP(YACA_ERROR_OUT_OF_MEMORY);
205 return YACA_ERROR_OUT_OF_MEMORY;
208 return YACA_ERROR_NONE;
211 API int yaca_zalloc(size_t size, void **memory)
213 int ret = yaca_malloc(size, memory);
214 if (ret != YACA_ERROR_NONE)
217 memset(*memory, 0, size);
219 return YACA_ERROR_NONE;
222 API int yaca_realloc(size_t size, void **memory)
224 if (size == 0 || memory == NULL)
225 return YACA_ERROR_INVALID_PARAMETER;
227 void *tmp = OPENSSL_realloc(*memory, size);
229 ERROR_DUMP(YACA_ERROR_OUT_OF_MEMORY);
230 return YACA_ERROR_OUT_OF_MEMORY;
235 return YACA_ERROR_NONE;
238 API void yaca_free(void *memory)
240 OPENSSL_free(memory);
243 API int yaca_randomize_bytes(char *data, size_t data_len)
247 if (data == NULL || data_len == 0)
248 return YACA_ERROR_INVALID_PARAMETER;
250 ret = RAND_bytes((unsigned char *)data, data_len);
252 ret = YACA_ERROR_INTERNAL;
257 return YACA_ERROR_NONE;
260 API int yaca_context_set_property(yaca_context_h ctx, yaca_property_e property,
261 const void *value, size_t value_len)
263 if (ctx == YACA_CONTEXT_NULL || ctx->set_param == NULL)
264 return YACA_ERROR_INVALID_PARAMETER;
266 return ctx->set_param(ctx, property, value, value_len);
269 API int yaca_context_get_property(const yaca_context_h ctx, yaca_property_e property,
270 void **value, size_t *value_len)
272 if (ctx == YACA_CONTEXT_NULL || ctx->get_param == NULL)
273 return YACA_ERROR_INVALID_PARAMETER;
275 return ctx->get_param(ctx, property, value, value_len);
278 API void yaca_context_destroy(yaca_context_h ctx)
280 if (ctx != YACA_CONTEXT_NULL) {
281 assert(ctx->ctx_destroy != NULL);
282 ctx->ctx_destroy(ctx);
287 API int yaca_context_get_output_length(const yaca_context_h ctx,
288 size_t input_len, size_t *output_len)
290 if (ctx == YACA_CONTEXT_NULL || output_len == NULL ||
291 ctx->get_output_length == NULL)
292 return YACA_ERROR_INVALID_PARAMETER;
294 return ctx->get_output_length(ctx, input_len, output_len);
297 API int yaca_memcmp(const void *first, const void *second, size_t len)
299 if (CRYPTO_memcmp(first, second, len) == 0)
300 return YACA_ERROR_NONE;
302 return YACA_ERROR_DATA_MISMATCH;