Re: Re: Proposal for encrypting pg_shadow passwords - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: Re: Proposal for encrypting pg_shadow passwords
Date
Msg-id 200108161808.f7GI8hi12803@candle.pha.pa.us
Whole thread Raw
In response to Re: Re: Proposal for encrypting pg_shadow passwords  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-patches
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> >> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Also, I now need two salts, one base62 for crypt and a new one for MD5.
> >>
> >> They're carried in two different messages, so I don't see the problem.
>
> > But the salt is configured on startup, before you know your auth method,
> > right?  Do I need to move that?
>
> Oh, I see what you're looking at: the salt is computed at ConnCreate
> time in the postmaster.  Hmm.  You cannot move the call into the later
> auth process, because it needs to happen before the postmaster forks.
> (Else, every forked child would start with the same random() state and
> compute the same salt ... good security eh?)

Yes, I knew we had to do it in the postmaster but I couldn't remember
why. :-)

> Yes, I think initializing two salt fields in ConnCreate is fine.  That's
> probably actually a little more secure in itself, because it ensures
> that would-be sniffers cannot see every random() result in the
> postmaster's random() sequence, only some of them.  IIRC, that makes it
> a lot harder to guess the underlying seed.

OK, here is the patch for separate salts for crypt and MD5, and allowing
null's in MD5 salt.  I haven't tested it yet.

Yes, I realized computing it every time helps.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
Index: src/backend/commands/user.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/commands/user.c,v
retrieving revision 1.81
diff -c -r1.81 user.c
*** src/backend/commands/user.c    2001/08/15 21:08:20    1.81
--- src/backend/commands/user.c    2001/08/16 18:06:43
***************
*** 351,357 ****
                  DirectFunctionCall1(textin, CStringGetDatum(password));
          else
          {
!             if (!EncryptMD5(password, stmt->user, encrypted_password))
                  elog(ERROR, "CREATE USER: password encryption failed");
              new_record[Anum_pg_shadow_passwd - 1] =
                  DirectFunctionCall1(textin, CStringGetDatum(encrypted_password));
--- 351,358 ----
                  DirectFunctionCall1(textin, CStringGetDatum(password));
          else
          {
!             if (!EncryptMD5(password, stmt->user, strlen(stmt->user),
!                 encrypted_password))
                  elog(ERROR, "CREATE USER: password encryption failed");
              new_record[Anum_pg_shadow_passwd - 1] =
                  DirectFunctionCall1(textin, CStringGetDatum(encrypted_password));
***************
*** 583,589 ****
                  DirectFunctionCall1(textin, CStringGetDatum(password));
          else
          {
!             if (!EncryptMD5(password, stmt->user, encrypted_password))
                  elog(ERROR, "CREATE USER: password encryption failed");
              new_record[Anum_pg_shadow_passwd - 1] =
                  DirectFunctionCall1(textin, CStringGetDatum(encrypted_password));
--- 584,591 ----
                  DirectFunctionCall1(textin, CStringGetDatum(password));
          else
          {
!             if (!EncryptMD5(password, stmt->user, strlen(stmt->user),
!                 encrypted_password))
                  elog(ERROR, "CREATE USER: password encryption failed");
              new_record[Anum_pg_shadow_passwd - 1] =
                  DirectFunctionCall1(textin, CStringGetDatum(encrypted_password));
Index: src/backend/libpq/auth.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/libpq/auth.c,v
retrieving revision 1.59
diff -c -r1.59 auth.c
*** src/backend/libpq/auth.c    2001/08/16 16:24:15    1.59
--- src/backend/libpq/auth.c    2001/08/16 18:06:43
***************
*** 536,545 ****
      pq_sendint(&buf, (int32) areq, sizeof(int32));

      /* Add the salt for encrypted passwords. */
!     if (areq == AUTH_REQ_CRYPT || areq == AUTH_REQ_MD5)
      {
!         pq_sendint(&buf, port->salt[0], 1);
!         pq_sendint(&buf, port->salt[1], 1);
      }

      pq_endmessage(&buf);
--- 536,552 ----
      pq_sendint(&buf, (int32) areq, sizeof(int32));

      /* Add the salt for encrypted passwords. */
!     if (areq == AUTH_REQ_MD5)
      {
!         pq_sendint(&buf, port->md5Salt[0], 1);
!         pq_sendint(&buf, port->md5Salt[1], 1);
!         pq_sendint(&buf, port->md5Salt[2], 1);
!         pq_sendint(&buf, port->md5Salt[3], 1);
!     }
!     if (areq == AUTH_REQ_CRYPT)
!     {
!         pq_sendint(&buf, port->cryptSalt[0], 1);
!         pq_sendint(&buf, port->cryptSalt[1], 1);
      }

      pq_endmessage(&buf);
Index: src/backend/libpq/crypt.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/libpq/crypt.c,v
retrieving revision 1.34
diff -c -r1.34 crypt.c
*** src/backend/libpq/crypt.c    2001/08/15 21:08:21    1.34
--- src/backend/libpq/crypt.c    2001/08/16 18:06:43
***************
*** 283,289 ****
       switch (port->auth_method)
       {
          case uaCrypt:
!             crypt_pwd = crypt(passwd, port->salt);
              break;
          case uaMD5:
              crypt_pwd = palloc(MD5_PASSWD_LEN+1);
--- 283,289 ----
       switch (port->auth_method)
       {
          case uaCrypt:
!             crypt_pwd = crypt(passwd, port->cryptSalt);
              break;
          case uaMD5:
              crypt_pwd = palloc(MD5_PASSWD_LEN+1);
***************
*** 291,297 ****
              if (isMD5(passwd))
              {
                  if (!EncryptMD5(passwd + strlen("md5"),
!                                 (char *)port->salt, crypt_pwd))
                  {
                      pfree(crypt_pwd);
                      return STATUS_ERROR;
--- 291,298 ----
              if (isMD5(passwd))
              {
                  if (!EncryptMD5(passwd + strlen("md5"),
!                     (char *)port->md5Salt, sizeof(port->md5Salt),
!                     crypt_pwd))
                  {
                      pfree(crypt_pwd);
                      return STATUS_ERROR;
***************
*** 301,314 ****
              {
                  char *crypt_pwd2 = palloc(MD5_PASSWD_LEN+1);

!                 if (!EncryptMD5(passwd, port->user, crypt_pwd2))
                  {
                      pfree(crypt_pwd);
                      pfree(crypt_pwd2);
                      return STATUS_ERROR;
                  }
!                 if (!EncryptMD5(crypt_pwd2 + strlen("md5"), port->salt,
!                                 crypt_pwd))
                  {
                      pfree(crypt_pwd);
                      pfree(crypt_pwd2);
--- 302,316 ----
              {
                  char *crypt_pwd2 = palloc(MD5_PASSWD_LEN+1);

!                 if (!EncryptMD5(passwd, port->user, strlen(port->user),
!                     crypt_pwd2))
                  {
                      pfree(crypt_pwd);
                      pfree(crypt_pwd2);
                      return STATUS_ERROR;
                  }
!                 if (!EncryptMD5(crypt_pwd2 + strlen("md5"), port->md5Salt,
!                                 sizeof(port->md5Salt), crypt_pwd))
                  {
                      pfree(crypt_pwd);
                      pfree(crypt_pwd2);
Index: src/backend/libpq/md5.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/libpq/md5.c,v
retrieving revision 1.3
diff -c -r1.3 md5.c
*** src/backend/libpq/md5.c    2001/08/15 23:22:49    1.3
--- src/backend/libpq/md5.c    2001/08/16 18:06:44
***************
*** 295,310 ****
   * puts  md5(username+passwd)  in buf provided buflen is at least 36 bytes
   * returns 1 on success, 0 on any kind of failure and sets errno accordingly
   */
! bool EncryptMD5(const char *passwd, const char *salt, char *buf)
  {
      char crypt_buf[128];

!     if (strlen(salt) + strlen(passwd) > 127)
          return false;

      strcpy(buf, "md5");
      memset(crypt_buf, 0, 128);
!     sprintf(crypt_buf,"%s%s", salt, passwd);

!     return md5_hash(crypt_buf, strlen(crypt_buf), buf + 3);
  }
--- 295,312 ----
   * puts  md5(username+passwd)  in buf provided buflen is at least 36 bytes
   * returns 1 on success, 0 on any kind of failure and sets errno accordingly
   */
! bool EncryptMD5(const char *passwd, const char *salt, size_t salt_len,
!                 char *buf)
  {
      char crypt_buf[128];

!     if (salt_len + strlen(passwd) > 127)
          return false;

      strcpy(buf, "md5");
      memset(crypt_buf, 0, 128);
!     memcpy(crypt_buf, salt, salt_len);
!     memcpy(crypt_buf+salt_len, passwd, strlen(passwd));

!     return md5_hash(crypt_buf, salt_len + strlen(passwd), buf + 3);
  }
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.235
diff -c -r1.235 postmaster.c
*** src/backend/postmaster/postmaster.c    2001/08/05 02:06:50    1.235
--- src/backend/postmaster/postmaster.c    2001/08/16 18:06:45
***************
*** 243,249 ****
  static int    initMasks(fd_set *rmask, fd_set *wmask);
  static char *canAcceptConnections(void);
  static long PostmasterRandom(void);
! static void RandomSalt(char *salt);
  static void SignalChildren(int signal);
  static int    CountChildren(void);
  static bool CreateOptsFile(int argc, char *argv[]);
--- 243,249 ----
  static int    initMasks(fd_set *rmask, fd_set *wmask);
  static char *canAcceptConnections(void);
  static long PostmasterRandom(void);
! static void RandomSalt(char *cryptSalt, char *md5Salt);
  static void SignalChildren(int signal);
  static int    CountChildren(void);
  static bool CreateOptsFile(int argc, char *argv[]);
***************
*** 1211,1217 ****
      }
      else
      {
!         RandomSalt(port->salt);
          port->pktInfo.state = Idle;
      }

--- 1211,1217 ----
      }
      else
      {
!         RandomSalt(port->cryptSalt, port->md5Salt);
          port->pktInfo.state = Idle;
      }

***************
*** 2099,2110 ****
   * RandomSalt
   */
  static void
! RandomSalt(char *salt)
  {
      long        rand = PostmasterRandom();

!     *salt = CharRemap(rand % 62);
!     *(salt + 1) = CharRemap(rand / 62);
  }

  /*
--- 2099,2113 ----
   * RandomSalt
   */
  static void
! RandomSalt(char *cryptSalt, char *md5Salt)
  {
      long        rand = PostmasterRandom();
+     int            i;

!     cryptSalt[0] = CharRemap(rand % 62);
!     cryptSalt[1] = CharRemap(rand / 62);
!     for (i=0; i < 4; i++)
!         md5Salt[i] = (rand >> (i * 4)) & 0xff;
  }

  /*
Index: src/include/libpq/crypt.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/libpq/crypt.h,v
retrieving revision 1.13
diff -c -r1.13 crypt.h
*** src/include/libpq/crypt.h    2001/08/15 21:08:21    1.13
--- src/include/libpq/crypt.h    2001/08/16 18:06:46
***************
*** 26,32 ****

  extern bool md5_hash(const void *buff, size_t len, char *hexsum);
  extern bool CheckMD5Pwd(char *passwd, char *storedpwd, char *seed);
! extern bool EncryptMD5(const char *passwd, const char *salt, char *buf);

  #define MD5_PASSWD_LEN    35

--- 26,33 ----

  extern bool md5_hash(const void *buff, size_t len, char *hexsum);
  extern bool CheckMD5Pwd(char *passwd, char *storedpwd, char *seed);
! extern bool EncryptMD5(const char *passwd, const char *salt,
!                        size_t salt_len, char *buf);

  #define MD5_PASSWD_LEN    35

Index: src/include/libpq/libpq-be.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/libpq/libpq-be.h,v
retrieving revision 1.21
diff -c -r1.21 libpq-be.h
*** src/include/libpq/libpq-be.h    2001/01/24 19:43:24    1.21
--- src/include/libpq/libpq-be.h    2001/08/16 18:06:46
***************
*** 58,64 ****

  typedef struct AuthRequestPacket
  {
!     char        data[1 + sizeof(AuthRequest) + 2];        /* 'R' + the request +
                                                           * optional salt. */
  } AuthRequestPacket;

--- 58,64 ----

  typedef struct AuthRequestPacket
  {
!     char        data[1 + sizeof(AuthRequest) + 4];        /* 'R' + the request +
                                                           * optional salt. */
  } AuthRequestPacket;

***************
*** 119,125 ****
      Packet        pktInfo;        /* For the packet handlers */
      SockAddr    laddr;            /* local addr (us) */
      SockAddr    raddr;            /* remote addr (them) */
!     char        salt[2];        /* Password salt */

      /*
       * Information that needs to be held during the fe/be authentication
--- 119,126 ----
      Packet        pktInfo;        /* For the packet handlers */
      SockAddr    laddr;            /* local addr (us) */
      SockAddr    raddr;            /* remote addr (them) */
!     char        md5Salt[4];        /* Password salt */
!      char        cryptSalt[2];    /* Password salt */

      /*
       * Information that needs to be held during the fe/be authentication
Index: src/interfaces/libpq/fe-auth.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v
retrieving revision 1.50
diff -c -r1.50 fe-auth.c
*** src/interfaces/libpq/fe-auth.c    2001/08/15 21:08:21    1.50
--- src/interfaces/libpq/fe-auth.c    2001/08/16 18:06:47
***************
*** 443,449 ****
      switch (areq)
      {
          case AUTH_REQ_CRYPT:
!             crypt_pwd = crypt(password, conn->salt);
              break;
          case AUTH_REQ_MD5:
              {
--- 443,449 ----
      switch (areq)
      {
          case AUTH_REQ_CRYPT:
!             crypt_pwd = crypt(password, conn->cryptSalt);
              break;
          case AUTH_REQ_MD5:
              {
***************
*** 455,468 ****
                      perror("malloc");
                      return STATUS_ERROR;
                  }
!                 if (!EncryptMD5(password, conn->pguser, crypt_pwd2))
                  {
                      free(crypt_pwd);
                      free(crypt_pwd2);
                      return STATUS_ERROR;
                  }
!                 if (!EncryptMD5(crypt_pwd2 + strlen("md5"), conn->salt,
!                                 crypt_pwd))
                  {
                      free(crypt_pwd);
                      free(crypt_pwd2);
--- 455,469 ----
                      perror("malloc");
                      return STATUS_ERROR;
                  }
!                 if (!EncryptMD5(password, conn->pguser,
!                     strlen(conn->pguser), crypt_pwd2))
                  {
                      free(crypt_pwd);
                      free(crypt_pwd2);
                      return STATUS_ERROR;
                  }
!                 if (!EncryptMD5(crypt_pwd2 + strlen("md5"), conn->md5Salt,
!                                 strlen(conn->md5Salt), crypt_pwd))
                  {
                      free(crypt_pwd);
                      free(crypt_pwd2);
Index: src/interfaces/libpq/fe-connect.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v
retrieving revision 1.173
diff -c -r1.173 fe-connect.c
*** src/interfaces/libpq/fe-connect.c    2001/08/15 18:42:15    1.173
--- src/interfaces/libpq/fe-connect.c    2001/08/16 18:06:48
***************
*** 1341,1349 ****
                  }

                  /* Get the password salt if there is one. */
!                 if (areq == AUTH_REQ_CRYPT || areq == AUTH_REQ_MD5)
                  {
!                     if (pqGetnchar(conn->salt, sizeof(conn->salt), conn))
                      {
                          /* We'll come back when there are more data */
                          return PGRES_POLLING_READING;
--- 1341,1359 ----
                  }

                  /* Get the password salt if there is one. */
!                 if (areq == AUTH_REQ_MD5)
                  {
!                     if (pqGetnchar(conn->md5Salt,
!                         sizeof(conn->md5Salt)-1, conn))
!                     {
!                         /* We'll come back when there are more data */
!                         return PGRES_POLLING_READING;
!                     }
!                 }
!                 if (areq == AUTH_REQ_CRYPT)
!                 {
!                     if (pqGetnchar(conn->cryptSalt,
!                         sizeof(conn->cryptSalt)-1, conn))
                      {
                          /* We'll come back when there are more data */
                          return PGRES_POLLING_READING;
Index: src/interfaces/libpq/libpq-int.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/libpq/libpq-int.h,v
retrieving revision 1.38
diff -c -r1.38 libpq-int.h
*** src/interfaces/libpq/libpq-int.h    2001/08/16 04:27:18    1.38
--- src/interfaces/libpq/libpq-int.h    2001/08/16 18:06:49
***************
*** 236,242 ****
      /* Miscellaneous stuff */
      int            be_pid;            /* PID of backend --- needed for cancels */
      int            be_key;            /* key of backend --- needed for cancels */
!     char        salt[2];        /* password salt received from backend */
      PGlobjfuncs *lobjfuncs;        /* private state for large-object access
                                   * fns */

--- 236,243 ----
      /* Miscellaneous stuff */
      int            be_pid;            /* PID of backend --- needed for cancels */
      int            be_key;            /* key of backend --- needed for cancels */
!      char        md5Salt[4];        /* password salt received from backend */
!      char        cryptSalt[2];        /* password salt received from backend */
      PGlobjfuncs *lobjfuncs;        /* private state for large-object access
                                   * fns */

Index: src/interfaces/odbc/connection.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/interfaces/odbc/connection.c,v
retrieving revision 1.33
diff -c -r1.33 connection.c
*** src/interfaces/odbc/connection.c    2001/08/15 18:42:16    1.33
--- src/interfaces/odbc/connection.c    2001/08/16 18:06:49
***************
*** 507,513 ****
      int            areq = -1;
      int            beresp;
      char        msgbuffer[ERROR_MSG_LENGTH];
!     char        salt[2];
      static char *func = "CC_connect";

      mylog("%s: entering...\n", func);
--- 507,513 ----
      int            areq = -1;
      int            beresp;
      char        msgbuffer[ERROR_MSG_LENGTH];
!     char        salt[5];
      static char *func = "CC_connect";

      mylog("%s: entering...\n", func);
***************
*** 677,683 ****
                          mylog("auth got 'R'\n");

                          areq = SOCK_get_int(sock, 4);
!                         if (areq == AUTH_REQ_CRYPT || areq == AUTH_REQ_MD5)
                              SOCK_get_n_char(sock, salt, 2);

                          mylog("areq = %d\n", areq);
--- 677,685 ----
                          mylog("auth got 'R'\n");

                          areq = SOCK_get_int(sock, 4);
!                         if (areq == AUTH_REQ_MD5)
!                             SOCK_get_n_char(sock, salt, 4);
!                         if (areq == AUTH_REQ_CRYPT)
                              SOCK_get_n_char(sock, salt, 2);

                          mylog("areq = %d\n", areq);

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: Re: Proposal for encrypting pg_shadow passwords
Next
From: Tom Lane
Date:
Subject: Re: Re: Proposal for encrypting pg_shadow passwords