1 /* 2 * QEMU crypto TLS session support 3 * 4 * Copyright (c) 2015 Red Hat, Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qemu/thread.h" 23 #include "crypto/tlssession.h" 24 #include "crypto/tlscredsanon.h" 25 #include "crypto/tlscredspsk.h" 26 #include "crypto/tlscredsx509.h" 27 #include "qapi/error.h" 28 #include "authz/base.h" 29 #include "tlscredspriv.h" 30 #include "trace.h" 31 32 #ifdef CONFIG_GNUTLS 33 34 35 #include <gnutls/x509.h> 36 37 38 struct QCryptoTLSSession { 39 QCryptoTLSCreds *creds; 40 gnutls_session_t handle; 41 char *hostname; 42 char *authzid; 43 bool handshakeComplete; 44 QCryptoTLSSessionWriteFunc writeFunc; 45 QCryptoTLSSessionReadFunc readFunc; 46 void *opaque; 47 char *peername; 48 49 /* 50 * Allow concurrent reads and writes, so track 51 * errors separately 52 */ 53 Error *rerr; 54 Error *werr; 55 56 /* 57 * Used to protect against broken GNUTLS thread safety 58 * https://gitlab.com/gnutls/gnutls/-/issues/1717 59 */ 60 bool requireThreadSafety; 61 bool lockEnabled; 62 QemuMutex lock; 63 }; 64 65 66 void 67 qcrypto_tls_session_free(QCryptoTLSSession *session) 68 { 69 if (!session) { 70 return; 71 } 72 73 error_free(session->rerr); 74 error_free(session->werr); 75 76 gnutls_deinit(session->handle); 77 g_free(session->hostname); 78 g_free(session->peername); 79 g_free(session->authzid); 80 object_unref(OBJECT(session->creds)); 81 qemu_mutex_destroy(&session->lock); 82 g_free(session); 83 } 84 85 86 static ssize_t 87 qcrypto_tls_session_push(void *opaque, const void *buf, size_t len) 88 { 89 QCryptoTLSSession *session = opaque; 90 ssize_t ret; 91 92 if (!session->writeFunc) { 93 errno = EIO; 94 return -1; 95 }; 96 97 if (session->lockEnabled) { 98 qemu_mutex_unlock(&session->lock); 99 } 100 101 error_free(session->werr); 102 session->werr = NULL; 103 104 ret = session->writeFunc(buf, len, session->opaque, &session->werr); 105 106 if (session->lockEnabled) { 107 qemu_mutex_lock(&session->lock); 108 } 109 110 if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) { 111 errno = EAGAIN; 112 return -1; 113 } else if (ret < 0) { 114 errno = EIO; 115 return -1; 116 } else { 117 return ret; 118 } 119 } 120 121 122 static ssize_t 123 qcrypto_tls_session_pull(void *opaque, void *buf, size_t len) 124 { 125 QCryptoTLSSession *session = opaque; 126 ssize_t ret; 127 128 if (!session->readFunc) { 129 errno = EIO; 130 return -1; 131 }; 132 133 error_free(session->rerr); 134 session->rerr = NULL; 135 136 if (session->lockEnabled) { 137 qemu_mutex_unlock(&session->lock); 138 } 139 140 ret = session->readFunc(buf, len, session->opaque, &session->rerr); 141 142 if (session->lockEnabled) { 143 qemu_mutex_lock(&session->lock); 144 } 145 146 if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) { 147 errno = EAGAIN; 148 return -1; 149 } else if (ret < 0) { 150 errno = EIO; 151 return -1; 152 } else { 153 return ret; 154 } 155 } 156 157 #define TLS_PRIORITY_ADDITIONAL_ANON "+ANON-DH" 158 #define TLS_PRIORITY_ADDITIONAL_PSK "+ECDHE-PSK:+DHE-PSK:+PSK" 159 160 QCryptoTLSSession * 161 qcrypto_tls_session_new(QCryptoTLSCreds *creds, 162 const char *hostname, 163 const char *authzid, 164 QCryptoTLSCredsEndpoint endpoint, 165 Error **errp) 166 { 167 QCryptoTLSSession *session; 168 int ret; 169 170 session = g_new0(QCryptoTLSSession, 1); 171 trace_qcrypto_tls_session_new( 172 session, creds, hostname ? hostname : "<none>", 173 authzid ? authzid : "<none>", endpoint); 174 175 if (hostname) { 176 session->hostname = g_strdup(hostname); 177 } 178 if (authzid) { 179 session->authzid = g_strdup(authzid); 180 } 181 session->creds = creds; 182 object_ref(OBJECT(creds)); 183 184 qemu_mutex_init(&session->lock); 185 186 if (creds->endpoint != endpoint) { 187 error_setg(errp, "Credentials endpoint doesn't match session"); 188 goto error; 189 } 190 191 if (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { 192 ret = gnutls_init(&session->handle, GNUTLS_SERVER); 193 } else { 194 ret = gnutls_init(&session->handle, GNUTLS_CLIENT); 195 } 196 if (ret < 0) { 197 error_setg(errp, "Cannot initialize TLS session: %s", 198 gnutls_strerror(ret)); 199 goto error; 200 } 201 202 if (object_dynamic_cast(OBJECT(creds), 203 TYPE_QCRYPTO_TLS_CREDS_ANON)) { 204 QCryptoTLSCredsAnon *acreds = QCRYPTO_TLS_CREDS_ANON(creds); 205 char *prio; 206 207 if (creds->priority != NULL) { 208 prio = g_strdup_printf("%s:%s", 209 creds->priority, 210 TLS_PRIORITY_ADDITIONAL_ANON); 211 } else { 212 prio = g_strdup(CONFIG_TLS_PRIORITY ":" 213 TLS_PRIORITY_ADDITIONAL_ANON); 214 } 215 216 ret = gnutls_priority_set_direct(session->handle, prio, NULL); 217 if (ret < 0) { 218 error_setg(errp, "Unable to set TLS session priority %s: %s", 219 prio, gnutls_strerror(ret)); 220 g_free(prio); 221 goto error; 222 } 223 g_free(prio); 224 if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { 225 ret = gnutls_credentials_set(session->handle, 226 GNUTLS_CRD_ANON, 227 acreds->data.server); 228 } else { 229 ret = gnutls_credentials_set(session->handle, 230 GNUTLS_CRD_ANON, 231 acreds->data.client); 232 } 233 if (ret < 0) { 234 error_setg(errp, "Cannot set session credentials: %s", 235 gnutls_strerror(ret)); 236 goto error; 237 } 238 } else if (object_dynamic_cast(OBJECT(creds), 239 TYPE_QCRYPTO_TLS_CREDS_PSK)) { 240 QCryptoTLSCredsPSK *pcreds = QCRYPTO_TLS_CREDS_PSK(creds); 241 char *prio; 242 243 if (creds->priority != NULL) { 244 prio = g_strdup_printf("%s:%s", 245 creds->priority, 246 TLS_PRIORITY_ADDITIONAL_PSK); 247 } else { 248 prio = g_strdup(CONFIG_TLS_PRIORITY ":" 249 TLS_PRIORITY_ADDITIONAL_PSK); 250 } 251 252 ret = gnutls_priority_set_direct(session->handle, prio, NULL); 253 if (ret < 0) { 254 error_setg(errp, "Unable to set TLS session priority %s: %s", 255 prio, gnutls_strerror(ret)); 256 g_free(prio); 257 goto error; 258 } 259 g_free(prio); 260 if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { 261 ret = gnutls_credentials_set(session->handle, 262 GNUTLS_CRD_PSK, 263 pcreds->data.server); 264 } else { 265 ret = gnutls_credentials_set(session->handle, 266 GNUTLS_CRD_PSK, 267 pcreds->data.client); 268 } 269 if (ret < 0) { 270 error_setg(errp, "Cannot set session credentials: %s", 271 gnutls_strerror(ret)); 272 goto error; 273 } 274 } else if (object_dynamic_cast(OBJECT(creds), 275 TYPE_QCRYPTO_TLS_CREDS_X509)) { 276 QCryptoTLSCredsX509 *tcreds = QCRYPTO_TLS_CREDS_X509(creds); 277 const char *prio = creds->priority; 278 if (!prio) { 279 prio = CONFIG_TLS_PRIORITY; 280 } 281 282 ret = gnutls_priority_set_direct(session->handle, prio, NULL); 283 if (ret < 0) { 284 error_setg(errp, "Cannot set default TLS session priority %s: %s", 285 prio, gnutls_strerror(ret)); 286 goto error; 287 } 288 ret = gnutls_credentials_set(session->handle, 289 GNUTLS_CRD_CERTIFICATE, 290 tcreds->data); 291 if (ret < 0) { 292 error_setg(errp, "Cannot set session credentials: %s", 293 gnutls_strerror(ret)); 294 goto error; 295 } 296 297 if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) { 298 /* This requests, but does not enforce a client cert. 299 * The cert checking code later does enforcement */ 300 gnutls_certificate_server_set_request(session->handle, 301 GNUTLS_CERT_REQUEST); 302 } 303 } else { 304 error_setg(errp, "Unsupported TLS credentials type %s", 305 object_get_typename(OBJECT(creds))); 306 goto error; 307 } 308 309 gnutls_transport_set_ptr(session->handle, session); 310 gnutls_transport_set_push_function(session->handle, 311 qcrypto_tls_session_push); 312 gnutls_transport_set_pull_function(session->handle, 313 qcrypto_tls_session_pull); 314 315 return session; 316 317 error: 318 qcrypto_tls_session_free(session); 319 return NULL; 320 } 321 322 void qcrypto_tls_session_require_thread_safety(QCryptoTLSSession *sess) 323 { 324 sess->requireThreadSafety = true; 325 } 326 327 static int 328 qcrypto_tls_session_check_certificate(QCryptoTLSSession *session, 329 Error **errp) 330 { 331 int ret; 332 unsigned int status; 333 const gnutls_datum_t *certs; 334 unsigned int nCerts, i; 335 time_t now; 336 gnutls_x509_crt_t cert = NULL; 337 Error *err = NULL; 338 339 now = time(NULL); 340 if (now == ((time_t)-1)) { 341 error_setg_errno(errp, errno, "Cannot get current time"); 342 return -1; 343 } 344 345 ret = gnutls_certificate_verify_peers2(session->handle, &status); 346 if (ret < 0) { 347 error_setg(errp, "Verify failed: %s", gnutls_strerror(ret)); 348 return -1; 349 } 350 351 if (status != 0) { 352 const char *reason = "Invalid certificate"; 353 354 if (status & GNUTLS_CERT_INVALID) { 355 reason = "The certificate is not trusted"; 356 } 357 358 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { 359 reason = "The certificate hasn't got a known issuer"; 360 } 361 362 if (status & GNUTLS_CERT_REVOKED) { 363 reason = "The certificate has been revoked"; 364 } 365 366 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { 367 reason = "The certificate uses an insecure algorithm"; 368 } 369 370 error_setg(errp, "%s", reason); 371 return -1; 372 } 373 374 certs = gnutls_certificate_get_peers(session->handle, &nCerts); 375 if (!certs) { 376 error_setg(errp, "No certificate peers"); 377 return -1; 378 } 379 380 for (i = 0; i < nCerts; i++) { 381 ret = gnutls_x509_crt_init(&cert); 382 if (ret < 0) { 383 error_setg(errp, "Cannot initialize certificate: %s", 384 gnutls_strerror(ret)); 385 return -1; 386 } 387 388 ret = gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER); 389 if (ret < 0) { 390 error_setg(errp, "Cannot import certificate: %s", 391 gnutls_strerror(ret)); 392 goto error; 393 } 394 395 if (gnutls_x509_crt_get_expiration_time(cert) < now) { 396 error_setg(errp, "The certificate has expired"); 397 goto error; 398 } 399 400 if (gnutls_x509_crt_get_activation_time(cert) > now) { 401 error_setg(errp, "The certificate is not yet activated"); 402 goto error; 403 } 404 405 if (gnutls_x509_crt_get_activation_time(cert) > now) { 406 error_setg(errp, "The certificate is not yet activated"); 407 goto error; 408 } 409 410 if (i == 0) { 411 size_t dnameSize = 1024; 412 session->peername = g_malloc(dnameSize); 413 requery: 414 ret = gnutls_x509_crt_get_dn(cert, session->peername, &dnameSize); 415 if (ret < 0) { 416 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { 417 session->peername = g_realloc(session->peername, 418 dnameSize); 419 goto requery; 420 } 421 error_setg(errp, "Cannot get client distinguished name: %s", 422 gnutls_strerror(ret)); 423 goto error; 424 } 425 if (session->authzid) { 426 bool allow; 427 428 allow = qauthz_is_allowed_by_id(session->authzid, 429 session->peername, &err); 430 if (err) { 431 error_propagate(errp, err); 432 goto error; 433 } 434 if (!allow) { 435 error_setg(errp, "TLS x509 authz check for %s is denied", 436 session->peername); 437 goto error; 438 } 439 } 440 if (session->hostname) { 441 if (!gnutls_x509_crt_check_hostname(cert, session->hostname)) { 442 error_setg(errp, 443 "Certificate does not match the hostname %s", 444 session->hostname); 445 goto error; 446 } 447 } else { 448 if (session->creds->endpoint == 449 QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) { 450 error_setg(errp, "No hostname for certificate validation"); 451 goto error; 452 } 453 } 454 } 455 456 gnutls_x509_crt_deinit(cert); 457 } 458 459 return 0; 460 461 error: 462 gnutls_x509_crt_deinit(cert); 463 return -1; 464 } 465 466 467 int 468 qcrypto_tls_session_check_credentials(QCryptoTLSSession *session, 469 Error **errp) 470 { 471 if (object_dynamic_cast(OBJECT(session->creds), 472 TYPE_QCRYPTO_TLS_CREDS_ANON)) { 473 trace_qcrypto_tls_session_check_creds(session, "nop"); 474 return 0; 475 } else if (object_dynamic_cast(OBJECT(session->creds), 476 TYPE_QCRYPTO_TLS_CREDS_PSK)) { 477 trace_qcrypto_tls_session_check_creds(session, "nop"); 478 return 0; 479 } else if (object_dynamic_cast(OBJECT(session->creds), 480 TYPE_QCRYPTO_TLS_CREDS_X509)) { 481 if (session->creds->verifyPeer) { 482 int ret = qcrypto_tls_session_check_certificate(session, 483 errp); 484 trace_qcrypto_tls_session_check_creds(session, 485 ret == 0 ? "pass" : "fail"); 486 return ret; 487 } else { 488 trace_qcrypto_tls_session_check_creds(session, "skip"); 489 return 0; 490 } 491 } else { 492 trace_qcrypto_tls_session_check_creds(session, "error"); 493 error_setg(errp, "Unexpected credential type %s", 494 object_get_typename(OBJECT(session->creds))); 495 return -1; 496 } 497 } 498 499 500 void 501 qcrypto_tls_session_set_callbacks(QCryptoTLSSession *session, 502 QCryptoTLSSessionWriteFunc writeFunc, 503 QCryptoTLSSessionReadFunc readFunc, 504 void *opaque) 505 { 506 session->writeFunc = writeFunc; 507 session->readFunc = readFunc; 508 session->opaque = opaque; 509 } 510 511 512 ssize_t 513 qcrypto_tls_session_write(QCryptoTLSSession *session, 514 const char *buf, 515 size_t len, 516 Error **errp) 517 { 518 ssize_t ret; 519 520 if (session->lockEnabled) { 521 qemu_mutex_lock(&session->lock); 522 } 523 524 ret = gnutls_record_send(session->handle, buf, len); 525 526 if (session->lockEnabled) { 527 qemu_mutex_unlock(&session->lock); 528 } 529 530 if (ret < 0) { 531 if (ret == GNUTLS_E_AGAIN) { 532 return QCRYPTO_TLS_SESSION_ERR_BLOCK; 533 } else { 534 if (session->werr) { 535 error_propagate(errp, session->werr); 536 session->werr = NULL; 537 } else { 538 error_setg(errp, 539 "Cannot write to TLS channel: %s", 540 gnutls_strerror(ret)); 541 } 542 return -1; 543 } 544 } 545 546 return ret; 547 } 548 549 550 ssize_t 551 qcrypto_tls_session_read(QCryptoTLSSession *session, 552 char *buf, 553 size_t len, 554 bool gracefulTermination, 555 Error **errp) 556 { 557 ssize_t ret; 558 559 if (session->lockEnabled) { 560 qemu_mutex_lock(&session->lock); 561 } 562 563 ret = gnutls_record_recv(session->handle, buf, len); 564 565 if (session->lockEnabled) { 566 qemu_mutex_unlock(&session->lock); 567 } 568 569 if (ret < 0) { 570 if (ret == GNUTLS_E_AGAIN) { 571 return QCRYPTO_TLS_SESSION_ERR_BLOCK; 572 } else if ((ret == GNUTLS_E_PREMATURE_TERMINATION) && 573 gracefulTermination){ 574 return 0; 575 } else { 576 if (session->rerr) { 577 error_propagate(errp, session->rerr); 578 session->rerr = NULL; 579 } else { 580 error_setg(errp, 581 "Cannot read from TLS channel: %s", 582 gnutls_strerror(ret)); 583 } 584 return -1; 585 } 586 } 587 588 return ret; 589 } 590 591 592 size_t 593 qcrypto_tls_session_check_pending(QCryptoTLSSession *session) 594 { 595 return gnutls_record_check_pending(session->handle); 596 } 597 598 599 int 600 qcrypto_tls_session_handshake(QCryptoTLSSession *session, 601 Error **errp) 602 { 603 int ret; 604 ret = gnutls_handshake(session->handle); 605 606 if (!ret) { 607 #ifdef CONFIG_GNUTLS_BUG1717_WORKAROUND 608 gnutls_cipher_algorithm_t cipher = 609 gnutls_cipher_get(session->handle); 610 611 /* 612 * Any use of rekeying in TLS 1.3 is unsafe for 613 * a gnutls with bug 1717, however, we know that 614 * QEMU won't initiate manual rekeying. Thus we 615 * only have to protect against automatic rekeying 616 * which doesn't trigger with CHACHA20 617 */ 618 if (session->requireThreadSafety && 619 gnutls_protocol_get_version(session->handle) == 620 GNUTLS_TLS1_3 && 621 cipher != GNUTLS_CIPHER_CHACHA20_POLY1305) { 622 session->lockEnabled = true; 623 } 624 #endif 625 626 session->handshakeComplete = true; 627 return QCRYPTO_TLS_HANDSHAKE_COMPLETE; 628 } 629 630 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) { 631 int direction = gnutls_record_get_direction(session->handle); 632 return direction ? QCRYPTO_TLS_HANDSHAKE_SENDING : 633 QCRYPTO_TLS_HANDSHAKE_RECVING; 634 } 635 636 if (session->rerr || session->werr) { 637 error_setg(errp, "TLS handshake failed: %s: %s", 638 gnutls_strerror(ret), 639 error_get_pretty(session->rerr ? 640 session->rerr : session->werr)); 641 } else { 642 error_setg(errp, "TLS handshake failed: %s", 643 gnutls_strerror(ret)); 644 } 645 646 error_free(session->rerr); 647 error_free(session->werr); 648 session->rerr = session->werr = NULL; 649 650 return -1; 651 } 652 653 654 int 655 qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp) 656 { 657 int ret; 658 659 if (!session->handshakeComplete) { 660 return 0; 661 } 662 663 if (session->lockEnabled) { 664 qemu_mutex_lock(&session->lock); 665 } 666 ret = gnutls_bye(session->handle, GNUTLS_SHUT_WR); 667 668 if (session->lockEnabled) { 669 qemu_mutex_unlock(&session->lock); 670 } 671 672 if (!ret) { 673 return QCRYPTO_TLS_BYE_COMPLETE; 674 } 675 676 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) { 677 int direction = gnutls_record_get_direction(session->handle); 678 return direction ? QCRYPTO_TLS_BYE_SENDING : QCRYPTO_TLS_BYE_RECVING; 679 } 680 681 if (session->rerr || session->werr) { 682 error_setg(errp, "TLS termination failed: %s: %s", gnutls_strerror(ret), 683 error_get_pretty(session->rerr ? 684 session->rerr : session->werr)); 685 } else { 686 error_setg(errp, "TLS termination failed: %s", gnutls_strerror(ret)); 687 } 688 689 error_free(session->rerr); 690 error_free(session->werr); 691 session->rerr = session->werr = NULL; 692 693 return -1; 694 } 695 696 int 697 qcrypto_tls_session_get_key_size(QCryptoTLSSession *session, 698 Error **errp) 699 { 700 gnutls_cipher_algorithm_t cipher; 701 int ssf; 702 703 cipher = gnutls_cipher_get(session->handle); 704 ssf = gnutls_cipher_get_key_size(cipher); 705 if (!ssf) { 706 error_setg(errp, "Cannot get TLS cipher key size"); 707 return -1; 708 } 709 return ssf; 710 } 711 712 713 char * 714 qcrypto_tls_session_get_peer_name(QCryptoTLSSession *session) 715 { 716 if (session->peername) { 717 return g_strdup(session->peername); 718 } 719 return NULL; 720 } 721 722 723 #else /* ! CONFIG_GNUTLS */ 724 725 726 QCryptoTLSSession * 727 qcrypto_tls_session_new(QCryptoTLSCreds *creds G_GNUC_UNUSED, 728 const char *hostname G_GNUC_UNUSED, 729 const char *authzid G_GNUC_UNUSED, 730 QCryptoTLSCredsEndpoint endpoint G_GNUC_UNUSED, 731 Error **errp) 732 { 733 error_setg(errp, "TLS requires GNUTLS support"); 734 return NULL; 735 } 736 737 void qcrypto_tls_session_require_thread_safety(QCryptoTLSSession *sess) 738 { 739 } 740 741 void 742 qcrypto_tls_session_free(QCryptoTLSSession *sess G_GNUC_UNUSED) 743 { 744 } 745 746 747 int 748 qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess G_GNUC_UNUSED, 749 Error **errp) 750 { 751 error_setg(errp, "TLS requires GNUTLS support"); 752 return -1; 753 } 754 755 756 void 757 qcrypto_tls_session_set_callbacks( 758 QCryptoTLSSession *sess G_GNUC_UNUSED, 759 QCryptoTLSSessionWriteFunc writeFunc G_GNUC_UNUSED, 760 QCryptoTLSSessionReadFunc readFunc G_GNUC_UNUSED, 761 void *opaque G_GNUC_UNUSED) 762 { 763 } 764 765 766 ssize_t 767 qcrypto_tls_session_write(QCryptoTLSSession *sess, 768 const char *buf, 769 size_t len, 770 Error **errp) 771 { 772 error_setg(errp, "TLS requires GNUTLS support"); 773 return -1; 774 } 775 776 777 ssize_t 778 qcrypto_tls_session_read(QCryptoTLSSession *sess, 779 char *buf, 780 size_t len, 781 bool gracefulTermination, 782 Error **errp) 783 { 784 error_setg(errp, "TLS requires GNUTLS support"); 785 return -1; 786 } 787 788 789 size_t 790 qcrypto_tls_session_check_pending(QCryptoTLSSession *session) 791 { 792 return 0; 793 } 794 795 796 int 797 qcrypto_tls_session_handshake(QCryptoTLSSession *sess, 798 Error **errp) 799 { 800 error_setg(errp, "TLS requires GNUTLS support"); 801 return -1; 802 } 803 804 805 int 806 qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp) 807 { 808 return QCRYPTO_TLS_BYE_COMPLETE; 809 } 810 811 812 int 813 qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess, 814 Error **errp) 815 { 816 error_setg(errp, "TLS requires GNUTLS support"); 817 return -1; 818 } 819 820 821 char * 822 qcrypto_tls_session_get_peer_name(QCryptoTLSSession *sess) 823 { 824 return NULL; 825 } 826 827 #endif 828