Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistencies in SCRAM-SHA-256 verification #407

Closed
milesrichardson opened this issue Aug 24, 2019 · 2 comments

Comments

@milesrichardson
Copy link

commented Aug 24, 2019

Hello

I've been testing out the SCRAM-SHA-256 PR (thank you @petere). I'm able to successfully authenticate a given (username,password) pair against some verifiers generated from it, but not all. It seems to be inconsistent.

Summary

I generated many different verifiers for one user, password pair. Some of them authenticated and some of them failed.

Background

I am using the same technique from here:

https://github.com/DenisMedeirosBBD/PostgresSCRAM256PasswordGenerator/blob/014d5e80895faae5cd053eafd3d8a4caace645b3/src/main.c#L39-L42

in order to generate verifiers. That is, I'm linking to postgres and calling the libpq code PQencryptPasswordConn directly. This should theoretically be the same code postgres calls when running CREATE USER. I packaged my code as a very simple extension:

#include "postgres.h"
#include "fmgr.h"
#include "utils/builtins.h"
#include <postgresql/libpq-fe.h>

PG_MODULE_MAGIC;

text *gen_scram_sha_256(const char *uname, const char *pword);
text *gen_scram_sha_256(const char *uname, const char *pword)
{
    PGconn *conn;
    conn = PQconnectdb("");
    return cstring_to_text(PQencryptPasswordConn(conn, pword, uname, "scram-sha-256"));
}

Datum scramsha_gen_scram_sha_256(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(scramsha_gen_scram_sha_256);
Datum
scramsha_gen_scram_sha_256(PG_FUNCTION_ARGS)
{
    text *uname = PG_GETARG_TEXT_PP(0);
    text *pword = PG_GETARG_TEXT_PP(1);

    text *result = gen_scram_sha_256(VARDATA(uname), VARDATA(pword));

    PG_RETURN_TEXT_P(result);
}
CREATE FUNCTION scramsha.gen_scram_sha_256(text, text)
RETURNS text
AS '$libdir/scramsha', 'scramsha_gen_scram_sha_256'
LANGUAGE C VOLATILE STRICT;

This allows me to quickly generate verifiers like this:

admin@myhost:mydb> select scramsha.gen_scram_sha_256('jeff', 'hunter2')
+---------------------------------------------------------------------------------------------------------------------------------------+
| gen_scram_sha_256                                                                                                                     |
|---------------------------------------------------------------------------------------------------------------------------------------|
| SCRAM-SHA-256$4096:lIPOd60E3O/Fos0zAEehcw==$15r2vSe+ySVTj8hBXEBp5DosZ5pvWlSnlqPpNwQ/4io=:yHK0mK4f3EfCflOJTFtg/RbznGBfRlNBGzUOYeEhxe0= |
+---------------------------------------------------------------------------------------------------------------------------------------+

I am generating these verifiers and storing them in users.txt like so:

"jeff" "SCRAM-SHA-256$4096:7B0sm068k/FBVzFscRpmLQ==$LbHUbNPAqk3Z3wgF37fuBjfvBo06/O65uYSERjAOo0Y=:CHOE161jcPggOMZaZ9JdmTCyuXyW/8T1K83YzJgRc7Y="

Problem

The following verifiers are all generated from the user, password combo (jeff, hunter2). I am connecting to pgbouncer with the same jeff:hunter2@pgbouncer credentials.

pgbouncer fails to authenticate all of these:

SCRAM-SHA-256$4096:HgyU9Dn7Hsfw0oH0QtBXA==$shnhhVUgeNJB8hUBctC4h9hjhZc3jcSgeIQjJhhZaJo=:KxLVn1q7He8USstGY0qYpbOfmHL/3BorIGzbUPr5RG0=
SCRAM-SHA-256$4096:Pyvbgibgxonlri9hH7zU5A==$pB6FZYB+IYKgvSTVGRsBRwkyo6+ItUNer8YWoHhHeGo=:UHKZL3NPGcUepQxunlWSXXbEI9oy5hkLeC4YYvsBJCw=
SCRAM-SHA-256$4096:t2o20V3JAhTmXzvlL357qQ==$7jzirpOwVuXh0nOpBOdo69NwnXc5LlKgOyqrNjEcMw8=:jxTImduvfIN1lCWCaJASwmnM224BAPiPyy1lOryXck4=
SCRAM-SHA-256$4096:IDjsfByN8DPT3GjNVAOe1w==$DOHuEJjsfNu4bsatEsDvRpVRwQo4+ll1ZsE6aQdAqIw=:GAnVC397j3RBku7O/aYRpHiypYN5MsqxTg0WDY5AUkA=

pgbouncer successfully authenticates this:

SCRAM-SHA-256$4096:7B0sm068k/FBVzFscRpmLQ==$LbHUbNPAqk3Z3wgF37fuBjfvBo06/O65uYSERjAOo0Y=:CHOE161jcPggOMZaZ9JdmTCyuXyW/8T1K83YzJgRc7Y=

These failures happen consistently and reliably when changing only the verifier. I was able to reproduce when using a users list and when using an auth query.

Specifically, the failure happens here:

pgbouncer/src/client.c

Lines 592 to 595 in 6d4409f

if (!verify_client_proof(&client->scram_state, proof)) {
slog_error(client, "password authentication failed");
goto failed;
}

Please let me know if there is anything obviously wrong with my methods, or if this might actually be a bug. If it is, I'm happy to help however I can. Thanks again for all your work on pgbouncer!

@milesrichardson

This comment has been minimized.

Copy link
Author

commented Aug 24, 2019

Update

Surprise surprise, the problem was on my end. After a long debugging session that is a war story in itself, I managed to isolate the problem to the extension. I rewrote it to be simpler (no need to create a PGconn) and memory safe (I think?? since pg_be_scram_build_verifier calls palloc?)

This is what I came up with. I ran it through my test script and it never generated a bad verifier (whereas previously it would generate a bad verifier the first one or two times being called).

scramsha.c

#include "postgres.h"
#include "fmgr.h"
#include "utils/builtins.h"
#include <postgresql/libpq-fe.h>

#include "libpq/scram.h"

PG_MODULE_MAGIC;

Datum scramsha_gen_scram_sha_256(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(scramsha_gen_scram_sha_256);
Datum
scramsha_gen_scram_sha_256(PG_FUNCTION_ARGS)
{
    text *pword_arg = PG_GETARG_TEXT_PP(0);
    const char *pword = text_to_cstring(pword_arg);
    const char *verifier = pg_be_scram_build_verifier(pword);

    PG_RETURN_TEXT_P(cstring_to_text(verifier));
}

scramsha--0.0.1.sql

CREATE FUNCTION scramsha.gen_scram_sha_256(text)
RETURNS text
AS '$libdir/scramsha', 'scramsha_gen_scram_sha_256'
LANGUAGE C VOLATILE STRICT;

Makefile

EXTENSION = scramsha
MODULE_big = scramsha
DATA = scramsha--0.0.1.sql
OBJS = scramsha.o
PG_CONFIG = pg_config
SHLIB_LINK = -lpq
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)

scramsha.control

# scramsha extension
comment = 'generate scram-sha-256 verifiers'
default_version = '0.0.1'
relocatable = false
schema = scramsha

Requires postgres development headers, openssl development headers and gssapi headers. On ubuntu the latter two are libssl-devel and libkrb5-dev.

Hopefully this is helpful to someone else. I might put it together as an extension in its own repository (as it's definitely useful), but I'd like to be a bit more sure there are no memory leaks before doing that. C is not really my strong point.

@petere

This comment has been minimized.

Copy link
Contributor

commented Aug 25, 2019

Thanks for testing! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.