SpiceOpenSSLVerify* spice_openssl_verify_new(SSL *ssl, SPICE_SSL_VERIFY_OP verifyop, const char *hostname, const char *pubkey, size_t pubkey_size, const char *subject) { SpiceOpenSSLVerify *v; if (!verifyop) return NULL; v = spice_new0(SpiceOpenSSLVerify, 1); v->ssl = ssl; v->verifyop = verifyop; v->hostname = spice_strdup(hostname); v->pubkey = (char*)spice_memdup(pubkey, pubkey_size); v->pubkey_size = pubkey_size; v->subject = spice_strdup(subject); v->all_preverify_ok = 1; SSL_set_app_data(ssl, v); SSL_set_verify(ssl, SSL_VERIFY_PEER, openssl_verify); return v; }
bool reds_sasl_handle_auth_mechname(RedsStream *stream, AsyncReadDone read_cb, void *opaque) { RedsSASL *sasl = &stream->priv->sasl; sasl->mechname[sasl->len] = '\0'; spice_debug("Got client mechname '%s' check against '%s'", sasl->mechname, sasl->mechlist); if (strncmp(sasl->mechlist, sasl->mechname, sasl->len) == 0) { if (sasl->mechlist[sasl->len] != '\0' && sasl->mechlist[sasl->len] != ',') { spice_debug("One %d", sasl->mechlist[sasl->len]); return false; } } else { char *offset = strstr(sasl->mechlist, sasl->mechname); spice_debug("Two %p", offset); if (!offset) { return false; } spice_debug("Two '%s'", offset); if (offset[-1] != ',' || (offset[sasl->len] != '\0'&& offset[sasl->len] != ',')) { return false; } } free(sasl->mechlist); sasl->mechlist = spice_strdup(sasl->mechname); spice_debug("Validated mechname '%s'", sasl->mechname); reds_stream_async_read(stream, (uint8_t *)&sasl->len, sizeof(uint32_t), read_cb, opaque); return true; }
bool reds_sasl_start_auth(RedsStream *stream, AsyncReadDone read_cb, void *opaque) { const char *mechlist = NULL; sasl_security_properties_t secprops; int err; char *localAddr, *remoteAddr; int mechlistlen; RedsSASL *sasl = &stream->priv->sasl; if (!(localAddr = reds_stream_get_local_address(stream))) { goto error; } if (!(remoteAddr = reds_stream_get_remote_address(stream))) { free(localAddr); goto error; } err = sasl_server_new("spice", NULL, /* FQDN - just delegates to gethostname */ NULL, /* User realm */ localAddr, remoteAddr, NULL, /* Callbacks, not needed */ SASL_SUCCESS_DATA, &sasl->conn); free(localAddr); free(remoteAddr); localAddr = remoteAddr = NULL; if (err != SASL_OK) { spice_warning("sasl context setup failed %d (%s)", err, sasl_errstring(err, NULL, NULL)); sasl->conn = NULL; goto error; } /* Inform SASL that we've got an external SSF layer from TLS */ if (stream->priv->ssl) { sasl_ssf_t ssf; ssf = SSL_get_cipher_bits(stream->priv->ssl, NULL); err = sasl_setprop(sasl->conn, SASL_SSF_EXTERNAL, &ssf); if (err != SASL_OK) { spice_warning("cannot set SASL external SSF %d (%s)", err, sasl_errstring(err, NULL, NULL)); goto error_dispose; } } else { sasl->wantSSF = 1; } memset(&secprops, 0, sizeof secprops); /* Inform SASL that we've got an external SSF layer from TLS */ if (stream->priv->ssl) { /* If we've got TLS (or UNIX domain sock), we don't care about SSF */ secprops.min_ssf = 0; secprops.max_ssf = 0; secprops.maxbufsize = 8192; secprops.security_flags = 0; } else { /* Plain TCP, better get an SSF layer */ secprops.min_ssf = 56; /* Good enough to require kerberos */ secprops.max_ssf = 100000; /* Arbitrary big number */ secprops.maxbufsize = 8192; /* Forbid any anonymous or trivially crackable auth */ secprops.security_flags = SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT; } err = sasl_setprop(sasl->conn, SASL_SEC_PROPS, &secprops); if (err != SASL_OK) { spice_warning("cannot set SASL security props %d (%s)", err, sasl_errstring(err, NULL, NULL)); goto error_dispose; } err = sasl_listmech(sasl->conn, NULL, /* Don't need to set user */ "", /* Prefix */ ",", /* Separator */ "", /* Suffix */ &mechlist, NULL, NULL); if (err != SASL_OK || mechlist == NULL) { spice_warning("cannot list SASL mechanisms %d (%s)", err, sasl_errdetail(sasl->conn)); goto error_dispose; } spice_debug("Available mechanisms for client: '%s'", mechlist); sasl->mechlist = spice_strdup(mechlist); mechlistlen = strlen(mechlist); if (!reds_stream_write_all(stream, &mechlistlen, sizeof(uint32_t)) || !reds_stream_write_all(stream, sasl->mechlist, mechlistlen)) { spice_warning("SASL mechanisms write error"); goto error; } spice_debug("Wait for client mechname length"); reds_stream_async_read(stream, (uint8_t *)&sasl->len, sizeof(uint32_t), read_cb, opaque); return true; error_dispose: sasl_dispose(&sasl->conn); sasl->conn = NULL; error: return false; }