--- postgresql-7.2.1.orig/src/include/libpq/libpq-be.h Sun Nov 11 22:43:25 2001 +++ postgresql-7.2.1/src/include/libpq/libpq-be.h Thu May 16 12:19:09 2002 @@ -70,6 +70,7 @@ */ #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 +++ postgresql-7.2.1/src/interfaces/libpq/fe-misc.c Thu May 16 17:01:20 2002 @@ -57,6 +57,9 @@ #include "mb/pg_wchar.h" #endif +#ifdef USE_SSL +#include +#endif #define DONOTICE(conn,message) \ ((*(conn)->noticeHook) ((conn)->noticeArg, (message))) @@ -461,8 +464,30 @@ 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 nread = recv(conn->sock, conn->inBuffer + conn->inEnd, @@ -547,8 +572,30 @@ 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 nread = recv(conn->sock, conn->inBuffer + conn->inEnd, @@ -638,7 +685,29 @@ #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 +++ postgresql-7.2.1/src/interfaces/libpq/fe-connect.c Thu May 16 20:53:31 2002 @@ -20,6 +20,11 @@ #include #include +#ifdef USE_SSL +#include +#include +#endif + #include "libpq-fe.h" #include "libpq-int.h" #include "fe-auth.h" @@ -64,6 +69,8 @@ #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 #define NOTIFYLIST_INITIAL_SIZE 10 @@ -136,6 +143,12 @@ #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 /* Terminating entry --- MUST BE LAST */ @@ -310,6 +323,12 @@ #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 /* @@ -506,6 +525,16 @@ 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 if (error) @@ -766,7 +795,6 @@ conn->pgport); } - /* ---------- * connectDBStart - * Start to make a connection to the backend so it is ready to receive @@ -967,8 +995,10 @@ 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) { @@ -1901,7 +1931,12 @@ 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) { @@ -2856,3 +2891,155 @@ /* 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 +++ postgresql-7.2.1/src/backend/libpq/pqcomm.c Thu May 16 17:34:57 2002 @@ -80,6 +80,10 @@ #include "libpq/libpq.h" #include "miscadmin.h" +#ifdef USE_SSL +#include +extern const char *SSLerrmessage(void); +#endif static void pq_close(void); @@ -491,8 +495,31 @@ #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 r = recv(MyProcPort->sock, PqRecvBuffer + PqRecvLength, @@ -666,7 +693,30 @@ #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 +++ postgresql-7.2.1/src/backend/postmaster/postmaster.c Thu May 16 23:04:04 2002 @@ -166,7 +166,21 @@ #endif #ifdef USE_SSL +#include +#include +#include + 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 /* @@ -272,7 +286,7 @@ #ifdef USE_SSL static void InitSSL(void); -static const char *SSLerrmessage(void); +const char *SSLerrmessage(void); #endif @@ -1058,6 +1072,10 @@ 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) { @@ -1124,6 +1142,29 @@ 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 /* regular startup packet, cancel, etc packet should follow... */ @@ -1330,6 +1371,8 @@ { #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 free(conn); @@ -2427,7 +2470,6 @@ } #ifdef USE_SSL - /* * Initialize SSL library and structures */ @@ -2435,9 +2477,32 @@ 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) { @@ -2445,26 +2510,64 @@ 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); } /* @@ -2474,7 +2577,7 @@ * 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) { unsigned long errcode; @@ -2695,3 +2798,380 @@ 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 +#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