void rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout) { struct ssl_connect *sconn; if (F == NULL) return; sconn = rb_malloc(sizeof(struct ssl_connect)); sconn->data = data; sconn->callback = callback; sconn->timeout = timeout; F->connect = rb_malloc(sizeof(struct conndata)); F->connect->callback = callback; F->connect->data = data; F->type |= RB_FD_SSL; F->ssl = rb_malloc(sizeof(gnutls_session_t)); gnutls_init(F->ssl, GNUTLS_CLIENT); gnutls_set_default_priority(SSL_P(F)); gnutls_dh_set_prime_bits(SSL_P(F), 1024); gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)F->fd); rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); if (do_ssl_handshake(F, rb_ssl_tryconn_cb)) { rb_ssl_connect_realcb(F, RB_OK, sconn); } }
static void rb_ssl_tryconn(rb_fde_t *F, int status, void *data) { struct ssl_connect *sconn = data; if (status != RB_OK) { rb_ssl_connect_realcb(F, status, sconn); return; } F->type |= RB_FD_SSL; rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn); F->ssl = rb_malloc(sizeof(gnutls_session_t)); gnutls_init(F->ssl, GNUTLS_CLIENT); gnutls_set_default_priority(SSL_P(F)); gnutls_dh_set_prime_bits(SSL_P(F), 1024); gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)F->fd); if (do_ssl_handshake(F, rb_ssl_tryconn_cb)) { rb_ssl_connect_realcb(F, RB_OK, sconn); } }
void rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen) { new_F->type |= RB_FD_SSL; new_F->ssl = rb_malloc(sizeof(gnutls_session_t)); new_F->accept = rb_malloc(sizeof(struct acceptdata)); new_F->accept->callback = F->accept->callback; new_F->accept->data = F->accept->data; rb_settimeout(new_F, 10, rb_ssl_timeout, NULL); memcpy(&new_F->accept->S, st, addrlen); new_F->accept->addrlen = addrlen; gnutls_init((gnutls_session_t *) new_F->ssl, GNUTLS_SERVER); gnutls_set_default_priority(SSL_P(new_F)); gnutls_credentials_set(SSL_P(new_F), GNUTLS_CRD_CERTIFICATE, x509); gnutls_dh_set_prime_bits(SSL_P(new_F), 1024); gnutls_transport_set_ptr(SSL_P(new_F), (gnutls_transport_ptr_t) (long int)rb_get_fd(new_F)); if (do_ssl_handshake(F, rb_ssl_tryaccept)) { struct acceptdata *ad = F->accept; F->accept = NULL; ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); rb_free(ad); } }
int rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) { gnutls_x509_crt_t cert; gnutls_digest_algorithm_t algo; unsigned int cert_list_size; const gnutls_datum_t *cert_list; uint8_t digest[RB_SSL_CERTFP_LEN * 2]; size_t digest_size; int len; if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509) return 0; if (gnutls_x509_crt_init(&cert) < 0) return 0; cert_list_size = 0; cert_list = gnutls_certificate_get_peers(SSL_P(F), &cert_list_size); if (cert_list == NULL) { gnutls_x509_crt_deinit(cert); return 0; } if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) { gnutls_x509_crt_deinit(cert); return 0; } switch(method) { case RB_SSL_CERTFP_METH_SHA1: algo = GNUTLS_DIG_SHA1; len = RB_SSL_CERTFP_LEN_SHA1; break; case RB_SSL_CERTFP_METH_SHA256: algo = GNUTLS_DIG_SHA256; len = RB_SSL_CERTFP_LEN_SHA256; break; case RB_SSL_CERTFP_METH_SHA512: algo = GNUTLS_DIG_SHA512; len = RB_SSL_CERTFP_LEN_SHA512; break; default: return 0; } if (gnutls_x509_crt_get_fingerprint(cert, algo, digest, &digest_size) < 0) { gnutls_x509_crt_deinit(cert); return 0; } memcpy(certfp, digest, len); gnutls_x509_crt_deinit(cert); return len; }
const char * rb_ssl_get_cipher(rb_fde_t *F) { static char buf[1024]; snprintf(buf, sizeof(buf), "%s-%s-%s-%s", gnutls_protocol_get_name(gnutls_protocol_get_version(SSL_P(F))), gnutls_kx_get_name(gnutls_kx_get(SSL_P(F))), gnutls_cipher_get_name(gnutls_cipher_get(SSL_P(F))), gnutls_mac_get_name(gnutls_mac_get(SSL_P(F)))); return buf; }
void rb_ssl_shutdown(rb_fde_t *F) { int i; if (F == NULL || F->ssl == NULL) return; for (i = 0; i < 4; i++) { if (gnutls_bye(SSL_P(F), GNUTLS_SHUT_RDWR) == GNUTLS_E_SUCCESS) break; } gnutls_deinit(SSL_P(F)); rb_free(F->ssl); }
void rb_ssl_shutdown(rb_fde_t *F) { int i; if(F == NULL || F->ssl == NULL) return; for(i = 0; i < 4; i++) { int r = mbedtls_ssl_close_notify(SSL_P(F)); if(r != MBEDTLS_ERR_SSL_WANT_READ && r != MBEDTLS_ERR_SSL_WANT_WRITE) break; } mbedtls_ssl_free(SSL_P(F)); rb_free(F->ssl); }
static void rb_ssl_setup_client_context(rb_fde_t *F) { int ret; mbedtls_ssl_init(SSL_P(ssl)); if ((ret = mbedtls_ssl_setup(SSL_P(F), &F->sctx->config)) != 0) { rb_lib_log("rb_ssl_setup_client_context: failed to set up ssl context: -0x%x", -ret); rb_close(F); return; } mbedtls_ssl_set_bio(SSL_P(ssl), F, rb_ssl_write_cb, rb_ssl_read_cb, NULL); }
const char * rb_ssl_get_cipher(rb_fde_t *F) { if(F == NULL || F->ssl == NULL) return NULL; return mbedtls_ssl_get_ciphersuite(SSL_P(F)); }
int rb_ssl_get_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]) { const mbedtls_x509_crt *peer_cert; uint8_t hash[RB_SSL_CERTFP_LEN]; const mbedtls_md_info_t *md_info; int ret; peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F)); if (peer_cert == NULL) return 0; md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); if (md_info == NULL) return 0; if ((ret = mbedtls_md(md_info, peer_cert->raw.p, peer_cert->raw.len, hash)) != 0) { rb_lib_log("rb_get_ssl_certfp: unable to get certfp for F: %p, %d", F, ret); return 0; } memcpy(certfp, hash, RB_SSL_CERTFP_LEN); return 1; }
static int do_ssl_handshake(rb_fde_t *F, PF * callback, void *data) { int ret; int flags; ret = mbedtls_ssl_handshake(SSL_P(F)); if(ret < 0) { if (ret == -1 && rb_ignore_errno(errno)) ret = MBEDTLS_ERR_SSL_WANT_READ; if((ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)) { if(ret == MBEDTLS_ERR_SSL_WANT_READ) flags = RB_SELECT_READ; else flags = RB_SELECT_WRITE; rb_setselect(F, flags, callback, data); return 0; } F->sslerr.ssl_errno = ret; return -1; } return 1; /* handshake is finished..go about life */ }
void rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) { gnutls_session_t *ssl; new_F->type |= RB_FD_SSL; ssl = new_F->ssl = rb_malloc(sizeof(gnutls_session_t)); new_F->accept = rb_malloc(sizeof(struct acceptdata)); new_F->accept->callback = cb; new_F->accept->data = data; rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL); new_F->accept->addrlen = 0; gnutls_init(ssl, GNUTLS_SERVER); gnutls_set_default_priority(*ssl); gnutls_credentials_set(SSL_P(F), GNUTLS_CRD_CERTIFICATE, x509); gnutls_dh_set_prime_bits(*ssl, 1024); gnutls_transport_set_ptr(*ssl, (gnutls_transport_ptr_t) (long int)new_F->fd); gnutls_certificate_server_set_request(*ssl, GNUTLS_CERT_REQUEST); if(do_ssl_handshake(new_F, rb_ssl_tryaccept)) { struct acceptdata *ad = new_F->accept; new_F->accept = NULL; ad->callback(new_F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); rb_free(ad); } }
int rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]) { gnutls_x509_crt_t cert; unsigned int cert_list_size; const gnutls_datum_t *cert_list; uint8_t digest[RB_SSL_CERTFP_LEN * 2]; size_t digest_size; if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509) return 0; if (gnutls_x509_crt_init(&cert) < 0) return 0; cert_list_size = 0; cert_list = gnutls_certificate_get_peers(SSL_P(F), &cert_list_size); if (cert_list == NULL) { gnutls_x509_crt_deinit(cert); return 0; } if (gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0) { gnutls_x509_crt_deinit(cert); return 0; } if (gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, digest, &digest_size) < 0) { gnutls_x509_crt_deinit(cert); return 0; } memcpy(certfp, digest, RB_SSL_CERTFP_LEN); gnutls_x509_crt_deinit(cert); return 1; }
static int do_ssl_handshake(rb_fde_t *F, PF * callback) { int ret; int flags; ret = gnutls_handshake(SSL_P(F)); if (ret < 0) { if ((ret == GNUTLS_E_INTERRUPTED && rb_ignore_errno(errno)) || ret == GNUTLS_E_AGAIN) { if (gnutls_record_get_direction(SSL_P(F)) == 0) flags = RB_SELECT_READ; else flags = RB_SELECT_WRITE; rb_setselect(F, flags, callback, NULL); return 0; } F->ssl_errno = ret; return -1; } return 1; /* handshake is finished..go about life */ }