Changes On Branch ben-security
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch ben-security Excluding Merge-Ins

This is equivalent to a diff from 1343cfad7b to 0bed863b69

2011-06-02
19:31
Merge SSL client certificate support from ben-security branch check-in: 397f434a4d user: ben tags: ben-testing
2011-05-29
12:53
Remove accidentally included line of code. Closed-Leaf check-in: 0bed863b69 user: ben tags: ben-security
12:49
Support for client side SSL certificates for extra authentication to https servers. Adds --ssl-identity command line option and ssl-identity setting to specify the filename of a identity file containing a PEM encoded certificate and private key. check-in: e06ea26e97 user: ben tags: ben-security
2011-05-23
15:06
Merge the solaris10 branch into the trunk. check-in: 3e0efc3827 user: drh tags: trunk
2011-05-22
14:23
Create new branch named "ben-security" check-in: 2b4a6a66e1 user: ben tags: ben-security
09:11
Create new branch named "versionable-settings" check-in: 3db75c4803 user: ben tags: versionable-settings
07:33
Create new branch named "solaris10" check-in: eb4b5e3beb user: ben tags: solaris10
2011-05-21
16:57
If at the tip of the current branch but there are children in other branches, the "fossil up" command should do nothing. check-in: 1343cfad7b user: drh tags: trunk
16:45
Print an "Internal Error" if the update command is unable to find a version to update to. check-in: 88e9f24aff user: drh tags: trunk

Changes to src/cgi.c.

   189    189   */
   190    190   void cgi_set_cookie(
   191    191     const char *zName,    /* Name of the cookie */
   192    192     const char *zValue,   /* Value of the cookie.  Automatically escaped */
   193    193     const char *zPath,    /* Path cookie applies to.  NULL means "/" */
   194    194     int lifetime          /* Expiration of the cookie in seconds from now */
   195    195   ){
          196  +  char *zSecure = "";
   196    197     if( zPath==0 ) zPath = g.zTop;
          198  +  if( g.zBaseURL!=0 && strncmp(g.zBaseURL, "https:", 6)==0 ){
          199  +    zSecure = " secure;";
          200  +  }
   197    201     if( lifetime>0 ){
   198    202       lifetime += (int)time(0);
   199    203       blob_appendf(&extraHeader,
   200         -       "Set-Cookie: %s=%t; Path=%s; expires=%z; Version=1\r\n",
   201         -        zName, zValue, zPath, cgi_rfc822_datestamp(lifetime));
          204  +       "Set-Cookie: %s=%t; Path=%s; expires=%z; HttpOnly;%s Version=1\r\n",
          205  +        zName, zValue, zPath, cgi_rfc822_datestamp(lifetime), zSecure);
   202    206     }else{
   203    207       blob_appendf(&extraHeader,
   204         -       "Set-Cookie: %s=%t; Path=%s; Version=1\r\n",
   205         -       zName, zValue, zPath);
          208  +       "Set-Cookie: %s=%t; Path=%s; HttpOnly;%s Version=1\r\n",
          209  +       zName, zValue, zPath, zSecure);
   206    210     }
   207    211   }
   208    212   
   209    213   #if 0
   210    214   /*
   211    215   ** Add an ETag header line
   212    216   */
................................................................................
   287    291     }else{
   288    292       fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
   289    293     }
   290    294   
   291    295     if( blob_size(&extraHeader)>0 ){
   292    296       fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
   293    297     }
          298  +
          299  +  /* Add headers to turn on useful security options in browsers. */
          300  +  fprintf(g.httpOut, "X-Frame-Options: DENY\r\n");
          301  +  /* This stops fossil pages appearing in frames or iframes, preventing
          302  +  ** click-jacking attacks on supporting browsers.
          303  +  **
          304  +  ** Other good headers would be
          305  +  **   Strict-Transport-Security: max-age=62208000
          306  +  ** if we're using https. However, this would break sites which serve different
          307  +  ** content on http and https protocols. Also,
          308  +  **   X-Content-Security-Policy: allow 'self'
          309  +  ** would help mitigate some XSS and data injection attacks, but will break
          310  +  ** deliberate inclusion of external resources, such as JavaScript syntax
          311  +  ** highlighter scripts.
          312  +  **
          313  +  ** These headers are probably best added by the web server hosting fossil as
          314  +  ** a CGI script.
          315  +  */
   294    316   
   295    317     if( g.isConst ){
   296    318       /* constant means that the input URL will _never_ generate anything
   297    319       ** else. In the case of attachments, the contents won't change because
   298    320       ** an attempt to change them generates a new attachment number. In the
   299    321       ** case of most /getfile calls for specific versions, the only way the
   300    322       ** content changes is if someone breaks the SCM. And if that happens, a

Changes to src/clone.c.

    35     35   ** admin user. This can be overridden using the -A|--admin-user
    36     36   ** parameter.
    37     37   **
    38     38   ** Options:
    39     39   **
    40     40   **    --admin-user|-A USERNAME    Make USERNAME the administrator
    41     41   **    --private                   Also clone private branches 
           42  +**    --ssl-identity=filename     Use the SSL identity if requested by the server
    42     43   **
    43     44   */
    44     45   void clone_cmd(void){
    45     46     char *zPassword;
    46     47     const char *zDefaultUser;   /* Optional name of the default user */
    47     48     int nErr = 0;
    48     49     int bPrivate;               /* Also clone private branches */
................................................................................
    89     90       db_begin_transaction();
    90     91       db_record_repository_filename(g.argv[3]);
    91     92       db_initial_setup(0, zDefaultUser, 0);
    92     93       user_select();
    93     94       db_set("content-schema", CONTENT_SCHEMA, 0);
    94     95       db_set("aux-schema", AUX_SCHEMA, 0);
    95     96       db_set("last-sync-url", g.argv[2], 0);
           97  +    if( g.zSSLIdentity!=0 ){
           98  +      /* If the --ssl-identity option was specified, store it as a setting */
           99  +      Blob fn;
          100  +      blob_zero(&fn);
          101  +      file_canonical_name(g.zSSLIdentity, &fn);
          102  +      db_set("ssl-identity", blob_str(&fn), 0);
          103  +      blob_reset(&fn);
          104  +    }
    96    105       db_multi_exec(
    97    106         "REPLACE INTO config(name,value,mtime)"
    98    107         " VALUES('server-code', lower(hex(randomblob(20))), now());"
    99    108       );
   100    109       url_enable_proxy(0);
   101    110       url_get_password_if_needed();
   102    111       g.xlinkClusterOnly = 1;

Changes to src/db.c.

  1660   1660     { "manifest",      0,                0, "off"                 },
  1661   1661     { "max-upload",    0,               25, "250000"              },
  1662   1662     { "mtime-changes", 0,                0, "on"                  },
  1663   1663     { "pgp-command",   0,               32, "gpg --clearsign -o " },
  1664   1664     { "proxy",         0,               32, "off"                 },
  1665   1665     { "repo-cksum",    0,                0, "on"                  },
  1666   1666     { "self-register", 0,                0, "off"                 },
         1667  +  { "ssl-identity",  0,               40, ""                    },
  1667   1668     { "ssh-command",   0,               32, ""                    },
  1668   1669     { "web-browser",   0,               32, ""                    },
  1669   1670     { 0,0,0,0 }
  1670   1671   };
  1671   1672   
  1672   1673   /*
  1673   1674   ** COMMAND: settings
................................................................................
  1769   1770   **                     Disable on large repositories for a performance
  1770   1771   **                     improvement.
  1771   1772   **
  1772   1773   **    self-register    Allow users to register themselves through the HTTP UI.
  1773   1774   **                     This is useful if you want to see other names than
  1774   1775   **                     "Anonymous" in e.g. ticketing system. On the other hand
  1775   1776   **                     users can not be deleted. Default: off.
         1777  +**
         1778  +**    ssl-identity     The full pathname to a file containing a certificate
         1779  +**                     and private key in PEM format. Create by concatenating
         1780  +**                     the certificate and private key files.
         1781  +**                     This identity will be presented to SSL servers to
         1782  +**                     authenticate this client, in addition to the normal
         1783  +**                     password authentication.
  1776   1784   **
  1777   1785   **    ssh-command      Command used to talk to a remote machine with
  1778   1786   **                     the "ssh://" protocol.
  1779   1787   **
  1780   1788   **    web-browser      A shell command used to launch your preferred
  1781   1789   **                     web browser when given a URL as an argument.
  1782   1790   **                     Defaults to "start" on windows, "open" on Mac,

Changes to src/http_ssl.c.

    76     76   
    77     77   /*
    78     78   ** Return the current SSL error message
    79     79   */
    80     80   const char *ssl_errmsg(void){
    81     81     return sslErrMsg;
    82     82   }
           83  +
           84  +/*
           85  +** When a server requests a client certificate that hasn't been provided,
           86  +** display a warning message explaining what to do next.
           87  +*/
           88  +static int ssl_client_cert_callback(SSL *ssl, X509 **x509, EVP_PKEY **pkey){
           89  +  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.");
           90  +  return 0; /* no cert available */    
           91  +}
    83     92   
    84     93   /*
    85     94   ** Call this routine once before any other use of the SSL interface.
    86     95   ** This routine does initial configuration of the SSL module.
    87     96   */
    88     97   void ssl_global_init(void){
    89     98     if( sslIsInit==0 ){
    90     99       SSL_library_init();
    91    100       SSL_load_error_strings();
    92    101       ERR_load_BIO_strings();
    93    102       OpenSSL_add_all_algorithms();    
    94    103       sslCtx = SSL_CTX_new(SSLv23_client_method());
    95    104       X509_STORE_set_default_paths(SSL_CTX_get_cert_store(sslCtx));
          105  +    
          106  +    /* Load client SSL identity, preferring the filename specified on the command line */
          107  +    const char *identityFile = ( g.zSSLIdentity!= 0) ? g.zSSLIdentity : db_get("ssl-identity", 0);
          108  +    if( identityFile!=0 && identityFile[0]!='\0' ){
          109  +      if( SSL_CTX_use_certificate_file(sslCtx, identityFile, SSL_FILETYPE_PEM)!= 1
          110  +          || SSL_CTX_use_PrivateKey_file(sslCtx, identityFile, SSL_FILETYPE_PEM)!=1 ){
          111  +        fossil_fatal("Could not load SSL identity from %s", identityFile);
          112  +      }
          113  +    }
          114  +    /* Register a callback to tell the user what to do when the server asks for a cert */
          115  +    SSL_CTX_set_client_cert_cb(sslCtx, ssl_client_cert_callback);
          116  +
    96    117       sslIsInit = 1;
    97    118     }
    98    119   }
    99    120   
   100    121   /*
   101    122   ** Call this routine to shutdown the SSL module prior to program exit.
   102    123   */
................................................................................
   180    201     }
   181    202   
   182    203     if( SSL_get_verify_result(ssl) != X509_V_OK ){
   183    204       char *desc, *prompt;
   184    205       char *warning = "";
   185    206       Blob ans;
   186    207       BIO *mem;
          208  +    unsigned char md[32];
          209  +    unsigned int mdLength = 31;
   187    210       
   188    211       mem = BIO_new(BIO_s_mem());
   189    212       X509_NAME_print_ex(mem, X509_get_subject_name(cert), 2, XN_FLAG_MULTILINE);
   190    213       BIO_puts(mem, "\n\nIssued By:\n\n");
   191    214       X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 2, XN_FLAG_MULTILINE);
          215  +    BIO_puts(mem, "\n\nSHA1 Fingerprint:\n\n ");
          216  +    if(X509_digest(cert, EVP_sha1(), md, &mdLength)){
          217  +      int j;
          218  +      for( j = 0; j < mdLength; ++j ) {
          219  +        BIO_printf(mem, " %02x", md[j]);
          220  +      }
          221  +    }
   192    222       BIO_write(mem, "", 1); // null-terminate mem buffer
   193    223       BIO_get_mem_data(mem, &desc);
   194    224       
   195    225       if( hasSavedCertificate ){
   196    226         warning = "WARNING: Certificate doesn't match the "
   197    227                   "saved certificate for this host!";
   198    228       }

Changes to src/main.c.

   102    102     char *urlPasswd;        /* Password for http: */
   103    103     char *urlCanonical;     /* Canonical representation of the URL */
   104    104     char *urlProxyAuth;     /* Proxy-Authorizer: string */
   105    105     char *urlFossil;        /* The path of the ?fossil=path suffix on ssh: */
   106    106     int dontKeepUrl;        /* Do not persist the URL */
   107    107   
   108    108     const char *zLogin;     /* Login name.  "" if not logged in. */
          109  +  const char *zSSLIdentity;  /* Value of --ssl-identity option, filename of SSL client identity */
   109    110     int useLocalauth;       /* No login required if from 127.0.0.1 */
   110    111     int noPswd;             /* Logged in without password (on 127.0.0.1) */
   111    112     int userUid;            /* Integer user id */
   112    113   
   113    114     /* Information used to populate the RCVFROM table */
   114    115     int rcvid;              /* The rcvid.  0 if not yet defined. */
   115    116     char *zIpAddr;          /* The remote IP address */
................................................................................
   247    248       g.fQuiet = find_option("quiet", 0, 0)!=0;
   248    249       g.fSqlTrace = find_option("sqltrace", 0, 0)!=0;
   249    250       g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
   250    251       if( g.fSqlTrace ) g.fSqlStats = 1;
   251    252       g.fSqlPrint = find_option("sqlprint", 0, 0)!=0;
   252    253       g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
   253    254       g.zLogin = find_option("user", "U", 1);
          255  +    g.zSSLIdentity = find_option("ssl-identity", 0, 1);
   254    256       if( find_option("help",0,0)!=0 ){
   255    257         /* --help anywhere on the command line is translated into
   256    258         ** "fossil help argv[1] argv[2]..." */
   257    259         int i;
   258    260         char **zNewArgv = fossil_malloc( sizeof(char*)*(g.argc+2) );
   259    261         for(i=1; i<g.argc; i++) zNewArgv[i+1] = argv[i];
   260    262         zNewArgv[i+1] = 0;