Index: src/cgi.c
==================================================================
--- src/cgi.c
+++ src/cgi.c
@@ -191,20 +191,24 @@
   const char *zName,    /* Name of the cookie */
   const char *zValue,   /* Value of the cookie.  Automatically escaped */
   const char *zPath,    /* Path cookie applies to.  NULL means "/" */
   int lifetime          /* Expiration of the cookie in seconds from now */
 ){
+  char *zSecure = "";
   if( zPath==0 ) zPath = g.zTop;
+  if( g.zBaseURL!=0 && strncmp(g.zBaseURL, "https:", 6)==0 ){
+    zSecure = " secure;";
+  }
   if( lifetime>0 ){
     lifetime += (int)time(0);
     blob_appendf(&extraHeader,
-       "Set-Cookie: %s=%t; Path=%s; expires=%z; Version=1\r\n",
-        zName, zValue, zPath, cgi_rfc822_datestamp(lifetime));
+       "Set-Cookie: %s=%t; Path=%s; expires=%z; HttpOnly;%s Version=1\r\n",
+        zName, zValue, zPath, cgi_rfc822_datestamp(lifetime), zSecure);
   }else{
     blob_appendf(&extraHeader,
-       "Set-Cookie: %s=%t; Path=%s; Version=1\r\n",
-       zName, zValue, zPath);
+       "Set-Cookie: %s=%t; Path=%s; HttpOnly;%s Version=1\r\n",
+       zName, zValue, zPath, zSecure);
   }
 }
 
 #if 0
 /*
@@ -289,10 +293,28 @@
   }
 
   if( blob_size(&extraHeader)>0 ){
     fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
   }
+
+  /* Add headers to turn on useful security options in browsers. */
+  fprintf(g.httpOut, "X-Frame-Options: DENY\r\n");
+  /* This stops fossil pages appearing in frames or iframes, preventing
+  ** click-jacking attacks on supporting browsers.
+  **
+  ** Other good headers would be
+  **   Strict-Transport-Security: max-age=62208000
+  ** if we're using https. However, this would break sites which serve different
+  ** content on http and https protocols. Also,
+  **   X-Content-Security-Policy: allow 'self'
+  ** would help mitigate some XSS and data injection attacks, but will break
+  ** deliberate inclusion of external resources, such as JavaScript syntax
+  ** highlighter scripts.
+  **
+  ** These headers are probably best added by the web server hosting fossil as
+  ** a CGI script.
+  */
 
   if( g.isConst ){
     /* constant means that the input URL will _never_ generate anything
     ** else. In the case of attachments, the contents won't change because
     ** an attempt to change them generates a new attachment number. In the

Index: src/clone.c
==================================================================
--- src/clone.c
+++ src/clone.c
@@ -37,10 +37,11 @@
 **
 ** Options:
 **
 **    --admin-user|-A USERNAME    Make USERNAME the administrator
 **    --private                   Also clone private branches 
+**    --ssl-identity=filename     Use the SSL identity if requested by the server
 **
 */
 void clone_cmd(void){
   char *zPassword;
   const char *zDefaultUser;   /* Optional name of the default user */
@@ -91,10 +92,18 @@
     db_initial_setup(0, zDefaultUser, 0);
     user_select();
     db_set("content-schema", CONTENT_SCHEMA, 0);
     db_set("aux-schema", AUX_SCHEMA, 0);
     db_set("last-sync-url", g.argv[2], 0);
+    if( g.zSSLIdentity!=0 ){
+      /* If the --ssl-identity option was specified, store it as a setting */
+      Blob fn;
+      blob_zero(&fn);
+      file_canonical_name(g.zSSLIdentity, &fn);
+      db_set("ssl-identity", blob_str(&fn), 0);
+      blob_reset(&fn);
+    }
     db_multi_exec(
       "REPLACE INTO config(name,value,mtime)"
       " VALUES('server-code', lower(hex(randomblob(20))), now());"
     );
     url_enable_proxy(0);

Index: src/db.c
==================================================================
--- src/db.c
+++ src/db.c
@@ -1662,10 +1662,11 @@
   { "mtime-changes", 0,                0, "on"                  },
   { "pgp-command",   0,               32, "gpg --clearsign -o " },
   { "proxy",         0,               32, "off"                 },
   { "repo-cksum",    0,                0, "on"                  },
   { "self-register", 0,                0, "off"                 },
+  { "ssl-identity",  0,               40, ""                    },
   { "ssh-command",   0,               32, ""                    },
   { "web-browser",   0,               32, ""                    },
   { 0,0,0,0 }
 };
 
@@ -1771,10 +1772,17 @@
 **
 **    self-register    Allow users to register themselves through the HTTP UI.
 **                     This is useful if you want to see other names than
 **                     "Anonymous" in e.g. ticketing system. On the other hand
 **                     users can not be deleted. Default: off.
+**
+**    ssl-identity     The full pathname to a file containing a certificate
+**                     and private key in PEM format. Create by concatenating
+**                     the certificate and private key files.
+**                     This identity will be presented to SSL servers to
+**                     authenticate this client, in addition to the normal
+**                     password authentication.
 **
 **    ssh-command      Command used to talk to a remote machine with
 **                     the "ssh://" protocol.
 **
 **    web-browser      A shell command used to launch your preferred

Index: src/http_ssl.c
==================================================================
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -78,10 +78,19 @@
 ** Return the current SSL error message
 */
 const char *ssl_errmsg(void){
   return sslErrMsg;
 }
+
+/*
+** When a server requests a client certificate that hasn't been provided,
+** display a warning message explaining what to do next.
+*/
+static int ssl_client_cert_callback(SSL *ssl, X509 **x509, EVP_PKEY **pkey){
+  fossil_warning("The remote server requested a client certificate for authentication. Specify the pathname to a file containing the PEM encoded certificate and private key with the --ssl-identity option or the ssl-identity setting.");
+  return 0; /* no cert available */    
+}
 
 /*
 ** Call this routine once before any other use of the SSL interface.
 ** This routine does initial configuration of the SSL module.
 */
@@ -91,10 +100,22 @@
     SSL_load_error_strings();
     ERR_load_BIO_strings();
     OpenSSL_add_all_algorithms();    
     sslCtx = SSL_CTX_new(SSLv23_client_method());
     X509_STORE_set_default_paths(SSL_CTX_get_cert_store(sslCtx));
+    
+    /* Load client SSL identity, preferring the filename specified on the command line */
+    const char *identityFile = ( g.zSSLIdentity!= 0) ? g.zSSLIdentity : db_get("ssl-identity", 0);
+    if( identityFile!=0 && identityFile[0]!='\0' ){
+      if( SSL_CTX_use_certificate_file(sslCtx, identityFile, SSL_FILETYPE_PEM)!= 1
+          || SSL_CTX_use_PrivateKey_file(sslCtx, identityFile, SSL_FILETYPE_PEM)!=1 ){
+        fossil_fatal("Could not load SSL identity from %s", identityFile);
+      }
+    }
+    /* Register a callback to tell the user what to do when the server asks for a cert */
+    SSL_CTX_set_client_cert_cb(sslCtx, ssl_client_cert_callback);
+
     sslIsInit = 1;
   }
 }
 
 /*
@@ -182,15 +203,24 @@
   if( SSL_get_verify_result(ssl) != X509_V_OK ){
     char *desc, *prompt;
     char *warning = "";
     Blob ans;
     BIO *mem;
+    unsigned char md[32];
+    unsigned int mdLength = 31;
     
     mem = BIO_new(BIO_s_mem());
     X509_NAME_print_ex(mem, X509_get_subject_name(cert), 2, XN_FLAG_MULTILINE);
     BIO_puts(mem, "\n\nIssued By:\n\n");
     X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 2, XN_FLAG_MULTILINE);
+    BIO_puts(mem, "\n\nSHA1 Fingerprint:\n\n ");
+    if(X509_digest(cert, EVP_sha1(), md, &mdLength)){
+      int j;
+      for( j = 0; j < mdLength; ++j ) {
+        BIO_printf(mem, " %02x", md[j]);
+      }
+    }
     BIO_write(mem, "", 1); // null-terminate mem buffer
     BIO_get_mem_data(mem, &desc);
     
     if( hasSavedCertificate ){
       warning = "WARNING: Certificate doesn't match the "

Index: src/main.c
==================================================================
--- src/main.c
+++ src/main.c
@@ -104,10 +104,11 @@
   char *urlProxyAuth;     /* Proxy-Authorizer: string */
   char *urlFossil;        /* The path of the ?fossil=path suffix on ssh: */
   int dontKeepUrl;        /* Do not persist the URL */
 
   const char *zLogin;     /* Login name.  "" if not logged in. */
+  const char *zSSLIdentity;  /* Value of --ssl-identity option, filename of SSL client identity */
   int useLocalauth;       /* No login required if from 127.0.0.1 */
   int noPswd;             /* Logged in without password (on 127.0.0.1) */
   int userUid;            /* Integer user id */
 
   /* Information used to populate the RCVFROM table */
@@ -249,10 +250,11 @@
     g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
     if( g.fSqlTrace ) g.fSqlStats = 1;
     g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
     g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
     g.zLogin = find_option("user", "U", 1);
+    g.zSSLIdentity = find_option("ssl-identity", 0, 1);
     if( find_option("help",0,0)!=0 ){
       /* --help anywhere on the command line is translated into
       ** "fossil help argv[1] argv[2]..." */
       int i;
       char **zNewArgv = fossil_malloc( sizeof(char*)*(g.argc+2) );