2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of pwmd.
8 Pwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Pwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
21 #include <gnutls/x509.h>
33 #include "pwmd-error.h"
36 #include "util-misc.h"
37 #include "util-string.h"
42 #define WAIT_INTERVAL 50000
43 #define TEST_TIMEOUT(timeout, ret, start, rc) \
45 if (ret == GNUTLS_E_AGAIN) \
47 time_t now = time (NULL); \
48 if (timeout && now - start >= timeout) \
50 rc = gpg_error (GPG_ERR_ETIMEDOUT); \
53 struct timeval tv = { 0, WAIT_INTERVAL }; \
54 select (0, NULL, NULL, NULL, &tv); \
56 if (ret != GNUTLS_E_INTERRUPTED) \
62 tls_fingerprint (gnutls_session_t ses
)
64 gnutls_x509_crt_t crt
;
65 const gnutls_datum_t
*cert_list
;
67 unsigned char buf
[32];
68 size_t len
= sizeof (buf
);
70 gnutls_x509_crt_init (&crt
);
73 log_write ("%s(%i): %s(): %s", __FILE__
, __LINE__
, __FUNCTION__
,
74 gnutls_strerror (GNUTLS_E_MEMORY_ERROR
));
78 cert_list
= gnutls_certificate_get_peers (ses
, &count
);
81 gnutls_x509_crt_import (crt
, &cert_list
[0], GNUTLS_X509_FMT_DER
);
82 gnutls_x509_crt_get_fingerprint (crt
, GNUTLS_DIG_SHA256
, buf
, &len
);
83 gnutls_x509_crt_deinit (crt
);
85 return len
? bin2hex (buf
, len
) : NULL
;
88 gnutls_x509_crt_deinit (crt
);
93 verify_client_certificate (unsigned status
)
98 if (status
& GNUTLS_CERT_REVOKED
)
99 log_write (_("client certificate is revoked"));
101 if (status
& GNUTLS_CERT_SIGNER_NOT_FOUND
)
102 log_write (_("client certificate has no signer"));
104 if (status
& GNUTLS_CERT_SIGNATURE_FAILURE
)
105 log_write (_("client certificate signature verification failed"));
107 if (status
& GNUTLS_CERT_EXPIRED
)
108 log_write (_("client certificate expired"));
110 if (status
& GNUTLS_CERT_SIGNER_NOT_CA
)
111 log_write (_("client certificate signer is not from CA"));
113 if (status
& GNUTLS_CERT_INSECURE_ALGORITHM
)
114 log_write (_("client certificate has insecure algorithm"));
116 if (status
& GNUTLS_CERT_INVALID
)
117 log_write (_("client certificate is invalid"));
119 return GNUTLS_E_CERTIFICATE_ERROR
;
123 tls_init (int fd
, int timeout
, const char *prio
)
125 struct tls_s
*tls
= xcalloc (1, sizeof (struct tls_s
));
128 const char *prio_error
;
129 gnutls_kx_algorithm_t kx
;
134 log_write ("%s(%i): %s: %s", __FILE__
, __LINE__
, __FUNCTION__
,
139 ret
= gnutls_init (&tls
->ses
, GNUTLS_SERVER
);
140 if (ret
!= GNUTLS_E_SUCCESS
)
143 ret
= gnutls_priority_set_direct (tls
->ses
, prio
, &prio_error
);
144 if (ret
!= GNUTLS_E_SUCCESS
)
147 ret
= gnutls_credentials_set (tls
->ses
, GNUTLS_CRD_CERTIFICATE
, x509_cred
);
148 if (ret
!= GNUTLS_E_SUCCESS
)
151 gnutls_certificate_server_set_request (tls
->ses
, GNUTLS_CERT_REQUIRE
);
152 gnutls_transport_set_ptr (tls
->ses
, (gnutls_transport_ptr_t
) fd
);
153 time_t start
= time (NULL
);
156 ret
= gnutls_handshake (tls
->ses
);
157 TEST_TIMEOUT (timeout
, ret
, start
, rc
);
161 while (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
);
163 if (ret
!= GNUTLS_E_SUCCESS
)
166 ret
= gnutls_certificate_verify_peers2 (tls
->ses
, &status
);
170 kx
= gnutls_kx_get (tls
->ses
);
171 tls
->fp
= tls_fingerprint (tls
->ses
);
172 log_write ("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d) FP=%s",
173 gnutls_protocol_get_name (gnutls_protocol_get_version
175 gnutls_cipher_get_name (gnutls_cipher_get (tls
->ses
)),
176 gnutls_mac_get_name (gnutls_mac_get (tls
->ses
)),
177 gnutls_kx_get_name (kx
), gnutls_dh_get_prime_bits (tls
->ses
),
178 tls
->fp
? tls
->fp
: "N/A");
179 ret
= verify_client_certificate (status
);
186 log_write ("%s", rc
? pwmd_strerror(rc
) : gnutls_strerror (ret
));
187 gnutls_deinit (tls
->ses
);
194 tls_log (int level
, const char *msg
)
196 log_write ("TLS: %i: %s", level
, msg
);
200 tls_audit_log (gnutls_session_t s
, const char *msg
)
203 log_write ("TLS: %s", msg
);
207 tls_read_hook (assuan_context_t ctx
, assuan_fd_t fd
, void *data
, size_t len
)
209 struct client_s
*client
= assuan_get_pointer (ctx
);
210 time_t start
= time (NULL
);
218 ret
= gnutls_record_recv (client
->thd
->tls
->ses
, data
, len
);
219 if (ret
== GNUTLS_E_REHANDSHAKE
)
221 ret
= gnutls_rehandshake (client
->thd
->tls
->ses
);
222 if (ret
== GNUTLS_E_GOT_APPLICATION_DATA
)
224 else if (ret
!= GNUTLS_E_SUCCESS
)
226 log_write ("%s", gnutls_strerror (ret
));
233 ret
= gnutls_handshake (client
->thd
->tls
->ses
);
235 TEST_TIMEOUT (client
->thd
->timeout
, ret
, start
, rc
);
238 log_write ("%s", gnutls_strerror (ret
));
240 close (client
->thd
->fd
);
241 client
->thd
->fd
= -1;
245 while (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
);
253 TEST_TIMEOUT (client
->thd
->timeout
, ret
, start
, rc
);
257 close (client
->thd
->fd
);
258 client
->thd
->fd
= -1;
262 while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
266 log_write ("%s", gnutls_strerror (ret
));
274 tls_write_hook (assuan_context_t ctx
, assuan_fd_t fd
, const void *data
,
277 struct client_s
*client
= assuan_get_pointer (ctx
);
279 time_t start
= time (NULL
);
285 ret
= gnutls_record_send (client
->thd
->tls
->ses
, data
, len
);
286 TEST_TIMEOUT (client
->thd
->timeout
, ret
, start
, rc
);
290 close (client
->thd
->fd
);
291 client
->thd
->fd
= -1;
295 while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
301 parse_dh_sec_level (const char *str
, gpg_error_t
*rc
)
306 return gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH
, GNUTLS_SEC_PARAM_MEDIUM
);
308 if (!strcasecmp (str
, "low"))
309 return gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH
, GNUTLS_SEC_PARAM_LOW
);
310 else if (!strcasecmp (str
, "medium"))
311 return gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH
, GNUTLS_SEC_PARAM_MEDIUM
);
312 else if (!strcasecmp (str
, "high"))
313 return gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH
, GNUTLS_SEC_PARAM_HIGH
);
314 else if (!strcasecmp (str
, "ultra"))
315 return gnutls_sec_param_to_pk_bits (GNUTLS_PK_DH
, GNUTLS_SEC_PARAM_ULTRA
);
317 *rc
= GPG_ERR_INV_VALUE
;
318 return GNUTLS_SEC_PARAM_UNKNOWN
;
322 tls_init_params (const char *dh_sec_level
)
326 gpg_error_t rc
= GPG_ERR_UNKNOWN_ERRNO
;
327 static pthread_mutex_t tls_mutex
= PTHREAD_MUTEX_INITIALIZER
;
328 int bits
= parse_dh_sec_level (dh_sec_level
, &rc
);
332 log_write ("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror (rc
));
336 MUTEX_LOCK(&tls_mutex
);
337 tls_deinit_params ();
338 rc
= GPG_ERR_UNKNOWN_ERRNO
;
339 n
= gnutls_certificate_allocate_credentials (&x509_cred
);
340 if (n
!= GNUTLS_E_SUCCESS
)
342 log_write ("%s", gnutls_strerror (n
));
347 tmp
= str_asprintf ("%s/ca-cert.pem", homedir
);
351 log_write ("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror (rc
));
355 n
= gnutls_certificate_set_x509_trust_file (x509_cred
, tmp
,
356 GNUTLS_X509_FMT_PEM
);
359 log_write ("%s: %s", tmp
, gnutls_strerror (n
));
365 tmp
= str_asprintf ("%s/server-cert.pem", homedir
);
369 log_write ("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror (rc
));
373 tmp2
= str_asprintf ("%s/server-key.pem", homedir
);
378 log_write ("%s(%i): %s", __FILE__
, __LINE__
, pwmd_strerror (rc
));
382 n
= gnutls_certificate_set_x509_key_file (x509_cred
, tmp
, tmp2
,
383 GNUTLS_X509_FMT_PEM
);
386 if (n
!= GNUTLS_E_SUCCESS
)
388 log_write ("%s", gnutls_strerror (n
));
392 log_write ("%s", _("(Re)generating key exchange parameters..."));
393 n
= gnutls_dh_params_init (&dh_params
);
394 if (n
!= GNUTLS_E_SUCCESS
)
397 n
= gnutls_dh_params_generate2 (dh_params
, bits
);
398 if (n
!= GNUTLS_E_SUCCESS
)
400 log_write ("%s", gnutls_strerror (n
));
404 gnutls_certificate_set_dh_params (x509_cred
, dh_params
);
405 MUTEX_UNLOCK(&tls_mutex
);
409 tls_deinit_params ();
410 MUTEX_UNLOCK(&tls_mutex
);
419 gnutls_dh_params_deinit (dh_params
);
425 gnutls_certificate_free_credentials (x509_cred
);
431 do_tls_validate_access (struct client_s
*client
, const char *section
)
433 char **access
= config_get_list (section
, "allowed");
437 if (!access
|| !*access
)
438 return GPG_ERR_EACCES
;
440 for (p
= access
; p
&& *p
; p
++)
445 if (*fp
&& *fp
== '+' && *(fp
+ 1) == 0) // allow all connections
451 if (*fp
== '!' || *fp
== '-')
462 if (!strcasecmp (client
->thd
->tls
->fp
, fp
))
463 allowed
= not ? 0 : 1;
467 return allowed
? 0 : GPG_ERR_EACCES
;
471 tls_validate_access (struct client_s
*client
, const char *filename
)
473 gpg_error_t rc
= do_tls_validate_access (client
, "global");
476 rc
= do_tls_validate_access (client
, filename
);