aboutsummaryrefslogtreecommitdiff
path: root/src/common/scram-common.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2017-05-03 11:19:07 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2017-05-03 11:19:07 +0300
commit8f8b9be51fd788bb11276df89606bc653163524e (patch)
tree4d2daef287c2adb74da34bd6fcdbd47febbb47df /src/common/scram-common.c
parentaf2c5aa88d38573724e40fa029499b4db20b0eb2 (diff)
downloadpostgresql-8f8b9be51fd788bb11276df89606bc653163524e.tar.gz
postgresql-8f8b9be51fd788bb11276df89606bc653163524e.zip
Add PQencryptPasswordConn function to libpq, use it in psql and createuser.
The new function supports creating SCRAM verifiers, in addition to md5 hashes. The algorithm is chosen based on password_encryption, by default. This fixes the issue reported by Jeff Janes, that there was previously no way to create a SCRAM verifier with "\password". Michael Paquier and me Discussion: https://www.postgresql.org/message-id/CAMkU%3D1wfBgFPbfAMYZQE78p%3DVhZX7nN86aWkp0QcCp%3D%2BKxZ%3Dbg%40mail.gmail.com
Diffstat (limited to 'src/common/scram-common.c')
-rw-r--r--src/common/scram-common.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/common/scram-common.c b/src/common/scram-common.c
index a8ea44944c4..77b54c8a5e7 100644
--- a/src/common/scram-common.c
+++ b/src/common/scram-common.c
@@ -23,6 +23,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
+#include "common/base64.h"
#include "common/scram-common.h"
#define HMAC_IPAD 0x36
@@ -180,3 +181,66 @@ scram_ServerKey(const uint8 *salted_password, uint8 *result)
scram_HMAC_update(&ctx, "Server Key", strlen("Server Key"));
scram_HMAC_final(result, &ctx);
}
+
+
+/*
+ * Construct a verifier string for SCRAM, stored in pg_authid.rolpassword.
+ *
+ * The password should already have been processed with SASLprep, if necessary!
+ *
+ * If iterations is 0, default number of iterations is used. The result is
+ * palloc'd or malloc'd, so caller is responsible for freeing it.
+ */
+char *
+scram_build_verifier(const char *salt, int saltlen, int iterations,
+ const char *password)
+{
+ uint8 salted_password[SCRAM_KEY_LEN];
+ uint8 stored_key[SCRAM_KEY_LEN];
+ uint8 server_key[SCRAM_KEY_LEN];
+ char *result;
+ char *p;
+ int maxlen;
+
+ if (iterations <= 0)
+ iterations = SCRAM_DEFAULT_ITERATIONS;
+
+ /* Calculate StoredKey and ServerKey */
+ scram_SaltedPassword(password, salt, saltlen, iterations,
+ salted_password);
+ scram_ClientKey(salted_password, stored_key);
+ scram_H(stored_key, SCRAM_KEY_LEN, stored_key);
+
+ scram_ServerKey(salted_password, server_key);
+
+ /*
+ * The format is:
+ * SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>
+ */
+ maxlen = strlen("SCRAM-SHA-256") + 1
+ + 10 + 1 /* iteration count */
+ + pg_b64_enc_len(saltlen) + 1 /* Base64-encoded salt */
+ + pg_b64_enc_len(SCRAM_KEY_LEN) + 1 /* Base64-encoded StoredKey */
+ + pg_b64_enc_len(SCRAM_KEY_LEN) + 1; /* Base64-encoded ServerKey */
+
+#ifdef FRONTEND
+ result = malloc(maxlen);
+ if (!result)
+ return NULL;
+#else
+ result = palloc(maxlen);
+#endif
+
+ p = result + sprintf(result, "SCRAM-SHA-256$%d:", iterations);
+
+ p += pg_b64_encode(salt, saltlen, p);
+ *(p++) = '$';
+ p += pg_b64_encode((char *) stored_key, SCRAM_KEY_LEN, p);
+ *(p++) = ':';
+ p += pg_b64_encode((char *) server_key, SCRAM_KEY_LEN, p);
+ *(p++) = '\0';
+
+ Assert(p - result <= maxlen);
+
+ return result;
+}