2 * Copyright (C) 2013 Nikos Mavrogiannopoulos
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The gnutls library is free software; you can redistribute it
9 * and/or modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include <gnutls_int.h>
24 #include <gnutls_errors.h>
25 #include <gnutls_num.h>
26 #include <gnutls/xssl.h>
27 #include <auth/cert.h>
29 #include "vasprintf.h"
35 * @cred: is a #xssl_cred_t structure.
37 * This function deinitializes a #xssl_cred_t structure.
39 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
43 void xssl_cred_deinit(xssl_cred_t cred)
46 gnutls_certificate_free_credentials(cred->xcred);
51 static int _verify_certificate_callback(gnutls_session_t session)
56 const char *hostname = NULL;
57 const char *service = NULL;
58 const char *tofu_file = NULL;
60 sb = gnutls_session_get_ptr(session);
62 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
66 gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
68 if (sb->server_name[0] != 0)
69 hostname = sb->server_name;
71 if (sb->service_name[0] != 0)
72 service = sb->service_name;
74 if (sb->cred->tofu_file[0] != 0)
75 tofu_file = sb->cred->tofu_file;
77 /* This verification function uses the trusted CAs in the credentials
78 * structure. So you must have installed one or more CA certificates.
81 if (sb->cred->vflags & GNUTLS_VMETHOD_SYSTEM_CAS
82 || sb->cred->vflags & GNUTLS_VMETHOD_GIVEN_CAS) {
84 gnutls_certificate_verify_peers3(session, hostname,
87 return gnutls_assert_val(GNUTLS_E_AUTH_ERROR);
91 if (status != 0) /* Certificate is not trusted */
92 return gnutls_assert_val(GNUTLS_E_AUTH_ERROR);
95 if (hostname && sb->cred->vflags & GNUTLS_VMETHOD_TOFU) {
96 const gnutls_datum_t *cert_list;
97 unsigned int cert_list_size;
99 type = gnutls_certificate_type_get(session);
101 /* Do SSH verification */
103 gnutls_certificate_get_peers(session, &cert_list_size);
104 if (cert_list == NULL) {
105 sb->vstatus |= GNUTLS_CERT_INVALID;
106 return gnutls_assert_val(GNUTLS_E_AUTH_ERROR);
109 /* service may be obtained alternatively using getservbyport() */
111 gnutls_verify_stored_pubkey(tofu_file, NULL, hostname,
114 if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) {
115 /* host was not seen before. Store the key */
116 gnutls_store_pubkey(tofu_file, NULL, hostname,
117 service, type, &cert_list[0],
119 } else if (ret == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) {
120 sb->vstatus |= GNUTLS_CERT_MISMATCH;
121 return gnutls_assert_val(GNUTLS_E_AUTH_ERROR);
122 } else if (ret < 0) {
123 sb->vstatus |= GNUTLS_CERT_INVALID;
124 return gnutls_assert_val(GNUTLS_E_AUTH_ERROR);
128 /* notify gnutls to continue handshake normally */
134 * @c: is a pointer to #xssl_cred_t structure.
135 * @vflags: the requested peer verification methods
136 * @aux: Auxilary data to input any required CA certificate etc.
137 * @aux_size: the number of the auxillary data provided
139 * This function initializes X.509 certificates in
140 * a #xssl_cred_t structure.
142 * The @ca_file and @crl_file are required only if @vflags includes
143 * %GNUTLS_VMETHOD_GIVEN_CAS. The @tofu_file may be set if
144 * %GNUTLS_VMETHOD_TOFU is specified.
146 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
150 int xssl_cred_init(xssl_cred_t * c, unsigned vflags,
151 gnutls_cinput_st * aux, unsigned aux_size)
157 *c = gnutls_calloc(1, sizeof(*cred));
159 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
162 cred->vflags = vflags;
164 if (cred->xcred == NULL) {
166 gnutls_certificate_allocate_credentials(&cred->xcred);
168 return gnutls_assert_val(ret);
171 if (vflags & GNUTLS_VMETHOD_SYSTEM_CAS) {
173 gnutls_certificate_set_x509_system_trust(cred->xcred);
180 for (i = 0; i < aux_size; i++) {
181 if (aux[i].contents == GNUTLS_CINPUT_KEYPAIR) {
182 if (aux[i].type == GNUTLS_CINPUT_TYPE_FILE)
184 gnutls_certificate_set_x509_key_file
185 (cred->xcred, aux[i].i1.file,
186 aux[i].i2.file, aux[i].fmt);
187 else if (aux[i].type == GNUTLS_CINPUT_TYPE_MEM)
189 gnutls_certificate_set_x509_key_mem
190 (cred->xcred, &aux[i].i1.mem,
191 &aux[i].i2.mem, aux[i].fmt);
192 else if (aux[i].type ==
193 GNUTLS_CINPUT_TYPE_PIN_FUNC) {
195 gnutls_certificate_set_pin_function(cred->
206 (GNUTLS_E_INVALID_REQUEST);
214 if (aux[i].contents == GNUTLS_CINPUT_CAS
215 && (vflags & GNUTLS_VMETHOD_GIVEN_CAS)) {
216 if (aux[i].type == GNUTLS_CINPUT_TYPE_FILE)
218 gnutls_certificate_set_x509_trust_file
219 (cred->xcred, aux[i].i1.file,
223 gnutls_certificate_set_x509_trust_mem
224 (cred->xcred, &aux[i].i1.mem,
233 if (aux[i].contents == GNUTLS_CINPUT_CRLS
234 && (vflags & GNUTLS_VMETHOD_GIVEN_CAS)) {
235 if (aux[i].type == GNUTLS_CINPUT_TYPE_FILE)
237 gnutls_certificate_set_x509_crl_file
238 (cred->xcred, aux[i].i1.file,
242 gnutls_certificate_set_x509_crl_mem
243 (cred->xcred, &aux[i].i1.mem,
252 if (aux[i].contents == GNUTLS_CINPUT_TOFU_DB
253 && (vflags & GNUTLS_VMETHOD_TOFU)) {
254 if (aux[i].type == GNUTLS_CINPUT_TYPE_FILE) {
255 len = strlen(aux[i].i1.file);
256 if (len >= sizeof(cred->tofu_file)) {
259 (GNUTLS_E_INVALID_REQUEST);
262 memcpy(cred->tofu_file, aux[i].i1.file,
266 ret = GNUTLS_E_INVALID_REQUEST;
275 gnutls_certificate_set_verify_function(cred->xcred,
276 _verify_certificate_callback);
280 gnutls_certificate_free_credentials(cred->xcred);
289 * @isb: is a pointer to a #xssl_t structure.
290 * @session: a GnuTLS session
291 * @flags: should be zero or %GNUTLS_SBUF_WRITE_FLUSHES
293 * This function initializes a #xssl_t structure associated
294 * with the provided session. If the flag %GNUTLS_SBUF_WRITE_FLUSHES
295 * is set then xssl_queue() will flush when the maximum
296 * data size for a record is reached.
298 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
302 int xssl_sinit(xssl_t * isb, gnutls_session_t session, unsigned int flags)
306 sb = gnutls_calloc(1, sizeof(*sb));
308 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
310 _gnutls_buffer_init(&sb->buf);
311 sb->session = session;
321 * @isb: is a pointer to a #xssl_t structure.
322 * @hostname: The name of the host to connect to
323 * @service: The name of the host to connect to
324 * @fd: a socket descriptor
325 * @priority: A priority string to use (use %NULL for default)
326 * @cred: A credentials structure
327 * @status: An authentication failure status
328 * @flags: should be zero or %GNUTLS_SBUF_WRITE_FLUSHES
330 * This function initializes a #xssl_t structure.
331 * If the flag %GNUTLS_SBUF_WRITE_FLUSHES
332 * is set then xssl_queue() will flush when the maximum
333 * data size for a record is reached.
335 * If peer verification fails then %GNUTLS_E_AUTH_ERROR is returned.
337 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
341 int xssl_client_init(xssl_t * isb, const char *hostname,
343 gnutls_transport_ptr fd,
344 const char *priority, xssl_cred_t cred,
345 unsigned int *status, unsigned int flags)
348 gnutls_session_t session;
352 ret = gnutls_init(&session, GNUTLS_CLIENT);
354 return gnutls_assert_val(ret);
356 sb = gnutls_calloc(1, sizeof(*sb));
358 gnutls_deinit(session);
359 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
362 _gnutls_buffer_init(&sb->buf);
363 sb->session = session;
367 /* set session/handshake info
369 gnutls_handshake_set_timeout(session,
370 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
372 if (priority == NULL)
373 priority = "NORMAL:%COMPAT";
374 ret = gnutls_priority_set_direct(session, priority, NULL);
382 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
391 len = strlen(hostname);
393 if (len >= sizeof(sb->server_name))
394 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
395 memcpy(sb->server_name, hostname, len + 1);
398 gnutls_server_name_set(session, GNUTLS_NAME_DNS,
407 len = strlen(service);
409 if (len >= sizeof(sb->service_name))
410 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
411 memcpy(sb->service_name, service, len + 1);
414 gnutls_transport_set_ptr(session, fd);
415 gnutls_session_set_ptr(session, sb);
418 ret = gnutls_handshake(session);
420 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
422 *status = sb->vstatus;
428 gnutls_alert_send_appropriate(sb->session,
431 while (ret2 < 0 && gnutls_error_is_fatal(ret2) == 0);
433 return gnutls_assert_val(ret);
452 * @isb: is a pointer to a #xssl_t structure.
453 * @fd: a socket descriptor
454 * @priority: A priority string to use (use %NULL for default)
455 * @cred: A credentials structure
456 * @status: An authentication failure status
457 * @flags: should be zero or %GNUTLS_SBUF_WRITE_FLUSHES
459 * This function initializes a #xssl_t structure.
460 * If the flag %GNUTLS_SBUF_WRITE_FLUSHES
461 * is set then xssl_queue() will flush when the maximum
462 * data size for a record is reached.
464 * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
468 int xssl_server_init(xssl_t * isb,
469 gnutls_transport_ptr fd,
470 const char *priority, xssl_cred_t cred,
471 unsigned int *status, unsigned int flags)
474 gnutls_session_t session;
477 ret = gnutls_init(&session, GNUTLS_SERVER);
479 return gnutls_assert_val(ret);
481 sb = gnutls_calloc(1, sizeof(*sb));
483 gnutls_deinit(session);
484 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
487 _gnutls_buffer_init(&sb->buf);
488 sb->session = session;
492 /* set session/handshake info
494 gnutls_handshake_set_timeout(session,
495 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
497 if (priority == NULL)
498 priority = "NORMAL:%COMPAT";
499 ret = gnutls_priority_set_direct(session, priority, NULL);
506 if (cred->xcred->ncerts == 0
507 && cred->xcred->get_cert_callback2 == NULL) {
510 (GNUTLS_E_INSUFFICIENT_CREDENTIALS);
515 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
524 if (cred->vflags & GNUTLS_VMETHOD_GIVEN_CAS)
525 gnutls_certificate_server_set_request(session,
526 GNUTLS_CERT_REQUIRE);
528 gnutls_transport_set_ptr(session, fd);
529 gnutls_session_set_ptr(session, sb);
532 ret = gnutls_handshake(session);
534 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
536 *status = sb->vstatus;
542 gnutls_alert_send_appropriate(sb->session,
545 while (ret2 < 0 && gnutls_error_is_fatal(ret2) == 0);
547 return gnutls_assert_val(ret);
566 * @sb: is a #xssl_t structure.
568 * This function clears all buffers associated with the @sb
569 * structure. The GnuTLS session associated with the structure
574 void xssl_deinit(xssl_t sb)
577 gnutls_bye(sb->session, GNUTLS_SHUT_WR);
578 gnutls_deinit(sb->session);
580 _gnutls_buffer_clear(&sb->buf);
586 * @sb: is a #xssl_t structure.
587 * @data: contains the data to send
588 * @data_size: is the length of the data
590 * This function is the buffered equivalent of gnutls_record_send().
591 * Instead of sending the data immediately the data are buffered
592 * until xssl_queue() is called, or if the flag %GNUTLS_SBUF_WRITE_FLUSHES
593 * is set, until the number of bytes for a full record is reached.
595 * This function must only be used with blocking sockets.
597 * Returns: On success, the number of bytes written is returned, otherwise
598 * an error code is returned.
602 ssize_t xssl_write(xssl_t sb, const void *data, size_t data_size)
606 ret = _gnutls_buffer_append_data(&sb->buf, data, data_size);
608 return gnutls_assert_val(ret);
610 while ((sb->flags & GNUTLS_SBUF_WRITE_FLUSHES) &&
611 sb->buf.length >= MAX_RECORD_SEND_SIZE(sb->session)) {
614 gnutls_record_send(sb->session, sb->buf.data,
617 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
619 return gnutls_assert_val(ret);
622 sb->buf.length -= ret;
630 * @sb: is a #xssl_t structure.
631 * @fmt: printf-style format
633 * This function allows writing to a %xssl_t using printf
636 * This function must only be used with blocking sockets.
638 * Returns: On success, the number of bytes written is returned, otherwise
639 * an error code is returned.
643 ssize_t xssl_printf(xssl_t sb, const char *fmt, ...)
651 len = vasprintf(&str, fmt, args);
655 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
657 ret = xssl_write(sb, str, len);
666 * @sb: is a #xssl_t structure.
668 * This function flushes the buffer @sb. All the data stored are transmitted.
670 * This function must only be used with blocking sockets.
672 * Returns: On success, the number of bytes sent, otherwise a negative error code.
676 ssize_t xssl_flush(xssl_t sb)
681 while (sb->buf.length > 0) {
684 gnutls_record_send(sb->session, sb->buf.data,
687 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
689 return gnutls_assert_val(ret);
692 sb->buf.length -= ret;
701 * @sb: is a #xssl_t structure.
702 * @data: the buffer that the data will be read into
703 * @data_size: the number of requested bytes
705 * This function receives data from the underlying session.
706 * Only fatal errors are returned by this function.
708 * Returns: The number of bytes received and zero on EOF (for stream
709 * connections) or a negative error code.
713 ssize_t xssl_read(xssl_t sb, void *data, size_t data_size)
718 ret = gnutls_record_recv(sb->session, data, data_size);
720 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
723 return gnutls_assert_val(ret);
730 * @sb: is a #xssl_t structure.
732 * Returns: The associated session or %NULL.
736 gnutls_session_t xssl_get_session(xssl_t sb)