1/*	$NetBSD: tls_prng_exch.c,v 1.2 2017/02/14 01:16:48 christos Exp $	*/
2
3/*++
4/* NAME
5/*	tls_prng_exch 3
6/* SUMMARY
7/*	maintain PRNG exchange file
8/* SYNOPSIS
9/*	#include <tls_prng_src.h>
10/*
11/*	TLS_PRNG_SRC *tls_prng_exch_open(name, timeout)
12/*	const char *name;
13/*	int	timeout;
14/*
15/*	void	tls_prng_exch_update(fh, length)
16/*	TLS_PRNG_SRC *fh;
17/*	size_t length;
18/*
19/*	void	tls_prng_exch_close(fh)
20/*	TLS_PRNG_SRC *fh;
21/* DESCRIPTION
22/*	tls_prng_exch_open() opens the specified PRNG exchange file
23/*	and returns a handle that should be used with all subsequent
24/*	access.
25/*
26/*	tls_prng_exch_update() reads the requested number of bytes
27/*	from the PRNG exchange file, updates the OpenSSL PRNG, and
28/*	writes the requested number of bytes to the exchange file.
29/*	The file is locked for exclusive access.
30/*
31/*	tls_prng_exch_close() closes the specified PRNG exchange
32/*	file and releases memory that was allocated for the handle.
33/*
34/*	Arguments:
35/* .IP name
36/*	The name of the PRNG exchange file.
37/* .IP length
38/*	The number of bytes to read from/write to the entropy file.
39/* .IP timeout
40/*	Time limit on individual I/O operations.
41/* DIAGNOSTICS
42/*	All errors are fatal.
43/* LICENSE
44/* .ad
45/* .fi
46/*	The Secure Mailer license must be distributed with this software.
47/* AUTHOR(S)
48/*	Wietse Venema
49/*	IBM T.J. Watson Research
50/*	P.O. Box 704
51/*	Yorktown Heights, NY 10598, USA
52/*--*/
53
54/* System library. */
55
56#include <sys_defs.h>
57#include <fcntl.h>
58#include <unistd.h>
59#include <limits.h>
60
61/* OpenSSL library. */
62
63#ifdef USE_TLS
64#include <openssl/rand.h>		/* For the PRNG */
65
66/* Utility library. */
67
68#include <msg.h>
69#include <mymalloc.h>
70#include <iostuff.h>
71#include <myflock.h>
72
73/* TLS library. */
74
75#include <tls_prng.h>
76
77/* Application specific. */
78
79#define TLS_PRNG_EXCH_SIZE	1024	/* XXX Why not configurable? */
80
81/* tls_prng_exch_open - open PRNG exchange file */
82
83TLS_PRNG_SRC *tls_prng_exch_open(const char *name)
84{
85    const char *myname = "tls_prng_exch_open";
86    TLS_PRNG_SRC *eh;
87    int     fd;
88
89    if ((fd = open(name, O_RDWR | O_CREAT, 0600)) < 0)
90	msg_fatal("%s: cannot open PRNG exchange file %s: %m", myname, name);
91    eh = (TLS_PRNG_SRC *) mymalloc(sizeof(*eh));
92    eh->fd = fd;
93    eh->name = mystrdup(name);
94    eh->timeout = 0;
95    if (msg_verbose)
96	msg_info("%s: opened PRNG exchange file %s", myname, name);
97    return (eh);
98}
99
100/* tls_prng_exch_update - update PRNG exchange file */
101
102void    tls_prng_exch_update(TLS_PRNG_SRC *eh)
103{
104    unsigned char buffer[TLS_PRNG_EXCH_SIZE];
105    ssize_t count;
106
107    /*
108     * Update the PRNG exchange file. Since other processes may have added
109     * entropy, we use a read-stir-write cycle.
110     */
111    if (myflock(eh->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) != 0)
112	msg_fatal("cannot lock PRNG exchange file %s: %m", eh->name);
113    if (lseek(eh->fd, 0, SEEK_SET) < 0)
114	msg_fatal("cannot seek PRNG exchange file %s: %m", eh->name);
115    if ((count = read(eh->fd, buffer, sizeof(buffer))) < 0)
116	msg_fatal("cannot read PRNG exchange file %s: %m", eh->name);
117
118    if (count > 0)
119	RAND_seed(buffer, count);
120    RAND_bytes(buffer, sizeof(buffer));
121
122    if (lseek(eh->fd, 0, SEEK_SET) < 0)
123	msg_fatal("cannot seek PRNG exchange file %s: %m", eh->name);
124    if (write(eh->fd, buffer, sizeof(buffer)) != sizeof(buffer))
125	msg_fatal("cannot write PRNG exchange file %s: %m", eh->name);
126    if (myflock(eh->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) != 0)
127	msg_fatal("cannot unlock PRNG exchange file %s: %m", eh->name);
128}
129
130/* tls_prng_exch_close - close PRNG exchange file */
131
132void    tls_prng_exch_close(TLS_PRNG_SRC *eh)
133{
134    const char *myname = "tls_prng_exch_close";
135
136    if (close(eh->fd) < 0)
137	msg_fatal("close PRNG exchange file %s: %m", eh->name);
138    if (msg_verbose)
139	msg_info("%s: closed PRNG exchange file %s", myname, eh->name);
140    myfree(eh->name);
141    myfree((void *) eh);
142}
143
144#endif
145