bool_t check_encoding_zbase32(void) { stringer_t *zb32, *binary; byte_t buffer[ZBASE32_CHECK_SIZE]; for (uint64_t i = 0; status() && i < ZBASE32_CHECK_ITERATIONS; i++) { // Fill the buffer with random data and convert the buffer to hex. if (rand_write(PLACER(buffer, ZBASE32_CHECK_SIZE)) != ZBASE32_CHECK_SIZE) { return false; } else if (!(zb32 = zbase32_encode(PLACER(buffer, ZBASE32_CHECK_SIZE)))) { return false; } //log_pedantic("zb32 = %.*s", st_length_int(zb32), st_char_get(zb32)); // Convert the buffer back to binary and compare it with the original array. if (!(binary = zbase32_decode(zb32))) { st_free(zb32); return false; } else if (st_cmp_cs_eq(binary, PLACER(buffer, ZBASE32_CHECK_SIZE))) { st_free(binary); st_free(zb32); return false; } st_free(binary); st_free(zb32); } return true; }
S4Err testZbase32() { S4Err err = kS4Err_NoErr; katvector kat_vector_array[] = { { 1, (uint8_t*)"\x00", "y" }, { 1, (uint8_t*)"\x80", "o" }, { 2, (uint8_t*)"\x40", "e" }, { 2, (uint8_t*)"\xC0", "a" }, { 10, (uint8_t*)"\x00\x00", "yy" }, { 10, (uint8_t*)"\x80\x80", "on" }, { 20, (uint8_t*)"\x8B\x88\x80", "tqre" }, { 24, (uint8_t*)"\xF0\xBF\xC7", "6n9hq" }, { 24, (uint8_t*)"\xD4\x7A\x04", "4t7ye" }, { 30, (uint8_t*)"\xF5\x57\xBD\x0C", "6im54d" }, // the spec says "6im5sd" but I think it is wrong { 64, (uint8_t*)"\x28\x6F\x20\x29\x28\x20\x6F\x29", "fbz1ykjerbz11" }, { 128, (uint8_t*)"\x00\x01\x02\x03\x05\x06\x07\x08\x0A\x0B\x0C\x0D\x0F\x10\x11\x12", "yyyoryafyadoonombogo6rytne" }, { 160, (uint8_t*) "\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E\x25\x71\x78\x50\xC2\x6C" "\x9C\xD0\xD8\x9D", "igcuhp18y4ysiqt6riazowgnp1qpbsr7" } }; int i; for (i = 0; i < sizeof(kat_vector_array)/ sizeof(katvector) ; i++) { katvector* kat = &kat_vector_array[i]; uint8_t encoded[64] = {0}; uint8_t decoded[64] = {0}; int len, len2; char* binString[128] = {0}; bin_to_chars((uint8_t*)kat->base2, kat->bits, 24, (char*)binString); OPTESTLogVerbose("\t\t%4lu %2d %-30s %-32s\n", kat->bits, INT_CEIL(kat->bits, 8), binString, kat->zbase32); len = zbase32_encode((uint8_t*)encoded, (uint8_t*)kat->base2, kat->bits); /* check against encoded */ err = compareResults( kat->zbase32, encoded, len , kResultFormat_Byte, "Encoded"); CKERR; len2 = zbase32_decode((uint8_t*) decoded, (uint8_t*)encoded, kat->bits); err = compareResults(decoded, kat->base2, len/8 , kResultFormat_Byte, "Decoded"); CKERR; }; done: return err; }
/** * @brief Create a new session for a given web connection. * @note The session stores the following data points: remote IP address, request path, application name, the specified http hostname, * the remote client's user agent string, the server's host number, a unique session id, the server's current timestamp, a randomly- * generated session key for authentication, and an encrypted token for the session returned to the user as a cookie. * @param con a pointer to the connection underlying the web session. * @param path a pointer to a managed string containing the pathname of the generating request (should be "/portal/camel"). * @param application a pointer to a managed string containing the name of the parent application of the session (should be "portal"). * @return NULL on failure or a pointer to a newly allocated session object for the specified connection. */ session_t *sess_create(connection_t *con, stringer_t *path, stringer_t *application) { session_t *output; multi_t key = { .type = M_TYPE_UINT64, .val.u64 = 0 }; if (!(output = mm_alloc(sizeof(session_t)))) { log_pedantic("Unable to allocate %zu bytes for a session context.", sizeof(session_t)); return NULL; } else if (pthread_mutex_init(&(output->lock), NULL) != 0) { log_pedantic("Unable to initialize reference lock for new user session."); mm_free(output); return NULL; } else if (!(output->compositions = inx_alloc(M_INX_LINKED, &sess_release_composition))) { log_pedantic("Unable to allocate space for user session's compositions."); mm_free(output); return NULL; } if (!(ip_copy(&(output->warden.ip), con_addr(con, MEMORYBUF(64)))) || (path && !(output->request.path = st_dupe_opts(MANAGED_T | HEAP | CONTIGUOUS, path))) || (application && !(output->request.application = st_dupe_opts(MANAGED_T | HEAP | CONTIGUOUS, application))) || (con->http.host && !(output->request.host = st_dupe_opts(MANAGED_T | HEAP | CONTIGUOUS, con->http.host))) || (con->http.agent && !(output->warden.agent = st_dupe_opts(MANAGED_T | HEAP | CONTIGUOUS, con->http.agent))) || !(output->warden.host = magma.host.number) || !(key.val.u64 = output->warden.number = sess_number()) || !(output->warden.stamp = time(NULL)) || !(output->warden.key = sess_key()) || !(output->warden.token = sess_token(output))) { log_pedantic("Unable to initialize the session warden context."); sess_destroy(output); return NULL; } output->request.httponly = true; output->request.secure = (con_secure(con) == 1 ? true : false); sess_ref_add(output); if (inx_insert(objects.sessions, key, output) != 1) { log_pedantic("Unable to insert the session into the global context."); sess_ref_dec(output); sess_destroy(output); return NULL; } return output; } /** * @brief Try to retrieve the session associated with a client connection's supplied cookie. * @param con a pointer to the connection object sending the cookie. * @param application a managed string containing the application associated with the session. * @param path a managed string containing the path associated with the session. * @param token the encrypted user token retrieved from the supplied http cookie. * @return 1 if the cookie was found and valid, or one of the following values on failure: * 0 = Session not found. * -1 = Server error. * -2 = Invalid token. * -3 = Security violation / incorrect user-agent. * -4 = Security violation / incorrect session key. * -5 = Security violation / incorrect source address. * -6 = Session terminated by logout. * -7 = Session timed out. */ int_t sess_get(connection_t *con, stringer_t *application, stringer_t *path, stringer_t *token) { uint64_t *numbers; scramble_t *scramble; stringer_t *binary, *encrypted; multi_t key = { .type = M_TYPE_UINT64, .val.u64 = 0 }; int_t result = 1; /// Most session attributes need simple equality comparison, except for timeout checking. Make sure not to validate against a stale session that should have already timed out (which will have to be determined dynamically). encrypted = zbase32_decode(token); scramble = scramble_import(encrypted); binary = scramble_decrypt(magma.secure.sessions, scramble); st_cleanup(encrypted); if (!binary) { return 0; } numbers = st_data_get(binary); // QUESTION: Is this necessary? doesn't inx_find() lock the inx? inx_lock_read(objects.sessions); key.val.u64 = *(numbers + 2); if ((con->http.session = inx_find(objects.sessions, key))) { sess_ref_add(con->http.session); } inx_unlock(objects.sessions); st_free(binary); // Return if we didn't find the session or user. if (!con->http.session || !con->http.session->user) { return 0; } // We need to do full validation against the cookie and associated session. // First, the cookie. if ((*numbers != con->http.session->warden.host) || (*(numbers + 1) != con->http.session->warden.stamp) || (*(numbers + 2) != con->http.session->warden.number)) { log_error("Received mismatched cookie for authenticated session { user = %s }", st_char_get(con->http.session->user->username)); result = -2; } else if (*(numbers + 3) != con->http.session->warden.key) { log_error("Cookie contained an incorrect session key { user = %s }", st_char_get(con->http.session->user->username)); result = -4; } else if (st_cmp_cs_eq(application, con->http.session->request.application)) { log_error("Cookie did not match session's application { user = %s }", st_char_get(con->http.session->user->username)); result = -2; } else if (st_cmp_cs_eq(path, con->http.session->request.path)) { log_error("Cookie did not match session's path { user = %s }", st_char_get(con->http.session->user->username)); result = -2; } else if (st_cmp_cs_eq(con->http.agent, con->http.session->warden.agent)) { log_error("Cookie contained a mismatched user agent { user = %s }", st_char_get(con->http.session->user->username)); result = -3; } else if (con->http.session->request.secure != (con_secure(con) ? 1 : 0)) { log_error("Cookie was submitted from a mismatched transport layer { user = %s }", st_char_get(con->http.session->user->username)); result = -5; } else if (!ip_address_equal(&(con->http.session->warden.ip), (ip_t *)con_addr(con, MEMORYBUF(64)))) { log_error("Cookie was submitted from a mismatched IP address { user = %s }", st_char_get(con->http.session->user->username)); result = -5; } // Finally, do comparisons to see that we haven't timed out. /* Did we expire? */ if (magma.http.session_timeout <= (time(NULL) - con->http.session->warden.stamp)) { log_pedantic("User submitted expired or invalidated cookie; marking for deletion { user = %s }", st_char_get(con->http.session->user->username)); result = -7; } // QUESTION: This destruction needs a second look. if (result < 0) { if (!inx_delete(objects.sessions, key)) { log_pedantic("Unexpected error occurred attempting to delete expired cookie { user = %s }", st_char_get(con->http.session->user->username)); } sess_ref_dec(con->http.session); //sess_destroy(con->http.session); con->http.session = NULL; } // Otherwise, if the last session status update is more than 10 minutes ago, check now to see if things are current. // QUESTION: Why is it 600 here and 120 elsewhere? else if ((time(NULL) - sess_refresh_stamp(con->http.session)) > 600) { sess_update(con->http.session); } return result; }