1 /*
2  * This file Copyright (C) 2014-2015 Mnemosyne LLC
3  *
4  * It may be used under the GNU GPL versions 2 or 3
5  * or any future license endorsed by Mnemosyne LLC.
6  *
7  */
8 
9 /* *INDENT-OFF* */
10 #if defined(CYASSL_IS_WOLFSSL)
11 #define API_HEADER(x) <wolfssl/x>
12 #define API_HEADER_CRYPT(x) API_HEADER(wolfcrypt/x)
13 #define API(x) wc_ ## x
14 #define API_VERSION_HEX LIBWOLFSSL_VERSION_HEX
15 #else
16 #define API_HEADER(x) <cyassl/x>
17 #define API_HEADER_CRYPT(x) API_HEADER(ctaocrypt/x)
18 #define API(x) x
19 #define API_VERSION_HEX LIBCYASSL_VERSION_HEX
20 #endif
21 
22 #include API_HEADER_CRYPT(arc4.h)
23 #include API_HEADER_CRYPT(dh.h)
24 #include API_HEADER_CRYPT(error-crypt.h)
25 #include API_HEADER_CRYPT(random.h)
26 #include API_HEADER_CRYPT(sha.h)
27 #include API_HEADER(version.h)
28 /* *INDENT-ON* */
29 
30 #include "transmission.h"
31 #include "crypto-utils.h"
32 #include "log.h"
33 #include "platform.h"
34 #include "tr-assert.h"
35 #include "utils.h"
36 
37 #define TR_CRYPTO_DH_SECRET_FALLBACK
38 #define TR_CRYPTO_X509_FALLBACK
39 #include "crypto-utils-fallback.c"
40 
41 struct tr_dh_ctx
42 {
43     DhKey dh;
44     word32 key_length;
45     uint8_t* private_key;
46     word32 private_key_length;
47 };
48 
49 /***
50 ****
51 ***/
52 
53 #define MY_NAME "tr_crypto_utils"
54 
log_cyassl_error(int error_code,char const * file,int line)55 static void log_cyassl_error(int error_code, char const* file, int line)
56 {
57     if (tr_logLevelIsActive(TR_LOG_ERROR))
58     {
59 #if API_VERSION_HEX >= 0x03004000
60         char const* error_message = API(GetErrorString)(error_code);
61 #elif API_VERSION_HEX >= 0x03000002
62         char const* error_message = CTaoCryptGetErrorString(error_code);
63 #else
64         char error_message[CYASSL_MAX_ERROR_SZ];
65         CTaoCryptErrorString(error_code, error_message);
66 #endif
67 
68         tr_logAddMessage(file, line, TR_LOG_ERROR, MY_NAME, "CyaSSL error: %s", error_message);
69     }
70 }
71 
check_cyassl_result(int result,char const * file,int line)72 static bool check_cyassl_result(int result, char const* file, int line)
73 {
74     bool const ret = result == 0;
75 
76     if (!ret)
77     {
78         log_cyassl_error(result, file, line);
79     }
80 
81     return ret;
82 }
83 
84 #define check_result(result) check_cyassl_result((result), __FILE__, __LINE__)
85 
86 /***
87 ****
88 ***/
89 
get_rng(void)90 static RNG* get_rng(void)
91 {
92     static RNG rng;
93     static bool rng_initialized = false;
94 
95     if (!rng_initialized)
96     {
97         if (!check_result(API(InitRng)(&rng)))
98         {
99             return NULL;
100         }
101 
102         rng_initialized = true;
103     }
104 
105     return &rng;
106 }
107 
get_rng_lock(void)108 static tr_lock* get_rng_lock(void)
109 {
110     static tr_lock* lock = NULL;
111 
112     if (lock == NULL)
113     {
114         lock = tr_lockNew();
115     }
116 
117     return lock;
118 }
119 
120 /***
121 ****
122 ***/
123 
tr_sha1_init(void)124 tr_sha1_ctx_t tr_sha1_init(void)
125 {
126     Sha* handle = tr_new(Sha, 1);
127 
128     if (check_result(API(InitSha)(handle)))
129     {
130         return handle;
131     }
132 
133     tr_free(handle);
134     return NULL;
135 }
136 
tr_sha1_update(tr_sha1_ctx_t handle,void const * data,size_t data_length)137 bool tr_sha1_update(tr_sha1_ctx_t handle, void const* data, size_t data_length)
138 {
139     TR_ASSERT(handle != NULL);
140 
141     if (data_length == 0)
142     {
143         return true;
144     }
145 
146     TR_ASSERT(data != NULL);
147 
148     return check_result(API(ShaUpdate)(handle, data, data_length));
149 }
150 
tr_sha1_final(tr_sha1_ctx_t handle,uint8_t * hash)151 bool tr_sha1_final(tr_sha1_ctx_t handle, uint8_t* hash)
152 {
153     bool ret = true;
154 
155     if (hash != NULL)
156     {
157         TR_ASSERT(handle != NULL);
158 
159         ret = check_result(API(ShaFinal)(handle, hash));
160     }
161 
162     tr_free(handle);
163     return ret;
164 }
165 
166 /***
167 ****
168 ***/
169 
tr_rc4_new(void)170 tr_rc4_ctx_t tr_rc4_new(void)
171 {
172     return tr_new0(Arc4, 1);
173 }
174 
tr_rc4_free(tr_rc4_ctx_t handle)175 void tr_rc4_free(tr_rc4_ctx_t handle)
176 {
177     tr_free(handle);
178 }
179 
tr_rc4_set_key(tr_rc4_ctx_t handle,uint8_t const * key,size_t key_length)180 void tr_rc4_set_key(tr_rc4_ctx_t handle, uint8_t const* key, size_t key_length)
181 {
182     TR_ASSERT(handle != NULL);
183     TR_ASSERT(key != NULL);
184 
185     API(Arc4SetKey)(handle, key, key_length);
186 }
187 
tr_rc4_process(tr_rc4_ctx_t handle,void const * input,void * output,size_t length)188 void tr_rc4_process(tr_rc4_ctx_t handle, void const* input, void* output, size_t length)
189 {
190     TR_ASSERT(handle != NULL);
191 
192     if (length == 0)
193     {
194         return;
195     }
196 
197     TR_ASSERT(input != NULL);
198     TR_ASSERT(output != NULL);
199 
200     API(Arc4Process)(handle, output, input, length);
201 }
202 
203 /***
204 ****
205 ***/
206 
tr_dh_new(uint8_t const * prime_num,size_t prime_num_length,uint8_t const * generator_num,size_t generator_num_length)207 tr_dh_ctx_t tr_dh_new(uint8_t const* prime_num, size_t prime_num_length, uint8_t const* generator_num,
208     size_t generator_num_length)
209 {
210     TR_ASSERT(prime_num != NULL);
211     TR_ASSERT(generator_num != NULL);
212 
213     struct tr_dh_ctx* handle = tr_new0(struct tr_dh_ctx, 1);
214 
215     API(InitDhKey)(&handle->dh);
216 
217     if (!check_result(API(DhSetKey)(&handle->dh, prime_num, prime_num_length, generator_num, generator_num_length)))
218     {
219         tr_free(handle);
220         return NULL;
221     }
222 
223     handle->key_length = prime_num_length;
224 
225     return handle;
226 }
227 
tr_dh_free(tr_dh_ctx_t raw_handle)228 void tr_dh_free(tr_dh_ctx_t raw_handle)
229 {
230     struct tr_dh_ctx* handle = raw_handle;
231 
232     if (handle == NULL)
233     {
234         return;
235     }
236 
237     API(FreeDhKey)(&handle->dh);
238     tr_free(handle->private_key);
239     tr_free(handle);
240 }
241 
tr_dh_make_key(tr_dh_ctx_t raw_handle,size_t private_key_length UNUSED,uint8_t * public_key,size_t * public_key_length)242 bool tr_dh_make_key(tr_dh_ctx_t raw_handle, size_t private_key_length UNUSED, uint8_t* public_key, size_t* public_key_length)
243 {
244     TR_ASSERT(raw_handle != NULL);
245     TR_ASSERT(public_key != NULL);
246 
247     struct tr_dh_ctx* handle = raw_handle;
248     word32 my_private_key_length;
249     word32 my_public_key_length;
250     tr_lock* rng_lock = get_rng_lock();
251 
252     if (handle->private_key == NULL)
253     {
254         handle->private_key = tr_malloc(handle->key_length);
255     }
256 
257     tr_lockLock(rng_lock);
258 
259     if (!check_result(API(DhGenerateKeyPair)(&handle->dh, get_rng(), handle->private_key, &my_private_key_length, public_key,
260         &my_public_key_length)))
261     {
262         tr_lockUnlock(rng_lock);
263         return false;
264     }
265 
266     tr_lockUnlock(rng_lock);
267 
268     tr_dh_align_key(public_key, my_public_key_length, handle->key_length);
269 
270     handle->private_key_length = my_private_key_length;
271 
272     if (public_key_length != NULL)
273     {
274         *public_key_length = handle->key_length;
275     }
276 
277     return true;
278 }
279 
tr_dh_agree(tr_dh_ctx_t raw_handle,uint8_t const * other_public_key,size_t other_public_key_length)280 tr_dh_secret_t tr_dh_agree(tr_dh_ctx_t raw_handle, uint8_t const* other_public_key, size_t other_public_key_length)
281 {
282     TR_ASSERT(raw_handle != NULL);
283     TR_ASSERT(other_public_key != NULL);
284 
285     struct tr_dh_ctx* handle = raw_handle;
286     struct tr_dh_secret* ret;
287     word32 my_secret_key_length;
288 
289     ret = tr_dh_secret_new(handle->key_length);
290 
291     if (check_result(API(DhAgree)(&handle->dh, ret->key, &my_secret_key_length, handle->private_key, handle->private_key_length,
292         other_public_key, other_public_key_length)))
293     {
294         tr_dh_secret_align(ret, my_secret_key_length);
295     }
296     else
297     {
298         tr_dh_secret_free(ret);
299         ret = NULL;
300     }
301 
302     return ret;
303 }
304 
305 /***
306 ****
307 ***/
308 
tr_rand_buffer(void * buffer,size_t length)309 bool tr_rand_buffer(void* buffer, size_t length)
310 {
311     TR_ASSERT(buffer != NULL);
312 
313     bool ret;
314     tr_lock* rng_lock = get_rng_lock();
315 
316     tr_lockLock(rng_lock);
317     ret = check_result(API(RNG_GenerateBlock)(get_rng(), buffer, length));
318     tr_lockUnlock(rng_lock);
319 
320     return ret;
321 }
322