2 Copyright (C) 2008 Ben Kibbey <bjk@luxsci.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
18 #include <gnutls/x509.h>
24 #include "pwmd-error.h"
26 #include "util-misc.h"
27 #include "util-string.h"
32 static char *tls_fingerprint(gnutls_session_t ses
)
34 gnutls_x509_crt_t crt
;
35 const gnutls_datum_t
*cert_list
;
37 unsigned char buf
[20];
38 size_t len
= sizeof(buf
);
40 gnutls_x509_crt_init(&crt
);
42 log_write("%s(%i): %s(): %s", __FILE__
, __LINE__
, __FUNCTION__
,
43 gnutls_strerror(GNUTLS_E_MEMORY_ERROR
));
47 cert_list
= gnutls_certificate_get_peers(ses
, &count
);
49 gnutls_x509_crt_import(crt
, &cert_list
[0], GNUTLS_X509_FMT_DER
);
50 gnutls_x509_crt_get_fingerprint(crt
, GNUTLS_DIG_SHA1
, buf
, &len
);
53 gnutls_x509_crt_deinit(crt
);
54 return bin2hex(buf
, len
);
57 static int verify_client_certificate(unsigned status
)
62 if (status
& GNUTLS_CERT_INVALID
)
63 log_write(_("client certificate is invalid"));
65 if (status
& GNUTLS_CERT_REVOKED
)
66 log_write(_("client certificate is revoked"));
68 if (status
& GNUTLS_CERT_SIGNER_NOT_FOUND
)
69 log_write(_("client certificate has no signer"));
71 if (status
& GNUTLS_CERT_SIGNER_NOT_CA
)
72 log_write(_("client certificate signer is not from CA"));
74 if (status
& GNUTLS_CERT_INSECURE_ALGORITHM
)
75 log_write(_("client certificate has insecure algorithm"));
77 return GNUTLS_E_CERTIFICATE_ERROR
;
80 struct tls_s
*tls_init(int fd
, const char *prio
)
82 struct tls_s
*tls
= xcalloc(1, sizeof(struct tls_s
));
85 const char *prio_error
;
86 gnutls_kx_algorithm_t kx
;
89 log_write("%s(%i): %s: %s", __FILE__
, __LINE__
, __FUNCTION__
,
94 ret
= gnutls_init(&tls
->ses
, GNUTLS_SERVER
);
95 if (ret
!= GNUTLS_E_SUCCESS
)
98 ret
= gnutls_priority_set_direct(tls
->ses
, prio
, &prio_error
);
99 if (ret
!= GNUTLS_E_SUCCESS
)
102 ret
= gnutls_credentials_set(tls
->ses
, GNUTLS_CRD_CERTIFICATE
, x509_cred
);
103 if (ret
!= GNUTLS_E_SUCCESS
)
106 gnutls_certificate_server_set_request(tls
->ses
, GNUTLS_CERT_REQUIRE
);
107 gnutls_transport_set_ptr(tls
->ses
, (gnutls_transport_ptr_t
)fd
);
108 ret
= gnutls_handshake(tls
->ses
);
109 if (ret
!= GNUTLS_E_SUCCESS
)
112 ret
= gnutls_certificate_verify_peers2(tls
->ses
, &status
);
116 kx
= gnutls_kx_get(tls
->ses
);
117 tls
->fp
= tls_fingerprint(tls
->ses
);
118 log_write("PROTO=%s CIPHER=%s MAC=%s KX=%s(%d) FP=%s",
119 gnutls_protocol_get_name(gnutls_protocol_get_version(tls
->ses
)),
120 gnutls_cipher_get_name(gnutls_cipher_get(tls
->ses
)),
121 gnutls_mac_get_name(gnutls_mac_get(tls
->ses
)),
122 gnutls_kx_get_name(kx
),
123 gnutls_dh_get_prime_bits(tls
->ses
),
124 tls
->fp
? tls
->fp
: "N/A");
125 ret
= verify_client_certificate(status
);
132 log_write("%s", gnutls_strerror(ret
));
133 gnutls_deinit(tls
->ses
);
139 /* From the documentation. */
140 int tls_get_params(gnutls_session_t ses
, gnutls_params_type_t type
,
141 gnutls_params_st
*st
)
143 if (type
== GNUTLS_PARAMS_RSA_EXPORT
)
144 st
->params
.rsa_export
= rsa_params
;
145 else if (type
== GNUTLS_PARAMS_DH
)
146 st
->params
.dh
= dh_params
;
155 void tls_log(int level
, const char *msg
)
157 log_write("TLS: %i: %s", level
, msg
);
160 ssize_t
tls_read_hook(assuan_context_t ctx
, assuan_fd_t fd
, void *data
,
163 struct client_s
*client
= assuan_get_pointer(ctx
);
167 ret
= gnutls_record_recv(client
->thd
->tls
->ses
, data
, len
);
169 if (ret
== GNUTLS_E_REHANDSHAKE
) {
170 ret
= gnutls_rehandshake(client
->thd
->tls
->ses
);
171 if (ret
== GNUTLS_E_WARNING_ALERT_RECEIVED
||
172 ret
== GNUTLS_A_NO_RENEGOTIATION
) {
173 log_write("%s", gnutls_strerror(ret
));
177 if (ret
!= GNUTLS_E_SUCCESS
) {
178 log_write("%s", gnutls_strerror(ret
));
183 ret
= gnutls_handshake(client
->thd
->tls
->ses
);
184 if (ret
!= GNUTLS_E_SUCCESS
) {
185 log_write("%s", gnutls_strerror(ret
));
192 } while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
195 log_write("%s", gnutls_strerror(ret
));
202 ssize_t
tls_write_hook(assuan_context_t ctx
, assuan_fd_t fd
, const void *data
,
205 struct client_s
*client
= assuan_get_pointer(ctx
);
209 struct timeval tv
= { 0, 50000 };
211 ret
= gnutls_record_send(client
->thd
->tls
->ses
, data
, len
);
212 if (ret
== GNUTLS_E_AGAIN
)
213 select(0, NULL
, NULL
, NULL
, &tv
);
214 } while (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
);
219 gpg_error_t
tls_init_params()
223 gpg_error_t rc
= GPG_ERR_UNKNOWN_ERRNO
;
225 n
= gnutls_certificate_allocate_credentials(&x509_cred
);
226 if (n
!= GNUTLS_E_SUCCESS
) {
227 log_write("%s", gnutls_strerror(n
));
232 MUTEX_LOCK(&rcfile_mutex
);
234 if (config_get_boolean("global", "tls_use_crl")) {
235 MUTEX_UNLOCK(&rcfile_mutex
);
236 tmp
= expand_homedir("~/.pwmd/crl.pem");
242 n
= gnutls_certificate_set_x509_crl_file(x509_cred
, tmp
,
243 GNUTLS_X509_FMT_PEM
);
245 log_write("%s: %s", tmp
, gnutls_strerror(n
));
253 MUTEX_UNLOCK(&rcfile_mutex
);
255 tmp
= expand_homedir("~/.pwmd/ca-cert.pem");
261 n
= gnutls_certificate_set_x509_trust_file(x509_cred
, tmp
,
262 GNUTLS_X509_FMT_PEM
);
264 log_write("%s: %s", tmp
, gnutls_strerror(n
));
270 tmp
= expand_homedir("~/.pwmd/server-cert.pem");
276 tmp2
= expand_homedir("~/.pwmd/server-key.pem");
279 log_write("%s(%i): %s", __FILE__
, __LINE__
, strerror(ENOMEM
));
283 n
= gnutls_certificate_set_x509_key_file (x509_cred
, tmp
, tmp2
,
284 GNUTLS_X509_FMT_PEM
);
287 if (n
!= GNUTLS_E_SUCCESS
) {
288 log_write("%s", gnutls_strerror(n
));
292 log_write("%s", _("Generating key exchange parameters..."));
293 n
= gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM
, 0);
295 log_write("%s", pwmd_strerror(n
));
299 n
= gnutls_dh_params_init(&dh_params
);
300 if (n
!= GNUTLS_E_SUCCESS
) {
301 log_write("%s", gnutls_strerror(n
));
305 n
= gnutls_dh_params_generate2(dh_params
, 1024);
306 if (n
!= GNUTLS_E_SUCCESS
) {
307 log_write("%s", gnutls_strerror(n
));
311 gnutls_certificate_set_dh_params(x509_cred
, dh_params
);
312 n
= gnutls_rsa_params_init(&rsa_params
);
313 if (n
!= GNUTLS_E_SUCCESS
) {
314 log_write("%s", gnutls_strerror(n
));
318 n
= gnutls_rsa_params_generate2(rsa_params
, 512);
319 if (n
!= GNUTLS_E_SUCCESS
) {
320 log_write("%s", gnutls_strerror(n
));
324 gnutls_certificate_set_rsa_export_params(x509_cred
, rsa_params
);
325 gnutls_certificate_set_params_function(x509_cred
, tls_get_params
);
332 void tls_deinit_params()
335 gnutls_dh_params_deinit(dh_params
);
340 gnutls_rsa_params_deinit(rsa_params
);
345 gnutls_certificate_free_credentials(x509_cred
);
350 gpg_error_t
tls_validate_access(struct client_s
*cl
, const char
353 char **access
= config_get_list(filename
, "tls_access");
355 int allow
= 0, deny
= 0;
357 if (!access
|| !*access
)
358 return GPG_ERR_INV_USER_ID
;
360 for (p
= access
; p
&& *p
; p
++) {
364 if (*fp
&& *fp
== '+' && *(fp
+1) == 0) {
376 if (!strcasecmp(cl
->thd
->tls
->fp
, fp
)) {
389 return allow
&& !deny
? 0 : GPG_ERR_INV_USER_ID
;