patch for SSL cleanup, client certificates 
Author Message
 patch for SSL cleanup, client certificates

--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_--



Sat, 06 Nov 2004 07:32:23 GMT
 
 [ 1 post ] 

 Relevant Pages 

1. SSL client cert patch submitted

2. OWS 3.0 and SSL - certificate problems

3. Obtaining an SSL Certificate

4. Encryption (SSL & Certificates)

5. SSL Certificate

6. SSL and Certificates in 8.16

7. Problems installing a ssl-certificate under OAS4.0.8.1

8. SSL Certificates

9. SSL, Certificates and Encryption

10. SSL, MS Certificate Server with SQL Server 2000

11. SSL, Crypto, Certificates...... and stuff

12. Installing server certificate for SSL


 
Powered by phpBB® Forum Software