diff options
author | Cedric BAIL <cedric.bail@samsung.com> | 2015-03-17 08:50:13 +0100 |
---|---|---|
committer | Cedric BAIL <cedric@osg.samsung.com> | 2015-03-17 09:58:18 +0100 |
commit | a089d8cd7bd1386a7aa64774e17925a17e8e00bc (patch) | |
tree | 10032de8d8a8d29f41635eb9525b8bd617cca702 | |
parent | 0f5184bbe4d40dc0c6793d46ab1906b692c76a9b (diff) |
emile: Add SSL support.
-rw-r--r-- | src/lib/ecore_con/ecore_con_ssl.c | 2 | ||||
-rw-r--r-- | src/lib/emile/Emile.h | 36 | ||||
-rw-r--r-- | src/lib/emile/emile_cipher.c | 110 | ||||
-rw-r--r-- | src/lib/emile/emile_cipher_gnutls.c | 312 | ||||
-rw-r--r-- | src/lib/emile/emile_cipher_openssl.c | 844 | ||||
-rw-r--r-- | src/lib/emile/emile_main.c | 2 | ||||
-rw-r--r-- | src/lib/emile/emile_private.h | 8 |
7 files changed, 1311 insertions, 3 deletions
diff --git a/src/lib/ecore_con/ecore_con_ssl.c b/src/lib/ecore_con/ecore_con_ssl.c index c52567beaf..3ca865b277 100644 --- a/src/lib/ecore_con/ecore_con_ssl.c +++ b/src/lib/ecore_con/ecore_con_ssl.c | |||
@@ -1372,8 +1372,6 @@ _ecore_con_ssl_client_write_gnutls(Ecore_Con_Client *obj, | |||
1372 | */ | 1372 | */ |
1373 | 1373 | ||
1374 | static Ecore_Con_Ssl_Error | 1374 | static Ecore_Con_Ssl_Error |
1375 | |||
1376 | static Ecore_Con_Ssl_Error | ||
1377 | _ecore_con_ssl_server_prepare_openssl(Ecore_Con_Server *obj, | 1375 | _ecore_con_ssl_server_prepare_openssl(Ecore_Con_Server *obj, |
1378 | int ssl_type) | 1376 | int ssl_type) |
1379 | { | 1377 | { |
diff --git a/src/lib/emile/Emile.h b/src/lib/emile/Emile.h index b97c30eafe..47a9186d3b 100644 --- a/src/lib/emile/Emile.h +++ b/src/lib/emile/Emile.h | |||
@@ -106,7 +106,24 @@ EAPI int emile_shutdown(void); | |||
106 | * @} | 106 | * @} |
107 | */ | 107 | */ |
108 | 108 | ||
109 | typedef struct _Emile_SSL Emile_SSL; | ||
110 | |||
111 | typedef enum | ||
112 | { | ||
113 | EMILE_SSLv23, | ||
114 | EMILE_SSLv3, | ||
115 | EMILE_TLSv1 | ||
116 | } Emile_Cipher_Type; | ||
117 | |||
118 | typedef enum | ||
119 | { | ||
120 | EMILE_WANT_NOTHING = 0, | ||
121 | EMILE_WANT_READ = 1, | ||
122 | EMILE_WANT_WRITE = 3 | ||
123 | } Emile_Want_Type; | ||
124 | |||
109 | EAPI Eina_Bool emile_cipher_init(void); | 125 | EAPI Eina_Bool emile_cipher_init(void); |
126 | EAPI const char *emile_cipher_module_get(void); | ||
110 | 127 | ||
111 | EAPI Eina_Binbuf *emile_binbuf_cipher(const Eina_Binbuf *in, | 128 | EAPI Eina_Binbuf *emile_binbuf_cipher(const Eina_Binbuf *in, |
112 | const char *key, unsigned int length); | 129 | const char *key, unsigned int length); |
@@ -114,6 +131,25 @@ EAPI Eina_Binbuf *emile_binbuf_cipher(const Eina_Binbuf *in, | |||
114 | EAPI Eina_Binbuf *emile_binbuf_decipher(const Eina_Binbuf *in, | 131 | EAPI Eina_Binbuf *emile_binbuf_decipher(const Eina_Binbuf *in, |
115 | const char *key, unsigned int length); | 132 | const char *key, unsigned int length); |
116 | 133 | ||
134 | EAPI Emile_SSL *emile_cipher_server_listen(Emile_Cipher_Type t); | ||
135 | EAPI Emile_SSL *emile_cipher_client_connect(Emile_SSL *server, int fd); | ||
136 | EAPI Emile_SSL *emile_cipher_server_connect(Emile_Cipher_Type t); | ||
137 | EAPI Eina_Bool emile_cipher_free(Emile_SSL *emile); | ||
138 | |||
139 | EAPI Eina_Bool emile_cipher_cafile_add(Emile_SSL *emile, const char *file); | ||
140 | EAPI Eina_Bool emile_cipher_cert_add(Emile_SSL *emile, const char *file); | ||
141 | EAPI Eina_Bool emile_cipher_privkey_add(Emile_SSL *emile, const char *file); | ||
142 | EAPI Eina_Bool emile_cipher_crl_add(Emile_SSL *emile, const char *file); | ||
143 | EAPI int emile_cipher_read(Emile_SSL *emile, Eina_Binbuf *buffer); | ||
144 | EAPI int emile_cipher_write(Emile_SSL *emile, const Eina_Binbuf *buffer); | ||
145 | EAPI const char *emile_cipher_error_get(const Emile_SSL *emile); | ||
146 | EAPI Eina_Bool emile_cipher_verify_name_set(Emile_SSL *emile, const char *name); | ||
147 | EAPI const char *emile_cipher_verify_name_get(const Emile_SSL *emile); | ||
148 | EAPI void emile_cipher_verify_set(Emile_SSL *emile, Eina_Bool verify); | ||
149 | EAPI void emile_cipher_verify_basic_set(Emile_SSL *emile, Eina_Bool verify_basic); | ||
150 | EAPI Eina_Bool emile_cipher_verify_get(const Emile_SSL *emile); | ||
151 | EAPI Eina_Bool emile_cipher_verify_basic_get(const Emile_SSL *emile); | ||
152 | |||
117 | typedef enum | 153 | typedef enum |
118 | { | 154 | { |
119 | EMILE_ZLIB, | 155 | EMILE_ZLIB, |
diff --git a/src/lib/emile/emile_cipher.c b/src/lib/emile/emile_cipher.c index 3af06886b9..3c5fd185cc 100644 --- a/src/lib/emile/emile_cipher.c +++ b/src/lib/emile/emile_cipher.c | |||
@@ -28,3 +28,113 @@ emile_binbuf_decipher(const Eina_Binbuf *data EINA_UNUSED, | |||
28 | { | 28 | { |
29 | return NULL; | 29 | return NULL; |
30 | } | 30 | } |
31 | |||
32 | EAPI Emile_SSL * | ||
33 | emile_cipher_server_listen(Emile_Cipher_Type t EINA_UNUSED) | ||
34 | { | ||
35 | return NULL; | ||
36 | } | ||
37 | |||
38 | EAPI Emile_SSL * | ||
39 | emile_cipher_client_connect(Emile_SSL *server EINA_UNUSED, int fd EINA_UNUSED) | ||
40 | { | ||
41 | return NULL; | ||
42 | } | ||
43 | |||
44 | EAPI Emile_SSL * | ||
45 | emile_cipher_server_connect(Emile_Cipher_Type t EINA_UNUSED) | ||
46 | { | ||
47 | return NULL; | ||
48 | } | ||
49 | |||
50 | EAPI Eina_Bool | ||
51 | emile_cipher_free(Emile_SSL *emile EINA_UNUSED) | ||
52 | { | ||
53 | return EINA_TRUE; | ||
54 | } | ||
55 | |||
56 | EAPI Eina_Bool | ||
57 | emile_cipher_cafile_add(Emile_SSL *emile EINA_UNUSED, | ||
58 | const char *file EINA_UNUSED) | ||
59 | { | ||
60 | return EINA_FALSE; | ||
61 | } | ||
62 | |||
63 | EAPI Eina_Bool | ||
64 | emile_cipher_cert_add(Emile_SSL *emile EINA_UNUSED, | ||
65 | const char *file EINA_UNUSED) | ||
66 | { | ||
67 | return EINA_FALSE; | ||
68 | } | ||
69 | |||
70 | EAPI Eina_Bool | ||
71 | emile_cipher_privkey_add(Emile_SSL *emile EINA_UNUSED, | ||
72 | const char *file EINA_UNUSED) | ||
73 | { | ||
74 | return EINA_FALSE; | ||
75 | } | ||
76 | |||
77 | EAPI Eina_Bool | ||
78 | emile_cipher_crl_add(Emile_SSL *emile EINA_UNUSED, | ||
79 | const char *file EINA_UNUSED) | ||
80 | { | ||
81 | return EINA_FALSE; | ||
82 | } | ||
83 | |||
84 | EAPI int | ||
85 | emile_cipher_read(Emile_SSL *emile EINA_UNUSED, | ||
86 | Eina_Binbuf *buffer EINA_UNUSED) | ||
87 | { | ||
88 | return EINA_FALSE; | ||
89 | } | ||
90 | |||
91 | EAPI int | ||
92 | emile_cipher_write(Emile_SSL *emile EINA_UNUSED, | ||
93 | const Eina_Binbuf *buffer EINA_UNUSED) | ||
94 | { | ||
95 | return EINA_FALSE; | ||
96 | } | ||
97 | |||
98 | |||
99 | EAPI const char * | ||
100 | emile_cipher_error_get(const Emile_SSL *emile EINA_UNUSED) | ||
101 | { | ||
102 | return NULL; | ||
103 | } | ||
104 | |||
105 | EAPI Eina_Bool | ||
106 | emile_cipher_verify_name_set(Emile_SSL *emile EINA_UNUSED, | ||
107 | const char *name EINA_UNUSED) | ||
108 | { | ||
109 | return EINA_FALSE; | ||
110 | } | ||
111 | |||
112 | EAPI const char * | ||
113 | emile_cipher_verify_name_get(const Emile_SSL *emile EINA_UNUSED) | ||
114 | { | ||
115 | return NULL; | ||
116 | } | ||
117 | |||
118 | EAPI void | ||
119 | emile_cipher_verify_set(Emile_SSL *emile EINA_UNUSED, | ||
120 | Eina_Bool verify EINA_UNUSED) | ||
121 | { | ||
122 | } | ||
123 | |||
124 | EAPI void | ||
125 | emile_cipher_verify_basic_set(Emile_SSL *emile EINA_UNUSED, | ||
126 | Eina_Bool verify_basic EINA_UNUSED) | ||
127 | { | ||
128 | } | ||
129 | |||
130 | EAPI Eina_Bool | ||
131 | emile_cipher_verify_get(const Emile_SSL *emile EINA_UNUSED) | ||
132 | { | ||
133 | return EINA_FALSE; | ||
134 | } | ||
135 | |||
136 | EAPI Eina_Bool | ||
137 | emile_cipher_verify_basic_get(const Emile_SSL *emile EINA_UNUSED) | ||
138 | { | ||
139 | return EINA_FALSE; | ||
140 | } | ||
diff --git a/src/lib/emile/emile_cipher_gnutls.c b/src/lib/emile/emile_cipher_gnutls.c index f69d25d346..ed48af5f92 100644 --- a/src/lib/emile/emile_cipher_gnutls.c +++ b/src/lib/emile/emile_cipher_gnutls.c | |||
@@ -19,6 +19,37 @@ | |||
19 | #define MAX_KEY_LEN 32 | 19 | #define MAX_KEY_LEN 32 |
20 | #define MAX_IV_LEN 16 | 20 | #define MAX_IV_LEN 16 |
21 | 21 | ||
22 | struct _Emile_SSL | ||
23 | { | ||
24 | const char *last_error; | ||
25 | const char *cert_file; | ||
26 | const char *name; | ||
27 | |||
28 | gnutls_certificate_credentials_t cert; | ||
29 | gnutls_session_t session; | ||
30 | |||
31 | union { | ||
32 | struct { | ||
33 | gnutls_datum_t session_ticket; | ||
34 | } client; | ||
35 | struct { | ||
36 | gnutls_anon_client_credentials_t anoncred_c; | ||
37 | gnutls_anon_server_credentials_t anoncred_s; | ||
38 | gnutls_psk_client_credentials_t pskcred_c; | ||
39 | gnutls_psk_server_credentials_t pskcred_s; | ||
40 | char *cert_file; | ||
41 | gnutls_dh_params_t dh_params; | ||
42 | } server; | ||
43 | } u; | ||
44 | |||
45 | Emile_Cipher_Type t; | ||
46 | Emile_SSL_State ssl_state; | ||
47 | |||
48 | Eina_Bool server : 1; | ||
49 | Eina_Bool verify : 1; | ||
50 | Eina_Bool verify_basic : 1; | ||
51 | }; | ||
52 | |||
22 | static int | 53 | static int |
23 | _emile_thread_mutex_init(void **priv) | 54 | _emile_thread_mutex_init(void **priv) |
24 | { | 55 | { |
@@ -383,3 +414,284 @@ on_error: | |||
383 | 414 | ||
384 | return NULL; | 415 | return NULL; |
385 | } | 416 | } |
417 | |||
418 | |||
419 | EAPI Eina_Bool | ||
420 | emile_cipher_cafile_add(Emile_SSL *emile, const char *file) | ||
421 | { | ||
422 | struct stat st; | ||
423 | int count = 0; | ||
424 | |||
425 | if (stat(file, &st)) return EINA_FALSE; | ||
426 | if (S_ISDIR(st.st_mode)) | ||
427 | { | ||
428 | Eina_File_Direct_Info *info; | ||
429 | Eina_Iterator *it; | ||
430 | int err; | ||
431 | |||
432 | it = eina_file_direct_ls(file); | ||
433 | EINA_ITERATOR_FOREACH(it, info) | ||
434 | { | ||
435 | if (info->type != EINA_FILE_REG && | ||
436 | info->type != EINA_FILE_LNK) | ||
437 | continue; | ||
438 | |||
439 | err = gnutls_certificate_set_x509_trust_file(emile->cert, | ||
440 | info->path, | ||
441 | GNUTLS_X509_FMT_PEM); | ||
442 | if (err > 0) count += err; | ||
443 | else DBG("File '%s' could not be loaded.", info->path); | ||
444 | } | ||
445 | eina_iterator_free(it); | ||
446 | } | ||
447 | else | ||
448 | { | ||
449 | count = gnutls_certificate_set_x509_trust_file(emile->cert, | ||
450 | file, | ||
451 | GNUTLS_X509_FMT_PEM); | ||
452 | if (count <= 0) DBG("File '%s' could not be loaded.", file); | ||
453 | } | ||
454 | |||
455 | return count > 0 ? EINA_TRUE : EINA_FALSE; | ||
456 | } | ||
457 | |||
458 | EAPI Eina_Bool | ||
459 | emile_cipher_privkey_add(Emile_SSL *emile, const char *file) | ||
460 | { | ||
461 | int err; | ||
462 | |||
463 | err = gnutls_certificate_set_x509_key_file(emile->cert, | ||
464 | emile->cert_file, | ||
465 | file, | ||
466 | GNUTLS_X509_FMT_PEM); | ||
467 | |||
468 | if (err <= 0) DBG("Could not load certificate/key '%s'.", file); | ||
469 | return err > 0 ? EINA_TRUE : EINA_FALSE; | ||
470 | } | ||
471 | |||
472 | EAPI Eina_Bool | ||
473 | emile_cipher_crl_add(Emile_SSL *emile, const char *file) | ||
474 | { | ||
475 | int err; | ||
476 | |||
477 | err = gnutls_certificate_set_x509_crl_file(emile->cert, | ||
478 | file, | ||
479 | GNUTLS_X509_FMT_PEM); | ||
480 | if (err <= 0) DBG("Could not load CRL '%s'.", file); | ||
481 | return err > 0 ? EINA_TRUE : EINA_FALSE; | ||
482 | } | ||
483 | |||
484 | EAPI Emile_SSL * | ||
485 | emile_cipher_server_listen(Emile_Cipher_Type t) | ||
486 | { | ||
487 | Emile_SSL *r; | ||
488 | int ret; | ||
489 | |||
490 | if (t != EMILE_SSLv23 && | ||
491 | t != EMILE_SSLv3 && | ||
492 | t != EMILE_TLSv1) | ||
493 | return NULL; | ||
494 | |||
495 | r = calloc(1, sizeof (Emile_SSL)); | ||
496 | if (!r) return NULL; | ||
497 | |||
498 | ret = gnutls_certificate_allocate_credentials(&r->cert); | ||
499 | if (ret) goto on_error; | ||
500 | |||
501 | r->t = t; | ||
502 | r->server = EINA_TRUE; | ||
503 | |||
504 | return r; | ||
505 | |||
506 | on_error: | ||
507 | ERR("GNUTLS error: %s - %s.", | ||
508 | gnutls_strerror_name(ret), | ||
509 | gnutls_strerror(ret)); | ||
510 | emile_cipher_free(r); | ||
511 | return NULL; | ||
512 | } | ||
513 | |||
514 | EAPI Emile_SSL * | ||
515 | emile_cipher_client_connect(Emile_SSL *server, int fd) | ||
516 | { | ||
517 | } | ||
518 | |||
519 | EAPI Emile_SSL * | ||
520 | emile_cipher_server_connect(Emile_Cipher_Type t) | ||
521 | { | ||
522 | const char *priority = "NORMAL:%VERIFY_ALLOW_X509_V1_CA_CRT"; | ||
523 | Emile_SSL *r; | ||
524 | int ret; | ||
525 | |||
526 | switch (t) | ||
527 | { | ||
528 | case EMILE_SSLv23: | ||
529 | break; | ||
530 | case EMILE_SSLv3: | ||
531 | priority = "NORMAL:%VERIFY_ALLOW_X509_V1_CA_CRT:!VERS-TLS1.0:!VERS-TLS1.1:!VERS-TLS1.2"; | ||
532 | break; | ||
533 | case EMILE_TLSv1: | ||
534 | priority = "NORMAL:%VERIFY_ALLOW_X509_V1_CA_CRT:!VERS-SSL3.0"; | ||
535 | break; | ||
536 | default: | ||
537 | return NULL; | ||
538 | } | ||
539 | |||
540 | r = calloc(1, sizeof (Emile_SSL)); | ||
541 | if (!r) return NULL; | ||
542 | |||
543 | r->server = EINA_FALSE; | ||
544 | |||
545 | ret = gnutls_certificate_allocate_credentials(&r->cert); | ||
546 | if (ret) goto on_error; | ||
547 | |||
548 | ret = gnutls_init(&r->session, GNUTLS_CLIENT); | ||
549 | if (ret) goto on_error; | ||
550 | |||
551 | ret = gnutls_session_ticket_enable_client(r->session); | ||
552 | if (ret) goto on_error; | ||
553 | |||
554 | // FIXME: Delay that until later access | ||
555 | |||
556 | ret = gnutls_server_name_set(r->session, GNUTLS_NAME_DNS, | ||
557 | r->name, strlen(r->name)); | ||
558 | if (ret) goto on_error; | ||
559 | |||
560 | ret = gnutls_priority_set_direct(r->session, priority, NULL); | ||
561 | if (ret) goto on_error; | ||
562 | |||
563 | gnutls_handshake_set_private_extensions(r->session, 1); | ||
564 | ret = gnutls_credentials_set(r->session, GNUTLS_CRD_CERTIFICATE, r->cert)); | ||
565 | |||
566 | return r; | ||
567 | } | ||
568 | |||
569 | EAPI Eina_Bool | ||
570 | emile_cipher_free(Emile_SSL *emile) | ||
571 | { | ||
572 | } | ||
573 | |||
574 | EAPI Eina_Bool | ||
575 | emile_cipher_cafile_add(Emile_SSL *emile, const char *file) | ||
576 | { | ||
577 | Eina_File_Direct_Info *info; | ||
578 | Eina_Iterator *it; | ||
579 | struct stat st; | ||
580 | int count = 0; | ||
581 | int ret; | ||
582 | |||
583 | if (stat(file, &st)) return EINA_FALSE; | ||
584 | if (S_ISDIR(st.st_mode)) | ||
585 | { | ||
586 | it = eina_file_direct_ls(file); | ||
587 | EINA_ITERATOR_FOREACH(it, info) | ||
588 | { | ||
589 | if (!(info->type == EINA_FILE_UNKNOWN || | ||
590 | info->type == EINA_FILE_REG || | ||
591 | info->type == EINA_FILE_LNK)) | ||
592 | continue ; | ||
593 | |||
594 | ret = gnutls_certificate_set_x509_trust_file(emile->cert, | ||
595 | file, | ||
596 | GNUTLS_X509_FMT_PEM); | ||
597 | if (ret > 0) count += ret; | ||
598 | } | ||
599 | eina_iterator_free(it); | ||
600 | } | ||
601 | else | ||
602 | { | ||
603 | ret = gnutls_certificate_set_x509_trust_file(emile->cert, | ||
604 | file, | ||
605 | GNUTLS_X509_FMT_PEM); | ||
606 | if (ret > 0) count += ret; | ||
607 | } | ||
608 | |||
609 | if (!count) ERR("Could not load CA file from '%s'.", file); | ||
610 | return !count ? EINA_FALSE : EINA_TRUE; | ||
611 | } | ||
612 | |||
613 | EAPI Eina_Bool | ||
614 | emile_cipher_cert_add(Emile_SSL *emile, const char *file) | ||
615 | { | ||
616 | return eina_stringshare_replace(&emile->cert_file, file); | ||
617 | } | ||
618 | |||
619 | EAPI Eina_Bool | ||
620 | emile_cipher_privkey_add(Emile_SSL *emile, const char *file) | ||
621 | { | ||
622 | int ret; | ||
623 | |||
624 | ret = gnutls_certificate_set_x509_key_file(emile->cert, | ||
625 | emile->cert_file, | ||
626 | file, | ||
627 | GNUTLS_X509_FMT_PEM); | ||
628 | if (ret) | ||
629 | ERR("Could not load certificate/key file ('%s'/'%s').", | ||
630 | emile->cert_file, file); | ||
631 | return ret ? EINA_FALSE : EINA_TRUE; | ||
632 | } | ||
633 | |||
634 | EAPI Eina_Bool | ||
635 | emile_cipher_crl_add(Emile_SSL *emile, const char *file) | ||
636 | { | ||
637 | int ret; | ||
638 | |||
639 | ret = gnutls_certificate_set_x509_crl_file(emile->cert, file, | ||
640 | GNUTLS_X509_FMT_PEM); | ||
641 | if (ret) | ||
642 | ERR("Could not load CRL file from '%s'.", file); | ||
643 | return ret ? EINA_FALSE : EINA_TRUE; | ||
644 | } | ||
645 | |||
646 | EAPI int | ||
647 | emile_cipher_read(Emile_SSL *emile, Eina_Binbuf *buffer) | ||
648 | { | ||
649 | } | ||
650 | |||
651 | EAPI int | ||
652 | emile_cipher_write(Emile_SSL *emile, const Eina_Binbuf *buffer) | ||
653 | { | ||
654 | } | ||
655 | |||
656 | EAPI const char * | ||
657 | emile_cipher_error_get(const Emile_SSL *emile) | ||
658 | { | ||
659 | return emile->last_error; | ||
660 | } | ||
661 | |||
662 | EAPI Eina_Bool | ||
663 | emile_cipher_verify_name_set(Emile_SSL *emile, const char *name) | ||
664 | { | ||
665 | return eina_stringshare_replace(&emile->name, name); | ||
666 | } | ||
667 | |||
668 | EAPI const char * | ||
669 | emile_cipher_verify_name_get(const Emile_SSL *emile) | ||
670 | { | ||
671 | return emile->name; | ||
672 | } | ||
673 | |||
674 | EAPI void | ||
675 | emile_cipher_verify_set(Emile_SSL *emile, Eina_Bool verify) | ||
676 | { | ||
677 | emile->verify = verify; | ||
678 | } | ||
679 | |||
680 | EAPI void | ||
681 | emile_cipher_verify_basic_set(Emile_SSL *emile, Eina_Bool verify_basic) | ||
682 | { | ||
683 | emile->verify_basic = verify_basic; | ||
684 | } | ||
685 | |||
686 | EAPI Eina_Bool | ||
687 | emile_cipher_verify_get(const Emile_SSL *emile) | ||
688 | { | ||
689 | return emile->verify; | ||
690 | } | ||
691 | |||
692 | EAPI Eina_Bool | ||
693 | emile_cipher_verify_basic_get(const Emile_SSL *emile) | ||
694 | { | ||
695 | return emile->verify_basic; | ||
696 | } | ||
697 | |||
diff --git a/src/lib/emile/emile_cipher_openssl.c b/src/lib/emile/emile_cipher_openssl.c index fdb36a5f8e..6c3e746c37 100644 --- a/src/lib/emile/emile_cipher_openssl.c +++ b/src/lib/emile/emile_cipher_openssl.c | |||
@@ -10,6 +10,9 @@ | |||
10 | #include <openssl/evp.h> | 10 | #include <openssl/evp.h> |
11 | #include <openssl/hmac.h> | 11 | #include <openssl/hmac.h> |
12 | #include <openssl/rand.h> | 12 | #include <openssl/rand.h> |
13 | #include <openssl/ssl.h> | ||
14 | #include <openssl/err.h> | ||
15 | #include <openssl/dh.h> | ||
13 | 16 | ||
14 | #include <Eina.h> | 17 | #include <Eina.h> |
15 | 18 | ||
@@ -20,6 +23,29 @@ | |||
20 | #define MAX_KEY_LEN EVP_MAX_KEY_LENGTH | 23 | #define MAX_KEY_LEN EVP_MAX_KEY_LENGTH |
21 | #define MAX_IV_LEN EVP_MAX_IV_LENGTH | 24 | #define MAX_IV_LEN EVP_MAX_IV_LENGTH |
22 | 25 | ||
26 | struct _Emile_SSL | ||
27 | { | ||
28 | Emile_SSL *parent; | ||
29 | SSL_CTX *ssl_ctx; | ||
30 | SSL *ssl; | ||
31 | |||
32 | const char *last_error; | ||
33 | const char *verify_name; | ||
34 | |||
35 | int ssl_err; | ||
36 | Emile_SSL_State ssl_state; | ||
37 | Emile_Want_Type ssl_want; | ||
38 | |||
39 | Eina_Bool server : 1; | ||
40 | Eina_Bool listen : 1; | ||
41 | Eina_Bool connecting : 1; | ||
42 | Eina_Bool handshaking : 1; | ||
43 | Eina_Bool upgrade : 1; | ||
44 | Eina_Bool crl_flag : 1; | ||
45 | Eina_Bool verify : 1; | ||
46 | Eina_Bool verify_basic : 1; | ||
47 | }; | ||
48 | |||
23 | Eina_Bool | 49 | Eina_Bool |
24 | _emile_cipher_init(void) | 50 | _emile_cipher_init(void) |
25 | { | 51 | { |
@@ -281,3 +307,821 @@ on_error: | |||
281 | 307 | ||
282 | return NULL; | 308 | return NULL; |
283 | } | 309 | } |
310 | |||
311 | EAPI Emile_SSL * | ||
312 | emile_cipher_server_listen(Emile_Cipher_Type t) | ||
313 | { | ||
314 | Emile_SSL *r; | ||
315 | DH *dh_params = NULL; | ||
316 | int options; | ||
317 | int dh = 0; | ||
318 | |||
319 | if (!emile_cipher_init()) return NULL; | ||
320 | |||
321 | r = calloc(1, sizeof (Emile_SSL)); | ||
322 | if (!r) return NULL; | ||
323 | |||
324 | switch (t) | ||
325 | { | ||
326 | case EMILE_SSLv23: | ||
327 | r->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); | ||
328 | if (!r->ssl_ctx) goto on_error; | ||
329 | options = SSL_CTX_get_options(r->ssl_ctx); | ||
330 | SSL_CTX_set_options(r->ssl_ctx, | ||
331 | options | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE); | ||
332 | break; | ||
333 | case EMILE_SSLv3: | ||
334 | r->ssl_ctx = SSL_CTX_new(SSLv3_server_method()); | ||
335 | break; | ||
336 | case EMILE_TLSv1: | ||
337 | r->ssl_ctx = SSL_CTX_new(TLSv1_server_method()); | ||
338 | break; | ||
339 | default: | ||
340 | free(r); | ||
341 | return NULL; | ||
342 | } | ||
343 | |||
344 | if (!r->ssl_ctx) goto on_error; | ||
345 | |||
346 | dh_params = DH_new(); | ||
347 | if (!dh_params) goto on_error; | ||
348 | if (!DH_generate_parameters_ex(dh_params, 1024, DH_GENERATOR_5, NULL)) | ||
349 | goto on_error; | ||
350 | if (!DH_check(dh_params, &dh)) | ||
351 | goto on_error; | ||
352 | if ((dh & DH_CHECK_P_NOT_PRIME) || (dh & DH_CHECK_P_NOT_SAFE_PRIME)) | ||
353 | goto on_error; | ||
354 | if (!DH_generate_key(dh_params)) | ||
355 | goto on_error; | ||
356 | if (!SSL_CTX_set_tmp_dh(r->ssl_ctx, dh_params)) | ||
357 | goto on_error; | ||
358 | |||
359 | DH_free(dh_params); | ||
360 | INF("DH params successfully generated and applied!"); | ||
361 | |||
362 | if (!SSL_CTX_set_cipher_list(r->ssl_ctx, | ||
363 | "aNULL:!eNULL:!LOW:!EXPORT:@STRENGTH")) | ||
364 | goto on_error; | ||
365 | |||
366 | return r; | ||
367 | |||
368 | on_error: | ||
369 | if (dh) | ||
370 | { | ||
371 | if (dh & DH_CHECK_P_NOT_PRIME) | ||
372 | ERR("openssl error: dh_params could not generate a prime!"); | ||
373 | else | ||
374 | ERR("openssl error: dh_params could not generate a safe prime!"); | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | ERR("openssl error: %s.", ERR_reason_error_string(ERR_get_error())); | ||
379 | } | ||
380 | emile_cipher_free(r); | ||
381 | return NULL; | ||
382 | } | ||
383 | |||
384 | static void | ||
385 | _emile_cipher_print_verify_error(int error) | ||
386 | { | ||
387 | switch (error) | ||
388 | { | ||
389 | #define ERROR(X) \ | ||
390 | case (X): \ | ||
391 | ERR("%s", #X); \ | ||
392 | break | ||
393 | #ifdef X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT | ||
394 | ERROR(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT); | ||
395 | #endif | ||
396 | #ifdef X509_V_ERR_UNABLE_TO_GET_CRL | ||
397 | ERROR(X509_V_ERR_UNABLE_TO_GET_CRL); | ||
398 | #endif | ||
399 | #ifdef X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE | ||
400 | ERROR(X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE); | ||
401 | #endif | ||
402 | #ifdef X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE | ||
403 | ERROR(X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE); | ||
404 | #endif | ||
405 | #ifdef X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY | ||
406 | ERROR(X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY); | ||
407 | #endif | ||
408 | #ifdef X509_V_ERR_CERT_SIGNATURE_FAILURE | ||
409 | ERROR(X509_V_ERR_CERT_SIGNATURE_FAILURE); | ||
410 | #endif | ||
411 | #ifdef X509_V_ERR_CRL_SIGNATURE_FAILURE | ||
412 | ERROR(X509_V_ERR_CRL_SIGNATURE_FAILURE); | ||
413 | #endif | ||
414 | #ifdef X509_V_ERR_CERT_NOT_YET_VALID | ||
415 | ERROR(X509_V_ERR_CERT_NOT_YET_VALID); | ||
416 | #endif | ||
417 | #ifdef X509_V_ERR_CERT_HAS_EXPIRED | ||
418 | ERROR(X509_V_ERR_CERT_HAS_EXPIRED); | ||
419 | #endif | ||
420 | #ifdef X509_V_ERR_CRL_NOT_YET_VALID | ||
421 | ERROR(X509_V_ERR_CRL_NOT_YET_VALID); | ||
422 | #endif | ||
423 | #ifdef X509_V_ERR_CRL_HAS_EXPIRED | ||
424 | ERROR(X509_V_ERR_CRL_HAS_EXPIRED); | ||
425 | #endif | ||
426 | #ifdef X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD | ||
427 | ERROR(X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD); | ||
428 | #endif | ||
429 | #ifdef X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD | ||
430 | ERROR(X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD); | ||
431 | #endif | ||
432 | #ifdef X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD | ||
433 | ERROR(X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD); | ||
434 | #endif | ||
435 | #ifdef X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD | ||
436 | ERROR(X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); | ||
437 | #endif | ||
438 | #ifdef X509_V_ERR_OUT_OF_MEM | ||
439 | ERROR(X509_V_ERR_OUT_OF_MEM); | ||
440 | #endif | ||
441 | #ifdef X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT | ||
442 | ERROR(X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT); | ||
443 | #endif | ||
444 | #ifdef X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN | ||
445 | ERROR(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN); | ||
446 | #endif | ||
447 | #ifdef X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY | ||
448 | ERROR(X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY); | ||
449 | #endif | ||
450 | #ifdef X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE | ||
451 | ERROR(X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); | ||
452 | #endif | ||
453 | #ifdef X509_V_ERR_CERT_CHAIN_TOO_LONG | ||
454 | ERROR(X509_V_ERR_CERT_CHAIN_TOO_LONG); | ||
455 | #endif | ||
456 | #ifdef X509_V_ERR_CERT_REVOKED | ||
457 | ERROR(X509_V_ERR_CERT_REVOKED); | ||
458 | #endif | ||
459 | #ifdef X509_V_ERR_INVALID_CA | ||
460 | ERROR(X509_V_ERR_INVALID_CA); | ||
461 | #endif | ||
462 | #ifdef X509_V_ERR_PATH_LENGTH_EXCEEDED | ||
463 | ERROR(X509_V_ERR_PATH_LENGTH_EXCEEDED); | ||
464 | #endif | ||
465 | #ifdef X509_V_ERR_INVALID_PURPOSE | ||
466 | ERROR(X509_V_ERR_INVALID_PURPOSE); | ||
467 | #endif | ||
468 | #ifdef X509_V_ERR_CERT_UNTRUSTED | ||
469 | ERROR(X509_V_ERR_CERT_UNTRUSTED); | ||
470 | #endif | ||
471 | #ifdef X509_V_ERR_CERT_REJECTED | ||
472 | ERROR(X509_V_ERR_CERT_REJECTED); | ||
473 | #endif | ||
474 | /* These are 'informational' when looking for issuer cert */ | ||
475 | #ifdef X509_V_ERR_SUBJECT_ISSUER_MISMATCH | ||
476 | ERROR(X509_V_ERR_SUBJECT_ISSUER_MISMATCH); | ||
477 | #endif | ||
478 | #ifdef X509_V_ERR_AKID_SKID_MISMATCH | ||
479 | ERROR(X509_V_ERR_AKID_SKID_MISMATCH); | ||
480 | #endif | ||
481 | #ifdef X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH | ||
482 | ERROR(X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH); | ||
483 | #endif | ||
484 | #ifdef X509_V_ERR_KEYUSAGE_NO_CERTSIGN | ||
485 | ERROR(X509_V_ERR_KEYUSAGE_NO_CERTSIGN); | ||
486 | #endif | ||
487 | |||
488 | #ifdef X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER | ||
489 | ERROR(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER); | ||
490 | #endif | ||
491 | #ifdef X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION | ||
492 | ERROR(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION); | ||
493 | #endif | ||
494 | #ifdef X509_V_ERR_KEYUSAGE_NO_CRL_SIGN | ||
495 | ERROR(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN); | ||
496 | #endif | ||
497 | #ifdef X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION | ||
498 | ERROR(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION); | ||
499 | #endif | ||
500 | #ifdef X509_V_ERR_INVALID_NON_CA | ||
501 | ERROR(X509_V_ERR_INVALID_NON_CA); | ||
502 | #endif | ||
503 | #ifdef X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED | ||
504 | ERROR(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED); | ||
505 | #endif | ||
506 | #ifdef X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE | ||
507 | ERROR(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE); | ||
508 | #endif | ||
509 | #ifdef X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED | ||
510 | ERROR(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED); | ||
511 | #endif | ||
512 | |||
513 | #ifdef X509_V_ERR_INVALID_EXTENSION | ||
514 | ERROR(X509_V_ERR_INVALID_EXTENSION); | ||
515 | #endif | ||
516 | #ifdef X509_V_ERR_INVALID_POLICY_EXTENSION | ||
517 | ERROR(X509_V_ERR_INVALID_POLICY_EXTENSION); | ||
518 | #endif | ||
519 | #ifdef X509_V_ERR_NO_EXPLICIT_POLICY | ||
520 | ERROR(X509_V_ERR_NO_EXPLICIT_POLICY); | ||
521 | #endif | ||
522 | #ifdef X509_V_ERR_DIFFERENT_CRL_SCOPE | ||
523 | ERROR(X509_V_ERR_DIFFERENT_CRL_SCOPE); | ||
524 | #endif | ||
525 | #ifdef X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE | ||
526 | ERROR(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE); | ||
527 | #endif | ||
528 | |||
529 | #ifdef X509_V_ERR_UNNESTED_RESOURCE | ||
530 | ERROR(X509_V_ERR_UNNESTED_RESOURCE); | ||
531 | #endif | ||
532 | |||
533 | #ifdef X509_V_ERR_PERMITTED_VIOLATION | ||
534 | ERROR(X509_V_ERR_PERMITTED_VIOLATION); | ||
535 | #endif | ||
536 | #ifdef X509_V_ERR_EXCLUDED_VIOLATION | ||
537 | ERROR(X509_V_ERR_EXCLUDED_VIOLATION); | ||
538 | #endif | ||
539 | #ifdef X509_V_ERR_SUBTREE_MINMAX | ||
540 | ERROR(X509_V_ERR_SUBTREE_MINMAX); | ||
541 | #endif | ||
542 | #ifdef X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE | ||
543 | ERROR(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE); | ||
544 | #endif | ||
545 | #ifdef X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX | ||
546 | ERROR(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX); | ||
547 | #endif | ||
548 | #ifdef X509_V_ERR_UNSUPPORTED_NAME_SYNTAX | ||
549 | ERROR(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX); | ||
550 | #endif | ||
551 | #ifdef X509_V_ERR_CRL_PATH_VALIDATION_ERROR | ||
552 | ERROR(X509_V_ERR_CRL_PATH_VALIDATION_ERROR); | ||
553 | #endif | ||
554 | |||
555 | /* The application is not happy */ | ||
556 | #ifdef X509_V_ERR_APPLICATION_VERIFICATION | ||
557 | ERROR(X509_V_ERR_APPLICATION_VERIFICATION); | ||
558 | #endif | ||
559 | } | ||
560 | #undef ERROR | ||
561 | } | ||
562 | |||
563 | static void | ||
564 | _emile_cipher_session_print(SSL *ssl) | ||
565 | { | ||
566 | Eina_Strbuf *str; | ||
567 | SSL_SESSION *s; | ||
568 | STACK_OF(X509) *sk; | ||
569 | BIO *b; | ||
570 | BUF_MEM *bptr; | ||
571 | char log[4096]; | ||
572 | |||
573 | if (!eina_log_domain_level_check(_emile_log_dom_global, EINA_LOG_LEVEL_DBG)) | ||
574 | return ; | ||
575 | |||
576 | str = eina_strbuf_new(); | ||
577 | if (!str) return ; | ||
578 | |||
579 | log[0] = '\0'; | ||
580 | b = BIO_new(BIO_s_mem()); | ||
581 | sk = SSL_get_peer_cert_chain(ssl); | ||
582 | if (sk) | ||
583 | { | ||
584 | int i; | ||
585 | |||
586 | DBG("CERTIFICATES:"); | ||
587 | for (i = 0; i < sk_X509_num(sk); i++) | ||
588 | { | ||
589 | char *p; | ||
590 | |||
591 | p = X509_NAME_oneline(X509_get_subject_name(sk_X509_value(sk, i)), | ||
592 | log, sizeof (log)); | ||
593 | DBG("%2d s:%s", i, p); | ||
594 | p = X509_NAME_oneline(X509_get_issuer_name(sk_X509_value(sk, i)), | ||
595 | log, sizeof(log)); | ||
596 | DBG(" i:%s", p); | ||
597 | |||
598 | PEM_write_bio_X509(b, sk_X509_value(sk, i)); | ||
599 | BIO_get_mem_ptr(b, &bptr); | ||
600 | eina_strbuf_append_length(str, bptr->data, bptr->length); | ||
601 | DBG("%s", eina_strbuf_string_get(str)); | ||
602 | eina_strbuf_reset(str); | ||
603 | BIO_free(b); | ||
604 | } | ||
605 | } | ||
606 | |||
607 | s = SSL_get_session(ssl); | ||
608 | SSL_SESSION_print(b, s); | ||
609 | BIO_get_mem_ptr(b, &bptr); | ||
610 | eina_strbuf_append_length(str, bptr->data, bptr->length); | ||
611 | DBG("%s", eina_strbuf_string_get(str)); | ||
612 | eina_strbuf_free(str); | ||
613 | BIO_free(b); | ||
614 | } | ||
615 | |||
616 | static void | ||
617 | _emile_cipher_client_handshake(Emile_SSL *client) | ||
618 | { | ||
619 | X509 *cert; | ||
620 | int ret = -1; | ||
621 | |||
622 | if (!client) return ; | ||
623 | |||
624 | switch (client->ssl_state) | ||
625 | { | ||
626 | case EMILE_SSL_STATE_INIT: | ||
627 | client->ssl_state = EMILE_SSL_STATE_HANDSHAKING; | ||
628 | client->handshaking = EINA_TRUE; | ||
629 | |||
630 | case EMILE_SSL_STATE_HANDSHAKING: | ||
631 | if (!client->ssl) goto on_error; | ||
632 | |||
633 | ret = SSL_do_handshake(client->ssl); | ||
634 | client->ssl_err = SSL_get_error(client->ssl, ret); | ||
635 | |||
636 | if ((client->ssl_err == SSL_ERROR_SYSCALL) || | ||
637 | (client->ssl_err == SSL_ERROR_SSL)) | ||
638 | goto on_error; | ||
639 | |||
640 | if (ret != 1) | ||
641 | { | ||
642 | if (client->ssl_err == SSL_ERROR_WANT_READ) | ||
643 | client->ssl_want = EMILE_WANT_READ; | ||
644 | else if (client->ssl_err == SSL_ERROR_WANT_WRITE) | ||
645 | client->ssl_want = EMILE_WANT_WRITE; | ||
646 | |||
647 | return ; | ||
648 | } | ||
649 | |||
650 | client->handshaking = EINA_FALSE; | ||
651 | client->ssl_state = EMILE_SSL_STATE_DONE; | ||
652 | case EMILE_SSL_STATE_DONE: | ||
653 | break; | ||
654 | case EMILE_SSL_STATE_ERROR: | ||
655 | goto on_error; | ||
656 | } | ||
657 | |||
658 | _emile_cipher_session_print(client->ssl); | ||
659 | if (!client->parent->verify && | ||
660 | !client->parent->verify_basic) | ||
661 | return ; | ||
662 | |||
663 | SSL_set_verify(client->ssl, SSL_VERIFY_PEER, NULL); | ||
664 | /* use CRL/CA lists to verify */ | ||
665 | cert = SSL_get_peer_certificate(client->ssl); | ||
666 | if (cert) | ||
667 | { | ||
668 | const char *verify_name; | ||
669 | char *cert_name; | ||
670 | char *s; | ||
671 | int clen; | ||
672 | int err; | ||
673 | int name = 0; | ||
674 | |||
675 | if (client->parent->verify) | ||
676 | { | ||
677 | err = SSL_get_verify_result(client->ssl); | ||
678 | _emile_cipher_print_verify_error(err); | ||
679 | if (err) goto on_error; | ||
680 | } | ||
681 | |||
682 | clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), | ||
683 | NID_subject_alt_name, | ||
684 | NULL, 0); | ||
685 | if (clen > 0) | ||
686 | { | ||
687 | name = NID_subject_alt_name; | ||
688 | } | ||
689 | else | ||
690 | { | ||
691 | clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), | ||
692 | NID_commonName, | ||
693 | NULL, 0); | ||
694 | if (clen <= 0) goto on_error; | ||
695 | name = NID_commonName; | ||
696 | } | ||
697 | |||
698 | cert_name = alloca(++clen); | ||
699 | X509_NAME_get_text_by_NID(X509_get_subject_name(cert), | ||
700 | name, cert_name, clen); | ||
701 | verify_name = client->parent->verify_name; | ||
702 | |||
703 | INF("Cert name: '%s' vs verify name: '%s'.", cert_name, verify_name); | ||
704 | |||
705 | if (!verify_name) goto on_error; | ||
706 | if (strcasecmp(cert_name, verify_name)) goto on_error; | ||
707 | if (verify_name[0] != '*') goto on_error; | ||
708 | |||
709 | /* verify that their is only one wildcard in the client cert name */ | ||
710 | if (strchr(cert_name + 1, '*')) goto on_error; | ||
711 | /* verify that we have a domain of at least *.X.TLD and not *.TLD */ | ||
712 | if (!strchr(cert_name + 2, '.')) goto on_error; | ||
713 | s = strchr(verify_name, '.'); | ||
714 | if (!s) goto on_error; | ||
715 | /* same as above for the stored name */ | ||
716 | if (!strchr(s + 1, '.')) goto on_error; | ||
717 | if (strcasecmp(s, verify_name + 1)) goto on_error; | ||
718 | |||
719 | DBG("Successfully verified certificate."); | ||
720 | } | ||
721 | |||
722 | return ; | ||
723 | |||
724 | on_error: | ||
725 | DBG("Failed to finish handshake."); | ||
726 | client->ssl_state = EMILE_SSL_STATE_ERROR; | ||
727 | return ; | ||
728 | } | ||
729 | |||
730 | EAPI Emile_SSL * | ||
731 | emile_cipher_client_connect(Emile_SSL *server, int fd) | ||
732 | { | ||
733 | Emile_SSL *r; | ||
734 | |||
735 | if (!server) return NULL; | ||
736 | |||
737 | r = calloc(1, sizeof (Emile_SSL)); | ||
738 | if (!r) return NULL; | ||
739 | |||
740 | r->parent = server; | ||
741 | r->ssl = SSL_new(r->parent->ssl_ctx); | ||
742 | if (!r->ssl) goto on_error; | ||
743 | |||
744 | if (!SSL_set_fd(r->ssl, fd)) | ||
745 | goto on_error; | ||
746 | |||
747 | SSL_set_accept_state(r->ssl); | ||
748 | |||
749 | _emile_cipher_client_handshake(r); | ||
750 | |||
751 | if (r->ssl_state == EMILE_SSL_STATE_ERROR) goto on_error; | ||
752 | |||
753 | return r; | ||
754 | |||
755 | on_error: | ||
756 | emile_cipher_free(r); | ||
757 | return NULL; | ||
758 | } | ||
759 | |||
760 | EAPI Emile_SSL * | ||
761 | emile_cipher_server_connect(Emile_Cipher_Type t) | ||
762 | { | ||
763 | Emile_SSL *r; | ||
764 | const char *msg; | ||
765 | int options; | ||
766 | int dh = 0; | ||
767 | |||
768 | if (!emile_cipher_init()) return NULL; | ||
769 | |||
770 | r = calloc(1, sizeof (Emile_SSL)); | ||
771 | if (!r) return NULL; | ||
772 | |||
773 | switch (t) | ||
774 | { | ||
775 | case EMILE_SSLv23: | ||
776 | r->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); | ||
777 | if (!r->ssl_ctx) goto on_error; | ||
778 | options = SSL_CTX_get_options(r->ssl_ctx); | ||
779 | SSL_CTX_set_options(r->ssl_ctx, | ||
780 | options | SSL_OP_NO_SSLv2 | SSL_OP_SINGLE_DH_USE); | ||
781 | break; | ||
782 | case EMILE_SSLv3: | ||
783 | r->ssl_ctx = SSL_CTX_new(SSLv3_client_method()); | ||
784 | break; | ||
785 | case EMILE_TLSv1: | ||
786 | r->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); | ||
787 | break; | ||
788 | default: | ||
789 | free(r); | ||
790 | return NULL; | ||
791 | } | ||
792 | |||
793 | if (!SSL_CTX_set_cipher_list(r->ssl_ctx, | ||
794 | "aNULL:!eNULL:!LOW:!EXPORT:!ECDH:RSA:AES:!PSK:@STRENGTH")) | ||
795 | goto on_error; | ||
796 | |||
797 | return r; | ||
798 | |||
799 | on_error: | ||
800 | if (dh) | ||
801 | { | ||
802 | if (dh & DH_CHECK_P_NOT_PRIME) | ||
803 | msg = "dh_params could not generate a prime!"; | ||
804 | else | ||
805 | msg = "dh_params could not generate a safe prime!"; | ||
806 | } | ||
807 | else | ||
808 | { | ||
809 | msg = ERR_reason_error_string(ERR_get_error()); | ||
810 | } | ||
811 | |||
812 | ERR("OpenSSL error: '%s'.", msg); | ||
813 | emile_cipher_free(r); | ||
814 | return NULL; | ||
815 | } | ||
816 | |||
817 | EAPI Eina_Bool | ||
818 | emile_cipher_free(Emile_SSL *emile) | ||
819 | { | ||
820 | if (!emile) return EINA_FALSE; | ||
821 | |||
822 | eina_stringshare_del(emile->last_error); | ||
823 | emile->last_error = NULL; | ||
824 | |||
825 | eina_stringshare_del(emile->verify_name); | ||
826 | emile->verify_name = NULL; | ||
827 | |||
828 | if (emile->ssl) | ||
829 | { | ||
830 | if (!SSL_shutdown(emile->ssl)) | ||
831 | SSL_shutdown(emile->ssl); | ||
832 | |||
833 | SSL_free(emile->ssl); | ||
834 | } | ||
835 | emile->ssl = NULL; | ||
836 | |||
837 | if (emile->ssl_ctx) | ||
838 | SSL_CTX_free(emile->ssl_ctx); | ||
839 | emile->ssl_ctx = NULL; | ||
840 | |||
841 | free(emile); | ||
842 | return EINA_TRUE; | ||
843 | } | ||
844 | |||
845 | EAPI Eina_Bool | ||
846 | emile_cipher_cafile_add(Emile_SSL *emile, const char *file) | ||
847 | { | ||
848 | struct stat st; | ||
849 | unsigned long err; | ||
850 | |||
851 | if (stat(file, &st)) return EINA_FALSE; | ||
852 | if (S_ISDIR(st.st_mode)) | ||
853 | { | ||
854 | if (!SSL_CTX_load_verify_locations(emile->ssl_ctx, NULL, file)) | ||
855 | goto on_error; | ||
856 | } | ||
857 | else | ||
858 | { | ||
859 | if (!SSL_CTX_load_verify_locations(emile->ssl_ctx, file, NULL)) | ||
860 | goto on_error; | ||
861 | } | ||
862 | |||
863 | return EINA_TRUE; | ||
864 | |||
865 | on_error: | ||
866 | err = ERR_peek_last_error(); | ||
867 | if (!err) return EINA_FALSE; | ||
868 | |||
869 | DBG("OpenSSL error: '%s'.", ERR_reason_error_string(err)); | ||
870 | eina_stringshare_replace(&emile->last_error, ERR_reason_error_string(err)); | ||
871 | return EINA_FALSE; | ||
872 | } | ||
873 | |||
874 | EAPI Eina_Bool | ||
875 | emile_cipher_cert_add(Emile_SSL *emile, const char *file) | ||
876 | { | ||
877 | Eina_File *f; | ||
878 | void *m; | ||
879 | X509 *cert = NULL; | ||
880 | BIO *bio = NULL; | ||
881 | int err; | ||
882 | |||
883 | f = eina_file_open(file, EINA_FALSE); | ||
884 | if (!f) return EINA_FALSE; | ||
885 | |||
886 | m = eina_file_map_all(f, EINA_FILE_WILLNEED); | ||
887 | if (!m) goto on_error; | ||
888 | |||
889 | bio = BIO_new_mem_buf(m, eina_file_size_get(f)); | ||
890 | if (!bio) goto on_error; | ||
891 | |||
892 | cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); | ||
893 | if (!cert) goto on_error; | ||
894 | |||
895 | if (SSL_CTX_use_certificate(emile->ssl_ctx, cert) < 1) | ||
896 | goto on_error; | ||
897 | |||
898 | eina_file_map_free(f, m); | ||
899 | eina_file_close(f); | ||
900 | BIO_free(bio); | ||
901 | |||
902 | return EINA_TRUE; | ||
903 | |||
904 | on_error: | ||
905 | err = ERR_peek_last_error(); | ||
906 | |||
907 | if (m) eina_file_map_free(f, m); | ||
908 | if (f) eina_file_close(f); | ||
909 | if (bio) BIO_free(bio); | ||
910 | |||
911 | if (!err) return EINA_FALSE; | ||
912 | |||
913 | DBG("OpenSSL error: '%s'.", ERR_reason_error_string(err)); | ||
914 | eina_stringshare_replace(&emile->last_error, ERR_reason_error_string(err)); | ||
915 | return EINA_FALSE; | ||
916 | } | ||
917 | |||
918 | EAPI Eina_Bool | ||
919 | emile_cipher_privkey_add(Emile_SSL *emile, const char *file) | ||
920 | { | ||
921 | Eina_File *f; | ||
922 | void *m; | ||
923 | EVP_PKEY *privkey = NULL; | ||
924 | BIO *bio = NULL; | ||
925 | int err; | ||
926 | |||
927 | f = eina_file_open(file, EINA_FALSE); | ||
928 | if (!f) return EINA_FALSE; | ||
929 | |||
930 | m = eina_file_map_all(f, EINA_FILE_WILLNEED); | ||
931 | if (!m) goto on_error; | ||
932 | |||
933 | bio = BIO_new_mem_buf(m, eina_file_size_get(f)); | ||
934 | if (!bio) goto on_error; | ||
935 | |||
936 | privkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); | ||
937 | if (!privkey) goto on_error; | ||
938 | |||
939 | eina_file_map_free(f, m); | ||
940 | m = NULL; | ||
941 | |||
942 | eina_file_close(f); | ||
943 | f = NULL; | ||
944 | |||
945 | if (SSL_CTX_use_PrivateKey(emile->ssl_ctx, privkey) < 1) | ||
946 | goto on_error; | ||
947 | |||
948 | if (SSL_CTX_check_private_key(emile->ssl_ctx) < 1) | ||
949 | goto on_error; | ||
950 | |||
951 | BIO_free(bio); | ||
952 | |||
953 | return EINA_TRUE; | ||
954 | |||
955 | on_error: | ||
956 | err = ERR_peek_last_error(); | ||
957 | |||
958 | if (m) eina_file_map_free(f, m); | ||
959 | if (f) eina_file_close(f); | ||
960 | if (bio) BIO_free(bio); | ||
961 | |||
962 | if (!err) return EINA_FALSE; | ||
963 | |||
964 | DBG("OpenSSL error: '%s'.", ERR_reason_error_string(err)); | ||
965 | eina_stringshare_replace(&emile->last_error, ERR_reason_error_string(err)); | ||
966 | return EINA_FALSE; | ||
967 | } | ||
968 | |||
969 | EAPI Eina_Bool | ||
970 | emile_cipher_crl_add(Emile_SSL *emile, const char *file) | ||
971 | { | ||
972 | X509_LOOKUP *lu; | ||
973 | X509_STORE *st; | ||
974 | int err; | ||
975 | |||
976 | st = SSL_CTX_get_cert_store(emile->ssl_ctx); | ||
977 | if (!st) goto on_error; | ||
978 | |||
979 | lu = X509_STORE_add_lookup(st, X509_LOOKUP_file()); | ||
980 | if (!lu) goto on_error; | ||
981 | |||
982 | if (X509_load_crl_file(lu, file, X509_FILETYPE_PEM) < 1) | ||
983 | goto on_error; | ||
984 | |||
985 | if (!emile->crl_flag) | ||
986 | { | ||
987 | X509_STORE_set_flags(st, | ||
988 | X509_V_FLAG_CRL_CHECK | | ||
989 | X509_V_FLAG_CRL_CHECK_ALL); | ||
990 | emile->crl_flag = EINA_TRUE; | ||
991 | } | ||
992 | |||
993 | return EINA_TRUE; | ||
994 | |||
995 | on_error: | ||
996 | err = ERR_peek_last_error(); | ||
997 | if (!err) return EINA_FALSE; | ||
998 | |||
999 | DBG("OpenSSL error: '%s'.", ERR_reason_error_string(err)); | ||
1000 | eina_stringshare_replace(&emile->last_error, ERR_reason_error_string(err)); | ||
1001 | return EINA_FALSE; | ||
1002 | } | ||
1003 | |||
1004 | EAPI int | ||
1005 | emile_cipher_read(Emile_SSL *emile, Eina_Binbuf *buffer) | ||
1006 | { | ||
1007 | int err; | ||
1008 | int num; | ||
1009 | |||
1010 | if (!emile->ssl) return -1; | ||
1011 | if (eina_binbuf_length_get(buffer) <= 0) return 0; | ||
1012 | |||
1013 | num = SSL_read(emile->ssl, | ||
1014 | (void*) eina_binbuf_string_get(buffer), | ||
1015 | eina_binbuf_length_get(buffer)); | ||
1016 | emile->ssl_err = SSL_get_error(emile->ssl, num); | ||
1017 | |||
1018 | switch (emile->ssl_err) | ||
1019 | { | ||
1020 | case SSL_ERROR_WANT_READ: emile->ssl_want = EMILE_WANT_READ; break; | ||
1021 | case SSL_ERROR_WANT_WRITE: emile->ssl_want = EMILE_WANT_WRITE; break; | ||
1022 | case SSL_ERROR_ZERO_RETURN: | ||
1023 | case SSL_ERROR_SYSCALL: | ||
1024 | case SSL_ERROR_SSL: | ||
1025 | err = ERR_peek_last_error(); | ||
1026 | if (!err) return -1; | ||
1027 | |||
1028 | DBG("OpenSSL error: '%s'.", ERR_reason_error_string(err)); | ||
1029 | eina_stringshare_replace(&emile->last_error, ERR_reason_error_string(err)); | ||
1030 | return -1; | ||
1031 | |||
1032 | default: | ||
1033 | emile->ssl_want = EMILE_WANT_NOTHING; | ||
1034 | break; | ||
1035 | } | ||
1036 | |||
1037 | if (emile->ssl_state == EMILE_SSL_STATE_HANDSHAKING) | ||
1038 | _emile_cipher_client_handshake(emile); | ||
1039 | if (emile->ssl_state == EMILE_SSL_STATE_ERROR) | ||
1040 | return -1; | ||
1041 | |||
1042 | return num < 0 ? 0 : num; | ||
1043 | } | ||
1044 | |||
1045 | EAPI int | ||
1046 | emile_cipher_write(Emile_SSL *emile, const Eina_Binbuf *buffer) | ||
1047 | { | ||
1048 | int num; | ||
1049 | int err; | ||
1050 | |||
1051 | if (!emile->ssl) return -1; | ||
1052 | if (eina_binbuf_length_get(buffer) <= 0) return 0; | ||
1053 | |||
1054 | num = SSL_write(emile->ssl, | ||
1055 | (void*) eina_binbuf_string_get(buffer), | ||
1056 | eina_binbuf_length_get(buffer)); | ||
1057 | emile->ssl_err = SSL_get_error(emile->ssl, num); | ||
1058 | |||
1059 | switch (emile->ssl_err) | ||
1060 | { | ||
1061 | case SSL_ERROR_WANT_READ: emile->ssl_want = EMILE_WANT_READ; break; | ||
1062 | case SSL_ERROR_WANT_WRITE: emile->ssl_want = EMILE_WANT_WRITE; break; | ||
1063 | case SSL_ERROR_ZERO_RETURN: | ||
1064 | case SSL_ERROR_SYSCALL: | ||
1065 | case SSL_ERROR_SSL: | ||
1066 | err = ERR_peek_last_error(); | ||
1067 | if (!err) return -1; | ||
1068 | |||
1069 | DBG("OpenSSL error: '%s'.", ERR_reason_error_string(err)); | ||
1070 | eina_stringshare_replace(&emile->last_error, ERR_reason_error_string(err)); | ||
1071 | return -1; | ||
1072 | |||
1073 | default: | ||
1074 | emile->ssl_want = EMILE_WANT_NOTHING; | ||
1075 | break; | ||
1076 | } | ||
1077 | |||
1078 | if (emile->ssl_state == EMILE_SSL_STATE_HANDSHAKING) | ||
1079 | _emile_cipher_client_handshake(emile); | ||
1080 | if (emile->ssl_state == EMILE_SSL_STATE_ERROR) | ||
1081 | return -1; | ||
1082 | |||
1083 | return num < 0 ? 0 : num; | ||
1084 | } | ||
1085 | |||
1086 | EAPI const char * | ||
1087 | emile_cipher_error_get(const Emile_SSL *emile) | ||
1088 | { | ||
1089 | return emile->last_error; | ||
1090 | } | ||
1091 | |||
1092 | EAPI Eina_Bool | ||
1093 | emile_cipher_verify_name_set(Emile_SSL *emile, const char *name) | ||
1094 | { | ||
1095 | return eina_stringshare_replace(&emile->verify_name, name); | ||
1096 | } | ||
1097 | |||
1098 | EAPI const char * | ||
1099 | emile_cipher_verify_name_get(const Emile_SSL *emile) | ||
1100 | { | ||
1101 | return emile->verify_name; | ||
1102 | } | ||
1103 | |||
1104 | EAPI void | ||
1105 | emile_cipher_verify_set(Emile_SSL *emile, Eina_Bool verify) | ||
1106 | { | ||
1107 | emile->verify = verify; | ||
1108 | } | ||
1109 | |||
1110 | EAPI void | ||
1111 | emile_cipher_verify_basic_set(Emile_SSL *emile, Eina_Bool verify_basic) | ||
1112 | { | ||
1113 | emile->verify_basic = verify_basic; | ||
1114 | } | ||
1115 | |||
1116 | EAPI Eina_Bool | ||
1117 | emile_cipher_verify_get(const Emile_SSL *emile) | ||
1118 | { | ||
1119 | return emile->verify; | ||
1120 | } | ||
1121 | |||
1122 | EAPI Eina_Bool | ||
1123 | emile_cipher_verify_basic_get(const Emile_SSL *emile) | ||
1124 | { | ||
1125 | return emile->verify_basic; | ||
1126 | } | ||
1127 | |||
diff --git a/src/lib/emile/emile_main.c b/src/lib/emile/emile_main.c index d5939e8ad8..eb18a61de5 100644 --- a/src/lib/emile/emile_main.c +++ b/src/lib/emile/emile_main.c | |||
@@ -73,7 +73,7 @@ emile_shutdown(void) | |||
73 | EINA_LOG_STATE_START, | 73 | EINA_LOG_STATE_START, |
74 | EINA_LOG_STATE_SHUTDOWN); | 74 | EINA_LOG_STATE_SHUTDOWN); |
75 | 75 | ||
76 | if (_emile_cipher_init) | 76 | if (_emile_cipher_inited) |
77 | { | 77 | { |
78 | #ifdef HAVE_GNUTLS | 78 | #ifdef HAVE_GNUTLS |
79 | /* Note that gnutls has a leak where it doesnt free stuff it alloced | 79 | /* Note that gnutls has a leak where it doesnt free stuff it alloced |
diff --git a/src/lib/emile/emile_private.h b/src/lib/emile/emile_private.h index e6b4763f40..f6a005d44a 100644 --- a/src/lib/emile/emile_private.h +++ b/src/lib/emile/emile_private.h | |||
@@ -24,6 +24,14 @@ extern int _emile_log_dom_global; | |||
24 | #endif /* ifdef CRI */ | 24 | #endif /* ifdef CRI */ |
25 | #define CRI(...) EINA_LOG_DOM_CRIT(_emile_log_dom_global, __VA_ARGS__) | 25 | #define CRI(...) EINA_LOG_DOM_CRIT(_emile_log_dom_global, __VA_ARGS__) |
26 | 26 | ||
27 | typedef enum | ||
28 | { | ||
29 | EMILE_SSL_STATE_INIT = 0, | ||
30 | EMILE_SSL_STATE_HANDSHAKING, | ||
31 | EMILE_SSL_STATE_DONE, | ||
32 | EMILE_SSL_STATE_ERROR | ||
33 | } Emile_SSL_State; | ||
34 | |||
27 | Eina_Bool _emile_cipher_init(void); | 35 | Eina_Bool _emile_cipher_init(void); |
28 | 36 | ||
29 | #endif /* EMILE_PRIVATE_H_ */ | 37 | #endif /* EMILE_PRIVATE_H_ */ |