Updated FIPS140 initialization and added a self test for it.
[gnutls:gnutls.git] / lib / xssl.c
1 /*
2  * Copyright (C) 2013 Nikos Mavrogiannopoulos
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
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.
12  *
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.
17  *
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/>
20  *
21  */
22
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>
28 #include <fips.h>
29 #include "vasprintf.h"
30
31 #include <xssl.h>
32
33 /**
34  * xssl_cred_deinit:
35  * @cred: is a #xssl_cred_t structure.
36  *
37  * This function deinitializes a #xssl_cred_t structure.
38  *
39  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
40  *
41  * Since: 3.1.7
42  **/
43 void xssl_cred_deinit(xssl_cred_t cred)
44 {
45         if (cred->xcred)
46                 gnutls_certificate_free_credentials(cred->xcred);
47         gnutls_free(cred);
48 }
49
50
51 static int _verify_certificate_callback(gnutls_session_t session)
52 {
53         unsigned int status;
54         xssl_t sb;
55         int ret, type;
56         const char *hostname = NULL;
57         const char *service = NULL;
58         const char *tofu_file = NULL;
59
60         sb = gnutls_session_get_ptr(session);
61         if (sb == NULL)
62                 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
63
64         if (sb->cred == NULL)
65                 return
66                     gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
67
68         if (sb->server_name[0] != 0)
69                 hostname = sb->server_name;
70
71         if (sb->service_name[0] != 0)
72                 service = sb->service_name;
73
74         if (sb->cred->tofu_file[0] != 0)
75                 tofu_file = sb->cred->tofu_file;
76
77         /* This verification function uses the trusted CAs in the credentials
78          * structure. So you must have installed one or more CA certificates.
79          */
80         sb->vstatus = 0;
81         if (sb->cred->vflags & GNUTLS_VMETHOD_SYSTEM_CAS
82             || sb->cred->vflags & GNUTLS_VMETHOD_GIVEN_CAS) {
83                 ret =
84                     gnutls_certificate_verify_peers3(session, hostname,
85                                                      &status);
86                 if (ret < 0)
87                         return gnutls_assert_val(GNUTLS_E_AUTH_ERROR);
88
89                 sb->vstatus = status;
90
91                 if (status != 0)        /* Certificate is not trusted */
92                         return gnutls_assert_val(GNUTLS_E_AUTH_ERROR);
93         }
94
95         if (hostname && sb->cred->vflags & GNUTLS_VMETHOD_TOFU) {
96                 const gnutls_datum_t *cert_list;
97                 unsigned int cert_list_size;
98
99                 type = gnutls_certificate_type_get(session);
100
101                 /* Do SSH verification */
102                 cert_list =
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);
107                 }
108
109                 /* service may be obtained alternatively using getservbyport() */
110                 ret =
111                     gnutls_verify_stored_pubkey(tofu_file, NULL, hostname,
112                                                 service, type,
113                                                 &cert_list[0], 0);
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],
118                                             0, 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);
125                 }
126         }
127
128         /* notify gnutls to continue handshake normally */
129         return 0;
130 }
131
132 /**
133  * xssl_cred_init:
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
138  *
139  * This function initializes X.509 certificates in 
140  * a #xssl_cred_t structure.
141  *
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.
145  *
146  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
147  *
148  * Since: 3.1.7
149  **/
150 int xssl_cred_init(xssl_cred_t * c, unsigned vflags,
151                    gnutls_cinput_st * aux, unsigned aux_size)
152 {
153         int ret;
154         unsigned len, i;
155         xssl_cred_t cred;
156
157         *c = gnutls_calloc(1, sizeof(*cred));
158         if (*c == NULL)
159                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
160
161         cred = *c;
162         cred->vflags = vflags;
163
164         if (cred->xcred == NULL) {
165                 ret =
166                     gnutls_certificate_allocate_credentials(&cred->xcred);
167                 if (ret < 0)
168                         return gnutls_assert_val(ret);
169         }
170
171         if (vflags & GNUTLS_VMETHOD_SYSTEM_CAS) {
172                 ret =
173                     gnutls_certificate_set_x509_system_trust(cred->xcred);
174                 if (ret < 0) {
175                         gnutls_assert();
176                         goto fail1;
177                 }
178         }
179
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)
183                                 ret =
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)
188                                 ret =
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) {
194                                 ret = 0;
195                                 gnutls_certificate_set_pin_function(cred->
196                                                                     xcred,
197                                                                     aux[i].
198                                                                     i1.
199                                                                     pin_fn,
200                                                                     aux[i].
201                                                                     i2.
202                                                                     udata);
203                         } else
204                                 ret =
205                                     gnutls_assert_val
206                                     (GNUTLS_E_INVALID_REQUEST);
207
208                         if (ret < 0) {
209                                 gnutls_assert();
210                                 goto fail1;
211                         }
212                 }
213
214                 if (aux[i].contents == GNUTLS_CINPUT_CAS
215                     && (vflags & GNUTLS_VMETHOD_GIVEN_CAS)) {
216                         if (aux[i].type == GNUTLS_CINPUT_TYPE_FILE)
217                                 ret =
218                                     gnutls_certificate_set_x509_trust_file
219                                     (cred->xcred, aux[i].i1.file,
220                                      aux[i].fmt);
221                         else
222                                 ret =
223                                     gnutls_certificate_set_x509_trust_mem
224                                     (cred->xcred, &aux[i].i1.mem,
225                                      aux[i].fmt);
226
227                         if (ret < 0) {
228                                 gnutls_assert();
229                                 goto fail1;
230                         }
231                 }
232
233                 if (aux[i].contents == GNUTLS_CINPUT_CRLS
234                     && (vflags & GNUTLS_VMETHOD_GIVEN_CAS)) {
235                         if (aux[i].type == GNUTLS_CINPUT_TYPE_FILE)
236                                 ret =
237                                     gnutls_certificate_set_x509_crl_file
238                                     (cred->xcred, aux[i].i1.file,
239                                      aux[i].fmt);
240                         else
241                                 ret =
242                                     gnutls_certificate_set_x509_crl_mem
243                                     (cred->xcred, &aux[i].i1.mem,
244                                      aux[i].fmt);
245
246                         if (ret < 0) {
247                                 gnutls_assert();
248                                 goto fail1;
249                         }
250                 }
251
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)) {
257                                         ret =
258                                             gnutls_assert_val
259                                             (GNUTLS_E_INVALID_REQUEST);
260                                         goto fail1;
261                                 }
262                                 memcpy(cred->tofu_file, aux[i].i1.file,
263                                        len + 1);
264                                 ret = 0;
265                         } else
266                                 ret = GNUTLS_E_INVALID_REQUEST;
267
268                         if (ret < 0) {
269                                 gnutls_assert();
270                                 goto fail1;
271                         }
272                 }
273         }
274
275         gnutls_certificate_set_verify_function(cred->xcred,
276                                                _verify_certificate_callback);
277
278         return 0;
279       fail1:
280         gnutls_certificate_free_credentials(cred->xcred);
281         cred->xcred = NULL;
282         gnutls_free(*c);
283
284         return ret;
285 }
286
287 /**
288  * xssl_sinit:
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
292  *
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.
297  *
298  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
299  *
300  * Since: 3.1.7
301  **/
302 int xssl_sinit(xssl_t * isb, gnutls_session_t session, unsigned int flags)
303 {
304         struct xssl_st *sb;
305         
306         sb = gnutls_calloc(1, sizeof(*sb));
307         if (sb == NULL)
308                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
309
310         _gnutls_buffer_init(&sb->buf);
311         sb->session = session;
312         sb->flags = flags;
313
314         *isb = sb;
315
316         return 0;
317 }
318
319 /**
320  * xssl_client_init:
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
329  *
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.
334  *
335  * If peer verification fails then %GNUTLS_E_AUTH_ERROR is returned.
336  *
337  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
338  *
339  * Since: 3.1.7
340  **/
341 int xssl_client_init(xssl_t * isb, const char *hostname,
342                      const char *service,
343                      gnutls_transport_ptr fd,
344                      const char *priority, xssl_cred_t cred,
345                      unsigned int *status, unsigned int flags)
346 {
347         struct xssl_st *sb;
348         gnutls_session_t session;
349         int ret;
350         unsigned len;
351         
352         ret = gnutls_init(&session, GNUTLS_CLIENT);
353         if (ret < 0)
354                 return gnutls_assert_val(ret);
355
356         sb = gnutls_calloc(1, sizeof(*sb));
357         if (sb == NULL) {
358                 gnutls_deinit(session);
359                 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
360                 goto fail1;
361         }
362         _gnutls_buffer_init(&sb->buf);
363         sb->session = session;
364         sb->flags = flags;
365         sb->cred = cred;
366
367         /* set session/handshake info 
368          */
369         gnutls_handshake_set_timeout(session,
370                                      GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
371
372         if (priority == NULL)
373                 priority = "NORMAL:%COMPAT";
374         ret = gnutls_priority_set_direct(session, priority, NULL);
375         if (ret < 0) {
376                 gnutls_assert();
377                 goto fail1;
378         }
379
380         if (cred->xcred) {
381                 ret =
382                     gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
383                                            cred->xcred);
384                 if (ret < 0) {
385                         gnutls_assert();
386                         goto fail1;
387                 }
388         }
389
390         if (hostname) {
391                 len = strlen(hostname);
392
393                 if (len >= sizeof(sb->server_name))
394                         return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
395                 memcpy(sb->server_name, hostname, len + 1);
396
397                 ret =
398                     gnutls_server_name_set(session, GNUTLS_NAME_DNS,
399                                            hostname, len);
400                 if (ret < 0) {
401                         gnutls_assert();
402                         goto fail1;
403                 }
404         }
405
406         if (service) {
407                 len = strlen(service);
408
409                 if (len >= sizeof(sb->service_name))
410                         return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
411                 memcpy(sb->service_name, service, len + 1);
412         }
413
414         gnutls_transport_set_ptr(session, fd);
415         gnutls_session_set_ptr(session, sb);
416
417         do {
418                 ret = gnutls_handshake(session);
419         }
420         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
421         if (status)
422                 *status = sb->vstatus;
423
424         if (ret < 0) {
425                 int ret2;
426                 do {
427                         ret2 =
428                             gnutls_alert_send_appropriate(sb->session,
429                                                           ret);
430                 }
431                 while (ret2 < 0 && gnutls_error_is_fatal(ret2) == 0);
432
433                 return gnutls_assert_val(ret);
434
435                 gnutls_assert();
436                 goto fail1;
437         }
438
439         *isb = sb;
440
441         return 0;
442
443       fail1:
444         if (sb)
445                 xssl_deinit(sb);
446
447         return ret;
448 }
449
450 /**
451  * xssl_server_init:
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
458  *
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.
463  *
464  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
465  *
466  * Since: 3.1.7
467  **/
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)
472 {
473         struct xssl_st *sb;
474         gnutls_session_t session;
475         int ret;
476
477         ret = gnutls_init(&session, GNUTLS_SERVER);
478         if (ret < 0)
479                 return gnutls_assert_val(ret);
480
481         sb = gnutls_calloc(1, sizeof(*sb));
482         if (sb == NULL) {
483                 gnutls_deinit(session);
484                 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
485                 goto fail1;
486         }
487         _gnutls_buffer_init(&sb->buf);
488         sb->session = session;
489         sb->flags = flags;
490         sb->cred = cred;
491
492         /* set session/handshake info 
493          */
494         gnutls_handshake_set_timeout(session,
495                                      GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
496
497         if (priority == NULL)
498                 priority = "NORMAL:%COMPAT";
499         ret = gnutls_priority_set_direct(session, priority, NULL);
500         if (ret < 0) {
501                 gnutls_assert();
502                 goto fail1;
503         }
504
505         if (cred->xcred) {
506                 if (cred->xcred->ncerts == 0
507                     && cred->xcred->get_cert_callback2 == NULL) {
508                         ret =
509                             gnutls_assert_val
510                             (GNUTLS_E_INSUFFICIENT_CREDENTIALS);
511                         goto fail1;
512                 }
513
514                 ret =
515                     gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
516                                            cred->xcred);
517                 if (ret < 0) {
518                         gnutls_assert();
519                         goto fail1;
520                 }
521
522         }
523
524         if (cred->vflags & GNUTLS_VMETHOD_GIVEN_CAS)
525                 gnutls_certificate_server_set_request(session,
526                                                       GNUTLS_CERT_REQUIRE);
527
528         gnutls_transport_set_ptr(session, fd);
529         gnutls_session_set_ptr(session, sb);
530
531         do {
532                 ret = gnutls_handshake(session);
533         }
534         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
535         if (status)
536                 *status = sb->vstatus;
537
538         if (ret < 0) {
539                 int ret2;
540                 do {
541                         ret2 =
542                             gnutls_alert_send_appropriate(sb->session,
543                                                           ret);
544                 }
545                 while (ret2 < 0 && gnutls_error_is_fatal(ret2) == 0);
546
547                 return gnutls_assert_val(ret);
548
549                 gnutls_assert();
550                 goto fail1;
551         }
552
553         *isb = sb;
554
555         return 0;
556
557       fail1:
558         if (sb)
559                 xssl_deinit(sb);
560
561         return ret;
562 }
563
564 /**
565  * xssl_deinit:
566  * @sb: is a #xssl_t structure.
567  *
568  * This function clears all buffers associated with the @sb
569  * structure. The GnuTLS session associated with the structure
570  * is left intact.
571  *
572  * Since: 3.1.7
573  **/
574 void xssl_deinit(xssl_t sb)
575 {
576         if (sb->session) {
577                 gnutls_bye(sb->session, GNUTLS_SHUT_WR);
578                 gnutls_deinit(sb->session);
579         }
580         _gnutls_buffer_clear(&sb->buf);
581         gnutls_free(sb);
582 }
583
584 /**
585  * xssl_write:
586  * @sb: is a #xssl_t structure.
587  * @data: contains the data to send
588  * @data_size: is the length of the data
589  *
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.
594  *
595  * This function must only be used with blocking sockets.
596  *
597  * Returns: On success, the number of bytes written is returned, otherwise
598  *  an error code is returned.
599  *
600  * Since: 3.1.7
601  **/
602 ssize_t xssl_write(xssl_t sb, const void *data, size_t data_size)
603 {
604         int ret;
605
606         ret = _gnutls_buffer_append_data(&sb->buf, data, data_size);
607         if (ret < 0)
608                 return gnutls_assert_val(ret);
609
610         while ((sb->flags & GNUTLS_SBUF_WRITE_FLUSHES) &&
611                sb->buf.length >= MAX_RECORD_SEND_SIZE(sb->session)) {
612                 do {
613                         ret =
614                             gnutls_record_send(sb->session, sb->buf.data,
615                                                sb->buf.length);
616                 }
617                 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
618                 if (ret < 0)
619                         return gnutls_assert_val(ret);
620
621                 sb->buf.data += ret;
622                 sb->buf.length -= ret;
623         }
624
625         return data_size;
626 }
627
628 /**
629  * xssl_printf:
630  * @sb: is a #xssl_t structure.
631  * @fmt: printf-style format 
632  *
633  * This function allows writing to a %xssl_t using printf
634  * style arguments.
635  *
636  * This function must only be used with blocking sockets.
637  *
638  * Returns: On success, the number of bytes written is returned, otherwise
639  *  an error code is returned.
640  *
641  * Since: 3.1.7
642  **/
643 ssize_t xssl_printf(xssl_t sb, const char *fmt, ...)
644 {
645         int ret;
646         va_list args;
647         int len;
648         char *str;
649
650         va_start(args, fmt);
651         len = vasprintf(&str, fmt, args);
652         va_end(args);
653
654         if (len < 0 || !str)
655                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
656
657         ret = xssl_write(sb, str, len);
658
659         gnutls_free(str);
660
661         return ret;
662 }
663
664 /**
665  * xssl_flush:
666  * @sb: is a #xssl_t structure.
667  *
668  * This function flushes the buffer @sb. All the data stored are transmitted.
669  *
670  * This function must only be used with blocking sockets.
671  *
672  * Returns: On success, the number of bytes sent, otherwise a negative error code.
673  *
674  * Since: 3.1.7
675  **/
676 ssize_t xssl_flush(xssl_t sb)
677 {
678         int ret;
679         ssize_t total = 0;
680
681         while (sb->buf.length > 0) {
682                 do {
683                         ret =
684                             gnutls_record_send(sb->session, sb->buf.data,
685                                                sb->buf.length);
686                 }
687                 while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
688                 if (ret < 0)
689                         return gnutls_assert_val(ret);
690
691                 sb->buf.data += ret;
692                 sb->buf.length -= ret;
693                 total += ret;
694         }
695
696         return total;
697 }
698
699 /**
700  * xssl_read:
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
704  *
705  * This function receives data from the underlying session.
706  * Only fatal errors are returned by this function.
707  *
708  * Returns: The number of bytes received and zero on EOF (for stream
709  * connections) or a negative error code.
710  *
711  * Since: 3.1.7
712  **/
713 ssize_t xssl_read(xssl_t sb, void *data, size_t data_size)
714 {
715         int ret;
716
717         do {
718                 ret = gnutls_record_recv(sb->session, data, data_size);
719         }
720         while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
721
722         if (ret < 0)
723                 return gnutls_assert_val(ret);
724
725         return 0;
726 }
727
728 /**
729  * xssl_get_session:
730  * @sb: is a #xssl_t structure.
731  *
732  * Returns: The associated session or %NULL.
733  *
734  * Since: 3.1.7
735  **/
736 gnutls_session_t xssl_get_session(xssl_t sb)
737 {
738         return sb->session;
739 }