1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 2001 Damien Miller. All rights reserved. 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 5*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 6*0Sstevel@tonic-gate * are met: 7*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 8*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 9*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 10*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 11*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 12*0Sstevel@tonic-gate * 13*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14*0Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15*0Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16*0Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17*0Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18*0Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19*0Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20*0Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21*0Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22*0Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23*0Sstevel@tonic-gate */ 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate #include "includes.h" 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #include <openssl/rand.h> 28*0Sstevel@tonic-gate #include <openssl/crypto.h> 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #include "ssh.h" 31*0Sstevel@tonic-gate #include "misc.h" 32*0Sstevel@tonic-gate #include "xmalloc.h" 33*0Sstevel@tonic-gate #include "atomicio.h" 34*0Sstevel@tonic-gate #include "pathnames.h" 35*0Sstevel@tonic-gate #include "log.h" 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate /* 38*0Sstevel@tonic-gate * Portable OpenSSH PRNG seeding: 39*0Sstevel@tonic-gate * If OpenSSL has not "internally seeded" itself (e.g. pulled data from 40*0Sstevel@tonic-gate * /dev/random), then we execute a "ssh-rand-helper" program which 41*0Sstevel@tonic-gate * collects entropy and writes it to stdout. The child program must 42*0Sstevel@tonic-gate * write at least RANDOM_SEED_SIZE bytes. The child is run with stderr 43*0Sstevel@tonic-gate * attached, so error/debugging output should be visible. 44*0Sstevel@tonic-gate * 45*0Sstevel@tonic-gate * XXX: we should tell the child how many bytes we need. 46*0Sstevel@tonic-gate */ 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate RCSID("$Id: entropy.c,v 1.44 2002/06/09 19:41:48 mouring Exp $"); 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate #ifndef OPENSSL_PRNG_ONLY 53*0Sstevel@tonic-gate #define RANDOM_SEED_SIZE 48 54*0Sstevel@tonic-gate static uid_t original_uid, original_euid; 55*0Sstevel@tonic-gate #endif 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate void 58*0Sstevel@tonic-gate seed_rng(void) 59*0Sstevel@tonic-gate { 60*0Sstevel@tonic-gate #ifndef OPENSSL_PRNG_ONLY 61*0Sstevel@tonic-gate int devnull; 62*0Sstevel@tonic-gate int p[2]; 63*0Sstevel@tonic-gate pid_t pid; 64*0Sstevel@tonic-gate int ret; 65*0Sstevel@tonic-gate unsigned char buf[RANDOM_SEED_SIZE]; 66*0Sstevel@tonic-gate mysig_t old_sigchld; 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate if (RAND_status() == 1) { 69*0Sstevel@tonic-gate debug3("RNG is ready, skipping seeding"); 70*0Sstevel@tonic-gate return; 71*0Sstevel@tonic-gate } 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate debug3("Seeding PRNG from %s", SSH_RAND_HELPER); 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate if ((devnull = open("/dev/null", O_RDWR)) == -1) 76*0Sstevel@tonic-gate fatal("Couldn't open /dev/null: %s", strerror(errno)); 77*0Sstevel@tonic-gate if (pipe(p) == -1) 78*0Sstevel@tonic-gate fatal("pipe: %s", strerror(errno)); 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate old_sigchld = mysignal(SIGCHLD, SIG_DFL); 81*0Sstevel@tonic-gate if ((pid = fork()) == -1) 82*0Sstevel@tonic-gate fatal("Couldn't fork: %s", strerror(errno)); 83*0Sstevel@tonic-gate if (pid == 0) { 84*0Sstevel@tonic-gate dup2(devnull, STDIN_FILENO); 85*0Sstevel@tonic-gate dup2(p[1], STDOUT_FILENO); 86*0Sstevel@tonic-gate /* Keep stderr open for errors */ 87*0Sstevel@tonic-gate close(p[0]); 88*0Sstevel@tonic-gate close(p[1]); 89*0Sstevel@tonic-gate close(devnull); 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate if (original_uid != original_euid && 92*0Sstevel@tonic-gate ( seteuid(getuid()) == -1 || 93*0Sstevel@tonic-gate setuid(original_uid) == -1) ) { 94*0Sstevel@tonic-gate fprintf(stderr, "(rand child) setuid(%d): %s\n", 95*0Sstevel@tonic-gate original_uid, strerror(errno)); 96*0Sstevel@tonic-gate _exit(1); 97*0Sstevel@tonic-gate } 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate execl(SSH_RAND_HELPER, "ssh-rand-helper", NULL); 100*0Sstevel@tonic-gate fprintf(stderr, "(rand child) Couldn't exec '%s': %s\n", 101*0Sstevel@tonic-gate SSH_RAND_HELPER, strerror(errno)); 102*0Sstevel@tonic-gate _exit(1); 103*0Sstevel@tonic-gate } 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate close(devnull); 106*0Sstevel@tonic-gate close(p[1]); 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate memset(buf, '\0', sizeof(buf)); 109*0Sstevel@tonic-gate ret = atomicio(read, p[0], buf, sizeof(buf)); 110*0Sstevel@tonic-gate if (ret == -1) 111*0Sstevel@tonic-gate fatal("Couldn't read from ssh-rand-helper: %s", 112*0Sstevel@tonic-gate strerror(errno)); 113*0Sstevel@tonic-gate if (ret != sizeof(buf)) 114*0Sstevel@tonic-gate fatal("ssh-rand-helper child produced insufficient data"); 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate close(p[0]); 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gate if (waitpid(pid, &ret, 0) == -1) 119*0Sstevel@tonic-gate fatal("Couldn't wait for ssh-rand-helper completion: %s", 120*0Sstevel@tonic-gate strerror(errno)); 121*0Sstevel@tonic-gate mysignal(SIGCHLD, old_sigchld); 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate /* We don't mind if the child exits upon a SIGPIPE */ 124*0Sstevel@tonic-gate if (!WIFEXITED(ret) && 125*0Sstevel@tonic-gate (!WIFSIGNALED(ret) || WTERMSIG(ret) != SIGPIPE)) 126*0Sstevel@tonic-gate fatal("ssh-rand-helper terminated abnormally"); 127*0Sstevel@tonic-gate if (WEXITSTATUS(ret) != 0) 128*0Sstevel@tonic-gate fatal("ssh-rand-helper exit with exit status %d", ret); 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate RAND_add(buf, sizeof(buf), sizeof(buf)); 131*0Sstevel@tonic-gate memset(buf, '\0', sizeof(buf)); 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate #endif /* OPENSSL_PRNG_ONLY */ 134*0Sstevel@tonic-gate if (RAND_status() != 1) 135*0Sstevel@tonic-gate fatal("PRNG is not seeded"); 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate void 139*0Sstevel@tonic-gate init_rng(void) 140*0Sstevel@tonic-gate { 141*0Sstevel@tonic-gate /* 142*0Sstevel@tonic-gate * OpenSSL version numbers: MNNFFPPS: major minor fix patch status 143*0Sstevel@tonic-gate * We match major, minor, fix and status (not patch) 144*0Sstevel@tonic-gate */ 145*0Sstevel@tonic-gate if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) 146*0Sstevel@tonic-gate fatal("OpenSSL version mismatch. Built against %lx, you " 147*0Sstevel@tonic-gate "have %lx", OPENSSL_VERSION_NUMBER, SSLeay()); 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate #ifndef OPENSSL_PRNG_ONLY 150*0Sstevel@tonic-gate if ((original_uid = getuid()) == -1) 151*0Sstevel@tonic-gate fatal("getuid: %s", strerror(errno)); 152*0Sstevel@tonic-gate if ((original_euid = geteuid()) == -1) 153*0Sstevel@tonic-gate fatal("geteuid: %s", strerror(errno)); 154*0Sstevel@tonic-gate #endif 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157