summaryrefslogtreecommitdiffstats
path: root/src/tls/tls_prng_exch.c
blob: 31523a35279ac5bd6517d8a0f0eac0e3657de3b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*++
/* NAME
/*	tls_prng_exch 3
/* SUMMARY
/*	maintain PRNG exchange file
/* SYNOPSIS
/*	#include <tls_prng_src.h>
/*
/*	TLS_PRNG_SRC *tls_prng_exch_open(name, timeout)
/*	const char *name;
/*	int	timeout;
/*
/*	void	tls_prng_exch_update(fh, length)
/*	TLS_PRNG_SRC *fh;
/*	size_t length;
/*
/*	void	tls_prng_exch_close(fh)
/*	TLS_PRNG_SRC *fh;
/* DESCRIPTION
/*	tls_prng_exch_open() opens the specified PRNG exchange file
/*	and returns a handle that should be used with all subsequent
/*	access.
/*
/*	tls_prng_exch_update() reads the requested number of bytes
/*	from the PRNG exchange file, updates the OpenSSL PRNG, and
/*	writes the requested number of bytes to the exchange file.
/*	The file is locked for exclusive access.
/*
/*	tls_prng_exch_close() closes the specified PRNG exchange
/*	file and releases memory that was allocated for the handle.
/*
/*	Arguments:
/* .IP name
/*	The name of the PRNG exchange file.
/* .IP length
/*	The number of bytes to read from/write to the entropy file.
/* .IP timeout
/*	Time limit on individual I/O operations.
/* DIAGNOSTICS
/*	All errors are fatal.
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*--*/

/* System library. */

#include <sys_defs.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>

/* OpenSSL library. */

#ifdef USE_TLS
#include <openssl/rand.h>		/* For the PRNG */

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <iostuff.h>
#include <myflock.h>

/* TLS library. */

#include <tls_prng.h>

/* Application specific. */

#define TLS_PRNG_EXCH_SIZE	1024	/* XXX Why not configurable? */

/* tls_prng_exch_open - open PRNG exchange file */

TLS_PRNG_SRC *tls_prng_exch_open(const char *name)
{
    const char *myname = "tls_prng_exch_open";
    TLS_PRNG_SRC *eh;
    int     fd;

    if ((fd = open(name, O_RDWR | O_CREAT, 0600)) < 0)
	msg_fatal("%s: cannot open PRNG exchange file %s: %m", myname, name);
    eh = (TLS_PRNG_SRC *) mymalloc(sizeof(*eh));
    eh->fd = fd;
    eh->name = mystrdup(name);
    eh->timeout = 0;
    if (msg_verbose)
	msg_info("%s: opened PRNG exchange file %s", myname, name);
    return (eh);
}

/* tls_prng_exch_update - update PRNG exchange file */

void    tls_prng_exch_update(TLS_PRNG_SRC *eh)
{
    unsigned char buffer[TLS_PRNG_EXCH_SIZE];
    ssize_t count;

    /*
     * Update the PRNG exchange file. Since other processes may have added
     * entropy, we use a read-stir-write cycle.
     */
    if (myflock(eh->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) != 0)
	msg_fatal("cannot lock PRNG exchange file %s: %m", eh->name);
    if (lseek(eh->fd, 0, SEEK_SET) < 0)
	msg_fatal("cannot seek PRNG exchange file %s: %m", eh->name);
    if ((count = read(eh->fd, buffer, sizeof(buffer))) < 0)
	msg_fatal("cannot read PRNG exchange file %s: %m", eh->name);

    if (count > 0)
	RAND_seed(buffer, count);
    RAND_bytes(buffer, sizeof(buffer));

    if (lseek(eh->fd, 0, SEEK_SET) < 0)
	msg_fatal("cannot seek PRNG exchange file %s: %m", eh->name);
    if (write(eh->fd, buffer, sizeof(buffer)) != sizeof(buffer))
	msg_fatal("cannot write PRNG exchange file %s: %m", eh->name);
    if (myflock(eh->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) != 0)
	msg_fatal("cannot unlock PRNG exchange file %s: %m", eh->name);
}

/* tls_prng_exch_close - close PRNG exchange file */

void    tls_prng_exch_close(TLS_PRNG_SRC *eh)
{
    const char *myname = "tls_prng_exch_close";

    if (close(eh->fd) < 0)
	msg_fatal("close PRNG exchange file %s: %m", eh->name);
    if (msg_verbose)
	msg_info("%s: closed PRNG exchange file %s", myname, eh->name);
    myfree(eh->name);
    myfree((void *) eh);
}

#endif