summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
authorHeikki Linnakangas2017-03-07 12:25:40 +0000
committerHeikki Linnakangas2017-03-07 12:25:40 +0000
commit818fd4a67d610991757b610755e3065fb99d80a5 (patch)
tree6902ced6e8316044e9b706f93586c84bc24e2010 /src/include
parent273c458a2b3a0fb73968020ea5e9e35eb6928967 (diff)
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the GSS and SSPI methods. The server first tells the client which SASL authentication mechanism to use, and then the mechanism-specific SASL messages are exchanged in AuthenticationSASLcontinue and PasswordMessage messages. Only SCRAM-SHA-256 is supported at the moment, but this allows adding more SASL mechanisms in the future, without changing the overall protocol. Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later. The SASLPrep algorithm, for pre-processing the password, is not yet implemented. That could cause trouble, if you use a password with non-ASCII characters, and a client library that does implement SASLprep. That will hopefully be added later. Authorization identities, as specified in the SCRAM-SHA-256 specification, are ignored. SET SESSION AUTHORIZATION provides more or less the same functionality, anyway. If a user doesn't exist, perform a "mock" authentication, by constructing an authentic-looking challenge on the fly. The challenge is derived from a new system-wide random value, "mock authentication nonce", which is created at initdb, and stored in the control file. We go through these motions, in order to not give away the information on whether the user exists, to unauthenticated users. Bumps PG_CONTROL_VERSION, because of the new field in control file. Patch by Michael Paquier and Heikki Linnakangas, reviewed at different stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev, and many others. Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com Discussion: https://www.postgresql.org/message-id/[email protected]
Diffstat (limited to 'src/include')
-rw-r--r--src/include/access/xlog.h1
-rw-r--r--src/include/catalog/pg_control.h11
-rw-r--r--src/include/common/base64.h19
-rw-r--r--src/include/common/scram-common.h62
-rw-r--r--src/include/libpq/crypt.h3
-rw-r--r--src/include/libpq/hba.h1
-rw-r--r--src/include/libpq/pqcomm.h2
-rw-r--r--src/include/libpq/scram.h35
8 files changed, 132 insertions, 2 deletions
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 9f036c72d89..104ee7dd5ed 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -256,6 +256,7 @@ extern char *XLogFileNameP(TimeLineID tli, XLogSegNo segno);
extern void UpdateControlFile(void);
extern uint64 GetSystemIdentifier(void);
+extern char *GetMockAuthenticationNonce(void);
extern bool DataChecksumsEnabled(void);
extern XLogRecPtr GetFakeLSNForUnloggedRel(void);
extern Size XLOGShmemSize(void);
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index e4194b9de1f..3a25cc84b2a 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -20,8 +20,10 @@
#include "port/pg_crc32c.h"
+#define MOCK_AUTH_NONCE_LEN 32
+
/* Version identifier for this pg_control format */
-#define PG_CONTROL_VERSION 1001
+#define PG_CONTROL_VERSION 1002
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
@@ -222,6 +224,13 @@ typedef struct ControlFileData
/* Are data pages protected by checksums? Zero if no checksum version */
uint32 data_checksum_version;
+ /*
+ * Random nonce, used in authentication requests that need to proceed
+ * based on values that are cluster-unique, like a SASL exchange that
+ * failed at an early stage.
+ */
+ char mock_authentication_nonce[MOCK_AUTH_NONCE_LEN];
+
/* CRC of all above ... MUST BE LAST! */
pg_crc32c crc;
} ControlFileData;
diff --git a/src/include/common/base64.h b/src/include/common/base64.h
new file mode 100644
index 00000000000..47c28c3b62f
--- /dev/null
+++ b/src/include/common/base64.h
@@ -0,0 +1,19 @@
+/*
+ * base64.h
+ * Encoding and decoding routines for base64 without whitespace
+ * support.
+ *
+ * Portions Copyright (c) 2001-2016, PostgreSQL Global Development Group
+ *
+ * src/include/common/base64.h
+ */
+#ifndef BASE64_H
+#define BASE64_H
+
+/* base 64 */
+extern int pg_b64_encode(const char *src, int len, char *dst);
+extern int pg_b64_decode(const char *src, int len, char *dst);
+extern int pg_b64_enc_len(int srclen);
+extern int pg_b64_dec_len(int srclen);
+
+#endif /* BASE64_H */
diff --git a/src/include/common/scram-common.h b/src/include/common/scram-common.h
new file mode 100644
index 00000000000..14bb0538321
--- /dev/null
+++ b/src/include/common/scram-common.h
@@ -0,0 +1,62 @@
+/*-------------------------------------------------------------------------
+ *
+ * scram-common.h
+ * Declarations for helper functions used for SCRAM authentication
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/common/relpath.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SCRAM_COMMON_H
+#define SCRAM_COMMON_H
+
+#include "common/sha2.h"
+
+/* Length of SCRAM keys (client and server) */
+#define SCRAM_KEY_LEN PG_SHA256_DIGEST_LENGTH
+
+/* length of HMAC */
+#define SHA256_HMAC_B PG_SHA256_BLOCK_LENGTH
+
+/*
+ * Size of random nonce generated in the authentication exchange. This
+ * is in "raw" number of bytes, the actual nonces sent over the wire are
+ * encoded using only ASCII-printable characters.
+ */
+#define SCRAM_RAW_NONCE_LEN 10
+
+/* length of salt when generating new verifiers */
+#define SCRAM_SALT_LEN 10
+
+/* number of bytes used when sending iteration number during exchange */
+#define SCRAM_ITERATION_LEN 10
+
+/* default number of iterations when generating verifier */
+#define SCRAM_ITERATIONS_DEFAULT 4096
+
+/* Base name of keys used for proof generation */
+#define SCRAM_SERVER_KEY_NAME "Server Key"
+#define SCRAM_CLIENT_KEY_NAME "Client Key"
+
+/*
+ * Context data for HMAC used in SCRAM authentication.
+ */
+typedef struct
+{
+ pg_sha256_ctx sha256ctx;
+ uint8 k_opad[SHA256_HMAC_B];
+} scram_HMAC_ctx;
+
+extern void scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen);
+extern void scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen);
+extern void scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx);
+
+extern void scram_H(const uint8 *str, int len, uint8 *result);
+extern void scram_ClientOrServerKey(const char *password, const char *salt,
+ int saltlen, int iterations,
+ const char *keystr, uint8 *result);
+
+#endif /* SCRAM_COMMON_H */
diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h
index f94bc6339bf..0502d6a0e5b 100644
--- a/src/include/libpq/crypt.h
+++ b/src/include/libpq/crypt.h
@@ -24,7 +24,8 @@
typedef enum PasswordType
{
PASSWORD_TYPE_PLAINTEXT = 0,
- PASSWORD_TYPE_MD5
+ PASSWORD_TYPE_MD5,
+ PASSWORD_TYPE_SCRAM
} PasswordType;
extern PasswordType get_password_type(const char *shadow_pass);
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 748a0728541..8f55edb16aa 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -30,6 +30,7 @@ typedef enum UserAuth
uaIdent,
uaPassword,
uaMD5,
+ uaSASL,
uaGSS,
uaSSPI,
uaPAM,
diff --git a/src/include/libpq/pqcomm.h b/src/include/libpq/pqcomm.h
index de9ccc63b13..5441aaa93ac 100644
--- a/src/include/libpq/pqcomm.h
+++ b/src/include/libpq/pqcomm.h
@@ -172,6 +172,8 @@ extern bool Db_user_namespace;
#define AUTH_REQ_GSS 7 /* GSSAPI without wrap() */
#define AUTH_REQ_GSS_CONT 8 /* Continue GSS exchanges */
#define AUTH_REQ_SSPI 9 /* SSPI negotiate without wrap() */
+#define AUTH_REQ_SASL 10 /* SASL */
+#define AUTH_REQ_SASL_CONT 11 /* continue SASL exchange */
typedef uint32 AuthRequest;
diff --git a/src/include/libpq/scram.h b/src/include/libpq/scram.h
new file mode 100644
index 00000000000..563462fb1cc
--- /dev/null
+++ b/src/include/libpq/scram.h
@@ -0,0 +1,35 @@
+/*-------------------------------------------------------------------------
+ *
+ * scram.h
+ * Interface to libpq/scram.c
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/libpq/scram.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_SCRAM_H
+#define PG_SCRAM_H
+
+/* Name of SCRAM-SHA-256 per IANA */
+#define SCRAM_SHA256_NAME "SCRAM-SHA-256"
+
+/* Status codes for message exchange */
+#define SASL_EXCHANGE_CONTINUE 0
+#define SASL_EXCHANGE_SUCCESS 1
+#define SASL_EXCHANGE_FAILURE 2
+
+/* Routines dedicated to authentication */
+extern void *pg_be_scram_init(const char *username, const char *shadow_pass, bool doomed);
+extern int pg_be_scram_exchange(void *opaq, char *input, int inputlen,
+ char **output, int *outputlen, char **logdetail);
+
+/* Routines to handle and check SCRAM-SHA-256 verifier */
+extern char *scram_build_verifier(const char *username,
+ const char *password,
+ int iterations);
+extern bool is_scram_verifier(const char *verifier);
+
+#endif /* PG_SCRAM_H */