LCOV - code coverage report
Current view: top level - src/interfaces/libpq - scram-common.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 0 79 0.0 %
Date: 2017-09-29 15:12:54 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  * scram-common.c
       3             :  *      Shared frontend/backend code for SCRAM authentication
       4             :  *
       5             :  * This contains the common low-level functions needed in both frontend and
       6             :  * backend, for implement the Salted Challenge Response Authentication
       7             :  * Mechanism (SCRAM), per IETF's RFC 5802.
       8             :  *
       9             :  * Portions Copyright (c) 2017, PostgreSQL Global Development Group
      10             :  *
      11             :  * IDENTIFICATION
      12             :  *    src/common/scram-common.c
      13             :  *
      14             :  *-------------------------------------------------------------------------
      15             :  */
      16             : #ifndef FRONTEND
      17             : #include "postgres.h"
      18             : #else
      19             : #include "postgres_fe.h"
      20             : #endif
      21             : 
      22             : /* for htonl */
      23             : #include <netinet/in.h>
      24             : #include <arpa/inet.h>
      25             : 
      26             : #include "common/base64.h"
      27             : #include "common/scram-common.h"
      28             : 
      29             : #define HMAC_IPAD 0x36
      30             : #define HMAC_OPAD 0x5C
      31             : 
      32             : /*
      33             :  * Calculate HMAC per RFC2104.
      34             :  *
      35             :  * The hash function used is SHA-256.
      36             :  */
      37             : void
      38           0 : scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
      39             : {
      40             :     uint8       k_ipad[SHA256_HMAC_B];
      41             :     int         i;
      42             :     uint8       keybuf[SCRAM_KEY_LEN];
      43             : 
      44             :     /*
      45             :      * If the key is longer than the block size (64 bytes for SHA-256), pass
      46             :      * it through SHA-256 once to shrink it down.
      47             :      */
      48           0 :     if (keylen > SHA256_HMAC_B)
      49             :     {
      50             :         pg_sha256_ctx sha256_ctx;
      51             : 
      52           0 :         pg_sha256_init(&sha256_ctx);
      53           0 :         pg_sha256_update(&sha256_ctx, key, keylen);
      54           0 :         pg_sha256_final(&sha256_ctx, keybuf);
      55           0 :         key = keybuf;
      56           0 :         keylen = SCRAM_KEY_LEN;
      57             :     }
      58             : 
      59           0 :     memset(k_ipad, HMAC_IPAD, SHA256_HMAC_B);
      60           0 :     memset(ctx->k_opad, HMAC_OPAD, SHA256_HMAC_B);
      61             : 
      62           0 :     for (i = 0; i < keylen; i++)
      63             :     {
      64           0 :         k_ipad[i] ^= key[i];
      65           0 :         ctx->k_opad[i] ^= key[i];
      66             :     }
      67             : 
      68             :     /* tmp = H(K XOR ipad, text) */
      69           0 :     pg_sha256_init(&ctx->sha256ctx);
      70           0 :     pg_sha256_update(&ctx->sha256ctx, k_ipad, SHA256_HMAC_B);
      71           0 : }
      72             : 
      73             : /*
      74             :  * Update HMAC calculation
      75             :  * The hash function used is SHA-256.
      76             :  */
      77             : void
      78           0 : scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen)
      79             : {
      80           0 :     pg_sha256_update(&ctx->sha256ctx, (const uint8 *) str, slen);
      81           0 : }
      82             : 
      83             : /*
      84             :  * Finalize HMAC calculation.
      85             :  * The hash function used is SHA-256.
      86             :  */
      87             : void
      88           0 : scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
      89             : {
      90             :     uint8       h[SCRAM_KEY_LEN];
      91             : 
      92           0 :     pg_sha256_final(&ctx->sha256ctx, h);
      93             : 
      94             :     /* H(K XOR opad, tmp) */
      95           0 :     pg_sha256_init(&ctx->sha256ctx);
      96           0 :     pg_sha256_update(&ctx->sha256ctx, ctx->k_opad, SHA256_HMAC_B);
      97           0 :     pg_sha256_update(&ctx->sha256ctx, h, SCRAM_KEY_LEN);
      98           0 :     pg_sha256_final(&ctx->sha256ctx, result);
      99           0 : }
     100             : 
     101             : /*
     102             :  * Calculate SaltedPassword.
     103             :  *
     104             :  * The password should already be normalized by SASLprep.
     105             :  */
     106             : void
     107           0 : scram_SaltedPassword(const char *password,
     108             :                      const char *salt, int saltlen, int iterations,
     109             :                      uint8 *result)
     110             : {
     111           0 :     int         password_len = strlen(password);
     112           0 :     uint32      one = htonl(1);
     113             :     int         i,
     114             :                 j;
     115             :     uint8       Ui[SCRAM_KEY_LEN];
     116             :     uint8       Ui_prev[SCRAM_KEY_LEN];
     117             :     scram_HMAC_ctx hmac_ctx;
     118             : 
     119             :     /*
     120             :      * Iterate hash calculation of HMAC entry using given salt.  This is
     121             :      * essentially PBKDF2 (see RFC2898) with HMAC() as the pseudorandom
     122             :      * function.
     123             :      */
     124             : 
     125             :     /* First iteration */
     126           0 :     scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len);
     127           0 :     scram_HMAC_update(&hmac_ctx, salt, saltlen);
     128           0 :     scram_HMAC_update(&hmac_ctx, (char *) &one, sizeof(uint32));
     129           0 :     scram_HMAC_final(Ui_prev, &hmac_ctx);
     130           0 :     memcpy(result, Ui_prev, SCRAM_KEY_LEN);
     131             : 
     132             :     /* Subsequent iterations */
     133           0 :     for (i = 2; i <= iterations; i++)
     134             :     {
     135           0 :         scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len);
     136           0 :         scram_HMAC_update(&hmac_ctx, (const char *) Ui_prev, SCRAM_KEY_LEN);
     137           0 :         scram_HMAC_final(Ui, &hmac_ctx);
     138           0 :         for (j = 0; j < SCRAM_KEY_LEN; j++)
     139           0 :             result[j] ^= Ui[j];
     140           0 :         memcpy(Ui_prev, Ui, SCRAM_KEY_LEN);
     141             :     }
     142           0 : }
     143             : 
     144             : 
     145             : /*
     146             :  * Calculate SHA-256 hash for a NULL-terminated string. (The NULL terminator is
     147             :  * not included in the hash).
     148             :  */
     149             : void
     150           0 : scram_H(const uint8 *input, int len, uint8 *result)
     151             : {
     152             :     pg_sha256_ctx ctx;
     153             : 
     154           0 :     pg_sha256_init(&ctx);
     155           0 :     pg_sha256_update(&ctx, input, len);
     156           0 :     pg_sha256_final(&ctx, result);
     157           0 : }
     158             : 
     159             : /*
     160             :  * Calculate ClientKey.
     161             :  */
     162             : void
     163           0 : scram_ClientKey(const uint8 *salted_password, uint8 *result)
     164             : {
     165             :     scram_HMAC_ctx ctx;
     166             : 
     167           0 :     scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
     168           0 :     scram_HMAC_update(&ctx, "Client Key", strlen("Client Key"));
     169           0 :     scram_HMAC_final(result, &ctx);
     170           0 : }
     171             : 
     172             : /*
     173             :  * Calculate ServerKey.
     174             :  */
     175             : void
     176           0 : scram_ServerKey(const uint8 *salted_password, uint8 *result)
     177             : {
     178             :     scram_HMAC_ctx ctx;
     179             : 
     180           0 :     scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
     181           0 :     scram_HMAC_update(&ctx, "Server Key", strlen("Server Key"));
     182           0 :     scram_HMAC_final(result, &ctx);
     183           0 : }
     184             : 
     185             : 
     186             : /*
     187             :  * Construct a verifier string for SCRAM, stored in pg_authid.rolpassword.
     188             :  *
     189             :  * The password should already have been processed with SASLprep, if necessary!
     190             :  *
     191             :  * If iterations is 0, default number of iterations is used.  The result is
     192             :  * palloc'd or malloc'd, so caller is responsible for freeing it.
     193             :  */
     194             : char *
     195           0 : scram_build_verifier(const char *salt, int saltlen, int iterations,
     196             :                      const char *password)
     197             : {
     198             :     uint8       salted_password[SCRAM_KEY_LEN];
     199             :     uint8       stored_key[SCRAM_KEY_LEN];
     200             :     uint8       server_key[SCRAM_KEY_LEN];
     201             :     char       *result;
     202             :     char       *p;
     203             :     int         maxlen;
     204             : 
     205           0 :     if (iterations <= 0)
     206           0 :         iterations = SCRAM_DEFAULT_ITERATIONS;
     207             : 
     208             :     /* Calculate StoredKey and ServerKey */
     209           0 :     scram_SaltedPassword(password, salt, saltlen, iterations,
     210             :                          salted_password);
     211           0 :     scram_ClientKey(salted_password, stored_key);
     212           0 :     scram_H(stored_key, SCRAM_KEY_LEN, stored_key);
     213             : 
     214           0 :     scram_ServerKey(salted_password, server_key);
     215             : 
     216             :     /*----------
     217             :      * The format is:
     218             :      * SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>
     219             :      *----------
     220             :      */
     221           0 :     maxlen = strlen("SCRAM-SHA-256") + 1
     222             :         + 10 + 1                /* iteration count */
     223           0 :         + pg_b64_enc_len(saltlen) + 1   /* Base64-encoded salt */
     224           0 :         + pg_b64_enc_len(SCRAM_KEY_LEN) + 1 /* Base64-encoded StoredKey */
     225           0 :         + pg_b64_enc_len(SCRAM_KEY_LEN) + 1;    /* Base64-encoded ServerKey */
     226             : 
     227             : #ifdef FRONTEND
     228           0 :     result = malloc(maxlen);
     229           0 :     if (!result)
     230           0 :         return NULL;
     231             : #else
     232             :     result = palloc(maxlen);
     233             : #endif
     234             : 
     235           0 :     p = result + sprintf(result, "SCRAM-SHA-256$%d:", iterations);
     236             : 
     237           0 :     p += pg_b64_encode(salt, saltlen, p);
     238           0 :     *(p++) = '$';
     239           0 :     p += pg_b64_encode((char *) stored_key, SCRAM_KEY_LEN, p);
     240           0 :     *(p++) = ':';
     241           0 :     p += pg_b64_encode((char *) server_key, SCRAM_KEY_LEN, p);
     242           0 :     *(p++) = '\0';
     243             : 
     244           0 :     Assert(p - result <= maxlen);
     245             : 
     246           0 :     return result;
     247             : }

Generated by: LCOV version 1.11