luci-app-mwan3: add dependecy to size option
[project/luci.git] / libs / luci-lib-nixio / axTLS / ssl / loader.c
1 /*
2  * Copyright (c) 2007, Cameron Rich
3  * 
4  * All rights reserved.
5  * 
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright notice, 
10  *   this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright notice, 
12  *   this list of conditions and the following disclaimer in the documentation 
13  *   and/or other materials provided with the distribution.
14  * * Neither the name of the axTLS project nor the names of its contributors 
15  *   may be used to endorse or promote products derived from this software 
16  *   without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /**
32  * Load certificates/keys into memory. These can be in many different formats.
33  * PEM support and other formats can be processed here.
34  *
35  * The PEM private keys may be optionally encrypted with AES128 or AES256. 
36  * The encrypted PEM keys were generated with something like:
37  *
38  * openssl genrsa -aes128 -passout pass:abcd -out axTLS.key_aes128.pem 512
39  */
40
41 #include <stdlib.h>
42 #include <string.h>
43 #include <stdio.h>
44
45 #include "ssl.h"
46
47 static int do_obj(SSL_CTX *ssl_ctx, int obj_type, 
48                     SSLObjLoader *ssl_obj, const char *password);
49 #ifdef CONFIG_SSL_HAS_PEM
50 static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, 
51                         SSLObjLoader *ssl_obj, const char *password);
52 #endif
53
54 /*
55  * Load a file into memory that is in binary DER (or ascii PEM) format.
56  */
57 EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, 
58                             const char *filename, const char *password)
59 {
60 #ifndef CONFIG_SSL_SKELETON_MODE
61     static const char * const begin = "-----BEGIN";
62     int ret = SSL_OK;
63     SSLObjLoader *ssl_obj = NULL;
64
65     if (filename == NULL)
66     {
67         ret = SSL_ERROR_INVALID_KEY;
68         goto error;
69     }
70
71     ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
72     ssl_obj->len = get_file(filename, &ssl_obj->buf); 
73     if (ssl_obj->len <= 0)
74     {
75         ret = SSL_ERROR_INVALID_KEY;
76         goto error;
77     }
78
79     /* is the file a PEM file? */
80     if (strncmp((char *)ssl_obj->buf, begin, strlen(begin)) == 0)
81     {
82 #ifdef CONFIG_SSL_HAS_PEM
83         ret = ssl_obj_PEM_load(ssl_ctx, obj_type, ssl_obj, password);
84 #else
85         printf(unsupported_str);
86         ret = SSL_ERROR_NOT_SUPPORTED;
87 #endif
88     }
89     else
90         ret = do_obj(ssl_ctx, obj_type, ssl_obj, password);
91
92 error:
93     ssl_obj_free(ssl_obj);
94     return ret;
95 #else
96     printf(unsupported_str);
97     return SSL_ERROR_NOT_SUPPORTED;
98 #endif /* CONFIG_SSL_SKELETON_MODE */
99 }
100
101 /*
102  * Transfer binary data into the object loader.
103  */
104 EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int mem_type, 
105         const uint8_t *data, int len, const char *password)
106 {
107     int ret;
108     SSLObjLoader *ssl_obj;
109
110     ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
111     ssl_obj->buf = (uint8_t *)malloc(len);
112     memcpy(ssl_obj->buf, data, len);
113     ssl_obj->len = len;
114     ret = do_obj(ssl_ctx, mem_type, ssl_obj, password);
115     ssl_obj_free(ssl_obj);
116     return ret;
117 }
118
119 /*
120  * Actually work out what we are doing 
121  */
122 static int do_obj(SSL_CTX *ssl_ctx, int obj_type, 
123                     SSLObjLoader *ssl_obj, const char *password)
124 {
125     int ret = SSL_OK;
126
127     switch (obj_type)
128     {
129         case SSL_OBJ_RSA_KEY:
130             ret = add_private_key(ssl_ctx, ssl_obj);
131             break;
132
133         case SSL_OBJ_X509_CERT:
134             ret = add_cert(ssl_ctx, ssl_obj->buf, ssl_obj->len);
135             break;
136
137 #ifdef CONFIG_SSL_CERT_VERIFICATION
138         case SSL_OBJ_X509_CACERT:
139             ret = add_cert_auth(ssl_ctx, ssl_obj->buf, ssl_obj->len);
140             break;
141 #endif
142
143 #ifdef CONFIG_SSL_USE_PKCS12
144         case SSL_OBJ_PKCS8:
145             ret = pkcs8_decode(ssl_ctx, ssl_obj, password);
146             break;
147
148         case SSL_OBJ_PKCS12:
149             ret = pkcs12_decode(ssl_ctx, ssl_obj, password);
150             break;
151 #endif
152         default:
153             printf(unsupported_str);
154             ret = SSL_ERROR_NOT_SUPPORTED;
155             break;
156     }
157
158     return ret;
159 }
160
161 /*
162  * Clean up our mess.
163  */
164 void ssl_obj_free(SSLObjLoader *ssl_obj)
165 {
166     if (ssl_obj)
167     {
168         free(ssl_obj->buf);
169         free(ssl_obj);
170     }
171 }
172
173 /*
174  * Support for PEM encoded keys/certificates.
175  */
176 #ifdef CONFIG_SSL_HAS_PEM
177
178 #define NUM_PEM_TYPES               3
179 #define IV_SIZE                     16
180 #define IS_RSA_PRIVATE_KEY          0
181 #define IS_ENCRYPTED_PRIVATE_KEY    1
182 #define IS_CERTIFICATE              2
183
184 static const char * const begins[NUM_PEM_TYPES] =
185 {
186     "-----BEGIN RSA PRIVATE KEY-----",
187     "-----BEGIN ENCRYPTED PRIVATE KEY-----",
188     "-----BEGIN CERTIFICATE-----",
189 };
190
191 static const char * const ends[NUM_PEM_TYPES] =
192 {
193     "-----END RSA PRIVATE KEY-----",
194     "-----END ENCRYPTED PRIVATE KEY-----",
195     "-----END CERTIFICATE-----",
196 };
197
198 static const char * const aes_str[2] =
199 {
200     "DEK-Info: AES-128-CBC,",
201     "DEK-Info: AES-256-CBC," 
202 };
203
204 /**
205  * Take a base64 blob of data and decrypt it (using AES) into its 
206  * proper ASN.1 form.
207  */
208 static int pem_decrypt(const char *where, const char *end,
209                         const char *password, SSLObjLoader *ssl_obj)
210 {
211     int ret = -1;
212     int is_aes_256 = 0;
213     char *start = NULL;
214     uint8_t iv[IV_SIZE];
215     int i, pem_size;
216     MD5_CTX md5_ctx;
217     AES_CTX aes_ctx;
218     uint8_t key[32];        /* AES256 size */
219
220     if (password == NULL || strlen(password) == 0)
221     {
222 #ifdef CONFIG_SSL_FULL_MODE
223         printf("Error: Need a password for this PEM file\n"); TTY_FLUSH();
224 #endif
225         goto error;
226     }
227
228     if ((start = strstr((const char *)where, aes_str[0])))         /* AES128? */
229     {
230         start += strlen(aes_str[0]);
231     }
232     else if ((start = strstr((const char *)where, aes_str[1])))    /* AES256? */
233     {
234         is_aes_256 = 1;
235         start += strlen(aes_str[1]);
236     }
237     else 
238     {
239 #ifdef CONFIG_SSL_FULL_MODE
240         printf("Error: Unsupported password cipher\n"); TTY_FLUSH();
241 #endif
242         goto error;
243     }
244
245     /* convert from hex to binary - assumes uppercase hex */
246     for (i = 0; i < IV_SIZE; i++)
247     {
248         char c = *start++ - '0';
249         iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4;
250         c = *start++ - '0';
251         iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c);
252     }
253
254     while (*start == '\r' || *start == '\n')
255         start++;
256
257     /* turn base64 into binary */
258     pem_size = (int)(end-start);
259     if (base64_decode(start, pem_size, ssl_obj->buf, &ssl_obj->len) != 0)
260         goto error;
261
262     /* work out the key */
263     MD5_Init(&md5_ctx);
264     MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
265     MD5_Update(&md5_ctx, iv, SALT_SIZE);
266     MD5_Final(key, &md5_ctx);
267
268     if (is_aes_256)
269     {
270         MD5_Init(&md5_ctx);
271         MD5_Update(&md5_ctx, key, MD5_SIZE);
272         MD5_Update(&md5_ctx, (const uint8_t *)password, strlen(password));
273         MD5_Update(&md5_ctx, iv, SALT_SIZE);
274         MD5_Final(&key[MD5_SIZE], &md5_ctx);
275     }
276
277     /* decrypt using the key/iv */
278     AES_set_key(&aes_ctx, key, iv, is_aes_256 ? AES_MODE_256 : AES_MODE_128);
279     AES_convert_key(&aes_ctx);
280     AES_cbc_decrypt(&aes_ctx, ssl_obj->buf, ssl_obj->buf, ssl_obj->len);
281     ret = 0;
282
283 error:
284     return ret; 
285 }
286
287 /**
288  * Take a base64 blob of data and turn it into its proper ASN.1 form.
289  */
290 static int new_pem_obj(SSL_CTX *ssl_ctx, int is_cacert, char *where, 
291                     int remain, const char *password)
292 {
293     int ret = SSL_OK;
294     SSLObjLoader *ssl_obj = NULL;
295     int i, pem_size, obj_type;
296     char *start = NULL, *end = NULL;
297
298     for (i = 0; i < NUM_PEM_TYPES; i++)
299     {
300         if ((start = strstr(where, begins[i])) &&
301                 (end = strstr(where, ends[i])))
302         {
303             remain -= (int)(end-start);
304             start += strlen(begins[i]);
305             pem_size = (int)(end-start);
306
307             ssl_obj = (SSLObjLoader *)calloc(1, sizeof(SSLObjLoader));
308
309             /* 4/3 bigger than what we need but so what */
310             ssl_obj->buf = (uint8_t *)calloc(1, pem_size);
311
312             if (i == IS_RSA_PRIVATE_KEY && 
313                         strstr(start, "Proc-Type:") && 
314                         strstr(start, "4,ENCRYPTED"))
315             {
316                 /* check for encrypted PEM file */
317                 if (pem_decrypt(start, end, password, ssl_obj) < 0)
318                     goto error;
319             }
320             else if (base64_decode(start, pem_size, 
321                         ssl_obj->buf, &ssl_obj->len) != 0)
322                 goto error;
323
324             switch (i)
325             {
326                 case IS_RSA_PRIVATE_KEY:
327                     obj_type = SSL_OBJ_RSA_KEY;
328                     break;
329
330                 case IS_ENCRYPTED_PRIVATE_KEY:
331                     obj_type = SSL_OBJ_PKCS8;
332                     break;
333
334                 case IS_CERTIFICATE:
335                     obj_type = is_cacert ?
336                                     SSL_OBJ_X509_CACERT : SSL_OBJ_X509_CERT;
337                     break;
338
339                 default:
340                     goto error;
341             }
342
343             /* In a format we can now understand - so process it */
344             if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password)))
345                 goto error;
346
347             end += strlen(ends[i]);
348             remain -= strlen(ends[i]);
349             while (remain > 0 && (*end == '\r' || *end == '\n'))
350             {
351                 end++;
352                 remain--;
353             }
354
355             break;
356         }
357     }
358
359     if (i == NUM_PEM_TYPES)
360         goto error;
361
362     /* more PEM stuff to process? */
363     if (remain)
364         ret = new_pem_obj(ssl_ctx, is_cacert, end, remain, password);
365
366 error:
367     ssl_obj_free(ssl_obj);
368     return ret;
369 }
370
371 /*
372  * Load a file into memory that is in ASCII PEM format.
373  */
374 static int ssl_obj_PEM_load(SSL_CTX *ssl_ctx, int obj_type, 
375                         SSLObjLoader *ssl_obj, const char *password)
376 {
377     char *start;
378
379     /* add a null terminator */
380     ssl_obj->len++;
381     ssl_obj->buf = (uint8_t *)realloc(ssl_obj->buf, ssl_obj->len);
382     ssl_obj->buf[ssl_obj->len-1] = 0;
383     start = (char *)ssl_obj->buf;
384     return new_pem_obj(ssl_ctx, obj_type == SSL_OBJ_X509_CACERT,
385                                 start, ssl_obj->len, password);
386 }
387 #endif /* CONFIG_SSL_HAS_PEM */
388
389 /**
390  * Load the key/certificates in memory depending on compile-time and user
391  * options. 
392  */
393 int load_key_certs(SSL_CTX *ssl_ctx)
394 {
395     int ret = SSL_OK;
396     uint32_t options = ssl_ctx->options;
397 #ifdef CONFIG_SSL_GENERATE_X509_CERT 
398     uint8_t *cert_data = NULL;
399     int cert_size;
400     static const char *dn[] = 
401     {
402         CONFIG_SSL_X509_COMMON_NAME,
403         CONFIG_SSL_X509_ORGANIZATION_NAME,
404         CONFIG_SSL_X509_ORGANIZATION_UNIT_NAME
405     };
406 #endif
407
408     /* do the private key first */
409     if (strlen(CONFIG_SSL_PRIVATE_KEY_LOCATION) > 0)
410     {
411         if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_RSA_KEY, 
412                                 CONFIG_SSL_PRIVATE_KEY_LOCATION,
413                                 CONFIG_SSL_PRIVATE_KEY_PASSWORD)) < 0)
414             goto error;
415     }
416     else if (!(options & SSL_NO_DEFAULT_KEY))
417     {
418 #if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
419         static const    /* saves a few more bytes */
420 #include "private_key.h"
421
422         ssl_obj_memory_load(ssl_ctx, SSL_OBJ_RSA_KEY, default_private_key,
423                 default_private_key_len, NULL); 
424 #endif
425     }
426
427     /* now load the certificate */
428 #ifdef CONFIG_SSL_GENERATE_X509_CERT 
429     if ((cert_size = ssl_x509_create(ssl_ctx, 0, dn, &cert_data)) < 0)
430     {
431         ret = cert_size;
432         goto error;
433     }
434
435     ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, cert_data, cert_size, NULL);
436     free(cert_data);
437 #else
438     if (strlen(CONFIG_SSL_X509_CERT_LOCATION))
439     {
440         if ((ret = ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CERT, 
441                                 CONFIG_SSL_X509_CERT_LOCATION, NULL)) < 0)
442             goto error;
443     }
444     else if (!(options & SSL_NO_DEFAULT_KEY))
445     {
446 #if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE)
447         static const    /* saves a few bytes and RAM */
448 #include "cert.h"
449         ssl_obj_memory_load(ssl_ctx, SSL_OBJ_X509_CERT, 
450                     default_certificate, default_certificate_len, NULL);
451 #endif
452     }
453 #endif
454
455 error:
456 #ifdef CONFIG_SSL_FULL_MODE
457     if (ret)
458     {
459         printf("Error: Certificate or key not loaded\n"); TTY_FLUSH();
460     }
461 #endif
462
463     return ret;
464
465 }