ACR: extend parameter names a little in specific cases
[platform/core/security/yaca.git] / src / crypto.c
1 /*
2  *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Krzysztof Jackiewicz <k.jackiewicz@samsung.com>
5  *
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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
17  */
18
19 /**
20  * @file crypto.c
21  * @brief
22  */
23
24 #include <assert.h>
25 #include <string.h>
26 #include <pthread.h>
27
28 #include <openssl/crypto.h>
29 #include <openssl/evp.h>
30 #include <openssl/rand.h>
31 #include <openssl/err.h>
32
33 #include <yaca_crypto.h>
34 #include <yaca_error.h>
35
36 #include "internal.h"
37
38 static pthread_mutex_t *mutexes = NULL;
39
40 static void locking_callback(int mode, int type, const char *file, int line)
41 {
42         /* Ignore NULL mutexes and lock/unlock error codes as we can't do anything
43          * about them. */
44
45         if (mutexes == NULL)
46                 return;
47
48         if (mode & CRYPTO_LOCK)
49                 pthread_mutex_lock(&mutexes[type]);
50         else if (mode & CRYPTO_UNLOCK)
51                 pthread_mutex_unlock(&mutexes[type]);
52 }
53
54 static unsigned long thread_id_callback()
55 {
56         return pthread_self();
57 }
58
59 static void destroy_mutexes(int count)
60 {
61         if (mutexes != NULL) {
62                 for (int i = 0; i < count; i++) {
63                         /* Ignore returned value as we can't do anything about it */
64                         pthread_mutex_destroy(&mutexes[i]);
65                 }
66                 yaca_free(mutexes);
67                 mutexes = NULL;
68         }
69 }
70
71 API int yaca_initialize(void)
72 {
73         int ret;
74         if (mutexes != NULL)
75                 return YACA_ERROR_INTERNAL; // TODO introduce new one?
76
77         OPENSSL_init();
78
79         /* This should never fail on a /dev/random equipped system. If it does it
80          * means we might need to figure out another way of a truly random seed.
81          * https://wiki.openssl.org/index.php/Random_Numbers
82          *
83          * Another things to maybe consider for the future:
84          * - entropy on a mobile device (no mouse/keyboard)
85          * - fork safety: https://wiki.openssl.org/index.php/Random_fork-safety
86          * - hardware random generator (RdRand on new Intels, Samsung hardware?)
87          */
88         if (RAND_status() != 1) {
89                 ERROR_DUMP(YACA_ERROR_INTERNAL);
90                 return YACA_ERROR_INTERNAL;
91         }
92
93         OpenSSL_add_all_digests();
94         OpenSSL_add_all_ciphers();
95
96         /* enable threads support */
97         if (CRYPTO_num_locks() > 0) {
98                 ret = yaca_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t), (void**)&mutexes);
99                 if (ret != YACA_ERROR_NONE)
100                         return ret;
101
102                 for (int i = 0; i < CRYPTO_num_locks(); i++) {
103                         if (pthread_mutex_init(&mutexes[i], NULL) != 0) {
104                                 int ret = YACA_ERROR_NONE;
105                                 switch (errno) {
106                                 case ENOMEM:
107                                         ret = YACA_ERROR_OUT_OF_MEMORY;
108                                         break;
109                                 case EAGAIN:
110                                 case EPERM:
111                                 case EBUSY:
112                                 case EINVAL:
113                                 default:
114                                         ret = YACA_ERROR_INTERNAL;
115                                 }
116                                 destroy_mutexes(i);
117
118                                 return ret;
119                         }
120                 }
121
122                 CRYPTO_set_id_callback(thread_id_callback);
123                 CRYPTO_set_locking_callback(locking_callback);
124         }
125
126         /*
127          * TODO:
128          * - We should also decide on Openssl config.
129          * - Here's a good tutorial for initalization and cleanup:
130          *   https://wiki.openssl.org/index.php/Library_Initialization
131          * - We should also initialize the entropy for random number generator:
132          *   https://wiki.openssl.org/index.php/Random_Numbers#Initialization
133          */
134
135         return YACA_ERROR_NONE;
136 }
137
138 API int yaca_cleanup(void)
139 {
140         ERR_free_strings();
141         ERR_remove_thread_state(NULL);
142         EVP_cleanup();
143         RAND_cleanup();
144         CRYPTO_cleanup_all_ex_data();
145
146         /* threads support cleanup */
147         CRYPTO_set_id_callback(NULL);
148         CRYPTO_set_locking_callback(NULL);
149
150         destroy_mutexes(CRYPTO_num_locks());
151
152         return YACA_ERROR_NONE;
153 }
154
155 API int yaca_malloc(size_t size, void **memory)
156 {
157         if (size == 0 || memory == NULL)
158                 return YACA_ERROR_INVALID_PARAMETER;
159
160         *memory = OPENSSL_malloc(size);
161         if (*memory == NULL) {
162                 ERROR_DUMP(YACA_ERROR_OUT_OF_MEMORY);
163                 return YACA_ERROR_OUT_OF_MEMORY;
164         }
165
166         return YACA_ERROR_NONE;
167 }
168
169 API int yaca_zalloc(size_t size, void **memory)
170 {
171         int ret = yaca_malloc(size, memory);
172         if (ret != YACA_ERROR_NONE)
173                 return ret;
174
175         memset(*memory, 0, size);
176
177         return YACA_ERROR_NONE;
178 }
179
180 API int yaca_realloc(size_t size, void **memory)
181 {
182         if (size == 0 || memory == NULL)
183                 return YACA_ERROR_INVALID_PARAMETER;
184
185         void *tmp = OPENSSL_realloc(*memory, size);
186         if (tmp == NULL) {
187                 ERROR_DUMP(YACA_ERROR_OUT_OF_MEMORY);
188                 return YACA_ERROR_OUT_OF_MEMORY;
189         }
190
191         *memory = tmp;
192
193         return YACA_ERROR_NONE;
194 }
195
196 API int yaca_free(void *memory)
197 {
198         OPENSSL_free(memory);
199
200         return YACA_ERROR_NONE;
201 }
202
203 API int yaca_randomize_bytes(char *data, size_t data_len)
204 {
205         int ret;
206
207         if (data == NULL || data_len == 0)
208                 return YACA_ERROR_INVALID_PARAMETER;
209
210         ret = RAND_bytes((unsigned char *)data, data_len);
211         if (ret != 1) {
212                 ret = YACA_ERROR_INTERNAL;
213                 ERROR_DUMP(ret);
214                 return ret;
215         }
216
217         return YACA_ERROR_NONE;
218 }
219
220 API int yaca_context_set_property(yaca_context_h ctx, yaca_property_e property,
221                                   const void *value, size_t value_len)
222 {
223         if (ctx == YACA_CONTEXT_NULL || ctx->set_param == NULL)
224                 return YACA_ERROR_INVALID_PARAMETER;
225
226         return ctx->set_param(ctx, property, value, value_len);
227 }
228
229 API int yaca_context_get_property(const yaca_context_h ctx, yaca_property_e property,
230                                   void **value, size_t *value_len)
231 {
232         if (ctx == YACA_CONTEXT_NULL || ctx->get_param == NULL)
233                 return YACA_ERROR_INVALID_PARAMETER;
234
235         return ctx->get_param(ctx, property, value, value_len);
236 }
237
238 API int yaca_context_destroy(yaca_context_h ctx)
239 {
240         if (ctx != YACA_CONTEXT_NULL) {
241                 assert(ctx->ctx_destroy != NULL);
242                 ctx->ctx_destroy(ctx);
243                 yaca_free(ctx);
244         }
245
246         return YACA_ERROR_NONE;
247 }
248
249 API int yaca_context_get_output_length(const yaca_context_h ctx,
250                                        size_t input_len, size_t *output_len)
251 {
252         if (ctx == YACA_CONTEXT_NULL)
253                 return YACA_ERROR_INVALID_PARAMETER;
254
255         return ctx->get_output_length(ctx, input_len, output_len);
256 }
257
258 API int yaca_memcmp(const void *first, const void *second, size_t len)
259 {
260         if (CRYPTO_memcmp(first, second, len) == 0)
261                 return YACA_ERROR_NONE;
262
263         return YACA_ERROR_DATA_MISMATCH;
264 }