--ELM724514011-16567-0_
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Attached is a patch that includes some SSL cleanup and adds support for
client certificates. The visible changes are:
1) postmaster logs anonymous SSL connections:
DEBUG: SSL connection from (anonymous) with cipher EDH-RSA-DES-CBC3-SHA
2) postmaster logs SSL connections with client certificates:
DEBUG: SSL connection from Bear Giles with cipher EDH-RSA-DES-CBC3-SHA
(The postmaster will also log any errors in the certificate.)
3) libpq recognizes two new environment variables/configuration file
options
PQCLIENTCERT: pathname of client certificate
PQCLIENTKEY: pathname of client key
At the current time, only unencrypted keys are supported.
There is a prototype callback that prompts the user for an
encryption passphrase, but it's not yet activated.
For security reasons, the key file must be a regular file
that is not world- or group-accessible. It should also be
owned by the server or user, but this is not yet checked.
The client cert, if provided, is available at 'port->peer', but
this value is not yet used to map a client cert into a PostgreSQL
user.
The patch also provides some cleanup of the SSL calls:
1) proper error checking for SSL_read() and SSL_write().
(You need to call SSL_get_error(), not just check the system
errno.)
2) proper shutdown of the SSL connection, at least on the client
side. Simply closing the socket is a sadly common error.
(SSL_shutdown()).
3) Empheral DH keys have been added, with fallbacks provided from
the OpenSSL source code.
4) keys must be regular files and not world- or group-accessible.
They should also be owned by the postmaster or client, but I
haven't added that test yet.
Unfortunately the error messages if the permissions tests fail
are cryptic at best. This definitely needs improvement!
Some serious work remains:
1) we should move towards TLSv1 instead of SSLv3 or SSLv2.
But this may have unforeseen consequences so we should make
sure everything else is working well first.
2) we need to provide a way to specify a good entropy source,
if one is available.
3) we need to provide a trigger to renegotiate the session key.
(E.g., renegotiate the session key after N hours or X megabytes
of data.)
4) certificates should be better validated.
5) backend/libpq/hba.c needs to be extended to support mapping
from client cert to database identity.
Bear
--ELM724514011-16567-0_
Content-Type: text/plain; charset=US-ASCII
Content-Disposition: attachment; filename=diff
Content-Description: /tmp/diff
Content-Transfer-Encoding: 7bit
--- postgresql-7.2.1.orig/src/include/libpq/libpq-be.h Sun Nov 11 22:43:25 2001
*/
#ifdef USE_SSL
SSL *ssl;
+ X509 *peer;
#endif
} Port;
--- postgresql-7.2.1.orig/src/interfaces/libpq/fe-misc.c Sun Dec 2 17:28:24 2001
#include "mb/pg_wchar.h"
#endif
+#ifdef USE_SSL
+#include <openssl/e_os.h>
+#endif
#define DONOTICE(conn,message) \
tryAgain:
#ifdef USE_SSL
if (conn->ssl)
+ {
nread = SSL_read(conn->ssl, conn->inBuffer + conn->inEnd,
conn->inBufSize - conn->inEnd);
+ switch(SSL_get_error(conn->ssl, nread))
+ {
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ /* blocked */
+ break;
+ case SSL_ERROR_SYSCALL:
+ SOCK_ERRNO = get_last_socket_error();
+ break;
+ case SSL_ERROR_SSL:
+ /* ERR_print_errors() */
+ SOCK_ERRNO = ECONNRESET;
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ SOCK_ERRNO = ECONNRESET;
+ break;
+ }
+ }
else
#endif
tryAgain2:
#ifdef USE_SSL
if (conn->ssl)
+ {
nread = SSL_read(conn->ssl, conn->inBuffer + conn->inEnd,
conn->inBufSize - conn->inEnd);
+ switch(SSL_get_error(conn->ssl, nread))
+ {
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ /* blocked */
+ break;
+ case SSL_ERROR_SYSCALL:
+ SOCK_ERRNO = get_last_socket_error();
+ break;
+ case SSL_ERROR_SSL:
+ /* ERR_print_errors() */
+ SOCK_ERRNO = ECONNRESET;
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ SOCK_ERRNO = ECONNRESET;
+ break;
+ }
+ }
else
#endif
#ifdef USE_SSL
if (conn->ssl)
+ {
sent = SSL_write(conn->ssl, ptr, len);
+ switch(SSL_get_error(conn->ssl, sent))
+ {
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ /* blocked */
+ break;
+ case SSL_ERROR_SYSCALL:
+ SOCK_ERRNO = get_last_socket_error();
+ break;
+ case SSL_ERROR_SSL:
+ /* ERR_print_errors() */
+ SOCK_ERRNO = ECONNRESET;
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ SOCK_ERRNO = ECONNRESET;
+ break;
+ }
+ }
else
#endif
sent = send(conn->sock, ptr, len, 0);
--- postgresql-7.2.1.orig/src/interfaces/libpq/fe-connect.c Sat Nov 10 19:09:05 2001
#include <errno.h>
#include <ctype.h>
+#ifdef USE_SSL
+#include <sys/stat.h>
+#include <sys/file.h>
+#endif
+
#include "libpq-fe.h"
#include "libpq-int.h"
#ifdef USE_SSL
static SSL_CTX *SSL_context = NULL;
+static int clientCertCB(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
+static int cliPasswordCB(char *buf, int size, int rwflag, void *userdata);
#endif
#ifdef USE_SSL
{"requiressl", "PGREQUIRESSL", "0", NULL,
"Require-SSL", "", 1},
+
+ {"clientcert", "PGCLIENTCERT", NULL, NULL,
+ "Client-Cert", "", 80},
+
+ {"clientkey", "PGCLIENTKEY", NULL, NULL,
+ "Client-Key", "", 80},
#endif
#ifdef USE_SSL
tmp = conninfo_getval(connOptions, "requiressl");
conn->require_ssl = tmp ? (tmp[0] == '1' ? true : false) : false;
+ tmp = conninfo_getval(connOptions, "clientcert");
+ conn->client_cert = tmp ? strdup(tmp) : NULL;
+ tmp = conninfo_getval(connOptions, "clientkey");
+ conn->client_key = tmp ? strdup(tmp) : NULL;
+ /* for now, require unencrypted client keys */
+ conn->clientKeyCB = NULL; /* type is pem_passwd_cb */
#endif
conn->require_ssl = (tmp[0] == '1') ? true : false;
else
conn->require_ssl = 0;
+ if ((tmp = getenv("PGCLIENTCERT")) != NULL)
+ conn->client_cert = strdup(tmp);
+ else
+ conn->client_cert = NULL;
+ if ((tmp = getenv("PGCLIENTKEY")) != NULL)
+ conn->client_key = strdup(tmp);
+ else
+ conn->client_key = NULL;
+ /* for now, require unencrypted client keys */
+ conn->clientKeyCB = NULL; /* type is pem_passwd_cb */
#endif
conn->pgport);
}
-
/* ----------
* connectDBStart -
SSLerrmessage());
goto connect_errReturn;
}
+ SSL_CTX_set_client_cert_cb(SSL_context, clientCertCB);
}
if (!(conn->ssl = SSL_new(SSL_context)) ||
+ !SSL_set_app_data(conn->ssl, conn) ||
!SSL_set_fd(conn->ssl, conn->sock) ||
SSL_connect(conn->ssl) <= 0)
pqClearAsyncResult(conn); /* deallocate result and curTuple */
#ifdef USE_SSL
if (conn->ssl)
+ SSL_shutdown(conn->ssl);
SSL_free(conn->ssl);
+ if (conn->client_cert)
+ free(conn->client_cert);
+ if (conn->client_key)
+ free(conn->client_key);
#endif
if (conn->sock >= 0)
/* Note: we expect the supplied string to end with a newline already. */
fprintf(stderr, "%s", message);
}
+
+#if defined USE_SSL
+/* ----------
+ * load_pkey -
+ * For security reasons, we fail if the file is not a regular file,
+ * if it's group- or world-accessible, etc. We should also verify
+ * the file's ownership.
+ * ----------
+ */
+static EVP_PKEY *load_pkey(const char *filename, pem_password_cb cb, void *u)
+{
+ int fd;
+ FILE *fp;
+ EVP_PKEY *pkey = NULL;
+ struct stat buf1, buf2;
+
+ if (lstat(filename, &buf1) == -1)
+ return NULL;
+ if (!S_ISREG(buf1.st_mode))
+ return NULL;
+ if ((buf1.st_mode & (S_IRWXG | S_IRWXO)) != 0)
+ return NULL;
+ if ((fd = open(filename, O_RDONLY)) == -1)
+ return NULL;
+ if (fstat(fd, &buf2) == -1)
+ return NULL;
+ if (buf1.st_dev != buf2.st_dev || buf1.st_ino != buf2.st_ino)
+ return NULL;
+
+ fp = fdopen(fd, "r");
+// flock(fileno(fp), LOCK_SH);
+ pkey = PEM_read_PrivateKey(fp, NULL, cb, u);
+if (pkey == NULL) { printf("pkey = null\n"); }
+// flock(fileno(fp), LOCK_UN);
+ fclose(fp);
+
+ return pkey;
+}
+
+/* ----------
+ * load_cert -
+ * Load user's certificate.
+ * ----------
+ */
+static X509 *load_cert(const char *filename)
+{
+ FILE *fp;
+ X509 *x = NULL;
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ return NULL;
+
+ flock(fileno(fp), LOCK_SH);
+ x = PEM_read_X509(fp, NULL, NULL, NULL);
+ flock(fileno(fp), LOCK_UN);
+ fclose(fp);
+if (x == NULL) { ERR_print_errors_fp(stderr); }
+
+ return x;
+}
+
+/* ----------
+ * cliPasswordCB -
+ * Callback used to prompt for password from stdin. The static buffer
+ * within getpass() is zeroed immediately after the data is copied.
+ * Returns -1 on error, otherwise the length of the password.
+ * This function isn't actually used yet.
+ * ----------
+ */
+static int
+cliPasswordCB(char *buf, int size, int rwflag, void *userdata)
+{
+ char *p;
+ int klen;
+
+ p = getpass(gettext("Password for private key: "));
+ if (p == NULL)
+ return -1;
+
+ klen = strlen(p);
+ strncpy(buf, p, size);
+ memset(p, 0, 128);
+
+ if (klen > size)
+ klen = size;
+
+ return (klen < size) ? klen : size;
+}
+
+/* ----------
+ * clientCertCB -
+ * Callback used by SSL to load client cert and key. If conn->clientKeyCB
+ * is non-null, we can support encrypted private keys ad the like.
+ * returns 1 on success, 0 on no data, -1 on error.
+ * ----------
+ */
+static int
+clientCertCB(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
+{
+ PGconn *conn;
+/* char cname[256]; */
+
+ /* this shouldn't be NULL, but if so quietly succeed. */
+ conn = SSL_get_app_data(ssl);
+ if (conn == NULL)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("connecting with anonymous connection\n"));
+ return 0;
+ }
+
+ /* if neither cert nor key is present, return success. */
+ if (conn->client_cert == NULL && conn->client_key == NULL)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("connecting with anonymous connection\n"));
+ return 0;
+ }
+
+ /* otherwise both cert and must be present. */
+ if (conn->client_cert == NULL || conn->client_key == NULL)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("both cert and key must be specified\n"));
+ return -1;
+ }
+
+ if ((*pkey = load_pkey(conn->client_key, conn->clientKeyCB, conn)) == NULL)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("load_pkey(%s) failed\n"), conn->client_key);
+ return -1;
+ }
+
+ if ((*x509 = load_cert(conn->client_cert)) == NULL)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("load_cert(%s) failed\n"), conn->client_key);
+ EVP_PKEY_free(*pkey);
+ *pkey = NULL;
+ return -1;
+ }
+
+/*
+ * X509_NAME_oneline(X509_get_subject_name(*x509), cname, sizeof cname);
+ * printfPQExpBuffer(&conn->errorMessage,
+ * libpq_gettext("connecting with client cert %s\n"), cname);
+ */
+
+ return 1;
+}
+#endif
--- postgresql-7.2.1.orig/src/backend/libpq/pqcomm.c Tue Dec 4 13:57:22 2001
#include "libpq/libpq.h"
#include "miscadmin.h"
+#ifdef USE_SSL
+#include <openssl/e_os.h>
+extern const char *SSLerrmessage(void);
+#endif
static void pq_close(void);
#ifdef USE_SSL
if (MyProcPort->ssl)
+ {
r = SSL_read(MyProcPort->ssl, PqRecvBuffer + PqRecvLength,
PQ_BUFFER_SIZE - PqRecvLength);
+ switch (SSL_get_error(MyProcPort->ssl, r))
+ {
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ /* blocked */
+ break;
+ case SSL_ERROR_SYSCALL:
+ errno = get_last_socket_error();
+ break;
+ case SSL_ERROR_SSL:
+ elog(ERROR, "SSL error: %s", SSLerrmessage());
+ errno = ECONNRESET;
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ elog(DEBUG, "SSL shutdown by peer");
+ errno = ECONNRESET;
+ break;
+ }
+ }
else
#endif
#ifdef USE_SSL
if (MyProcPort->ssl)
+ {
r = SSL_write(MyProcPort->ssl, bufptr, bufend - bufptr);
+ switch (SSL_get_error(MyProcPort->ssl, r))
+ {
+ case SSL_ERROR_NONE:
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ /* blocked */
+ break;
+ case SSL_ERROR_SYSCALL:
+ errno = get_last_socket_error();
+ break;
+ case SSL_ERROR_SSL:
+ elog(ERROR, "SSL error: %s", SSLerrmessage());
+ errno = ECONNRESET;
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ elog(DEBUG, "SSL shutdown by peer");
+ errno = ECONNRESET;
+ break;
+ }
+ }
else
#endif
r = send(MyProcPort->sock, bufptr, bufend - bufptr, 0);
--- postgresql-7.2.1.orig/src/backend/postmaster/postmaster.c Fri Mar 15 12:20:47 2002
#endif
#ifdef USE_SSL
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
static SSL_CTX *SSL_context = NULL; /* Global SSL context */
+static int postmaster_session_id_context = 1; /* anything will do */
+static int verifyCB (int ok, X509_STORE_CTX *ctx);
+static DH *load_dh_param(const char *filename);
+static EVP_PKEY *load_pkey(const char *filename);
+static X509 *load_cert(const char *filename);
+static DH *get_dh512(void);
+static DH *get_dh1024(void);
+static DH *get_dh2048(void);
+static DH *get_dh4096(void);
+static DH *tmp_dh_cb(SSL *, int, int);
#endif
#ifdef USE_SSL
static void InitSSL(void);
-static const char *SSLerrmessage(void);
+const char *SSLerrmessage(void);
#endif
enum CAC_state cac;
int32 len;
void *buf;
+#ifdef USE_SSL
+ const char *cipher = NULL;
+ char buffer[256];
+#endif
if (pq_getbytes((char *) &len, 4) == EOF)
SSLerrmessage());
return STATUS_ERROR;
}
+/* if (context)
+ * SSL_set_session_id_context(port->ssl, context,
+ * strlen((char *) context);
+ */
+/* SSL_clear(port->ssl); */
+/* SSL_set_accept_state(port->ssl); */
+
+ port->peer = SSL_get_peer_certificate(port->ssl);
+ if (port->peer == NULL)
+ strncpy(buffer, "(anonymous)", sizeof buffer);
+ else
+ {
+ X509_NAME_oneline(X509_get_subject_name(port->peer),
+ buffer, sizeof buffer);
+ }
+ cipher = SSL_CIPHER_get_name(SSL_get_current_cipher(port->ssl));
+ elog(DEBUG, "SSL connection from %s with cipher %s", buffer,
+ cipher != NULL ? cipher : "(NONE)");
+ if (SSL_ctrl(port->ssl, SSL_CTRL_GET_FLAGS, 0, NULL) &
+ TLS1_FLAGS_TLS_PADDING_BUG)
+ {
+ elog(ERROR, "Peer has incorrect TLSv1 block padding");
+ }
}
#endif
{
#ifdef USE_SSL
if (conn->ssl)
+/* this seems to shut down *all* connections, not just current one */
+/* SSL_set_shutdown(conn->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); */
SSL_free(conn->ssl);
#endif
}
#ifdef USE_SSL
-
/*
* Initialize SSL library and structures
InitSSL(void)
{
char fnbuf[2048];
+ int verify_mode = SSL_VERIFY_PEER;
+// char *inrand = NULL; // entropy source
+ char *CAfile = NULL;
+ char *CApath = NULL;
+ X509 *cert = NULL;
+ EVP_PKEY *pkey = NULL;
SSL_load_error_strings();
SSL_library_init();
+
+ /*
+ * set up an entropy source
+ * app_RAND_load_X is in openssl/apps source.
+ */
+#if 0
+ if (!app_RAND_load_file(NULL, NULL, 1) && inrand == NULL && !RAND_status())
+ {
+ postmaster_error("failed to load random: %s",
+ SSLerrmessage());
+ ExitPostmaster(1);
+ }
+ if (inrand != NULL)
+ app_RAND_load_files(inrand);
+#endif
+
+/* SSL_context = SSL_CTX_new(TLSv1_method()); */
SSL_context = SSL_CTX_new(SSLv23_method());
if (!SSL_context)
SSLerrmessage());
ExitPostmaster(1);
}
+
+ /*
+ * set up mechanism to verify certs
+ */
+ if (CAfile || CApath)
+ {
+ if (!SSL_CTX_load_verify_locations(SSL_context, CAfile, CApath) ||
+ !SSL_CTX_set_default_verify_paths(SSL_context))
+ {
+ postmaster_error("failed to load verification paths: %s",
+ SSLerrmessage());
+ ExitPostmaster(1);
+ }
+ }
+ if (CAfile != NULL)
+ {
+ SSL_CTX_set_client_CA_list(SSL_context,
+ SSL_load_client_CA_file(CAfile));
+ }
+
+ /*
+ * set up server cert and private key
+ */
snprintf(fnbuf, sizeof(fnbuf), "%s/server.crt", DataDir);
- if (!SSL_CTX_use_certificate_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
+ if ((cert = load_cert(fnbuf)) == NULL ||
+ !SSL_CTX_use_certificate(SSL_context, cert))
{
postmaster_error("failed to load server certificate (%s): %s",
fnbuf, SSLerrmessage());
ExitPostmaster(1);
}
snprintf(fnbuf, sizeof(fnbuf), "%s/server.key", DataDir);
- if (!SSL_CTX_use_PrivateKey_file(SSL_context, fnbuf, SSL_FILETYPE_PEM))
+ if ((pkey = load_pkey(fnbuf)) == NULL ||
+ !SSL_CTX_use_PrivateKey(SSL_context, pkey))
{
postmaster_error("failed to load private key file (%s): %s",
fnbuf, SSLerrmessage());
ExitPostmaster(1);
}
+ pkey = NULL;
if (!SSL_CTX_check_private_key(SSL_context))
{
postmaster_error("check of private key failed: %s",
SSLerrmessage());
ExitPostmaster(1);
}
+
+ /*
+ * make sure we use empheral DH keys
+ */
+ SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb);
+ SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE);
+
+ SSL_CTX_set_verify(SSL_context, verify_mode, verifyCB);
+
+ SSL_CTX_set_session_id_context(SSL_context,
+ (void*)&postmaster_session_id_context,
+ sizeof postmaster_session_id_context);
}
* return NULL if it doesn't recognize the error code. We don't
* want to return NULL ever.
*/
-static const char *
+const char *
SSLerrmessage(void)
{
va_end(ap);
fprintf(stderr, "\n");
}
+
+#ifdef USE_SSL
+/*
+ * Null authentication callback
+ */
+static int verifyCB (int ok, X509_STORE_CTX *ctx)
+{
+ char buf[256], buf1[256];
+ X509 *cert;
+ int err, depth, n;
+ BIO *bio;
+
+ cert = X509_STORE_CTX_get_current_cert(ctx);
+ err = X509_STORE_CTX_get_error(ctx);
+ depth= X509_STORE_CTX_get_error_depth(ctx);
+
+ X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof buf);
+ if (!ok)
+ {
+ switch (err)
+ {
+ /* accept self-signed certs */
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ ok = 1;
+ break;
+
+ default:
+ elog(ERROR,"client cert %s: %s", buf,
+ X509_verify_cert_error_string(err));
+ }
+ }
+
+ switch(ctx->error)
+ {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ X509_NAME_oneline(X509_get_issuer_name(cert), buf1, sizeof buf1);
+ elog(DEBUG, "client cert %s: cannot find issuer %s", buf, buf1);
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ bio = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(bio, X509_get_notBefore(cert));
+ BIO_flush(bio);
+ n = BIO_read(bio, buf1, sizeof(buf1)-1);
+ buf1[n] = '\0';
+ BIO_free(bio);
+ strncpy(buf, "(not yet translated)", sizeof buf);
+ elog(DEBUG, "client cert %s: not valid until %s", buf, buf1);
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ bio = BIO_new(BIO_s_mem());
+ ASN1_TIME_print(bio, X509_get_notAfter(cert));
+ BIO_flush(bio);
+ n = BIO_read(bio, buf1, sizeof(buf1)-1);
+ buf1[n] = '\0';
+ BIO_free(bio);
+ elog(DEBUG, "client cert %s: not valid after %s", buf, buf1);
+ break;
+ }
+
+ return ok;
+}
+
+/*
+ * Load the DH parameters file, if it exists.
+ */
+static DH *load_dh_param(const char *filename)
+{
+ FILE *fp;
+ DH *dh = NULL;
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ return NULL;
+
+ flock(fileno(fp), LOCK_SH);
+ dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
+ flock(fileno(fp), LOCK_UN);
+ fclose(fp);
+
+ return dh;
+}
+
+/*
+ * Load a private key.
+ * For security reasons, we fail if the file is not a regular file,
+ * if it's group- or world-accessible, etc. We should also verify
+ * the file's ownership.
+ */
+static EVP_PKEY *load_pkey(const char *filename)
+{
+ int fd;
+ FILE *fp;
+ EVP_PKEY *pkey = NULL;
+ struct stat buf1, buf2;
+
+ if (lstat(filename, &buf1) == -1)
+ return NULL;
+ if (!S_ISREG(buf1.st_mode))
+ return NULL;
+ if ((buf1.st_mode & (S_IRWXG | S_IRWXO)) != 0)
+ return NULL;
+ if ((fd = open(filename, O_RDONLY)) == -1)
+ return NULL;
+ if (fstat(fd, &buf2) == -1)
+ return NULL;
+ if (buf1.st_dev != buf2.st_dev || buf1.st_ino != buf2.st_ino)
+ return NULL;
+
+ fp = fdopen(fd, "r");
+ flock(fileno(fp), LOCK_SH);
+ pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
+ flock(fileno(fp), LOCK_UN);
+ fclose(fp);
+
+ return pkey;
+}
+
+/*
+ * Load a certificate.
+ */
+static X509 *load_cert(const char *filename)
+{
+ FILE *fp;
+ X509 *x = NULL;
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ return NULL;
+
+ flock(fileno(fp), LOCK_SH);
+ x = PEM_read_X509(fp, NULL, NULL, NULL);
+ flock(fileno(fp), LOCK_UN);
+ fclose(fp);
+
+ return x;
+}
+
+/*
+ * Generate a empheral DH key. Because this can take a long
+ * time to compute, we can use precomputed parameters of the
+ * common key sizes.
+ *
+ * N.B., see the documentation for SSL_CTX_set_tmp_dh_callback()
+ * for important notes about limitations if a DH parameter file
+ * generated from DSA keys is used.
+ */
+static DH *tmp_dh_cb (SSL *s, int is_export, int keylength)
+{
+ static DH *dh512 = NULL;
+ static DH *dh1024 = NULL;
+ static DH *dh2048 = NULL;
+ static DH *dh4096 = NULL;
+ static DH *dh = NULL;
+ char fnbuf[2048];
+
+ if (keylength == 512)
+ {
+ if (dh512 == NULL)
+ {
+ snprintf(fnbuf, sizeof(fnbuf), "%s/dh512.pem", DataDir);
+ dh512 = load_dh_param(fnbuf);
+ }
+ if (dh512 == NULL)
+ dh512 = get_dh512();
+ return dh512;
+ }
+
+ if (keylength == 1024)
+ {
+ if (dh1024 == NULL)
+ {
+ snprintf(fnbuf, sizeof(fnbuf), "%s/dh1024.pem", DataDir);
+ dh1024 = load_dh_param(fnbuf);
+ }
+ if (dh1024 == NULL)
+ dh1024 = get_dh1024();
+ return dh1024;
+ }
+
+ if (keylength == 2048)
+ {
+ if (dh2048 == NULL)
+ {
+ snprintf(fnbuf, sizeof(fnbuf), "%s/dh2048.pem", DataDir);
+ dh2048 = load_dh_param(fnbuf);
+ }
+ if (dh2048 == NULL)
+ dh2048 = get_dh2048();
+ return dh2048;
+ }
+
+ if (keylength == 4096)
+ {
+ if (dh4096 == NULL)
+ {
+ snprintf(fnbuf, sizeof(fnbuf), "%s/dh4096.pem", DataDir);
+ dh4096 = load_dh_param(fnbuf);
+ }
+ if (dh4096 == NULL)
+ dh4096 = get_dh4096();
+ return dh4096;
+ }
+
+ if (dh == NULL)
+ {
+ dh = DH_generate_parameters(keylength, 2, NULL, NULL);
+ }
+
+ return dh;
+}
+
+/*
+ * It is *highly* recommended that sites generate their own emphemeral
+ * DH parameters files with
+ *
+ * openssl dhparams -2 -rand /dev/random -out dh512.pem 512
+ *
+ * and the like during installation, with these files written into the
+ * standard DataDir.
+ *
+ * But since we all know that many sites won't bother, these routines
+ * provide fallback DH parameters distributed by the OpenSSL project.
+ */
+#ifndef HEADER_DH_H
+#include <openssl/dh.h>
+#endif
+
+static DH *get_dh512()
+ {
+ static unsigned char dh512_p[]={
+ 0xF5,0x2A,0xFF,0x3C,0xE1,0xB1,0x29,0x40,0x18,0x11,0x8D,0x7C,
+ 0x84,0xA7,0x0A,0x72,0xD6,0x86,0xC4,0x03,0x19,0xC8,0x07,0x29,
+ 0x7A,0xCA,0x95,0x0C,0xD9,0x96,0x9F,0xAB,0xD0,0x0A,0x50,0x9B,
+ 0x02,0x46,0xD3,0x08,0x3D,0x66,0xA4,0x5D,0x41,0x9F,0x9C,0x7C,
+ 0xBD,0x89,0x4B,0x22,0x19,0x26,0xBA,0xAB,0xA2,0x5E,0xC3,0x55,
+ 0xE9,0x2A,0x05,0x5F,
+ };
+ static unsigned char dh512_g[]={
+ 0x02,
+ };
+ DH *dh;
+
+ if ((dh=DH_new()) == NULL) return(NULL);
+ dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+ dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ { DH_free(dh); return(NULL); }
+ return(dh);
+ }
+
+static DH *get_dh1024()
+ {
+ static unsigned char dh1024_p[]={
+ 0xF4,0x88,0xFD,0x58,0x4E,0x49,0xDB,0xCD,0x20,0xB4,0x9D,0xE4,
+ 0x91,0x07,0x36,0x6B,0x33,0x6C,0x38,0x0D,0x45,0x1D,0x0F,0x7C,
+ 0x88,0xB3,0x1C,0x7C,0x5B,0x2D,0x8E,0xF6,0xF3,0xC9,0x23,0xC0,
+ 0x43,0xF0,0xA5,0x5B,0x18,0x8D,0x8E,0xBB,0x55,0x8C,0xB8,0x5D,
+ 0x38,0xD3,0x34,0xFD,0x7C,0x17,0x57,0x43,0xA3,0x1D,0x18,0x6C,
+ 0xDE,0x33,0x21,0x2C,0xB5,0x2A,0xFF,0x3C,0xE1,0xB1,0x29,0x40,
+ 0x18,0x11,0x8D,0x7C,0x84,0xA7,0x0A,0x72,0xD6,0x86,0xC4,0x03,
+ 0x19,0xC8,0x07,0x29,0x7A,0xCA,0x95,0x0C,0xD9,0x96,0x9F,0xAB,
+ 0xD0,0x0A,0x50,0x9B,0x02,0x46,0xD3,0x08,0x3D,0x66,0xA4,0x5D,
+ 0x41,0x9F,0x9C,0x7C,0xBD,0x89,0x4B,0x22,0x19,0x26,0xBA,0xAB,
+ 0xA2,0x5E,0xC3,0x55,0xE9,0x2F,0x78,0xC7,
+ };
+ static unsigned char dh1024_g[]={
+ 0x02,
+ };
+ DH *dh;
+
+ if ((dh=DH_new()) == NULL) return(NULL);
+ dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL);
+ dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ { DH_free(dh); return(NULL); }
+ return(dh);
+ }
+
+static DH *get_dh2048()
+ {
+ static unsigned char dh2048_p[]={
+ 0xF6,0x42,0x57,0xB7,0x08,0x7F,0x08,0x17,0x72,0xA2,0xBA,0xD6,
+ 0xA9,0x42,0xF3,0x05,0xE8,0xF9,0x53,0x11,0x39,0x4F,0xB6,0xF1,
+ 0x6E,0xB9,0x4B,0x38,0x20,0xDA,0x01,0xA7,0x56,0xA3,0x14,0xE9,
+ 0x8F,0x40,0x55,0xF3,0xD0,0x07,0xC6,0xCB,0x43,0xA9,0x94,0xAD,
+ 0xF7,0x4C,0x64,0x86,0x49,0xF8,0x0C,0x83,0xBD,0x65,0xE9,0x17,
+ 0xD4,0xA1,0xD3,0x50,0xF8,0xF5,0x59,0x5F,0xDC,0x76,0x52,0x4F,
+ 0x3D,0x3D,0x8D,0xDB,0xCE,0x99,0xE1,0x57,0x92,0x59,0xCD,0xFD,
+ 0xB8,0xAE,0x74,0x4F,0xC5,0xFC,0x76,0xBC,0x83,0xC5,0x47,0x30,
+ 0x61,0xCE,0x7C,0xC9,0x66,0xFF,0x15,0xF9,0xBB,0xFD,0x91,0x5E,
+ 0xC7,0x01,0xAA,0xD3,0x5B,0x9E,0x8D,0xA0,0xA5,0x72,0x3A,0xD4,
+ 0x1A,0xF0,0xBF,0x46,0x00,0x58,0x2B,0xE5,0xF4,0x88,0xFD,0x58,
+ 0x4E,0x49,0xDB,0xCD,0x20,0xB4,0x9D,0xE4,0x91,0x07,0x36,0x6B,
+ 0x33,0x6C,0x38,0x0D,0x45,0x1D,0x0F,0x7C,0x88,0xB3,0x1C,0x7C,
+ 0x5B,0x2D,0x8E,0xF6,0xF3,0xC9,0x23,0xC0,0x43,0xF0,0xA5,0x5B,
+ 0x18,0x8D,0x8E,0xBB,0x55,0x8C,0xB8,0x5D,0x38,0xD3,0x34,0xFD,
+ 0x7C,0x17,0x57,0x43,0xA3,0x1D,0x18,0x6C,0xDE,0x33,0x21,0x2C,
+ 0xB5,0x2A,0xFF,0x3C,0xE1,0xB1,0x29,0x40,0x18,0x11,0x8D,0x7C,
+ 0x84,0xA7,0x0A,0x72,0xD6,0x86,0xC4,0x03,0x19,0xC8,0x07,0x29,
+ 0x7A,0xCA,0x95,0x0C,0xD9,0x96,0x9F,0xAB,0xD0,0x0A,0x50,0x9B,
+ 0x02,0x46,0xD3,0x08,0x3D,0x66,0xA4,0x5D,0x41,0x9F,0x9C,0x7C,
+ 0xBD,0x89,0x4B,0x22,0x19,0x26,0xBA,0xAB,0xA2,0x5E,0xC3,0x55,
+ 0xE9,0x32,0x0B,0x3B,
+ };
+ static unsigned char dh2048_g[]={
+ 0x02,
+ };
+ DH *dh;
+
+ if ((dh=DH_new()) == NULL) return(NULL);
+ dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
+ dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ { DH_free(dh); return(NULL); }
+ return(dh);
+ }
+
+static DH *get_dh4096()
+ {
+ static unsigned char dh4096_p[]={
+ 0xFA,0x14,0x72,0x52,0xC1,0x4D,0xE1,0x5A,0x49,0xD4,0xEF,0x09,
+ 0x2D,0xC0,0xA8,0xFD,0x55,0xAB,0xD7,0xD9,0x37,0x04,0x28,0x09,
+ 0xE2,0xE9,0x3E,0x77,0xE2,0xA1,0x7A,0x18,0xDD,0x46,0xA3,0x43,
+ 0x37,0x23,0x90,0x97,0xF3,0x0E,0xC9,0x03,0x50,0x7D,0x65,0xCF,
+ 0x78,0x62,0xA6,0x3A,0x62,0x22,0x83,0xA1,0x2F,0xFE,0x79,0xBA,
+ 0x35,0xFF,0x59,0xD8,0x1D,0x61,0xDD,0x1E,0x21,0x13,0x17,0xFE,
+ 0xCD,0x38,0x87,0x9E,0xF5,0x4F,0x79,0x10,0x61,0x8D,0xD4,0x22,
+ 0xF3,0x5A,0xED,0x5D,0xEA,0x21,0xE9,0x33,0x6B,0x48,0x12,0x0A,
+ 0x20,0x77,0xD4,0x25,0x60,0x61,0xDE,0xF6,0xB4,0x4F,0x1C,0x63,
+ 0x40,0x8B,0x3A,0x21,0x93,0x8B,0x79,0x53,0x51,0x2C,0xCA,0xB3,
+ 0x7B,0x29,0x56,0xA8,0xC7,0xF8,0xF4,0x7B,0x08,0x5E,0xA6,0xDC,
+ 0xA2,0x45,0x12,0x56,0xDD,0x41,0x92,0xF2,0xDD,0x5B,0x8F,0x23,
+ 0xF0,0xF3,0xEF,0xE4,0x3B,0x0A,0x44,0xDD,0xED,0x96,0x84,0xF1,
+ 0xA8,0x32,0x46,0xA3,0xDB,0x4A,0xBE,0x3D,0x45,0xBA,0x4E,0xF8,
+ 0x03,0xE5,0xDD,0x6B,0x59,0x0D,0x84,0x1E,0xCA,0x16,0x5A,0x8C,
+ 0xC8,0xDF,0x7C,0x54,0x44,0xC4,0x27,0xA7,0x3B,0x2A,0x97,0xCE,
+ 0xA3,0x7D,0x26,0x9C,0xAD,0xF4,0xC2,0xAC,0x37,0x4B,0xC3,0xAD,
+ 0x68,0x84,0x7F,0x99,0xA6,0x17,0xEF,0x6B,0x46,0x3A,0x7A,0x36,
+ 0x7A,0x11,0x43,0x92,0xAD,0xE9,0x9C,0xFB,0x44,0x6C,0x3D,0x82,
+ 0x49,0xCC,0x5C,0x6A,0x52,0x42,0xF8,0x42,0xFB,0x44,0xF9,0x39,
+ 0x73,0xFB,0x60,0x79,0x3B,0xC2,0x9E,0x0B,0xDC,0xD4,0xA6,0x67,
+ 0xF7,0x66,0x3F,0xFC,0x42,0x3B,0x1B,0xDB,0x4F,0x66,0xDC,0xA5,
+ 0x8F,0x66,0xF9,0xEA,0xC1,0xED,0x31,0xFB,0x48,0xA1,0x82,0x7D,
+ 0xF8,0xE0,0xCC,0xB1,0xC7,0x03,0xE4,0xF8,0xB3,0xFE,0xB7,0xA3,
+ 0x13,0x73,0xA6,0x7B,0xC1,0x0E,0x39,0xC7,0x94,0x48,0x26,0x00,
+ 0x85,0x79,0xFC,0x6F,0x7A,0xAF,0xC5,0x52,0x35,0x75,0xD7,0x75,
+ 0xA4,0x40,0xFA,0x14,0x74,0x61,0x16,0xF2,0xEB,0x67,0x11,0x6F,
+ 0x04,0x43,0x3D,0x11,0x14,0x4C,0xA7,0x94,0x2A,0x39,0xA1,0xC9,
+ 0x90,0xCF,0x83,0xC6,0xFF,0x02,0x8F,0xA3,0x2A,0xAC,0x26,0xDF,
+ 0x0B,0x8B,0xBE,0x64,0x4A,0xF1,0xA1,0xDC,0xEE,0xBA,0xC8,0x03,
+ 0x82,0xF6,0x62,0x2C,0x5D,0xB6,0xBB,0x13,0x19,0x6E,0x86,0xC5,
+ 0x5B,0x2B,0x5E,0x3A,0xF3,0xB3,0x28,0x6B,0x70,0x71,0x3A,0x8E,
+ 0xFF,0x5C,0x15,0xE6,0x02,0xA4,0xCE,0xED,0x59,0x56,0xCC,0x15,
+ 0x51,0x07,0x79,0x1A,0x0F,0x25,0x26,0x27,0x30,0xA9,0x15,0xB2,
+ 0xC8,0xD4,0x5C,0xCC,0x30,0xE8,0x1B,0xD8,0xD5,0x0F,0x19,0xA8,
+ 0x80,0xA4,0xC7,0x01,0xAA,0x8B,0xBA,0x53,0xBB,0x47,0xC2,0x1F,
+ 0x6B,0x54,0xB0,0x17,0x60,0xED,0x79,0x21,0x95,0xB6,0x05,0x84,
+ 0x37,0xC8,0x03,0xA4,0xDD,0xD1,0x06,0x69,0x8F,0x4C,0x39,0xE0,
+ 0xC8,0x5D,0x83,0x1D,0xBE,0x6A,0x9A,0x99,0xF3,0x9F,0x0B,0x45,
+ 0x29,0xD4,0xCB,0x29,0x66,0xEE,0x1E,0x7E,0x3D,0xD7,0x13,0x4E,
+ 0xDB,0x90,0x90,0x58,0xCB,0x5E,0x9B,0xCD,0x2E,0x2B,0x0F,0xA9,
+ 0x4E,0x78,0xAC,0x05,0x11,0x7F,0xE3,0x9E,0x27,0xD4,0x99,0xE1,
+ 0xB9,0xBD,0x78,0xE1,0x84,0x41,0xA0,0xDF,
+ };
+ static unsigned char dh4096_g[]={
+ 0x02,
+ };
+ DH *dh;
+
+ if ((dh=DH_new()) == NULL) return(NULL);
+ dh->p=BN_bin2bn(dh4096_p,sizeof(dh4096_p),NULL);
+ dh->g=BN_bin2bn(dh4096_g,sizeof(dh4096_g),NULL);
+ if ((dh->p == NULL) || (dh->g == NULL))
+ { DH_free(dh); return(NULL); }
+ return(dh);
+ }
+#endif
--ELM724514011-16567-0_
Content-Type: text/plain
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
MIME-Version: 1.0
---------------------------(end of broadcast)---------------------------
TIP 6: Have you searched our list archives?
http://www.***.com/
--ELM724514011-16567-0_--