2 Copyright (C) 2012, 2013, 2014, 2015, 2016
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Libpwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
29 #include <sys/types.h>
30 #include <sys/socket.h>
40 #define DEFAULT_TLS_PRIORITY "SECURE256:SECURE192:SECURE128:-VERS-SSL3.0"
41 #define WAIT_INTERVAL 50000
42 #define TEST_TIMEOUT(pwm, timeout, ret, start, rc) \
45 if (ret == GNUTLS_E_AGAIN || pwm->cancel) \
47 time_t now = time (NULL); \
48 if (pwm->cancel || (timeout && now - start >= timeout)) \
51 rc = gpg_error (GPG_ERR_CANCELED); \
53 rc = gpg_error (GPG_ERR_ETIMEDOUT); \
54 ret = GNUTLS_E_TIMEDOUT; \
57 struct timeval tv = { 0, WAIT_INTERVAL }; \
58 select (0, NULL, NULL, NULL, &tv); \
60 if (ret != GNUTLS_E_INTERRUPTED) \
68 struct tls_s
*tls
= pwm
->tcp
->tls
;
75 pwmd_free (tls
->cert
);
77 pwmd_free (tls
->priority
);
78 pwmd_free (tls
->server_fp
);
82 time_t start
= time (NULL
);
88 ret
= gnutls_bye (tls
->session
, GNUTLS_SHUT_WR
);
89 TEST_TIMEOUT (pwm
, tls
->timeout
, ret
, start
, rc
);
93 while (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
);
95 gnutls_deinit (tls
->session
);
97 else if (pwm
->fd
!= -1)
104 gnutls_certificate_free_credentials (tls
->x509
);
109 pwm
->tls_error
= ret
;
113 tls_read_hook (pwm_t
*pwm
, assuan_fd_t fd
, void *data
, size_t len
)
115 struct tls_s
*tls
= pwm
->tcp
->tls
;
117 time_t start
= time (NULL
);
125 struct timeval tv
= { 0, 0 };
130 FD_SET (*tls
->fd
, &fds
);
131 n
= select (*tls
->fd
+1, &fds
, NULL
, NULL
, &tv
);
132 if (n
== 0 && tls
->nl
)
136 memcpy (data
, c
, sizeof(c
));
141 ret
= gnutls_record_recv (tls
->session
, data
, len
);
142 if (ret
== GNUTLS_E_REHANDSHAKE
)
146 ret
= gnutls_handshake (tls
->session
);
147 TEST_TIMEOUT (pwm
, tls
->timeout
, ret
, start
, rc
);
151 while (ret
< 0 && gnutls_error_is_fatal (ret
) == 0);
157 memcpy (data
, c
, sizeof(c
));
164 ret
= GNUTLS_E_AGAIN
;
167 TEST_TIMEOUT (pwm
, tls
->timeout
, ret
, start
, rc
);
171 while (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
);
174 pwm
->tls_error
= ret
;
178 else if (ret
== GNUTLS_E_PREMATURE_TERMINATION
)
182 tls
->nl
= ((char *)data
)[ret
-1] == '\n';
184 return ret
< 0 ? -1 : ret
;
188 tls_write_hook (pwm_t
*pwm
, assuan_fd_t fd
, const void *data
, size_t len
)
190 struct tls_s
*tls
= pwm
->tcp
->tls
;
192 /* This is probably the BYE command after a previous call timed
193 * out. If not done, the time(2) call seems to hang.*/
198 time_t start
= time (NULL
);
204 ret
= gnutls_record_send (tls
->session
, data
, len
);
205 TEST_TIMEOUT (pwm
, tls
->timeout
, ret
, start
, rc
);
209 while (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
);
212 pwm
->tls_error
= ret
;
216 else if (ret
== GNUTLS_E_PREMATURE_TERMINATION
)
219 return ret
< 0 ? -1 : ret
;
223 tls_fingerprint (pwm_t
*pwm
, char **result
)
225 gnutls_session_t ses
= pwm
->tcp
->tls
->session
;
226 gnutls_x509_crt_t crt
;
227 const gnutls_datum_t
*cert_list
;
229 unsigned char buf
[32];
230 size_t len
= sizeof (buf
);
233 gnutls_x509_crt_init (&crt
);
235 return GPG_ERR_ENOMEM
;
237 cert_list
= gnutls_certificate_get_peers (ses
, &count
);
240 pwm
->tls_error
= gnutls_x509_crt_import (crt
, &cert_list
[0],
241 GNUTLS_X509_FMT_DER
);
243 gnutls_x509_crt_get_fingerprint (crt
, GNUTLS_DIG_SHA256
, buf
, &len
);
246 gnutls_x509_crt_deinit (crt
);
249 pwm
->tls_error
= GNUTLS_CERT_INVALID
;
250 return GPG_ERR_MISSING_CERT
;
254 *result
= bin2hex (buf
, len
);
256 return !pwm
->tls_error
? 0 : GPG_ERR_ENOMEM
;
260 verify_server_certificate (unsigned status
)
262 if (status
& GNUTLS_CERT_REVOKED
)
264 fprintf (stderr
, "server certificate is revoked\n");
265 return GPG_ERR_CERT_REVOKED
;
268 if (status
& GNUTLS_CERT_SIGNER_NOT_FOUND
)
270 fprintf (stderr
, "server certificate has no signer\n");
271 return GPG_ERR_NO_SIGNATURE_SCHEME
;
274 if (status
& GNUTLS_CERT_SIGNATURE_FAILURE
)
276 fprintf (stderr
, "server certificate signature verification failed\n");
277 return GPG_ERR_BAD_SIGNATURE
;
280 if (status
& GNUTLS_CERT_EXPIRED
)
282 fprintf (stderr
, "server certificate expired\n");
283 return GPG_ERR_CERT_EXPIRED
;
286 if (status
& GNUTLS_CERT_SIGNER_NOT_CA
)
288 fprintf (stderr
, "server certificate signer is not from CA\n");
289 return GPG_ERR_BAD_CA_CERT
;
292 if (status
& GNUTLS_CERT_INSECURE_ALGORITHM
)
294 fprintf (stderr
, "server certificate has insecure algorithm\n");
295 return GPG_ERR_UNSUPPORTED_ALGORITHM
;
300 fprintf (stderr
, "server certificate is invalid: %u\n", status
);
301 return GPG_ERR_BAD_CERT
;
308 verify_certificate (pwm_t
*pwm
)
311 const gnutls_datum_t
*cert_list
;
312 unsigned int cert_list_size
;
314 gnutls_x509_crt_t cert
;
317 i
= gnutls_certificate_verify_peers2 (pwm
->tcp
->tls
->session
, &status
);
321 return GPG_ERR_BAD_CERT
;
324 rc
= verify_server_certificate (status
);
328 if (gnutls_certificate_type_get (pwm
->tcp
->tls
->session
) != GNUTLS_CRT_X509
)
329 return GPG_ERR_UNSUPPORTED_CERT
;
331 if (gnutls_x509_crt_init (&cert
) < 0)
332 return gpg_error_from_errno (ENOMEM
);
334 cert_list
= gnutls_certificate_get_peers (pwm
->tcp
->tls
->session
,
338 rc
= GPG_ERR_MISSING_CERT
;
342 for (i
= 0; i
< cert_list_size
; i
++)
344 pwm
->tls_error
= gnutls_x509_crt_import (cert
, &cert_list
[i
],
345 GNUTLS_X509_FMT_DER
);
346 if (pwm
->tls_error
< 0)
348 rc
= GPG_ERR_BAD_CERT_CHAIN
;
352 if (gnutls_x509_crt_get_expiration_time (cert
) < time (0))
354 rc
= GPG_ERR_CERT_EXPIRED
;
358 if (gnutls_x509_crt_get_activation_time (cert
) > time (0))
360 rc
= GPG_ERR_CERT_TOO_YOUNG
;
364 if (pwm
->tcp
->tls
->verify
)
366 if (!gnutls_x509_crt_check_hostname (cert
, pwm
->tcp
->host
))
368 rc
= GPG_ERR_BAD_CERT_CHAIN
;
374 if (pwm
->tcp
->tls
->server_fp
)
378 rc
= tls_fingerprint (pwm
, &result
);
381 if (!result
|| !*result
||
382 strcasecmp (result
, pwm
->tcp
->tls
->server_fp
))
383 rc
= GPG_ERR_BAD_CERT
;
390 gnutls_x509_crt_deinit (cert
);
395 tls_init (pwm_t
* pwm
)
401 ret
= gnutls_certificate_allocate_credentials (&pwm
->tcp
->tls
->x509
);
404 pwm
->tls_error
= ret
;
405 return gpg_error_from_errno (ENOMEM
);
408 /* The client certificate must be signed by the CA of the pwmd server
409 * certificate in order for the client to authenticate successfully. Man in
410 * the middle attacks are still possible if the attacker is running a pwmd
411 * that doesn't require client certificate authentication. So require the
412 * client to verify the server certificate.
414 ret
= gnutls_certificate_set_x509_trust_file (pwm
->tcp
->tls
->x509
,
416 GNUTLS_X509_FMT_PEM
);
419 rc
= GPG_ERR_INV_CERT_OBJ
;
423 ret
= gnutls_certificate_set_x509_key_file (pwm
->tcp
->tls
->x509
,
426 GNUTLS_X509_FMT_PEM
);
427 if (ret
!= GNUTLS_E_SUCCESS
)
429 pwm
->tls_error
= ret
;
430 rc
= GPG_ERR_INV_CERT_OBJ
;
434 ret
= gnutls_init (&pwm
->tcp
->tls
->session
, GNUTLS_CLIENT
);
435 if (ret
!= GNUTLS_E_SUCCESS
)
437 pwm
->tls_error
= ret
;
438 rc
= GPG_ERR_INV_CERT_OBJ
;
442 ret
= gnutls_priority_set_direct (pwm
->tcp
->tls
->session
,
443 pwm
->tcp
->tls
->priority
444 ? pwm
->tcp
->tls
->priority
445 : DEFAULT_TLS_PRIORITY
,
447 if (ret
!= GNUTLS_E_SUCCESS
)
449 pwm
->tls_error
= ret
;
450 rc
= GPG_ERR_INV_CERT_OBJ
;
454 ret
= gnutls_credentials_set (pwm
->tcp
->tls
->session
, GNUTLS_CRD_CERTIFICATE
,
455 pwm
->tcp
->tls
->x509
);
456 if (ret
!= GNUTLS_E_SUCCESS
)
458 pwm
->tls_error
= ret
;
459 rc
= GPG_ERR_INV_CERT_OBJ
;
463 gnutls_transport_set_ptr (pwm
->tcp
->tls
->session
,
464 (gnutls_transport_ptr_t
) pwm
->fd
);
465 if (fcntl (pwm
->fd
, F_SETFL
, O_NONBLOCK
) == -1)
467 rc
= gpg_error_from_errno (errno
);
471 time_t start
= time (NULL
);
474 ret
= gnutls_handshake (pwm
->tcp
->tls
->session
);
475 TEST_TIMEOUT (pwm
, pwm
->tcp
->tls
->timeout
, ret
, start
, rc
);
479 while (ret
== GNUTLS_E_AGAIN
|| ret
== GNUTLS_E_INTERRUPTED
);
481 if (ret
!= GNUTLS_E_SUCCESS
)
483 pwm
->tls_error
= ret
;
484 rc
= GPG_ERR_INV_CERT_OBJ
;
488 rc
= verify_certificate (pwm
);
493 /* Keep the original error since it maybe overwritten during TLS
495 ret
= pwm
->tls_error
;
496 /* The session may not have completed a handshake. Will crash during
498 gnutls_deinit (pwm
->tcp
->tls
->session
);
499 pwm
->tcp
->tls
->session
= NULL
;
501 pwm
->tls_error
= ret
;
508 tls_connect (pwm_t
* pwm
, const char *host
, int port
, const char *cert
,
509 const char *key
, const char *cacert
, const char *prio
,
510 const char *server_fp
, int verify
)
515 if (!cert
|| !key
|| !cacert
)
516 return GPG_ERR_INV_ARG
;
518 tcp
= pwmd_calloc (1, sizeof (struct tcp_s
));
520 return GPG_ERR_ENOMEM
;
522 pthread_cond_init (&tcp
->dns_cond
, NULL
);
523 pthread_mutex_init (&tcp
->dns_mutex
, NULL
);
526 tcp
->host
= pwmd_strdup (host
);
533 tcp
->tls
= pwmd_calloc (1, sizeof (struct tls_s
));
540 tcp
->tls
->timeout
= pwm
->socket_timeout
;
541 tcp
->tls
->verify
= verify
;
542 tcp
->tls
->cert
= pwmd_strdup (cert
);
549 tcp
->tls
->key
= pwmd_strdup (key
);
556 tcp
->tls
->ca
= pwmd_strdup (cacert
);
565 tcp
->tls
->priority
= pwmd_strdup (prio
);
566 if (!tcp
->tls
->priority
)
575 tcp
->tls
->server_fp
= pwmd_strdup (server_fp
);
576 if (!tcp
->tls
->server_fp
)
583 rc
= tcp_connect_common (pwm
);
589 pwm
->tcp
->fd
= pwm
->tcp
->tls
->fd
= &pwm
->fd
;
590 rc
= assuan_socket_connect_fd (pwm
->ctx
, pwm
->fd
, 0);
602 * tls[46]://[hostname][:port]
605 tls_parse_url (const char *str
, char **host
, int *port
)
608 return parse_hostname_common (str
, host
, port
);