SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer, SIZE_T *length) { gnutls_session_t s = (gnutls_session_t)session; ssize_t ret; again: ret = pgnutls_record_recv(s, buffer, *length); if (ret >= 0) *length = ret; else if (ret == GNUTLS_E_AGAIN) { struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s); SIZE_T count = 0; if (schan_get_buffer(t, &t->in, &count)) goto again; return SEC_I_CONTINUE_NEEDED; } else { pgnutls_perror(ret); return SEC_E_INTERNAL_ERROR; } return SEC_E_OK; }
BOOL schan_imp_allocate_certificate_credentials(schan_imp_certificate_credentials *c) { int ret = pgnutls_certificate_allocate_credentials((gnutls_certificate_credentials*)c); if (ret != GNUTLS_E_SUCCESS) pgnutls_perror(ret); return (ret == GNUTLS_E_SUCCESS); }
SECURITY_STATUS schan_imp_handshake(schan_imp_session session) { gnutls_session_t s = (gnutls_session_t)session; int err = pgnutls_handshake(s); switch(err) { case GNUTLS_E_SUCCESS: TRACE("Handshake completed\n"); return SEC_E_OK; case GNUTLS_E_AGAIN: TRACE("Continue...\n"); return SEC_I_CONTINUE_NEEDED; case GNUTLS_E_WARNING_ALERT_RECEIVED: case GNUTLS_E_FATAL_ALERT_RECEIVED: { gnutls_alert_description_t alert = pgnutls_alert_get(s); const char *alert_name = pgnutls_alert_get_name(alert); WARN("ALERT: %d %s\n", alert, alert_name); return SEC_E_INTERNAL_ERROR; } default: pgnutls_perror(err); return SEC_E_INTERNAL_ERROR; } /* Never reached */ return SEC_E_OK; }
BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred) { gnutls_session_t *s = (gnutls_session_t*)session; char priority[64] = "NORMAL", *p; unsigned i; int err = pgnutls_init(s, cred->credential_use == SECPKG_CRED_INBOUND ? GNUTLS_SERVER : GNUTLS_CLIENT); if (err != GNUTLS_E_SUCCESS) { pgnutls_perror(err); return FALSE; } p = priority + strlen(priority); for(i=0; i < sizeof(protocol_priority_flags)/sizeof(*protocol_priority_flags); i++) { *p++ = ':'; *p++ = (cred->enabled_protocols & protocol_priority_flags[i].enable_flag) ? '+' : '-'; strcpy(p, protocol_priority_flags[i].gnutls_flag); p += strlen(p); } TRACE("Using %s priority\n", debugstr_a(priority)); err = pgnutls_priority_set_direct(*s, priority, NULL); if (err != GNUTLS_E_SUCCESS) { pgnutls_perror(err); pgnutls_deinit(*s); return FALSE; } err = pgnutls_credentials_set(*s, GNUTLS_CRD_CERTIFICATE, (gnutls_certificate_credentials_t)cred->credentials); if (err != GNUTLS_E_SUCCESS) { pgnutls_perror(err); pgnutls_deinit(*s); return FALSE; } pgnutls_transport_set_pull_function(*s, schan_pull_adapter); pgnutls_transport_set_push_function(*s, schan_push_adapter); return TRUE; }
BOOL schan_imp_create_session(schan_imp_session *session, BOOL is_server, schan_imp_certificate_credentials cred) { gnutls_session_t *s = (gnutls_session_t*)session; int err = pgnutls_init(s, is_server ? GNUTLS_SERVER : GNUTLS_CLIENT); if (err != GNUTLS_E_SUCCESS) { pgnutls_perror(err); return FALSE; } /* FIXME: We should be using the information from the credentials here. */ FIXME("Using hardcoded \"NORMAL\" priority\n"); err = pgnutls_set_default_priority(*s); if (err != GNUTLS_E_SUCCESS) { pgnutls_perror(err); pgnutls_deinit(*s); return FALSE; } err = pgnutls_credentials_set(*s, GNUTLS_CRD_CERTIFICATE, (gnutls_certificate_credentials)cred); if (err != GNUTLS_E_SUCCESS) { pgnutls_perror(err); pgnutls_deinit(*s); return FALSE; } pgnutls_transport_set_pull_function(*s, schan_pull_adapter); pgnutls_transport_set_push_function(*s, schan_push_adapter); return TRUE; }
SECURITY_STATUS schan_imp_handshake(schan_imp_session session) { gnutls_session_t s = (gnutls_session_t)session; int err; while(1) { err = pgnutls_handshake(s); switch(err) { case GNUTLS_E_SUCCESS: TRACE("Handshake completed\n"); return SEC_E_OK; case GNUTLS_E_AGAIN: TRACE("Continue...\n"); return SEC_I_CONTINUE_NEEDED; case GNUTLS_E_WARNING_ALERT_RECEIVED: { gnutls_alert_description_t alert = pgnutls_alert_get(s); WARN("WARNING ALERT: %d %s\n", alert, pgnutls_alert_get_name(alert)); switch(alert) { case GNUTLS_A_UNRECOGNIZED_NAME: TRACE("Ignoring\n"); continue; default: return SEC_E_INTERNAL_ERROR; } } case GNUTLS_E_FATAL_ALERT_RECEIVED: { gnutls_alert_description_t alert = pgnutls_alert_get(s); WARN("FATAL ALERT: %d %s\n", alert, pgnutls_alert_get_name(alert)); return SEC_E_INTERNAL_ERROR; } default: pgnutls_perror(err); return SEC_E_INTERNAL_ERROR; } } /* Never reached */ return SEC_E_OK; }
static BOOL gnutls_initialize(void) { int ret; if (!(libgnutls_handle = wine_dlopen( SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0 ))) { ERR_(winediag)( "failed to load libgnutls, no support for crypto hashes\n" ); return FALSE; } #define LOAD_FUNCPTR(f) \ if (!(p##f = wine_dlsym( libgnutls_handle, #f, NULL, 0 ))) \ { \ ERR( "failed to load %s\n", #f ); \ goto fail; \ } LOAD_FUNCPTR(gnutls_global_deinit) LOAD_FUNCPTR(gnutls_global_init) LOAD_FUNCPTR(gnutls_global_set_log_function) LOAD_FUNCPTR(gnutls_global_set_log_level) LOAD_FUNCPTR(gnutls_hash); LOAD_FUNCPTR(gnutls_hash_deinit); LOAD_FUNCPTR(gnutls_hash_init); LOAD_FUNCPTR(gnutls_perror) #undef LOAD_FUNCPTR if ((ret = pgnutls_global_init()) != GNUTLS_E_SUCCESS) { pgnutls_perror( ret ); goto fail; } if (TRACE_ON( bcrypt )) { pgnutls_global_set_log_level( 4 ); pgnutls_global_set_log_function( gnutls_log ); } return TRUE; fail: wine_dlclose( libgnutls_handle, NULL, 0 ); libgnutls_handle = NULL; return FALSE; }
BOOL schan_imp_init(void) { int ret; libgnutls_handle = wine_dlopen(SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0); if (!libgnutls_handle) { WARN("Failed to load libgnutls.\n"); return FALSE; } #define LOAD_FUNCPTR(f) \ if (!(p##f = wine_dlsym(libgnutls_handle, #f, NULL, 0))) \ { \ ERR("Failed to load %s\n", #f); \ goto fail; \ } LOAD_FUNCPTR(gnutls_alert_get) LOAD_FUNCPTR(gnutls_alert_get_name) LOAD_FUNCPTR(gnutls_certificate_allocate_credentials) LOAD_FUNCPTR(gnutls_certificate_free_credentials) LOAD_FUNCPTR(gnutls_certificate_get_peers) LOAD_FUNCPTR(gnutls_cipher_get) LOAD_FUNCPTR(gnutls_cipher_get_key_size) LOAD_FUNCPTR(gnutls_credentials_set) LOAD_FUNCPTR(gnutls_deinit) LOAD_FUNCPTR(gnutls_global_deinit) LOAD_FUNCPTR(gnutls_global_init) LOAD_FUNCPTR(gnutls_global_set_log_function) LOAD_FUNCPTR(gnutls_global_set_log_level) LOAD_FUNCPTR(gnutls_handshake) LOAD_FUNCPTR(gnutls_init) LOAD_FUNCPTR(gnutls_kx_get) LOAD_FUNCPTR(gnutls_mac_get) LOAD_FUNCPTR(gnutls_mac_get_key_size) LOAD_FUNCPTR(gnutls_perror) LOAD_FUNCPTR(gnutls_protocol_get_version) LOAD_FUNCPTR(gnutls_set_default_priority) LOAD_FUNCPTR(gnutls_record_get_max_size); LOAD_FUNCPTR(gnutls_record_recv); LOAD_FUNCPTR(gnutls_record_send); LOAD_FUNCPTR(gnutls_transport_get_ptr) LOAD_FUNCPTR(gnutls_transport_set_errno) LOAD_FUNCPTR(gnutls_transport_set_ptr) LOAD_FUNCPTR(gnutls_transport_set_pull_function) LOAD_FUNCPTR(gnutls_transport_set_push_function) #undef LOAD_FUNCPTR ret = pgnutls_global_init(); if (ret != GNUTLS_E_SUCCESS) { pgnutls_perror(ret); goto fail; } if (TRACE_ON(secur32)) { pgnutls_global_set_log_level(4); pgnutls_global_set_log_function(schan_gnutls_log); } return TRUE; fail: wine_dlclose(libgnutls_handle, NULL, 0); libgnutls_handle = NULL; return FALSE; }