Alternc  latest
Alternc logiel libre pour l'h├ębergement
 All Classes Namespaces Files Functions Variables Pages
m_ssl Class Reference

SSL Certificates management class. More...

Public Member Functions

 m_ssl ()
 Constructor. More...
 
 hook_menu ()
 Hook to add the "ssl certificate" menu in the Panel. More...
 
 get_list (&$filter=null)
 Return all the SSL certificates for an account (or the searched one) More...
 
 get_vhosts ()
 Return all the Vhosts of this user using SSL certificates. More...
 
 new_csr ($fqdn)
 Generate a new CSR, a new Private RSA Key, for FQDN. More...
 
 get_certificate ($id)
 Return all informations of a given certificate for the current user. More...
 
 del_certificate ($id)
 Delete a Certificate for the current user. More...
 
 share ($id, $action=1)
 Share (or unshare) an ssl certificate. More...
 
 get_new_advice ()
 Return all the subdomains that can be ssl-enabled for the current account. More...
 
 import_cert ($key, $crt, $chain="")
 Import an existing ssl Key, Certificate and (maybe) a Chained Cert. More...
 
 finalize ($certid, $crt, $chain)
 Import an ssl certificate into an existing certificate entry in the DB. More...
 
 alternc_del_member ()
 Function called by a hook when an AlternC member is deleted. More...
 
 hook_quota_get ()
 Hook which returns the used quota for the $name service for the current user. More...
 
 updateTrigger ($fqdn, $altnames="")
 Launched by functions in this class when a certificate is validated, expired or shared. More...
 
 updateDomain ($action, $type, $fqdn, $mail=0, $value="")
 Launched by hosting_functions.sh launched by update_domaines.sh Action may be create/postinst/delete/enable/disable Change the template for this domain name to have the proper CERTIFICATE An algorithm determine the best possible certificate, which may be a BAD one (like a generic admin-shared or self-signed for localhost as a last chance) More...
 
 searchBestCert ($uid, $fqdn)
 Search for the best certificate for a user and a fqdn Return a hash with sslcrt, sslkey and maybe sslchain. More...
 
 alternc_export_conf ()
 Export every information for an AlternC's account private EXPERIMENTAL 'sid' function ;) More...
 
 parseAltNames ($str)
 Returns the list of alternate names of an X.509 SSL Certificate from the attribute list. More...
 
 alias_add ($name, $content)
 Add (immediately) a global alias to the HTTP certif_alias table and add it to apache configuration by launching a incron action. More...
 
 alias_del ($name)
 Removes (immediately) a global alias to the HTTP certif_alias table and add it to apache configuration by launching a incron action. More...
 
 check_cert ($crt, $chain, $key="", $certid=null)
 Check that a crt is a proper certificate. More...
 
 dummy ()
 

Public Attributes

const STATUS_PENDING = 0
 
const STATUS_OK = 1
 
const STATUS_EXPIRED = 99
 
 $error = ""
 
const FILTER_PENDING = 1
 
const FILTER_OK = 2
 
const FILTER_EXPIRED = 4
 
const FILTER_SHARED = 8
 
const SSL_INCRON_FILE = "/var/run/alternc-ssl/generate_certif_alias"
 
 $myDomainesTypes = array("vhost-ssl", "vhost-mixssl", "panel-ssl", "roundcube-ssl", "squirrelmail-ssl", "php52-ssl", "php52-mixssl", "url-ssl")
 
const KEY_REPOSITORY = "/var/lib/alternc/ssl/private"
 

Private Member Functions

 selfSigned ($fqdn)
 Generate a self-signed certificate. More...
 

Detailed Description

SSL Certificates management class.

Definition at line 31 of file m_ssl.php.

Member Function Documentation

m_ssl::alias_add (   $name,
  $content 
)

Add (immediately) a global alias to the HTTP certif_alias table and add it to apache configuration by launching a incron action.

name is the name of the alias, starting by / content is the content of the filename stored at this location If an alias with the same name already exists, return false. if the alias has been properly defined, return true.

Returns
boolean

Definition at line 630 of file m_ssl.php.

References $content, $cuid, $db, and $msg.

630  {
631  global $msg, $cuid, $db;
632  $db->query("SELECT name FROM certif_alias WHERE name='" . addslashes($name) . "';");
633  if ($db->next_record()) {
634  $msg->raise("ERROR","ssl", _("Alias already exists"));
635  return false;
636  }
637  $db->query("INSERT INTO certif_alias SET name='" . addslashes($name) . "', content='" . addslashes($content) . "', uid=" . intval($cuid) . ";");
638  touch(self::SSL_INCRON_FILE);
639  return true;
640  }
$content
Definition: bro_editor.php:89
global $db
Definition: bootstrap.php:22
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
m_ssl::alias_del (   $name)

Removes (immediately) a global alias to the HTTP certif_alias table and add it to apache configuration by launching a incron action.

name is the name of the alias, starting by /

Returns
boolean

Definition at line 649 of file m_ssl.php.

References $cuid, $db, and $msg.

649  {
650  global $msg, $cuid, $db;
651  $db->query("SELECT name FROM certif_alias WHERE name='" . addslashes($name) . "' AND uid=" . intval($cuid) . ";");
652  if (!$db->next_record()) {
653  $msg->raise("ERROR","ssl", _("Alias not found"));
654  return false;
655  }
656  $db->query("DELETE FROM certif_alias WHERE name='" . addslashes($name) . "' AND uid=" . intval($cuid) . ";");
657  touch(self::SSL_INCRON_FILE);
658  return true;
659  }
global $db
Definition: bootstrap.php:22
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
m_ssl::alternc_del_member ( )

Function called by a hook when an AlternC member is deleted.

private TODO: delete unused ssl certificates ?? > do this in the crontab.

Definition at line 402 of file m_ssl.php.

References $cuid, $db, and $msg.

402  {
403  global $db, $msg, $cuid;
404  $msg->log("ssl", "alternc_del_member");
405  $db->query("UPDATE certificates SET ssl_action='DELETE' WHERE uid='$cuid'");
406  return true;
407  }
global $db
Definition: bootstrap.php:22
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
m_ssl::alternc_export_conf ( )

Export every information for an AlternC's account private EXPERIMENTAL 'sid' function ;)

Definition at line 589 of file m_ssl.php.

References $cuid, $db, and $msg.

589  {
590  global $db, $msg, $cuid;
591  $msg->log("ssl", "export");
592  $str = " <ssl>";
593  $db->query("SELECT COUNT(*) AS cnt FROM certificates WHERE uid='$cuid' AND status!=" . self::STATUS_EXPIRED);
594  while ($db->next_record()) {
595  $str.=" <id>" . ($db->Record["id"]) . "</id>\n";
596  $str.=" <csr>" . ($db->Record["sslcsr"]) . "</key>\n";
597  $str.=" <key>" . ($db->Record["sslkey"]) . "<key>\n";
598  $str.=" <crt>" . ($db->Record["sslcrt"]) . "</crt>\n";
599  $str.=" <chain>" . ($db->Record["sslchain"]) . "<chain>\n";
600  }
601  $str.=" </ssl>\n";
602  return $str;
603  }
global $db
Definition: bootstrap.php:22
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
m_ssl::check_cert (   $crt,
  $chain,
  $key = "",
  $certid = null 
)

Check that a crt is a proper certificate.

Parameters
$crtstring an SSL Certificate
$chainstring is a list of certificates
$keystring is a rsa key associated with certificate
$certidif no key is specified, use it from this certificate ID in the table
Returns
array the crt, chain, key, crtdata(array) after a proper reformatting or false if an error occurred (in that case $this->error is filled)

Definition at line 670 of file m_ssl.php.

References $db, $i, $key, and $r.

Referenced by finalize(), and import_cert().

670  {
671  global $db;
672  // Check that the key crt and chain are really SSL certificates and keys
673  $crt = trim(str_replace("\r\n", "\n", $crt)) . "\n";
674  $key = trim(str_replace("\r\n", "\n", $key)) . "\n";
675  $chain = trim(str_replace("\r\n", "\n", $chain)) . "\n";
676 
677  $this->error = "";
678  if (trim($key) == "" && !is_null($certid)) {
679  // find it in the DB :
680  $db->query("SELECT sslkey FROM certificates WHERE id=" . intval($certid) . ";");
681  if (!$db->next_record()) {
682  $this->error.=_("Can't find the private key in the certificate table, please check your form.");
683  return false;
684  }
685  $key = $db->f("sslkey");
686  $key = trim(str_replace("\r\n", "\n", $key)) . "\n";
687  }
688 
689  if (substr($crt, 0, 28) != "-----BEGIN CERTIFICATE-----\n" ||
690  substr($crt, -26, 26) != "-----END CERTIFICATE-----\n") {
691  $this->error.=_("The certificate must begin by BEGIN CERTIFICATE and end by END CERTIFICATE lines. Please check you pasted it in PEM form.") . "<br>\n";
692  }
693  if (trim($chain) &&
694  (substr($chain, 0, 28) != "-----BEGIN CERTIFICATE-----\n" ||
695  substr($chain, -26, 26) != "-----END CERTIFICATE-----\n")) {
696  $this->error.=_("The chained certificate must begin by BEGIN CERTIFICATE and end by END CERTIFICATE lines. Please check you pasted it in PEM form.") . "<br>\n";
697  }
698  if ((substr($key, 0, 32) != "-----BEGIN RSA PRIVATE KEY-----\n" ||
699  substr($key, -30, 30) != "-----END RSA PRIVATE KEY-----\n") &&
700  (substr($key, 0, 28) != "-----BEGIN PRIVATE KEY-----\n" ||
701  substr($key, -26, 26) != "-----END PRIVATE KEY-----\n")) {
702  $this->error.=_("The private key must begin by BEGIN (RSA )PRIVATE KEY and end by END (RSA )PRIVATE KEY lines. Please check you pasted it in PEM form.") . "<br>\n";
703  }
704  if ($this->error) {
705  return false;
706  }
707 
708  // We split the chained certificates in individuals certificates :
709  $chains = array();
710  $status = 0;
711  $new = "";
712  $lines = explode("\n", $chain);
713  foreach ($lines as $line) {
714  if ($line == "-----BEGIN CERTIFICATE-----" && $status == 0) {
715  $status = 1;
716  $new = $line . "\n";
717  continue;
718  }
719  if ($line == "-----END CERTIFICATE-----" && $status == 1) {
720  $status = 0;
721  $new.=$line . "\n";
722  $chains[] = $new;
723  $new = "";
724  continue;
725  }
726  if ($status == 1) {
727  $new.=$line . "\n";
728  }
729  }
730  // here chains contains all the ssl certificates in the chained certs.
731  // Now we check those using Openssl functions (real check :) )
732  $rchains = array();
733  $i = 0;
734  foreach ($chains as $tmpcert) {
735  $i++;
736  $tmpr = openssl_x509_read($tmpcert);
737  if ($tmpr === false) {
738  $this->error.=sprintf(_("The %d-th certificate in the chain is invalid"), $i) . "<br>\n";
739  } else {
740  $rchains[] = $tmpr;
741  }
742  }
743  $rcrt = openssl_x509_read($crt);
744  $crtdata = openssl_x509_parse($crt);
745  if ($rcrt === false || $crtdata === false) {
746  $this->error.=_("The certificate is invalid.") . "<br>\n";
747  }
748 
749  $rkey = openssl_pkey_get_private($key);
750  if ($rkey === false) {
751  $this->error.=_("The private key is invalid.") . "<br>\n";
752  }
753  if (!$this->error) {
754  // check that the private key and the certificates are matching :
755  if (!openssl_x509_check_private_key($rcrt, $rkey)) {
756  $this->error.=_("The private key is not the one signed inside the certificate.") . "<br>\n";
757  }
758  }
759  if (!$this->error) {
760  // Everything is fine, let's recreate crt, chain, key from our internal OpenSSL structures:
761  if (!openssl_x509_export($rcrt, $crt)) {
762  $this->error.=_("Can't export your certificate as a string, please check its syntax.") . "<br>\n";
763  }
764  $chain = "";
765  foreach ($rchains as $r) {
766  if (!openssl_x509_export($r, $tmp)) {
767  $this->error.=_("Can't export one of your chained certificates as a string, please check its syntax.") . "<br>\n";
768  } else {
769  $chain.=$tmp;
770  }
771  }
772  if (!openssl_pkey_export($rkey, $key)) {
773  $this->error.=_("Can't export your private key as a string, please check its syntax.") . "<br>\n";
774  }
775  }
776  return array($crt, $chain, $key, $crtdata);
777  }
global $db
Definition: bootstrap.php:22
$r
Definition: aws_add.php:75
$i
if(empty($_POST['key'])||empty($_POST['val'])) $key
Definition: tempovars.php:14
m_ssl::del_certificate (   $id)

Delete a Certificate for the current user.

Returns
boolean TRUE if the certificate has been deleted successfully.

Definition at line 244 of file m_ssl.php.

References $cuid, $db, $id, $msg, and updateTrigger().

244  {
245  global $db, $msg, $cuid;
246  $msg->log("ssl", "del_certificate");
247  $id = intval($id);
248  $db->query("SELECT * FROM certificates WHERE uid='$cuid' AND id='$id';");
249  if (!$db->next_record()) {
250  $msg->raise("ERROR","ssl", _("Can't find this Certificate"));
251  return false;
252  }
253  $fqdn = $db->Record["fqdn"];
254  $altnames = $db->Record["altnames"];
255  $db->query("DELETE FROM certificates WHERE uid='$cuid' AND id='$id';");
256  // Update any existing VHOST using this cert/key
257  $this->updateTrigger($fqdn, $altnames);
258  return true;
259  }
updateTrigger($fqdn, $altnames="")
Launched by functions in this class when a certificate is validated, expired or shared.
Definition: m_ssl.php:434
global $db
Definition: bootstrap.php:22
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
if(!isset($is_include)) if(!$key &&!$crt) $id
m_ssl::dummy ( )

Definition at line 815 of file m_ssl.php.

815  {
816  _("Locally hosted forcing HTTPS");
817  _("Locally hosted HTTP and HTTPS");
818  _("HTTPS AlternC panel access");
819  _("HTTPS Roundcube Webmail");
820  _("HTTPS Squirrelmail Webmail");
821  _("php52 forcing HTTPS");
822  _("php52 HTTP and HTTPS");
823  }
m_ssl::finalize (   $certid,
  $crt,
  $chain 
)

Import an ssl certificate into an existing certificate entry in the DB.

(finalize an enrollment process)

Parameters
$certidinteger the ID in the database of the SSL Certificate
$crtstring the X.509 PEM-encoded certificate, which must be the one signing the private RSA key in certificate $certid
$chainstring the X.509 PEM-encoded list of SSL Certificate chain if intermediate authorities
Returns
integer the ID of the updated certificate in the table or false if an error occurred

Definition at line 370 of file m_ssl.php.

References $cuid, $db, $key, $msg, check_cert(), parseAltNames(), and updateTrigger().

370  {
371  global $cuid, $msg, $db;
372  $msg->log("ssl", "finalize");
373 
374  $certid = intval($certid);
375  $result = $this->check_cert($crt, $chain, "", $certid);
376  if ($result === false) {
377  $msg->raise("ERROR","ssl", $this->error);
378  return false;
379  }
380  list($crt, $chain, $key, $crtdata) = $result;
381 
382  $validstart = $crtdata['validFrom_time_t'];
383  $validend = $crtdata['validTo_time_t'];
384  $fqdn = $crtdata["subject"]["CN"];
385  $altnames = $this->parseAltNames($crtdata["extensions"]["subjectAltName"]);
386 
387  // Everything is PERFECT and has been thoroughly checked, let's insert those in the DB !
388  $sql = "UPDATE certificates SET status=" . self::STATUS_OK . ", shared=0, fqdn='" . addslashes($fqdn) . "', altnames='" . addslashes($altnames) . "', validstart=FROM_UNIXTIME(" . intval($validstart) . "), validend=FROM_UNIXTIME(" . intval($validend) . "), sslcrt='" . addslashes($crt) . "', sslchain='" . addslashes($chain) . "' WHERE id='$certid' ;";
389  if (!$db->query($sql)) {
390  $msg->raise("ERROR","ssl", _("Can't save the Crt/Chain now. Please try later."));
391  return false;
392  }
393  $this->updateTrigger($fqdn, $altnames);
394  return $certid;
395  }
updateTrigger($fqdn, $altnames="")
Launched by functions in this class when a certificate is validated, expired or shared.
Definition: m_ssl.php:434
global $db
Definition: bootstrap.php:22
check_cert($crt, $chain, $key="", $certid=null)
Check that a crt is a proper certificate.
Definition: m_ssl.php:670
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
if(empty($_POST['key'])||empty($_POST['val'])) $key
Definition: tempovars.php:14
parseAltNames($str)
Returns the list of alternate names of an X.509 SSL Certificate from the attribute list...
Definition: m_ssl.php:611
m_ssl::get_certificate (   $id)

Return all informations of a given certificate for the current user.

Returns
array all the informations of the current certificate as a hash.

Definition at line 228 of file m_ssl.php.

References $cuid, $db, $id, and $msg.

228  {
229  global $db, $msg, $cuid;
230  $msg->log("ssl", "get_certificate");
231  $id = intval($id);
232  $db->query("SELECT *, UNIX_TIMESTAMP(validstart) AS validstartts, UNIX_TIMESTAMP(validend) AS validendts FROM certificates WHERE (uid='$cuid' OR (shared=1 AND status=" . self::STATUS_OK . ") ) AND id='$id';");
233  if (!$db->next_record()) {
234  $msg->raise("ERROR","ssl", _("Can't find this Certificate"));
235  return false;
236  }
237  return $db->Record;
238  }
global $db
Definition: bootstrap.php:22
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
if(!isset($is_include)) if(!$key &&!$crt) $id
m_ssl::get_list ( $filter = null)

Return all the SSL certificates for an account (or the searched one)

Parameters
$filteran integer telling which certificate we want to see (see FILTER_* constants above) the default is showing all certificate, but only Pending and OK certificates, not expired or shared one when there is more than 10.
Returns
array all the ssl certificate this user can use (each array is the content of the certificates table)

Definition at line 109 of file m_ssl.php.

References $cuid, $db, $msg, and $r.

109  {
110  global $db, $msg, $cuid;
111  $msg->log("ssl", "get_list");
112  // Expire expired certificates:
113  $db->query("UPDATE certificates SET status=".self::STATUS_EXPIRED." WHERE status=".self::STATUS_OK." AND validend<NOW();");
114  $r = array();
115  // If we have no filter, we filter by default on pending and ok certificates if there is more than 10 of them for the same user.
116  if (is_null($filter)) {
117  $db->query("SELECT count(*) AS cnt FROM certificates WHERE uid='$cuid' OR shared=1;");
118  $db->next_record();
119  if ($db->f("cnt") > 10) {
120  $filter = (self::FILTER_PENDING | self::FILTER_OK);
121  } else {
122  $filter = (self::FILTER_PENDING | self::FILTER_OK | self::FILTER_EXPIRED | self::FILTER_SHARED);
123  }
124  }
125  // filter the filter values :)
126  $filter = ($filter & (self::FILTER_PENDING | self::FILTER_OK | self::FILTER_EXPIRED | self::FILTER_SHARED));
127  // Here filter can't be null (and will be returned to the caller !)
128  $sql = "";
129  if ($filter & self::FILTER_SHARED) {
130  $sql = " (uid='$cuid' OR shared=1) ";
131  } else {
132  $sql = " uid='$cuid' ";
133  }
134  $sql.=" AND status IN (-1";
135  if ($filter & self::FILTER_PENDING) {
136  $sql.="," . self::STATUS_PENDING;
137  }
138  if ($filter & self::FILTER_OK) {
139  $sql.="," . self::STATUS_OK;
140  }
141  if ($filter & self::FILTER_EXPIRED) {
142  $sql.="," . self::STATUS_EXPIRED;
143  }
144  $sql.=") ";
145  $db->query("SELECT *, UNIX_TIMESTAMP(validstart) AS validstartts, UNIX_TIMESTAMP(validend) AS validendts FROM certificates WHERE $sql ORDER BY shared, fqdn;");
146  if ($db->num_rows()) {
147  while ($db->next_record()) {
148  $r[] = $db->Record;
149  }
150  return $r;
151  } else {
152  $msg->raise("INFO", "ssl", _("No SSL certificates available"));
153  return array();
154  }
155  }
global $db
Definition: bootstrap.php:22
$r
Definition: aws_add.php:75
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
m_ssl::get_new_advice ( )

Return all the subdomains that can be ssl-enabled for the current account.

Returns
array of strings : all the subdomains. Excludes the one for which a cert is already available

Definition at line 291 of file m_ssl.php.

References $advice, $cuid, $db, $msg, and $r.

291  {
292  global $db, $msg, $cuid;
293  $msg->log("ssl", "get_new_advice");
294  $r = array();
295  // my certificates, either OK or PENDING (not expired) or the SHARED one (only OK then)
296  $db->query("SELECT fqdn FROM certificates WHERE
297  (uid='$cuid' AND status IN (" . self::STATUS_PENDING . "," . self::STATUS_OK . ") )
298  OR (shared=1 AND status=" . self::STATUS_OK . ")
299  ORDER BY shared, fqdn;");
300  $r = array();
301  while ($db->next_record()) {
302  $r[] = $db->f("fqdn");
303  }
304  // Now we get all our subdomains for certain domaines_types
305  $db->query("SELECT sub,domaine FROM sub_domaines WHERE compte='$cuid' AND type IN ('vhost', 'url', 'roundcube', 'squirrelmail', 'panel', 'php52');");
306  $advice = array();
307  while ($db->next_record()) {
308  $me = $db->f("sub");
309  if ($me) {
310  $me.=".";
311  }
312  $me.=$db->f("domaine");
313  if (!in_array($me, $r) && !in_array($me, $advice)) {
314  $advice[] = $me;
315  }
316  if (!in_array("*." . $db->f("domaine"), $r) && !in_array("*." . $db->f("domaine"), $advice)) {
317  $advice[] = "*." . $db->f("domaine");
318  }
319  }
320  sort($advice);
321  return($advice);
322  }
if(!isset($is_include)) $advice
Definition: ssl_new.php:39
global $db
Definition: bootstrap.php:22
$r
Definition: aws_add.php:75
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
m_ssl::get_vhosts ( )

Return all the Vhosts of this user using SSL certificates.

Returns
array all the ssl certificate and hosts of this user

Definition at line 161 of file m_ssl.php.

References $cuid, $db, $msg, and $r.

161  {
162  global $db, $msg, $cuid;
163  $msg->log("ssl", "get_vhosts");
164  $r=array();
165  $db->query("SELECT ch.*, UNIX_TIMESTAMP(c.validstart) AS validstartts, UNIX_TIMESTAMP(c.validend) AS validendts, sd.domaine, sd.sub "
166  . "FROM certif_hosts ch LEFT JOIN certificates c ON ch.certif=c.id "
167  . ", sub_domaines sd WHERE sd.id=ch.sub AND ch.uid=$cuid "
168  . "ORDER BY sd.domaine, sd.sub;");
169  if ($db->num_rows()) {
170  while ($db->next_record()) {
171  $r[] = $db->Record;
172  }
173  return $r;
174  } else {
175  $msg->raise("INFO","ssl", _("You currently have no hosting using SSL certificate"));
176  return array();
177  }
178  }
global $db
Definition: bootstrap.php:22
$r
Definition: aws_add.php:75
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
m_ssl::hook_menu ( )

Hook to add the "ssl certificate" menu in the Panel.

Definition at line 63 of file m_ssl.php.

References $cuid, $db, $q, and null.

63  {
64  global $quota, $db, $cuid;
65  $q = $quota->getquota("ssl");
66  $obj = null;
67  if ($q['t'] > 0) {
68  $obj = array(
69  'title' => _("SSL Certificates"),
70  'ico' => 'images/ssl.png',
71  'link' => 'toggle',
72  'pos' => 130,
73  'links' => array(),
74  );
75 
76  if ($quota->cancreate("ssl")) {
77  $obj['links'][] = array(
78  'ico' => 'images/new.png',
79  'txt' => _("New SSL certificate"),
80  'url' => "ssl_new.php",
81  'class' => '',
82  );
83  }
84 
85  // or admin shared >0 !
86  $db->query("SELECT COUNT(*) AS cnt FROM certificates WHERE uid='$cuid' OR shared=1");
87  $used = $q['u'];
88  if ($db->next_record()) {
89  $used = $db->f("cnt");
90  }
91  if ($used > 0) { // if there are some SSL certificates
92  $obj['links'][] = array(
93  'txt' => _("List SSL Certificates"),
94  'url' => "ssl_list.php"
95  );
96  }
97  }
98  return $obj;
99  }
global $db
Definition: bootstrap.php:22
PR null
Definition: lang-css.js:1
$cuid
Definition: bootstrap.php:43
m_ssl::hook_quota_get ( )

Hook which returns the used quota for the $name service for the current user.

Parameters
$namestring name of the quota
Returns
integer the number of service used or false if an error occured private

Definition at line 415 of file m_ssl.php.

References $cuid, $db, $msg, and $q.

415  {
416  global $db, $msg, $cuid;
417  $msg->log("ssl", "getquota");
418  $q = Array("name" => "ssl", "description" => _("SSL Certificates"), "used" => 0);
419  $db->query("SELECT COUNT(*) AS cnt FROM certificates WHERE uid='$cuid' AND status!=" . self::STATUS_EXPIRED);
420  if ($db->next_record()) {
421  $q['used'] = $db->f("cnt");
422  }
423  return $q;
424  }
global $db
Definition: bootstrap.php:22
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
m_ssl::import_cert (   $key,
  $crt,
  $chain = "" 
)

Import an existing ssl Key, Certificate and (maybe) a Chained Cert.

Parameters
$keystring the X.509 PEM-encoded RSA key
$crtstring the X.509 PEM-encoded certificate, which must be the one signinf the private RSA key in $key
$chainstring the X.509 PEM-encoded list of SSL Certificate chain if intermediate authorities
Returns
integer the ID of the newly created certificate in the table or false if an error occurred

Definition at line 333 of file m_ssl.php.

References $cuid, $db, $id, $key, $msg, check_cert(), parseAltNames(), and updateTrigger().

333  {
334  global $cuid, $msg, $db;
335  $msg->log("ssl", "import_cert");
336 
337  $result = $this->check_cert($crt, $chain, $key);
338  if ($result === false) {
339  $msg->raise("ERROR","ssl", $this->error);
340  return false;
341  }
342  list($crt, $chain, $key, $crtdata) = $result;
343 
344  $validstart = $crtdata['validFrom_time_t'];
345  $validend = $crtdata['validTo_time_t'];
346  $fqdn = $crtdata["subject"]["CN"];
347  $altnames = $this->parseAltNames($crtdata["extensions"]["subjectAltName"]);
348 
349  // Everything is PERFECT and has been thoroughly checked, let's insert those in the DB !
350  $sql = "INSERT INTO certificates SET uid='$cuid', status=" . self::STATUS_OK . ", shared=0, fqdn='" . addslashes($fqdn) . "', altnames='" . addslashes($altnames) . "', validstart=FROM_UNIXTIME(" . intval($validstart) . "), validend=FROM_UNIXTIME(" . intval($validend) . "), sslkey='" . addslashes($key) . "', sslcrt='" . addslashes($crt) . "', sslchain='" . addslashes($chain) . "';";
351  $db->query($sql);
352  if (!($id = $db->lastid())) {
353  $msg->raise("ERROR","ssl", _("Can't save the Key/Crt/Chain now. Please try later."));
354  return false;
355  }
356  $this->updateTrigger($fqdn, $altnames);
357  return $id;
358  }
updateTrigger($fqdn, $altnames="")
Launched by functions in this class when a certificate is validated, expired or shared.
Definition: m_ssl.php:434
global $db
Definition: bootstrap.php:22
check_cert($crt, $chain, $key="", $certid=null)
Check that a crt is a proper certificate.
Definition: m_ssl.php:670
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
if(empty($_POST['key'])||empty($_POST['val'])) $key
Definition: tempovars.php:14
parseAltNames($str)
Returns the list of alternate names of an X.509 SSL Certificate from the attribute list...
Definition: m_ssl.php:611
if(!isset($is_include)) if(!$key &&!$crt) $id
m_ssl::m_ssl ( )

Constructor.

Definition at line 55 of file m_ssl.php.

55  {
56 
57  }
m_ssl::new_csr (   $fqdn)

Generate a new CSR, a new Private RSA Key, for FQDN.

Parameters
$fqdnstring the FQDN of the domain name for which we want a CSR. a wildcard certificate must start by *.
Returns
integer the Certificate ID created in the MySQL database or false if an error occurred

Definition at line 187 of file m_ssl.php.

References $config, $cuid, $db, $f, $id, $msg, and checkfqdn().

187  {
188  global $db, $msg, $cuid;
189  $msg->log("ssl", "new_csr");
190  if (substr($fqdn, 0, 2) == "*.") {
191  $f = substr($fqdn, 2);
192  } else {
193  $f = $fqdn;
194  }
195  if (checkfqdn($f)) {
196  $msg->raise("ERROR","ssl", _("Bad FQDN domain name"));
197  return false;
198  }
199  putenv("OPENSSL_CONF=/etc/alternc/openssl.cnf");
200  $pkey = openssl_pkey_new();
201  if (!$pkey) {
202  $msg->raise("ERROR","ssl", _("Can't generate a private key (1)"));
203  return false;
204  }
205  $privKey = "";
206  if (!openssl_pkey_export($pkey, $privKey)) {
207  $msg->raise("ERROR","ssl", _("Can't generate a private key (2)"));
208  return false;
209  }
210  $dn = array("commonName" => $fqdn);
211  // override the (not taken from openssl.cnf) digest to use SHA-2 / SHA256 and not SHA-1 or MD5 :
212  $config = array("digest_alg" => "sha256");
213  $csr = openssl_csr_new($dn, $pkey, $config);
214  $csrout = "";
215  openssl_csr_export($csr, $csrout);
216  $db->query("INSERT INTO certificates SET uid='$cuid', status=" . self::STATUS_PENDING . ", shared=0, fqdn='" . addslashes($fqdn) . "', altnames='', validstart=NOW(), sslcsr='" . addslashes($csrout) . "', sslkey='" . addslashes($privKey) . "';");
217  if (!($id = $db->lastid())) {
218  $msg->raise("ERROR","ssl", _("Can't generate a CSR"));
219  return false;
220  }
221  return $id;
222  }
checkfqdn($fqdn)
Check that a domain name is fqdn compliant.
Definition: functions.php:258
global $db
Definition: bootstrap.php:22
$config
Le but de ce script est deux choses:
Definition: 0.9.2.php:25
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
if(!isset($is_include)) if(!$key &&!$crt) $id
m_ssl::parseAltNames (   $str)

Returns the list of alternate names of an X.509 SSL Certificate from the attribute list.

Parameters
$strstring the $crtdata["extensions"]["subjectAltName"] from openssl
Returns
array an array of FQDNs

Definition at line 611 of file m_ssl.php.

Referenced by finalize(), and import_cert().

611  {
612  $mat = array();
613  if (preg_match_all("#DNS:([^,]*)#", $str, $mat, PREG_PATTERN_ORDER)) {
614  return implode("\n", $mat[1]);
615  } else {
616  return "";
617  }
618  }
m_ssl::searchBestCert (   $uid,
  $fqdn 
)

Search for the best certificate for a user and a fqdn Return a hash with sslcrt, sslkey and maybe sslchain.

return ANYWAY : if necessary, return a newly created (and stored in KEY_REPOSITORY localhost self-signed certificate...

Definition at line 551 of file m_ssl.php.

References $db, $uid, and selfSigned().

Referenced by updateDomain().

551  {
552  global $db;
553  $uid = intval($uid);
554  // 1st search for a valid certificate in my account or shared by the admin:
555  // the ORDER BY make it so that we try VALID then EXPIRED one (sad)
556  $wildcard = "*." . substr($fqdn, strpos($fqdn, ".") + 1);
557  $db->query("SELECT * FROM certificates WHERE (status=".self::STATUS_OK." OR status=".self::STATUS_EXPIRED.") "
558  . "AND (uid=" . $uid . " OR shared=1) "
559  . "AND (fqdn='" . $fqdn . "' OR fqdn='" . $wildcard . "' OR altnames LIKE '%" . $fqdn . "%') "
560  . "ORDER BY (validstart<=NOW() AND validend>=NOW()) DESC, validstart DESC ");
561  while ($db->next_record()) {
562  // name
563  if ($db->Record["fqdn"] == $fqdn) {
564  return $db->Record;
565  }
566  // or alternative names
567  $altnames = explode("\n", $db->Record["altnames"]);
568  foreach ($altnames as $altname) {
569  if (trim($altname) == $fqdn) {
570  return $db->Record;
571  }
572  }
573  // or wildcard
574  if ($db->Record["fqdn"] == $wildcard) {
575  return $db->Record;
576  }
577  }
578  // not found, we generate a one-time self-signed certificate for this host.
579  $crt = $this->selfSigned($fqdn);
580  $crt["uid"] = $uid;
581  return $crt;
582  }
$uid
global $db
Definition: bootstrap.php:22
selfSigned($fqdn)
Generate a self-signed certificate.
Definition: m_ssl.php:785
m_ssl::selfSigned (   $fqdn)
private

Generate a self-signed certificate.

Parameters
string$fqdnthe fully qualified domain name to set as commonName for the certificate
Returns
hash an array similar to a certificate DB row containing everything (sslcrt, sslcsr, sslkey, sslchain)

Definition at line 785 of file m_ssl.php.

References $config, $msg, and null.

Referenced by searchBestCert().

785  {
786  global $msg;
787  putenv("OPENSSL_CONF=/etc/alternc/openssl.cnf");
788  $pkey = openssl_pkey_new();
789  if (!$pkey) {
790  $msg->raise("ERROR","ssl", _("Can't generate a private key (1)"));
791  return false;
792  }
793  $privKey = "";
794  if (!openssl_pkey_export($pkey, $privKey)) {
795  $msg->raise("ERROR","ssl", _("Can't generate a private key (2)"));
796  return false;
797  }
798  $dn = array("commonName" => $fqdn);
799  // override the (not taken from openssl.cnf) digest to use SHA-2 / SHA256 and not SHA-1 or MD5 :
800  $config = array("digest_alg" => "sha256");
801  $csr = openssl_csr_new($dn, $pkey, $config);
802  $csrout = "";
803  openssl_csr_export($csr, $csrout);
804  $crt = openssl_csr_sign($csr, null, $pkey, 3650, $config);
805  $crtout = "";
806  openssl_x509_export($crt, $crtout);
807  return array("id" => 0, "status" => 1, "shared" => 0, "fqdn" => $fqdn, "altnames" => "",
808  "validstart" => date("Y-m-d H:i:s"), "validend" => date("Y-m-d H:i:s", time() + 86400 * 10 * 365.249),
809  "sslcsr" => $csrout, "sslcrt" => $crtout, "sslkey" => $privKey, "sslchain" => "",
810  "selfsigned" => true,
811  );
812  }
$config
Le but de ce script est deux choses:
Definition: 0.9.2.php:25
PR null
Definition: lang-css.js:1
$msg
Definition: config.php:155
m_ssl::share (   $id,
  $action = 1 
)

Share (or unshare) an ssl certificate.

Parameters
$idinteger the id of the certificate in the table.
$actioninteger share (1) or unshare (0) this certificate
Returns
boolean

Definition at line 267 of file m_ssl.php.

References $cuid, $db, $id, $msg, and updateTrigger().

267  {
268  global $db, $msg, $cuid;
269  $msg->log("ssl", "share");
270  $id = intval($id);
271  $db->query("SELECT * FROM certificates WHERE uid='$cuid' AND status=" . self::STATUS_OK . " AND id='$id';");
272  if (!$db->next_record()) {
273  $msg->raise("ERROR","ssl", _("Can't find this Certificate"));
274  return false;
275  }
276  if ($action) {
277  $action = 1;
278  $this->updateTrigger($db->Record["fqdn"], $db->Record["altnames"]);
279  } else {
280  $action = 0;
281  }
282  $db->query("UPDATE certificates SET shared=$action WHERE id='$id';");
283  return true;
284  }
updateTrigger($fqdn, $altnames="")
Launched by functions in this class when a certificate is validated, expired or shared.
Definition: m_ssl.php:434
global $db
Definition: bootstrap.php:22
$msg
Definition: config.php:155
$cuid
Definition: bootstrap.php:43
if(!isset($is_include)) if(!$key &&!$crt) $id
m_ssl::updateDomain (   $action,
  $type,
  $fqdn,
  $mail = 0,
  $value = "" 
)

Launched by hosting_functions.sh launched by update_domaines.sh Action may be create/postinst/delete/enable/disable Change the template for this domain name to have the proper CERTIFICATE An algorithm determine the best possible certificate, which may be a BAD one (like a generic admin-shared or self-signed for localhost as a last chance)

Definition at line 453 of file m_ssl.php.

References $cert, $db, $found, $msg, and searchBestCert().

453  {
454  global $db, $msg;
455  $msg->log("ssl", "update_domain($action,$type,$fqdn)");
456  if (!in_array($type, $this->myDomainesTypes)) {
457  return; // nothing to do : the type is not our to start with ;)
458  }
459  if ($action == "postinst") {
460  $msg->log("ssl", "update_domain:CREATE($action,$type,$fqdn)");
461  $offset = 0;
462  $found = false;
463  do { // try each subdomain (strtok-style) and search them in sub_domaines table:
464  $db->query("SELECT * FROM sub_domaines WHERE "
465  . "sub='" . substr($fqdn, 0, $offset) . "' AND domaine='" . substr($fqdn, $offset + ($offset != 0)) . "' "
466  . "AND web_action NOT IN ('','OK') AND type='" . $type . "';");
467  if ($db->next_record()) {
468  $found = true;
469  break;
470  }
471  $offset = strpos($fqdn, ".", $offset+1);
472  //No more dot, we prevent an infinite loop
473  if (!$offset) {
474  break;
475  }
476  } while (true);
477  if (!$found) {
478  echo "FATAL: didn't found fqdn $fqdn in sub_domaines table !\n";
479  return;
480  }
481  // found and $db point to it:
482  $subdom = $db->Record;
483  $TARGET_FILE = "/var/lib/alternc/apache-vhost/" . substr($subdom["compte"], -1) . "/" . $subdom["compte"] . "/" . $fqdn . ".conf";
484  $cert = $this->searchBestCert($subdom["compte"], $fqdn);
485  // DEBUG echo "Return from searchBestCert(" . $subdom["compte"] . "," . $fqdn . ") is "; print_r($cert);
486  // Save crt/key/chain into KEY_REPOSITORY
487  $CRTDIR = self::KEY_REPOSITORY . "/" . $subdom["compte"];
488  @mkdir($CRTDIR);
489  // Don't *overwrite* existing self-signed certificates in KEY_REPOSITORY
490  if (isset($cert["selfsigned"]) &&
491  file_exists($CRTDIR . "/" . $fqdn . ".crt") &&
492  file_exists($CRTDIR . "/" . $fqdn . ".key")) {
493  echo "Self-Signed certificate reused...\n";
494  } else {
495  file_put_contents($CRTDIR . "/" . $fqdn . ".crt", $cert["sslcrt"]);
496  file_put_contents($CRTDIR . "/" . $fqdn . ".key", $cert["sslkey"]);
497  if (isset($cert["sslchain"]) && $cert["sslchain"]) {
498  file_put_contents($CRTDIR . "/" . $fqdn . ".chain", $cert["sslchain"]);
499  }
500  }
501  // edit apache conf file to set the certificate:
502  $s = file_get_contents($TARGET_FILE);
503  $s = str_replace("%%CRT%%", $CRTDIR . "/" . $fqdn . ".crt", $s);
504  $s = str_replace("%%KEY%%", $CRTDIR . "/" . $fqdn . ".key", $s);
505  if (isset($cert["sslchain"]) && $cert["sslchain"]) {
506  $s = str_replace("%%CHAINLINE%%", "SSLCertificateChainFile " . $CRTDIR . "/" . $fqdn . ".chain", $s);
507  } else {
508  $s = str_replace("%%CHAINLINE%%", "", $s);
509  }
510  file_put_contents($TARGET_FILE, $s);
511  // Edit certif_hosts:
512  $db->query("DELETE FROM certif_hosts WHERE sub=" . $subdom["id"] . ";");
513  $db->query("INSERT INTO certif_hosts SET "
514  . "sub=" . intval($subdom["id"]) . ", "
515  . "certif=" . intval($cert["id"]) . ", "
516  . "uid=" . intval($subdom["compte"]) . ";");
517  } // action==create
518  if ($action == "delete") {
519  $msg->log("ssl", "update_domain:DELETE($action,$type,$fqdn)");
520  $offset = 0;
521  $found = false;
522  do { // try each subdomain (strtok-style) and search them in sub_domaines table:
523  $db->query("SELECT * FROM sub_domaines WHERE "
524  . "sub='" . substr($fqdn, 0, $offset) . "' AND domaine='" . substr($fqdn, $offset + ($offset != 0)) . "' "
525  . "AND web_action NOT IN ('','OK') AND type='" . $type . "';");
526  if ($db->next_record()) {
527  $found = true;
528  break;
529  }
530  $offset = strpos($fqdn, ".", $offset+1);
531  //No more dot, we prevent an infinite loop
532  if (!$offset) {
533  break;
534  }
535  } while (true);
536  if (!$found) {
537  echo "FATAL: didn't found fqdn $fqdn in sub_domaines table !\n";
538  return;
539  }
540  // found and $db point to it:
541  $subdom = $db->Record;
542  $db->query("DELETE FROM certif_hosts WHERE sub=" . $subdom["id"] . ";");
543  }
544  }
$found
Definition: aws_del.php:29
global $db
Definition: bootstrap.php:22
$msg
Definition: config.php:155
searchBestCert($uid, $fqdn)
Search for the best certificate for a user and a fqdn Return a hash with sslcrt, sslkey and maybe ssl...
Definition: m_ssl.php:551
if($delete!="") $cert
m_ssl::updateTrigger (   $fqdn,
  $altnames = "" 
)

Launched by functions in this class when a certificate is validated, expired or shared.

so that existing vhost using expired or self-signed certificates may have the chance to use a proper one automagically

Parameters
string$fqdnthe FQDN of the certificate
string$altnamesany alternative names this certificate may have.

Definition at line 434 of file m_ssl.php.

References $db.

Referenced by del_certificate(), finalize(), import_cert(), and share().

434  {
435  global $db;
436  $fqdns = array($fqdn);
437  $an = explode("\n", $altnames);
438  foreach ($an as $a)
439  if (trim($a))
440  $fqdns[] = trim($a);
441  $db->query("UPDATE sub_domaines SET web_action='UPDATE' WHERE "
442  . "if(LENGTH(sub)>0,CONCAT(sub,'.',domaine),domaine) IN ('" . implode("','", $fqdns) . "') "
443  . "AND type LIKE '%ssl';");
444  }
global $db
Definition: bootstrap.php:22

Member Data Documentation

m_ssl::$error = ""

Definition at line 37 of file m_ssl.php.

m_ssl::$myDomainesTypes = array("vhost-ssl", "vhost-mixssl", "panel-ssl", "roundcube-ssl", "squirrelmail-ssl", "php52-ssl", "php52-mixssl", "url-ssl")

Definition at line 47 of file m_ssl.php.

const m_ssl::FILTER_EXPIRED = 4

Definition at line 43 of file m_ssl.php.

const m_ssl::FILTER_OK = 2

Definition at line 42 of file m_ssl.php.

const m_ssl::FILTER_PENDING = 1

Definition at line 41 of file m_ssl.php.

const m_ssl::FILTER_SHARED = 8

Definition at line 44 of file m_ssl.php.

const m_ssl::KEY_REPOSITORY = "/var/lib/alternc/ssl/private"

Definition at line 49 of file m_ssl.php.

const m_ssl::SSL_INCRON_FILE = "/var/run/alternc-ssl/generate_certif_alias"

Definition at line 45 of file m_ssl.php.

const m_ssl::STATUS_EXPIRED = 99

Definition at line 35 of file m_ssl.php.

const m_ssl::STATUS_OK = 1

Definition at line 34 of file m_ssl.php.

const m_ssl::STATUS_PENDING = 0

Definition at line 33 of file m_ssl.php.


The documentation for this class was generated from the following file: