Roxen.git / server / base_server / roxen.pike

version» Context lines:

Roxen.git/server/base_server/roxen.pike:2431: Inside #if undefined(ALLOW_WEAK_SSL)
   SSL.Constants.TLS_rsa_with_null_sha256,    SSL.Constants.SSL_rsa_with_null_sha,    SSL.Constants.SSL_rsa_with_null_md5,    SSL.Constants.SSL_dhe_dss_export_with_des40_cbc_sha,    SSL.Constants.SSL_null_with_null_null,    });   #endif   #endif /* SSL.ServerConnection */    }    + #if constant(Standards.X509) +  void certificates_changed(Variable.Variable|void ignored, +  void|int ignore_eaddrinuse) +  { +  int old_cert_failure = cert_failure; +  cert_failure = 0; +  +  array(string) certificates = ({}); +  array(object) decoded_certs = ({}); +  array(object) decoded_keys = ({}); +  +  void handle_pem_file(string pem_file, Variable.Variable conf_var) +  { +  string raw_cert; +  SSL3_WERR (sprintf ("Reading PEM file %O\n", pem_file)); +  if( catch{ raw_cert = lopen(pem_file, "r")->read(); } ) +  { +  CERT_WARNING (conf_var, +  LOC_M(8, "Reading PEM file %O failed: %s\n"), +  pem_file, strerror (errno())); +  return; +  } +  +  Standards.PEM.Messages msgs = Standards.PEM.Messages(raw_cert); +  +  foreach(msgs->fragments, string|Standards.PEM.Message msg) { +  if (stringp(msg)) { +  if (String.trim_all_whites(msg) != "") { +  CERT_WARNING(conf_var, +  LOC_M(0, "Invalid PEM in %O.\n"), +  pem_file); +  } +  continue; +  } +  string body = msg->body; +  if (msg->headers["dek-info"]) { +  mixed err = catch { +  body = Standards.PEM.decrypt_body(msg->headers["dek-info"], +  body, query("ssl_password")); +  }; +  if (err) { +  CERT_WARNING(conf_var, +  LOC_M(0, "Invalid decryption password for %O.\n"), +  pem_file); +  } +  } +  switch(msg->pre) { +  case "CERTIFICATE": +  case "X509 CERTIFICATE": +  Standards.X509.TBSCertificate tbs = +  Standards.X509.decode_certificate(body); +  if (!tbs) { +  CERT_WARNING (conf_var, +  LOC_M(13, "Certificate not valid (DER).\n")); +  return; +  } +  certificates += ({ body }); +  decoded_certs += ({ Standards.X509.decode_certificate(body) }); +  break; +  case "PRIVATE KEY": +  case "RSA PRIVATE KEY": +  case "DSA PRIVATE KEY": +  case "ECDSA PRIVATE KEY": +  Crypto.Sign key = Standards.X509.parse_private_key(body); +  if (!key) { +  CERT_ERROR (conf_var, +  LOC_M(11,"Private key not valid")+" (DER).\n"); +  return; +  } +  decoded_keys += ({ key }); +  break; +  } +  } +  }; +  +  Variable.Variable Certificates = getvar("ssl_cert_file"); +  Variable.Variable KeyFile = getvar("ssl_key_file"); +  +  object privs = Privs("Reading cert file"); +  +  foreach(map(Certificates->query(), String.trim_whites), string cert_file) { +  if (cert_file == "") continue; +  handle_pem_file(cert_file, Certificates); +  } +  +  string key_file = String.trim_whites(KeyFile->query()); +  if (key_file != "") { +  handle_pem_file(key_file, KeyFile); +  } else { +  KeyFile = Certificates; +  } +  +  privs = 0; +  +  if (!sizeof(decoded_certs)) { +  CERT_ERROR(Certificates, LOC_M(63,"No certificates found.\n")); +  report_error ("TLS port %s: %s", get_url(), +  LOC_M(63,"No certificates found.\n")); +  cert_err_unbind(); +  cert_failure = 1; +  return; +  } +  +  if (!sizeof(decoded_keys)) { +  CERT_ERROR (KeyFile, LOC_M (17,"No private key found.\n")); +  report_error ("TLS port %s: %s", get_url(), +  LOC_M (17,"No private key found.\n")); +  cert_err_unbind(); +  cert_failure = 1; +  return; +  } +  +  if (sizeof(ctx->cert_pairs)) { +  // We must reset the set of certificates. +  ctx = SSL.context(); +  set_version(); +  filter_preferred_suites(); +  } +  +  mapping(string:array(int)) cert_lookup = ([]); +  foreach(decoded_certs; int no; Standards.X509.TBSCertificate tbs) { +  cert_lookup[tbs->subject->get_der()] += ({ no }); +  } +  +  foreach(decoded_keys, Crypto.Sign key) { +  // FIXME: Multiple certificates with the same key? +  array(int) cert_nos; +  Standards.X509.TBSCertificate tbs; +  foreach(decoded_certs; int no; tbs) { +  if (tbs->public_key->pkc->public_key_equal(key)) { +  cert_nos = ({ no }); +  break; +  } +  } +  if (!cert_nos) { +  CERT_ERROR (KeyFile, +  LOC_M(14, "Certificate and private key do not match.\n")); +  continue; +  } +  +  // Build the certificate chain. +  Standards.X509.TBSCertificate issuer; +  do { +  string issuer_der = tbs->issuer->get_der(); +  array(int) issuer_nos = cert_lookup[issuer_der]; +  if (!issuer_nos) break; +  +  issuer = decoded_certs[issuer_nos[0]]; +  +  // FIXME: Verify that the issuer has signed the cert. +  +  if (issuer != tbs) { +  cert_nos += ({ issuer_nos[0] }); +  } else { +  // Self-signed. +  issuer = UNDEFINED; +  break; +  } +  } while ((tbs = issuer)); +  +  report_notice("Adding %s certificate (%d certs) for %s\n", +  key->name(), sizeof(cert_nos), get_url()); +  ctx->add_cert(key, rows(certificates, cert_nos), ({ name })); +  } +  +  if (!sizeof(ctx->cert_pairs)) { +  CERT_ERROR(Certificates, +  LOC_M(0,"No matching keys and certificates found.\n")); +  report_error ("TLS port %s: %s", get_url(), +  LOC_M(0,"No matching keys and certificates found.\n")); +  cert_err_unbind(); +  cert_failure = 1; +  return; +  } +  +  if (!bound) { +  bind (ignore_eaddrinuse); +  if (old_cert_failure && bound) +  report_notice (LOC_M(64, "TLS port %s opened.\n"), get_url()); +  if (!bound) +  report_notice("Failed to bind port %s.\n", get_url()); +  } +  } + #else    // NB: The TBS Tools.X509 API has been deprecated in Pike 8.0.   #pragma no_deprecation_warnings    void certificates_changed(Variable.Variable|void ignored,    void|int ignore_eaddrinuse)    {    int old_cert_failure = cert_failure; -  +  cert_failure = 0;       string raw_keydata;    array(string) certificates = ({});    array(object) decoded_certs = ({});    Variable.Variable Certificates = getvar("ssl_cert_file");       object privs = Privs("Reading cert file");       foreach(map(Certificates->query(), String.trim_whites), string cert_file) {    string raw_cert;
Roxen.git/server/base_server/roxen.pike:2611:    ctx->export_mode();   #endif       if (!bound) {    bind (ignore_eaddrinuse);    if (old_cert_failure && bound)    report_notice (LOC_M(64, "TLS port %s opened.\n"), get_url());    }    }   #pragma deprecation_warnings + #endif /* Tools.X509 */       class CertificateListVariable    {    inherit Variable.FileList;       string doc()    {    return sprintf(::doc() + "\n",    combine_path(getcwd(), "../local"),    getcwd());
Roxen.git/server/base_server/roxen.pike:2644:    }       SSL.sslfile accept()    {    Stdio.File q = ::accept();    if (q)    return SSL.sslfile (q, ctx);    return 0;    }    + #if constant(SSL.Connection)    protected void bind (void|int ignore_eaddrinuse)    {    // Don't bind if we don't have correct certs. -  +  if (!sizeof(ctx->cert_pairs)) return; +  ::bind (ignore_eaddrinuse); +  } + #else +  protected void bind (void|int ignore_eaddrinuse) +  { +  // Don't bind if we don't have correct certs.    if (!ctx->certificates) return;    ::bind (ignore_eaddrinuse);    } -  + #endif       void create(int pn, string i, void|int ignore_eaddrinuse)    {    ctx->random = Crypto.Random.random_string;       set_up_ssl_variables( this_object() );       filter_preferred_suites();       ::setup(pn, i);
Roxen.git/server/base_server/roxen.pike:6219: Inside #if defined(THREADS)
   backend_thread = this_thread();   #ifdef THREADS    name_thread( backend_thread, "Backend" );   #else    report_debug("\n"    "WARNING: Threads not enabled!\n"    "\n");   #endif /* THREADS */       foreach(({ "testca.pem", "demo_certificate.pem" }), string file_name) { -  if (sizeof(roxenloader.package_directories) && -  (lfile_path(file_name) == file_name)) { +  if (!sizeof(roxenloader.package_directories)) break; +  string cert; +  if (lfile_path(file_name) == file_name) {    file_name = roxen_path (roxenloader.package_directories[-1] + "/" +    file_name);    report_notice("Generating a new certificate %s...\n", file_name); -  string cert = Roxen.generate_self_signed_certificate("*"); +  cert = Roxen.generate_self_signed_certificate("*"); + #if constant(Standards.X509) +  } else { +  file_name = lfile_path(file_name);    -  +  // Check if we need to upgrade the cert. +  // +  // Certificates generated by old versions of Pike were +  // plain X.509v1, while certificates generated by Pike 8.0 +  // and later are X.509v3 with some required extensions. +     // Note: set_u_and_gid() hasn't been called yet,    // so there's no need for Privs. -  +  Standards.PEM.Messages msgs = +  Standards.PEM.Messages(Stdio.read_bytes(file_name)); +  +  int upgrade_needed; +  +  foreach(msgs->parts; string part; Standards.PEM.Message msg) { +  if (!has_suffix(part, "CERTIFICATE")) continue; +  Standards.X509.TBSCertificate tbs = +  Standards.X509.decode_certificate(msg->body); +  upgrade_needed = (tbs->version < 3); +  break; +  } +  +  if (!upgrade_needed || (sizeof(msgs->parts) != 2)) continue; +  +  // NB: We reuse the old key. +  Crypto.Sign key; +  foreach(msgs->parts; string part; Standards.PEM.Message msg) { +  if (!has_suffix(part, "PRIVATE KEY")) continue; +  if (msg->headers["dek-info"]) { +  // Not supported here. +  break; +  } +  key = Standards.X509.parse_private_key(msg->body); +  } +  if (!key) continue; +  +  report_notice("Renewing certificate: %O...\n", file_name); +  cert = Roxen.generate_self_signed_certificate("*", key); + #endif /* constant(Standards.X509) */ +  } +  +  if (cert) { +  // Note: set_u_and_gid() hasn't been called yet, +  // so there's no need for Privs.    Stdio.File file = Stdio.File(); -  if (!file->open(file_name, "wxc", 0600)) { +  if (!file->open(file_name, "wtc", 0600)) {    report_error("Couldn't create certificate file %s: %s\n", file_name,    strerror (file->errno()));    } else if (file->write(cert) != sizeof(cert)) { -  rm(cert); +  rm(file_name);    report_error("Couldn't write certificate file %s: %s\n", file_name,    strerror (file->errno()));    }    }    }       enable_configurations();       string pid_file = Getopt.find_option(argv, "p", "pid-file");    if (pid_file && query("permanent_uid")) rm(pid_file);