// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Author: Markus Gutschke #ifdef USE_GNUTLS #include #include #include "check.h" #include "ssl.h" struct SSL *newSSL(void) { struct SSL *ssl; check(ssl = malloc(sizeof(struct SSL))); initSSL(ssl); return ssl; } void initSSL(struct SSL *ssl) { static int initialized = 0; if (!initialized) { // Global initialization ++initialized; check(gnutls_global_init() == GNUTLS_E_SUCCESS); atexit(gnutls_global_deinit); } check(gnutls_init(&ssl->session, GNUTLS_CLIENT) == GNUTLS_E_SUCCESS); check(gnutls_certificate_allocate_credentials(&ssl->cred)==GNUTLS_E_SUCCESS); check(gnutls_credentials_set(ssl->session, GNUTLS_CRD_CERTIFICATE, ssl->cred) == GNUTLS_E_SUCCESS); check(gnutls_priority_set_direct(ssl->session, "PERFORMANCE:!ARCFOUR-128", NULL) == GNUTLS_E_SUCCESS); } void destroySSL(struct SSL *ssl) { if (ssl) { gnutls_deinit(ssl->session); gnutls_certificate_free_credentials(ssl->cred); } } void deleteSSL(struct SSL *ssl) { destroySSL(ssl); free(ssl); } struct SSLHandle *openSSLHandle(struct SSL *ssl, int fd) { gnutls_transport_set_ptr(ssl->session, (gnutls_transport_ptr_t)(intptr_t)fd); int rc; do { check((rc = gnutls_handshake(ssl->session)) == GNUTLS_E_SUCCESS || rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED); } while (rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED); return (struct SSLHandle *)&ssl->session; } void closeSSLHandle(struct SSLHandle *handle) { gnutls_session_t *session = (gnutls_session_t *)handle; gnutls_bye(*session, GNUTLS_SHUT_RDWR); } ssize_t SSLread(struct SSLHandle *handle, char *buf, size_t sz) { gnutls_session_t *session = (gnutls_session_t *)handle; int rc; do { rc = gnutls_record_recv(*session, buf, sz); if (rc == GNUTLS_E_REHANDSHAKE) { do { check((rc = gnutls_handshake(*session)) == GNUTLS_E_SUCCESS || rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED); } while (rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED); continue; } } while (0); if (rc == GNUTLS_E_AGAIN) { errno = EAGAIN; return -1; } else if (rc == GNUTLS_E_INTERRUPTED) { errno = EINTR; return -1; } else if (rc < 0) { errno = EIO; return -1; } return rc; } ssize_t SSLwrite(struct SSLHandle *handle, const char *buf, size_t sz) { gnutls_session_t *session = (gnutls_session_t *)handle; int rc = gnutls_record_send(*session, buf, sz); if (rc == GNUTLS_E_AGAIN) { errno = EAGAIN; return -1; } else if (rc == GNUTLS_E_INTERRUPTED) { errno = EINTR; return -1; } else if (rc < 0) { errno = EIO; return -1; } return rc; } #endif // USE_GNUTLS