1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
3 Copyright (C) 2008 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
20 #include <glib/gprintf.h>
21 #include <gnutls/x509.h>
33 static gchar
*tls_fingerprint(gnutls_session_t ses
)
35 gnutls_x509_crt_t crt
;
36 const gnutls_datum_t
*cert_list
;
41 gnutls_x509_crt_init(&crt
);
44 log_write("%s(%i): %s(): %s", __FILE__
, __LINE__
, __FUNCTION__
,
45 gnutls_strerror(GNUTLS_E_MEMORY_ERROR
));
49 cert_list
= gnutls_certificate_get_peers(ses
, &count
);
52 gnutls_x509_crt_import(crt
, &cert_list
[0], GNUTLS_X509_FMT_DER
);
54 gnutls_x509_crt_get_fingerprint(crt
, GNUTLS_MAC_SHA1
, buf
, &len
);
57 gnutls_x509_crt_deinit(crt
);
58 return tohex(buf
, len
);
61 static gint
verify_client_certificate(guint status
)
66 if (status
& GNUTLS_CERT_INVALID
)
67 log_write(N_("client certificate is invalid"));
69 if (status
& GNUTLS_CERT_REVOKED
)
70 log_write(N_("client certificate is revoked"));
72 if (status
& GNUTLS_CERT_SIGNER_NOT_FOUND
)
73 log_write(N_("client certificate has no signer"));
75 if (status
& GNUTLS_CERT_SIGNER_NOT_CA
)
76 log_write(N_("client certificate signer is not from CA"));
78 if (status
& GNUTLS_CERT_INSECURE_ALGORITHM
)
79 log_write(N_("client certificate has insecure algorithm"));
81 return GNUTLS_E_CERTIFICATE_ERROR
;
84 struct tls_s
*tls_init(gint fd
, const gchar
*prio
)
86 struct tls_s
*tls
= g_malloc0(sizeof(struct tls_s
));
89 const gchar
*prio_error
;
90 gnutls_kx_algorithm_t kx
;
93 log_write("%s(%i): %s: %s", __FILE__
, __LINE__
, __FUNCTION__
,
98 ret
= gnutls_init(&tls
->ses
, GNUTLS_SERVER
);
100 if (ret
!= GNUTLS_E_SUCCESS
)
103 ret
= gnutls_priority_set_direct(tls
->ses
, prio
, &prio_error
);
105 if (ret
!= GNUTLS_E_SUCCESS
)
108 ret
= gnutls_credentials_set(tls
->ses
, GNUTLS_CRD_CERTIFICATE
, x509_cred
);
110 if (ret
!= GNUTLS_E_SUCCESS
)
113 gnutls_certificate_server_set_request(tls
->ses
, GNUTLS_CERT_REQUIRE
);
114 gnutls_transport_set_ptr(tls
->ses
, (gnutls_transport_ptr_t
)fd
);
115 ret
= gnutls_handshake(tls
->ses
);
117 if (ret
!= GNUTLS_E_SUCCESS
)
120 ret
= gnutls_certificate_verify_peers2(tls
->ses
, &status
);
125 kx
= gnutls_kx_get(tls
->ses
);
126 tls
->fp
= tls_fingerprint(tls
->ses
);
127 log_write("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d) FP=%s",
128 gnutls_protocol_get_name(gnutls_protocol_get_version(tls
->ses
)),
129 gnutls_cipher_get_name(gnutls_cipher_get(tls
->ses
)),
130 gnutls_mac_get_name(gnutls_mac_get(tls
->ses
)),
131 gnutls_kx_get_name(kx
),
132 gnutls_dh_get_prime_bits(tls
->ses
),
133 tls
->fp
? tls
->fp
: "N/A");
134 ret
= verify_client_certificate(status
);
142 log_write("%s", gnutls_strerror(ret
));
143 gnutls_deinit(tls
->ses
);
152 /* From the documentation. */
153 gint
tls_get_params(gnutls_session_t ses
, gnutls_params_type_t type
,
154 gnutls_params_st
*st
)
156 if (type
== GNUTLS_PARAMS_RSA_EXPORT
)
157 st
->params
.rsa_export
= rsa_params
;
158 else if (type
== GNUTLS_PARAMS_DH
)
159 st
->params
.dh
= dh_params
;
168 void tls_log(gint level
, const char *msg
)
170 log_write("TLS: %i: %s", level
, msg
);
173 int read_hook(assuan_context_t ctx
, assuan_fd_t fd
, void *data
,
174 size_t len
, ssize_t
*ret
)
176 struct client_s
*cl
= assuan_get_pointer(ctx
);
178 if (!cl
|| !cl
->thd
->remote
)
179 *ret
= read((int)fd
, data
, len
);
182 *ret
= gnutls_record_recv(cl
->thd
->tls
->ses
, data
, len
);
184 if (*ret
== GNUTLS_E_REHANDSHAKE
) {
185 *ret
= gnutls_rehandshake(cl
->thd
->tls
->ses
);
187 if (*ret
== GNUTLS_E_WARNING_ALERT_RECEIVED
||
188 *ret
== GNUTLS_A_NO_RENEGOTIATION
) {
189 log_write("%s", gnutls_strerror(*ret
));
193 if (*ret
!= GNUTLS_E_SUCCESS
) {
194 log_write("%s", gnutls_strerror(*ret
));
199 *ret
= gnutls_handshake(cl
->thd
->tls
->ses
);
201 if (*ret
!= GNUTLS_E_SUCCESS
) {
202 log_write("%s", gnutls_strerror(*ret
));
209 } while (*ret
== GNUTLS_E_INTERRUPTED
|| *ret
== GNUTLS_E_AGAIN
);
212 return *ret
<= 0 ? 0 : 1;
215 int write_hook(assuan_context_t ctx
, assuan_fd_t fd
, const void *data
,
216 size_t len
, ssize_t
*ret
)
218 struct client_s
*cl
= assuan_get_pointer(ctx
);
220 if (!cl
|| !cl
->thd
->remote
)
221 *ret
= write((int)fd
, data
, len
);
224 *ret
= gnutls_record_send(cl
->thd
->tls
->ses
, data
, len
);
225 } while (*ret
== GNUTLS_E_INTERRUPTED
|| *ret
== GNUTLS_E_AGAIN
);
228 return *ret
<= 0 ? 0 : 1;
231 gboolean
initTlsParams()
236 n
= gnutls_certificate_allocate_credentials(&x509_cred
);
238 if (n
!= GNUTLS_E_SUCCESS
) {
239 log_write("%s", gnutls_strerror(n
));
244 MUTEX_LOCK(&rcfile_mutex
);
246 if (g_key_file_has_key(keyfileh
, "global", "tcp_use_crl", NULL
) &&
247 get_key_file_boolean("global", "tcp_use_crl") == TRUE
) {
248 MUTEX_UNLOCK(&rcfile_mutex
);
249 tmp
= expand_homedir("~/.pwmd/crl.pem");
252 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
256 n
= gnutls_certificate_set_x509_crl_file(x509_cred
, tmp
,
257 GNUTLS_X509_FMT_PEM
);
260 log_write("%s: %s", tmp
, gnutls_strerror(n
));
268 MUTEX_UNLOCK(&rcfile_mutex
);
270 tmp
= expand_homedir("~/.pwmd/ca-cert.pem");
273 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
277 n
= gnutls_certificate_set_x509_trust_file(x509_cred
, tmp
,
278 GNUTLS_X509_FMT_PEM
);
281 log_write("%s: %s", tmp
, gnutls_strerror(n
));
287 tmp
= expand_homedir("~/.pwmd/server-cert.pem");
290 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
294 tmp2
= expand_homedir("~/.pwmd/server-key.pem");
298 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
302 n
= gnutls_certificate_set_x509_key_file (x509_cred
, tmp
, tmp2
,
303 GNUTLS_X509_FMT_PEM
);
307 if (n
!= GNUTLS_E_SUCCESS
) {
308 log_write("%s", gnutls_strerror(n
));
312 log_write("%s", N_("Generating key exchange parameters..."));
313 n
= gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM
, 0);
316 log_write("%s", gpg_strerror(n
));
320 n
= gnutls_dh_params_init(&dh_params
);
322 if (n
!= GNUTLS_E_SUCCESS
) {
323 log_write("%s", gnutls_strerror(n
));
327 n
= gnutls_dh_params_generate2(dh_params
, 1024);
329 if (n
!= GNUTLS_E_SUCCESS
) {
330 log_write("%s", gnutls_strerror(n
));
334 gnutls_certificate_set_dh_params(x509_cred
, dh_params
);
335 n
= gnutls_rsa_params_init(&rsa_params
);
337 if (n
!= GNUTLS_E_SUCCESS
) {
338 log_write("%s", gnutls_strerror(n
));
342 n
= gnutls_rsa_params_generate2(rsa_params
, 512);
344 if (n
!= GNUTLS_E_SUCCESS
) {
345 log_write("%s", gnutls_strerror(n
));
349 gnutls_certificate_set_rsa_export_params(x509_cred
, rsa_params
);
350 gnutls_certificate_set_params_function(x509_cred
, tls_get_params
);
357 void deinitTlsParams()
360 gnutls_dh_params_deinit(dh_params
);
365 gnutls_rsa_params_deinit(rsa_params
);
370 gnutls_certificate_free_credentials(x509_cred
);