Line data Source code
1 : /* This file is part of the cmail project (http://cmail.rocks/)
2 : * (c) 2015 Fabian "cbdev" Stumpf
3 : * License: Simplified BSD (2-Clause)
4 : * For further information, consult LICENSE.txt
5 : */
6 :
7 : #ifndef CMAIL_NO_TLS
8 :
9 4 : char* tls_modestring(TLSMODE mode){
10 4 : switch(mode){
11 : case TLS_NONE:
12 2 : return "TLS_NONE";
13 : case TLS_NEGOTIATE:
14 0 : return "TLS_NEGOTIATE";
15 : case TLS_ONLY:
16 2 : return "TLS_ONLY";
17 : }
18 0 : return "Unknown";
19 : }
20 :
21 0 : int tls_handshake(LOGGER log, CONNECTION* conn){
22 : int status;
23 :
24 : do{
25 0 : status=gnutls_handshake(conn->tls_session);
26 0 : if(status){
27 0 : if(gnutls_error_is_fatal(status)){
28 0 : logprintf(log, LOG_WARNING, "Handshake failed: %s\n", gnutls_strerror(status));
29 0 : return -1;
30 : }
31 0 : logprintf(log, LOG_WARNING, "Handshake nonfatal: %s\n", gnutls_strerror(status));
32 : }
33 : }
34 0 : while(status && !gnutls_error_is_fatal(status));
35 0 : logprintf(log, LOG_INFO, "TLS Handshake succeeded\n");
36 :
37 0 : conn->tls_mode=TLS_ONLY;
38 0 : return 0;
39 : }
40 :
41 0 : int tls_init_clientpeer(LOGGER log, CONNECTION* conn, char* remote, gnutls_certificate_credentials_t credentials){
42 : int status;
43 :
44 0 : status=gnutls_init(&(conn->tls_session), GNUTLS_CLIENT);
45 0 : if(status){
46 0 : logprintf(log, LOG_WARNING, "Failed to initialize TLS session for client: %s\n", gnutls_strerror(status));
47 0 : return -1;
48 : }
49 :
50 0 : status=gnutls_server_name_set(conn->tls_session, GNUTLS_NAME_DNS, remote, strlen(remote));
51 0 : if(status){
52 0 : logprintf(log, LOG_WARNING, "Failed to update TLS server name: %s\n", gnutls_strerror(status));
53 0 : return -1;
54 : }
55 :
56 0 : status=gnutls_credentials_set(conn->tls_session, GNUTLS_CRD_CERTIFICATE, credentials);
57 0 : if(status){
58 0 : logprintf(log, LOG_WARNING, "Failed to update TLS credentials: %s\n", gnutls_strerror(status));
59 0 : return -1;
60 : }
61 :
62 0 : status=gnutls_set_default_priority(conn->tls_session); //FIXME this should probably be configurable
63 0 : if(status){
64 0 : logprintf(log, LOG_WARNING, "Failed to update client TLS priorities: %s\n", gnutls_strerror(status));
65 0 : return -1;
66 : }
67 :
68 0 : gnutls_handshake_set_timeout(conn->tls_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
69 0 : gnutls_transport_set_int(conn->tls_session, conn->fd);
70 0 : gnutls_session_set_ptr(conn->tls_session, (void*)remote);
71 :
72 0 : return 0;
73 : }
74 :
75 10 : int tls_init_serverpeer(LOGGER log, CONNECTION* client, gnutls_priority_t tls_priorities, gnutls_certificate_credentials_t tls_cert){
76 : int status;
77 :
78 10 : status=gnutls_init(&(client->tls_session), GNUTLS_SERVER);
79 10 : if(status){
80 0 : logprintf(log, LOG_WARNING, "Failed to initialize TLS session for client: %s\n", gnutls_strerror(status));
81 0 : return -1;
82 : }
83 :
84 10 : status=gnutls_priority_set(client->tls_session, tls_priorities);
85 10 : if(status){
86 0 : logprintf(log, LOG_WARNING, "Failed to update priority set for client: %s\n", gnutls_strerror(status));
87 : }
88 :
89 10 : status=gnutls_credentials_set(client->tls_session, GNUTLS_CRD_CERTIFICATE, tls_cert);
90 10 : if(status){
91 0 : logprintf(log, LOG_WARNING, "Failed to set credentials for client: %s\n", gnutls_strerror(status));
92 0 : return -1;
93 : }
94 :
95 10 : gnutls_certificate_server_set_request(client->tls_session, GNUTLS_CERT_IGNORE);
96 10 : gnutls_transport_set_int(client->tls_session, client->fd);
97 :
98 10 : return 0;
99 : }
100 :
101 : #ifdef CMAIL_HAVE_LISTENER_TYPE
102 4 : int tls_init_listener(LOGGER log, LISTENER* listener, char* cert, char* key, char* dh_params_file, char* priorities){
103 4 : ssize_t file_size = 0;
104 4 : uint8_t* file_buffer = NULL;
105 :
106 4 : logprintf(log, LOG_DEBUG, "Initializing TLS priorities\n");
107 4 : if(gnutls_priority_init(&(listener->tls_priorities), (priorities)?priorities:"NORMAL", NULL)){
108 0 : logprintf(log, LOG_ERROR, "Failed to initialize TLS priorities\n");
109 0 : return -1;
110 : }
111 :
112 4 : logprintf(log, LOG_DEBUG, "Initializing TLS certificate structure\n");
113 4 : if(gnutls_certificate_allocate_credentials(&(listener->tls_cert))){
114 0 : logprintf(log, LOG_ERROR, "Failed to allocate storage for TLS cert structure\n");
115 0 : return -1;
116 : }
117 :
118 4 : logprintf(log, LOG_DEBUG, "Initializing TLS certificate\n");
119 4 : if(gnutls_certificate_set_x509_key_file(listener->tls_cert, cert, key, GNUTLS_X509_FMT_PEM)){
120 0 : logprintf(log, LOG_ERROR, "Failed to find key or certificate files\n");
121 0 : return -1;
122 : }
123 :
124 4 : logprintf(log, LOG_DEBUG, "Initializing DH parameter structure\n");
125 4 : if(gnutls_dh_params_init(&(listener->tls_dhparams))){
126 0 : logprintf(log, LOG_ERROR, "Failed to initialize Diffie-Hellman parameters\n");
127 0 : return -1;
128 : }
129 :
130 4 : if(dh_params_file){
131 : //read dhparams from file
132 4 : logprintf(log, LOG_DEBUG, "Reading Diffie-Hellman parameters from %s\n", dh_params_file);
133 4 : file_size = common_read_file(dh_params_file, &file_buffer);
134 4 : gnutls_datum_t dh_param_data = {
135 : .data = file_buffer,
136 : .size = file_size
137 : };
138 :
139 4 : if(file_size < 0 || !file_buffer){
140 0 : logprintf(log, LOG_ERROR, "Failed to read Diffie-Hellman parameters from file\n");
141 0 : return -1;
142 : }
143 :
144 4 : if(gnutls_dh_params_import_pkcs3(listener->tls_dhparams, &dh_param_data, GNUTLS_X509_FMT_PEM)){
145 0 : logprintf(log, LOG_ERROR, "Failed to import Diffie-Hellman parameters, check file format (should be PEM)\n");
146 0 : return -1;
147 : }
148 :
149 4 : free(file_buffer);
150 : }
151 : else{
152 : //generate new diffie-hellman parameters (kind of slow)
153 0 : logprintf(log, LOG_DEBUG, "Generating Diffie-Hellman parameters\n");
154 0 : if(gnutls_dh_params_generate2(listener->tls_dhparams, gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, TLS_PARAM_STRENGTH))){
155 0 : logprintf(log, LOG_ERROR, "Failed to generate Diffie-Hellman parameters\n");
156 0 : return -1;
157 : }
158 : }
159 :
160 4 : gnutls_certificate_set_dh_params(listener->tls_cert, listener->tls_dhparams);
161 4 : return 0;
162 : }
163 : //CMAIL_LISTENER_TYPE
164 : #endif
165 : //CMAIL_NO_TLS
166 : #endif
|