# extended support for (re-)seeding the OpenSSL PRNG from /dev/random # bnc#703221, FATE#312172 diff --git a/openssh-6.6p1/audit-bsm.c b/openssh-6.6p1/audit-bsm.c --- a/openssh-6.6p1/audit-bsm.c +++ b/openssh-6.6p1/audit-bsm.c @@ -504,9 +504,15 @@ audit_destroy_sensitive_data(const char /* not implemented */ } void audit_generate_ephemeral_server_key(const char *fp) { /* not implemented */ } + +void +audit_linux_prng_seed(long bytes, const char *rf) +{ + /* not implemented */ +} #endif /* BSM */ diff --git a/openssh-6.6p1/audit-linux.c b/openssh-6.6p1/audit-linux.c --- a/openssh-6.6p1/audit-linux.c +++ b/openssh-6.6p1/audit-linux.c @@ -398,9 +398,31 @@ audit_generate_ephemeral_server_key(cons } audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL, 0, NULL, 1); audit_close(audit_fd); /* do not abort if the error is EPERM and sshd is run as non root user */ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) error("cannot write into audit"); } + +void +audit_linux_prng_seed(long bytes, const char *rf) +{ + char buf[AUDIT_LOG_SIZE]; + int audit_fd, audit_ok; + + snprintf(buf, sizeof(buf), "op=prng_seed kind=server bytes=%li source=%s ", bytes, rf); + audit_fd = audit_open(); + if (audit_fd < 0) { + if (errno != EINVAL && errno != EPROTONOSUPPORT && + errno != EAFNOSUPPORT) + error("cannot open audit"); + return; + } + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_PARAM_CHANGE_USER, + buf, NULL, 0, NULL, 1); + audit_close(audit_fd); + /* do not abort if the error is EPERM and sshd is run as non root user */ + if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0))) + error("cannot write into audit"); +} #endif /* USE_LINUX_AUDIT */ diff --git a/openssh-6.6p1/audit.c b/openssh-6.6p1/audit.c --- a/openssh-6.6p1/audit.c +++ b/openssh-6.6p1/audit.c @@ -304,10 +304,16 @@ audit_destroy_sensitive_data(const char /* * This will be called on generation of the ephemeral server key */ void audit_generate_ephemeral_server_key(const char *) { debug("audit create ephemeral server key euid %d fingerprint %s", geteuid(), fp); } + +void +audit_linux_prng_seed(long bytes, const char *rf) +{ + debug("audit PRNG seed euid %d bytes %li source %s", geteuid(), bytes, rf); +} # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ #endif /* SSH_AUDIT_EVENTS */ diff --git a/openssh-6.6p1/audit.h b/openssh-6.6p1/audit.h --- a/openssh-6.6p1/audit.h +++ b/openssh-6.6p1/audit.h @@ -63,10 +63,11 @@ void audit_key(int, int *, const Key *); void audit_unsupported(int); void audit_kex(int, char *, char *, char *); void audit_unsupported_body(int); void audit_kex_body(int, char *, char *, char *, pid_t, uid_t); void audit_session_key_free(int ctos); void audit_session_key_free_body(int ctos, pid_t, uid_t); void audit_destroy_sensitive_data(const char *, pid_t, uid_t); void audit_generate_ephemeral_server_key(const char *); +void audit_linux_prng_seed(long, const char *); #endif /* _SSH_AUDIT_H */ diff --git a/openssh-6.6p1/entropy.c b/openssh-6.6p1/entropy.c --- a/openssh-6.6p1/entropy.c +++ b/openssh-6.6p1/entropy.c @@ -45,16 +45,17 @@ #include "ssh.h" #include "misc.h" #include "xmalloc.h" #include "atomicio.h" #include "pathnames.h" #include "log.h" #include "buffer.h" +#include "openbsd-compat/port-linux.h" /* * Portable OpenSSH PRNG seeding: * If OpenSSL has not "internally seeded" itself (e.g. pulled data from * /dev/random), then collect RANDOM_SEED_SIZE bytes of randomness from * PRNGd. */ #ifndef OPENSSL_PRNG_ONLY @@ -229,11 +230,14 @@ seed_rng(void) } if (seed_from_prngd(buf, sizeof(buf)) == -1) fatal("Could not obtain seed from PRNGd"); RAND_add(buf, sizeof(buf), sizeof(buf)); memset(buf, '\0', sizeof(buf)); #endif /* OPENSSL_PRNG_ONLY */ + + linux_seed(); + if (RAND_status() != 1) fatal("PRNG is not seeded"); } diff --git a/openssh-6.6p1/openbsd-compat/Makefile.in b/openssh-6.6p1/openbsd-compat/Makefile.in --- a/openssh-6.6p1/openbsd-compat/Makefile.in +++ b/openssh-6.6p1/openbsd-compat/Makefile.in @@ -15,17 +15,17 @@ AR=@AR@ RANLIB=@RANLIB@ INSTALL=@INSTALL@ LDFLAGS=-L. @LDFLAGS@ OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o realpath.o rresvport.o setenv.o setproctitle.o sha2.o sigact.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xmmap.o xcrypt.o -PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o +PORTS=port-aix.o port-irix.o port-linux.o port-linux-prng.o port-solaris.o port-tun.o port-uw.o .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c $< all: libopenbsd-compat.a $(COMPAT): ../config.h $(OPENBSD): ../config.h diff --git a/openssh-6.6p1/openbsd-compat/port-linux-prng.c b/openssh-6.6p1/openbsd-compat/port-linux-prng.c new file mode 100644 --- /dev/null +++ b/openssh-6.6p1/openbsd-compat/port-linux-prng.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011 Jan F. Chadima + * (c) 2011 Petr Cerny + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Linux-specific portability code - prng support + */ + +#include "includes.h" +#include "defines.h" + +#include +#include +#include +#include +#include + +#include "log.h" +#include "port-linux.h" +#include "audit.h" + +#define RNG_BYTES_DEFAULT 6L +#define RNG_ENV_VAR "SSH_USE_STRONG_RNG" + +long rand_bytes = 0; +char *rand_file = NULL; + +static void +linux_seed_init(void) +{ + long elen = 0; + char *env = getenv(RNG_ENV_VAR); + + if (env) { + errno = 0; + elen = strtol(env, NULL, 10); + if (errno) { + debug("bogus value in the %s environment variable, using default %li\n", + RNG_ENV_VAR, RNG_BYTES_DEFAULT); + } + } + + if (elen) + rand_file = "/dev/random"; + else + rand_file = "/dev/urandom"; + + rand_bytes = MAX(elen, RNG_BYTES_DEFAULT); +} + +void +linux_seed(void) +{ + long len; + if (!rand_file) + linux_seed_init(); + + errno = 0; + len = RAND_load_file(rand_file, rand_bytes); + if (len != rand_bytes) { + if (errno) + fatal ("cannot read from %s, %s", random, strerror(errno)); + else + fatal ("EOF reading %s", random); + } +} diff --git a/openssh-6.6p1/openbsd-compat/port-linux.h b/openssh-6.6p1/openbsd-compat/port-linux.h --- a/openssh-6.6p1/openbsd-compat/port-linux.h +++ b/openssh-6.6p1/openbsd-compat/port-linux.h @@ -14,16 +14,20 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _PORT_LINUX_H #define _PORT_LINUX_H +extern long rand_bytes; +extern char *rand_file; +void linux_seed(void); + #ifdef WITH_SELINUX int ssh_selinux_enabled(void); void ssh_selinux_setup_pty(char *, const char *); void ssh_selinux_setup_exec_context(char *); void ssh_selinux_change_context(const char *); void ssh_selinux_setfscreatecon(const char *); #endif diff --git a/openssh-6.6p1/ssh-add.1 b/openssh-6.6p1/ssh-add.1 --- a/openssh-6.6p1/ssh-add.1 +++ b/openssh-6.6p1/ssh-add.1 @@ -156,16 +156,30 @@ or related script. (Note that on some machines it may be necessary to redirect the input from .Pa /dev/null to make this work.) .It Ev SSH_AUTH_SOCK Identifies the path of a .Ux Ns -domain socket used to communicate with the agent. +.It Ev SSH_USE_STRONG_RNG +The reseeding of the OpenSSL random generator is usually done from +.Cm /dev/urandom . +If the +.Cm SSH_USE_STRONG_RNG +environment variable is set to value other than +.Cm 0 +the OpenSSL random generator is reseeded from +.Cm /dev/random . +The number of bytes read is defined by the SSH_USE_STRONG_RNG value. +Minimum is 6 bytes. +This setting is not recommended on the computers without the hardware +random generator because insufficient entropy causes the connection to +be blocked until enough entropy is available. .El .Sh FILES .Bl -tag -width Ds .It Pa ~/.ssh/identity Contains the protocol version 1 RSA authentication identity of the user. .It Pa ~/.ssh/id_dsa Contains the protocol version 2 DSA authentication identity of the user. .It Pa ~/.ssh/id_ecdsa diff --git a/openssh-6.6p1/ssh-agent.1 b/openssh-6.6p1/ssh-agent.1 --- a/openssh-6.6p1/ssh-agent.1 +++ b/openssh-6.6p1/ssh-agent.1 @@ -196,16 +196,33 @@ Contains the protocol version 2 ED25519 .It Pa ~/.ssh/id_rsa Contains the protocol version 2 RSA authentication identity of the user. .It Pa $TMPDIR/ssh-XXXXXXXXXX/agent.\*(Ltppid\*(Gt .Ux Ns -domain sockets used to contain the connection to the authentication agent. These sockets should only be readable by the owner. The sockets should get automatically removed when the agent exits. .El +.Sh ENVIRONMENT +.Bl -tag -width Ds -compact +.Pp +.It Pa SSH_USE_STRONG_RNG +The reseeding of the OpenSSL random generator is usually done from +.Cm /dev/urandom . +If the +.Cm SSH_USE_STRONG_RNG +environment variable is set to value other than +.Cm 0 +the OpenSSL random generator is reseeded from +.Cm /dev/random . +The number of bytes read is defined by the SSH_USE_STRONG_RNG value. +Minimum is 6 bytes. +This setting is not recommended on the computers without the hardware +random generator because insufficient entropy causes the connection to +be blocked until enough entropy is available. .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-keygen 1 , .Xr sshd 8 .Sh AUTHORS OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. diff --git a/openssh-6.6p1/ssh-keygen.1 b/openssh-6.6p1/ssh-keygen.1 --- a/openssh-6.6p1/ssh-keygen.1 +++ b/openssh-6.6p1/ssh-keygen.1 @@ -827,16 +827,33 @@ on all machines where the user wishes to log in using public key authentication. There is no need to keep the contents of this file secret. .Pp .It Pa /etc/moduli Contains Diffie-Hellman groups used for DH-GEX. The file format is described in .Xr moduli 5 . .El +.Sh ENVIRONMENT +.Bl -tag -width Ds -compact +.Pp +.It Pa SSH_USE_STRONG_RNG +The reseeding of the OpenSSL random generator is usually done from +.Cm /dev/urandom . +If the +.Cm SSH_USE_STRONG_RNG +environment variable is set to value other than +.Cm 0 +the OpenSSL random generator is reseeded from +.Cm /dev/random . +The number of bytes read is defined by the SSH_USE_STRONG_RNG value. +Minimum is 6 bytes. +This setting is not recommended on the computers without the hardware +random generator because insufficient entropy causes the connection to +be blocked until enough entropy is available. .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-agent 1 , .Xr moduli 5 , .Xr sshd 8 .Rs .%R RFC 4716 diff --git a/openssh-6.6p1/ssh-keysign.8 b/openssh-6.6p1/ssh-keysign.8 --- a/openssh-6.6p1/ssh-keysign.8 +++ b/openssh-6.6p1/ssh-keysign.8 @@ -75,16 +75,33 @@ must be set-uid root if host-based authe .Pp .It Pa /etc/ssh/ssh_host_dsa_key-cert.pub .It Pa /etc/ssh/ssh_host_ecdsa_key-cert.pub .It Pa /etc/ssh/ssh_host_ed25519_key-cert.pub .It Pa /etc/ssh/ssh_host_rsa_key-cert.pub If these files exist they are assumed to contain public certificate information corresponding with the private keys above. .El +.Sh ENVIRONMENT +.Bl -tag -width Ds -compact +.Pp +.It Pa SSH_USE_STRONG_RNG +The reseeding of the OpenSSL random generator is usually done from +.Cm /dev/urandom . +If the +.Cm SSH_USE_STRONG_RNG +environment variable is set to value other than +.Cm 0 +the OpenSSL random generator is reseeded from +.Cm /dev/random . +The number of bytes read is defined by the SSH_USE_STRONG_RNG value. +Minimum is 6 bytes. +This setting is not recommended on the computers without the hardware +random generator because insufficient entropy causes the connection to +be blocked until enough entropy is available. .Sh SEE ALSO .Xr ssh 1 , .Xr ssh-keygen 1 , .Xr ssh_config 5 , .Xr sshd 8 .Sh HISTORY .Nm first appeared in diff --git a/openssh-6.6p1/ssh.1 b/openssh-6.6p1/ssh.1 --- a/openssh-6.6p1/ssh.1 +++ b/openssh-6.6p1/ssh.1 @@ -1304,16 +1304,30 @@ reads and adds lines of the format .Dq VARNAME=value to the environment if the file exists and users are allowed to change their environment. For more information, see the .Cm PermitUserEnvironment option in .Xr sshd_config 5 . +.It Ev SSH_USE_STRONG_RNG +The reseeding of the OpenSSL random generator is usually done from +.Cm /dev/urandom . +If the +.Cm SSH_USE_STRONG_RNG +environment variable is set to value other than +.Cm 0 +the OpenSSL random generator is reseeded from +.Cm /dev/random . +The number of bytes read is defined by the SSH_USE_STRONG_RNG value. +Minimum is 6 bytes. +This setting is not recommended on the computers without the hardware +random generator because insufficient entropy causes the connection to +be blocked until enough entropy is available. .Sh FILES .Bl -tag -width Ds -compact .It Pa ~/.rhosts This file is used for host-based authentication (see above). On some machines this file may need to be world-readable if the user's home directory is on an NFS partition, because .Xr sshd 8 diff --git a/openssh-6.6p1/sshd.8 b/openssh-6.6p1/sshd.8 --- a/openssh-6.6p1/sshd.8 +++ b/openssh-6.6p1/sshd.8 @@ -946,16 +946,33 @@ and not group or world-writable. .It Pa /var/run/sshd.pid Contains the process ID of the .Nm listening for connections (if there are several daemons running concurrently for different ports, this contains the process ID of the one started last). The content of this file is not sensitive; it can be world-readable. .El +.Sh ENVIRONMENT +.Bl -tag -width Ds -compact +.Pp +.It Pa SSH_USE_STRONG_RNG +The reseeding of the OpenSSL random generator is usually done from +.Cm /dev/urandom . +If the +.Cm SSH_USE_STRONG_RNG +environment variable is set to value other than +.Cm 0 +the OpenSSL random generator is reseeded from +.Cm /dev/random . +The number of bytes read is defined by the SSH_USE_STRONG_RNG value. +Minimum is 6 bytes. +This setting is not recommended on the computers without the hardware +random generator because insufficient entropy causes the connection to +be blocked until enough entropy is available. .Sh SEE ALSO .Xr scp 1 , .Xr sftp 1 , .Xr ssh 1 , .Xr ssh-add 1 , .Xr ssh-agent 1 , .Xr ssh-keygen 1 , .Xr ssh-keyscan 1 , diff --git a/openssh-6.6p1/sshd.c b/openssh-6.6p1/sshd.c --- a/openssh-6.6p1/sshd.c +++ b/openssh-6.6p1/sshd.c @@ -50,16 +50,18 @@ #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #include "openbsd-compat/sys-tree.h" #include "openbsd-compat/sys-queue.h" +#include "openbsd-compat/port-linux.h" + #include #include #include #include #ifdef HAVE_PATHS_H #include #endif @@ -218,16 +220,23 @@ struct { Key **host_pubkeys; /* all public host keys */ Key **host_certificates; /* all public host certificates */ int have_ssh1_key; int have_ssh2_key; u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; } sensitive_data; /* + * Every RESEED_AFTERth connection triggers call to linux_seed() to re-seed the + * random pool. + */ +#define RESEED_AFTER 100 +static int re_seeding_counter = RESEED_AFTER; + +/* * Flag indicating whether the RSA server key needs to be regenerated. * Is set in the SIGALRM handler and cleared when the key is regenerated. */ static volatile sig_atomic_t key_do_regen = 0; /* This is set to true when a signal is received. */ static volatile sig_atomic_t received_sighup = 0; static volatile sig_atomic_t received_sigterm = 0; @@ -1322,16 +1331,21 @@ server_accept_loop(int *sock_in, int *so for (j = 0; j < options.max_startups; j++) if (startup_pipes[j] == -1) { startup_pipes[j] = startup_p[0]; if (maxfd < startup_p[0]) maxfd = startup_p[0]; startups++; break; } + if(!(--re_seeding_counter)) { + re_seeding_counter = RESEED_AFTER; + linux_seed(); + audit_linux_prng_seed(rand_bytes, rand_file); + } /* * Got connection. Fork a child to handle it, unless * we are in debugging mode. */ if (debug_flag) { /* * In debugging mode. Close the listening