LCOV - code coverage report
Current view: top level - openssh-6.6p1 - entropy.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 6 8 75.0 %
Date: 2014-08-01 Functions: 1 1 100.0 %
Branches: 4 8 50.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2001 Damien Miller.  All rights reserved.
       3                 :            :  *
       4                 :            :  * Redistribution and use in source and binary forms, with or without
       5                 :            :  * modification, are permitted provided that the following conditions
       6                 :            :  * are met:
       7                 :            :  * 1. Redistributions of source code must retain the above copyright
       8                 :            :  *    notice, this list of conditions and the following disclaimer.
       9                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      10                 :            :  *    notice, this list of conditions and the following disclaimer in the
      11                 :            :  *    documentation and/or other materials provided with the distribution.
      12                 :            :  *
      13                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      14                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      15                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      16                 :            :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      17                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      18                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      19                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      20                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      21                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      22                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      23                 :            :  */
      24                 :            : 
      25                 :            : #include "includes.h"
      26                 :            : 
      27                 :            : #include <sys/types.h>
      28                 :            : #include <sys/socket.h>
      29                 :            : #ifdef HAVE_SYS_UN_H
      30                 :            : # include <sys/un.h>
      31                 :            : #endif
      32                 :            : 
      33                 :            : #include <netinet/in.h>
      34                 :            : #include <arpa/inet.h>
      35                 :            : 
      36                 :            : #include <errno.h>
      37                 :            : #include <signal.h>
      38                 :            : #include <string.h>
      39                 :            : #include <unistd.h>
      40                 :            : #include <stddef.h> /* for offsetof */
      41                 :            : 
      42                 :            : #include <openssl/rand.h>
      43                 :            : #include <openssl/crypto.h>
      44                 :            : #include <openssl/err.h>
      45                 :            : 
      46                 :            : #include "ssh.h"
      47                 :            : #include "misc.h"
      48                 :            : #include "xmalloc.h"
      49                 :            : #include "atomicio.h"
      50                 :            : #include "pathnames.h"
      51                 :            : #include "log.h"
      52                 :            : #include "buffer.h"
      53                 :            : 
      54                 :            : /*
      55                 :            :  * Portable OpenSSH PRNG seeding:
      56                 :            :  * If OpenSSL has not "internally seeded" itself (e.g. pulled data from
      57                 :            :  * /dev/random), then collect RANDOM_SEED_SIZE bytes of randomness from
      58                 :            :  * PRNGd.
      59                 :            :  */
      60                 :            : #ifndef OPENSSL_PRNG_ONLY
      61                 :            : 
      62                 :            : #define RANDOM_SEED_SIZE 48
      63                 :            : 
      64                 :            : /*
      65                 :            :  * Collect 'len' bytes of entropy into 'buf' from PRNGD/EGD daemon
      66                 :            :  * listening either on 'tcp_port', or via Unix domain socket at *
      67                 :            :  * 'socket_path'.
      68                 :            :  * Either a non-zero tcp_port or a non-null socket_path must be
      69                 :            :  * supplied.
      70                 :            :  * Returns 0 on success, -1 on error
      71                 :            :  */
      72                 :            : int
      73                 :            : get_random_bytes_prngd(unsigned char *buf, int len,
      74                 :            :     unsigned short tcp_port, char *socket_path)
      75                 :            : {
      76                 :            :         int fd, addr_len, rval, errors;
      77                 :            :         u_char msg[2];
      78                 :            :         struct sockaddr_storage addr;
      79                 :            :         struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr;
      80                 :            :         struct sockaddr_un *addr_un = (struct sockaddr_un *)&addr;
      81                 :            :         mysig_t old_sigpipe;
      82                 :            : 
      83                 :            :         /* Sanity checks */
      84                 :            :         if (socket_path == NULL && tcp_port == 0)
      85                 :            :                 fatal("You must specify a port or a socket");
      86                 :            :         if (socket_path != NULL &&
      87                 :            :             strlen(socket_path) >= sizeof(addr_un->sun_path))
      88                 :            :                 fatal("Random pool path is too long");
      89                 :            :         if (len <= 0 || len > 255)
      90                 :            :                 fatal("Too many bytes (%d) to read from PRNGD", len);
      91                 :            : 
      92                 :            :         memset(&addr, '\0', sizeof(addr));
      93                 :            : 
      94                 :            :         if (tcp_port != 0) {
      95                 :            :                 addr_in->sin_family = AF_INET;
      96                 :            :                 addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
      97                 :            :                 addr_in->sin_port = htons(tcp_port);
      98                 :            :                 addr_len = sizeof(*addr_in);
      99                 :            :         } else {
     100                 :            :                 addr_un->sun_family = AF_UNIX;
     101                 :            :                 strlcpy(addr_un->sun_path, socket_path,
     102                 :            :                     sizeof(addr_un->sun_path));
     103                 :            :                 addr_len = offsetof(struct sockaddr_un, sun_path) +
     104                 :            :                     strlen(socket_path) + 1;
     105                 :            :         }
     106                 :            : 
     107                 :            :         old_sigpipe = mysignal(SIGPIPE, SIG_IGN);
     108                 :            : 
     109                 :            :         errors = 0;
     110                 :            :         rval = -1;
     111                 :            : reopen:
     112                 :            :         fd = socket(addr.ss_family, SOCK_STREAM, 0);
     113                 :            :         if (fd == -1) {
     114                 :            :                 error("Couldn't create socket: %s", strerror(errno));
     115                 :            :                 goto done;
     116                 :            :         }
     117                 :            : 
     118                 :            :         if (connect(fd, (struct sockaddr*)&addr, addr_len) == -1) {
     119                 :            :                 if (tcp_port != 0) {
     120                 :            :                         error("Couldn't connect to PRNGD port %d: %s",
     121                 :            :                             tcp_port, strerror(errno));
     122                 :            :                 } else {
     123                 :            :                         error("Couldn't connect to PRNGD socket \"%s\": %s",
     124                 :            :                             addr_un->sun_path, strerror(errno));
     125                 :            :                 }
     126                 :            :                 goto done;
     127                 :            :         }
     128                 :            : 
     129                 :            :         /* Send blocking read request to PRNGD */
     130                 :            :         msg[0] = 0x02;
     131                 :            :         msg[1] = len;
     132                 :            : 
     133                 :            :         if (atomicio(vwrite, fd, msg, sizeof(msg)) != sizeof(msg)) {
     134                 :            :                 if (errno == EPIPE && errors < 10) {
     135                 :            :                         close(fd);
     136                 :            :                         errors++;
     137                 :            :                         goto reopen;
     138                 :            :                 }
     139                 :            :                 error("Couldn't write to PRNGD socket: %s",
     140                 :            :                     strerror(errno));
     141                 :            :                 goto done;
     142                 :            :         }
     143                 :            : 
     144                 :            :         if (atomicio(read, fd, buf, len) != (size_t)len) {
     145                 :            :                 if (errno == EPIPE && errors < 10) {
     146                 :            :                         close(fd);
     147                 :            :                         errors++;
     148                 :            :                         goto reopen;
     149                 :            :                 }
     150                 :            :                 error("Couldn't read from PRNGD socket: %s",
     151                 :            :                     strerror(errno));
     152                 :            :                 goto done;
     153                 :            :         }
     154                 :            : 
     155                 :            :         rval = 0;
     156                 :            : done:
     157                 :            :         mysignal(SIGPIPE, old_sigpipe);
     158                 :            :         if (fd != -1)
     159                 :            :                 close(fd);
     160                 :            :         return rval;
     161                 :            : }
     162                 :            : 
     163                 :            : static int
     164                 :            : seed_from_prngd(unsigned char *buf, size_t bytes)
     165                 :            : {
     166                 :            : #ifdef PRNGD_PORT
     167                 :            :         debug("trying egd/prngd port %d", PRNGD_PORT);
     168                 :            :         if (get_random_bytes_prngd(buf, bytes, PRNGD_PORT, NULL) == 0)
     169                 :            :                 return 0;
     170                 :            : #endif
     171                 :            : #ifdef PRNGD_SOCKET
     172                 :            :         debug("trying egd/prngd socket %s", PRNGD_SOCKET);
     173                 :            :         if (get_random_bytes_prngd(buf, bytes, 0, PRNGD_SOCKET) == 0)
     174                 :            :                 return 0;
     175                 :            : #endif
     176                 :            :         return -1;
     177                 :            : }
     178                 :            : 
     179                 :            : void
     180                 :            : rexec_send_rng_seed(Buffer *m)
     181                 :            : {
     182                 :            :         u_char buf[RANDOM_SEED_SIZE];
     183                 :            : 
     184                 :            :         if (RAND_bytes(buf, sizeof(buf)) <= 0) {
     185                 :            :                 error("Couldn't obtain random bytes (error %ld)",
     186                 :            :                     ERR_get_error());
     187                 :            :                 buffer_put_string(m, "", 0);
     188                 :            :         } else 
     189                 :            :                 buffer_put_string(m, buf, sizeof(buf));
     190                 :            : }
     191                 :            : 
     192                 :            : void
     193                 :            : rexec_recv_rng_seed(Buffer *m)
     194                 :            : {
     195                 :            :         u_char *buf;
     196                 :            :         u_int len;
     197                 :            : 
     198                 :            :         buf = buffer_get_string_ret(m, &len);
     199                 :            :         if (buf != NULL) {
     200                 :            :                 debug3("rexec_recv_rng_seed: seeding rng with %u bytes", len);
     201                 :            :                 RAND_add(buf, len, len);
     202                 :            :         }
     203                 :            : }
     204                 :            : #endif /* OPENSSL_PRNG_ONLY */
     205                 :            : 
     206                 :            : void
     207                 :       3309 : seed_rng(void)
     208                 :            : {
     209                 :            : #ifndef OPENSSL_PRNG_ONLY
     210                 :            :         unsigned char buf[RANDOM_SEED_SIZE];
     211                 :            : #endif
     212                 :            :         /*
     213                 :            :          * OpenSSL version numbers: MNNFFPPS: major minor fix patch status
     214                 :            :          * We match major, minor, fix and status (not patch) for <1.0.0.
     215                 :            :          * After that, we acceptable compatible fix versions (so we
     216                 :            :          * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed
     217                 :            :          * within a patch series.
     218                 :            :          */
     219         [ -  + ]:       3309 :         u_long version_mask = SSLeay() >= 0x1000000f ?  ~0xffff0L : ~0xff0L;
     220   [ +  -  -  + ]:       6618 :         if (((SSLeay() ^ OPENSSL_VERSION_NUMBER) & version_mask) ||
     221                 :       3309 :             (SSLeay() >> 12) < (OPENSSL_VERSION_NUMBER >> 12))
     222                 :          0 :                 fatal("OpenSSL version mismatch. Built against %lx, you "
     223                 :            :                     "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay());
     224                 :            : 
     225                 :            : #ifndef OPENSSL_PRNG_ONLY
     226                 :            :         if (RAND_status() == 1) {
     227                 :            :                 debug3("RNG is ready, skipping seeding");
     228                 :            :                 return;
     229                 :            :         }
     230                 :            : 
     231                 :            :         if (seed_from_prngd(buf, sizeof(buf)) == -1)
     232                 :            :                 fatal("Could not obtain seed from PRNGd");
     233                 :            :         RAND_add(buf, sizeof(buf), sizeof(buf));
     234                 :            :         memset(buf, '\0', sizeof(buf));
     235                 :            : 
     236                 :            : #endif /* OPENSSL_PRNG_ONLY */
     237         [ -  + ]:       3309 :         if (RAND_status() != 1)
     238                 :          0 :                 fatal("PRNG is not seeded");
     239                 :       3309 : }

Generated by: LCOV version 1.9