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 622 of file m_ssl.php.

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

622  {
623  global $err, $cuid, $db;
624  $db->query("SELECT name FROM certif_alias WHERE name='" . addslashes($name) . "';");
625  if ($db->next_record()) {
626  $err->raise("ssl", _("Alias already exists"));
627  return false;
628  }
629  $db->query("INSERT INTO certif_alias SET name='" . addslashes($name) . "', content='" . addslashes($content) . "', uid=" . intval($cuid) . ";");
630  touch(self::SSL_INCRON_FILE);
631  return true;
632  }
$content
Definition: bro_editor.php:94
global $db
Definition: bootstrap.php:22
$err
Definition: bootstrap.php:72
$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 641 of file m_ssl.php.

References $cuid, $db, and $err.

641  {
642  global $err, $cuid, $db;
643  $db->query("SELECT name FROM certif_alias WHERE name='" . addslashes($name) . "' AND uid=" . intval($cuid) . ";");
644  if (!$db->next_record()) {
645  $err->raise("ssl", _("Alias not found"));
646  return false;
647  }
648  $db->query("DELETE FROM certif_alias WHERE name='" . addslashes($name) . "' AND uid=" . intval($cuid) . ";");
649  touch(self::SSL_INCRON_FILE);
650  return true;
651  }
global $db
Definition: bootstrap.php:22
$err
Definition: bootstrap.php:72
$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 $err.

402  {
403  global $db, $err, $cuid;
404  $err->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
$err
Definition: bootstrap.php:72
$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 581 of file m_ssl.php.

References $cuid, $db, and $err.

581  {
582  global $db, $err, $cuid;
583  $err->log("ssl", "export");
584  $str = " <ssl>";
585  $db->query("SELECT COUNT(*) AS cnt FROM certificates WHERE uid='$cuid' AND status!=" . self::STATUS_EXPIRED);
586  while ($db->next_record()) {
587  $str.=" <id>" . ($db->Record["id"]) . "</id>\n";
588  $str.=" <csr>" . ($db->Record["sslcsr"]) . "</key>\n";
589  $str.=" <key>" . ($db->Record["sslkey"]) . "<key>\n";
590  $str.=" <crt>" . ($db->Record["sslcrt"]) . "</crt>\n";
591  $str.=" <chain>" . ($db->Record["sslchain"]) . "<chain>\n";
592  }
593  $str.=" </ssl>\n";
594  return $str;
595  }
global $db
Definition: bootstrap.php:22
$err
Definition: bootstrap.php:72
$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 662 of file m_ssl.php.

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

Referenced by finalize(), and import_cert().

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

244  {
245  global $db, $err, $cuid;
246  $err->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  $err->raise("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
$err
Definition: bootstrap.php:72
$cuid
Definition: bootstrap.php:43
if(!isset($is_include)) if(!$key &&!$crt) $id
m_ssl::dummy ( )

Definition at line 807 of file m_ssl.php.

807  {
808  _("Locally hosted forcing HTTPS");
809  _("Locally hosted HTTP and HTTPS");
810  _("HTTPS AlternC panel access");
811  _("HTTPS Roundcube Webmail");
812  _("HTTPS Squirrelmail Webmail");
813  _("php52 forcing HTTPS");
814  _("php52 HTTP and HTTPS");
815  }
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, $err, $key, check_cert(), parseAltNames(), and updateTrigger().

370  {
371  global $cuid, $err, $db;
372  $err->log("ssl", "finalize");
373 
374  $certid = intval($certid);
375  $result = $this->check_cert($crt, $chain, "", $certid);
376  if ($result === false) {
377  $err->raise("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  $err->raise("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
$err
Definition: bootstrap.php:72
check_cert($crt, $chain, $key="", $certid=null)
Check that a crt is a proper certificate.
Definition: m_ssl.php:662
$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:603
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, $err, and $id.

228  {
229  global $db, $err, $cuid;
230  $err->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  $err->raise("ssl", _("Can't find this Certificate"));
235  return false;
236  }
237  return $db->Record;
238  }
global $db
Definition: bootstrap.php:22
$err
Definition: bootstrap.php:72
$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, $err, and $r.

109  {
110  global $db, $err, $cuid;
111  $err->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  $err->raise("ssl", _("No SSL certificates available"));
153  return array();
154  }
155  }
global $db
Definition: bootstrap.php:22
$r
Definition: aws_add.php:77
$err
Definition: bootstrap.php:72
$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, $err, and $r.

291  {
292  global $db, $err, $cuid;
293  $err->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:77
$err
Definition: bootstrap.php:72
$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, $err, and $r.

161  {
162  global $db, $err, $cuid;
163  $err->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  $err->raise("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:77
$err
Definition: bootstrap.php:72
$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, $err, and $q.

415  {
416  global $db, $err, $cuid;
417  $err->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
$err
Definition: bootstrap.php:72
$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, $err, $id, $key, check_cert(), parseAltNames(), and updateTrigger().

333  {
334  global $cuid, $err, $db;
335  $err->log("ssl", "import_cert");
336 
337  $result = $this->check_cert($crt, $chain, $key);
338  if ($result === false) {
339  $err->raise("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  $err->raise("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
$err
Definition: bootstrap.php:72
check_cert($crt, $chain, $key="", $certid=null)
Check that a crt is a proper certificate.
Definition: m_ssl.php:662
$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:603
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, $err, $f, $id, and checkfqdn().

187  {
188  global $db, $err, $cuid;
189  $err->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  $err->raise("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  $err->raise("ssl", _("Can't generate a private key (1)"));
203  return false;
204  }
205  $privKey = "";
206  if (!openssl_pkey_export($pkey, $privKey)) {
207  $err->raise("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  $err->raise("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:249
global $db
Definition: bootstrap.php:22
$config
Le but de ce script est deux choses:
Definition: 0.9.2.php:25
$err
Definition: bootstrap.php:72
$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 603 of file m_ssl.php.

Referenced by finalize(), and import_cert().

603  {
604  $mat = array();
605  if (preg_match_all("#DNS:([^,]*)#", $str, $mat, PREG_PATTERN_ORDER)) {
606  return implode("\n", $mat[1]);
607  } else {
608  return "";
609  }
610  }
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 543 of file m_ssl.php.

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

Referenced by updateDomain().

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

References $config, $err, and null.

Referenced by searchBestCert().

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

267  {
268  global $db, $err, $cuid;
269  $err->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  $err->raise("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
$err
Definition: bootstrap.php:72
$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, $err, $found, and searchBestCert().

453  {
454  global $db, $err;
455  $err->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  $err->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);
472  } while (true);
473  if (!$found) {
474  echo "FATAL: didn't found fqdn $fqdn in sub_domaines table !\n";
475  return;
476  }
477  // found and $db point to it:
478  $subdom = $db->Record;
479  $TARGET_FILE = "/var/lib/alternc/apache-vhost/" . substr($subdom["compte"], -1) . "/" . $subdom["compte"] . "/" . $fqdn . ".conf";
480  $cert = $this->searchBestCert($subdom["compte"], $fqdn);
481  // DEBUG echo "Return from searchBestCert(" . $subdom["compte"] . "," . $fqdn . ") is "; print_r($cert);
482  // Save crt/key/chain into KEY_REPOSITORY
483  $CRTDIR = self::KEY_REPOSITORY . "/" . $subdom["compte"];
484  @mkdir($CRTDIR);
485  // Don't *overwrite* existing self-signed certificates in KEY_REPOSITORY
486  if (isset($cert["selfsigned"]) &&
487  file_exists($CRTDIR . "/" . $fqdn . ".crt") &&
488  file_exists($CRTDIR . "/" . $fqdn . ".key")) {
489  echo "Self-Signed certificate reused...\n";
490  } else {
491  file_put_contents($CRTDIR . "/" . $fqdn . ".crt", $cert["sslcrt"]);
492  file_put_contents($CRTDIR . "/" . $fqdn . ".key", $cert["sslkey"]);
493  if (isset($cert["sslchain"]) && $cert["sslchain"]) {
494  file_put_contents($CRTDIR . "/" . $fqdn . ".chain", $cert["sslchain"]);
495  }
496  }
497  // edit apache conf file to set the certificate:
498  $s = file_get_contents($TARGET_FILE);
499  $s = str_replace("%%CRT%%", $CRTDIR . "/" . $fqdn . ".crt", $s);
500  $s = str_replace("%%KEY%%", $CRTDIR . "/" . $fqdn . ".key", $s);
501  if (isset($cert["sslchain"]) && $cert["sslchain"]) {
502  $s = str_replace("%%CHAINLINE%%", "SSLCertificateChainFile " . $CRTDIR . "/" . $fqdn . ".chain", $s);
503  } else {
504  $s = str_replace("%%CHAINLINE%%", "", $s);
505  }
506  file_put_contents($TARGET_FILE, $s);
507  // Edit certif_hosts:
508  $db->query("DELETE FROM certif_hosts WHERE sub=" . $subdom["id"] . ";");
509  $db->query("INSERT INTO certif_hosts SET "
510  . "sub=" . intval($subdom["id"]) . ", "
511  . "certif=" . intval($cert["id"]) . ", "
512  . "uid=" . intval($subdom["compte"]) . ";");
513  } // action==create
514  if ($action == "delete") {
515  $err->log("ssl", "update_domain:DELETE($action,$type,$fqdn)");
516  $offset = 0;
517  $found = false;
518  do { // try each subdomain (strtok-style) and search them in sub_domaines table:
519  $db->query("SELECT * FROM sub_domaines WHERE "
520  . "sub='" . substr($fqdn, 0, $offset) . "' AND domaine='" . substr($fqdn, $offset + ($offset != 0)) . "' "
521  . "AND web_action NOT IN ('','OK') AND type='" . $type . "';");
522  if ($db->next_record()) {
523  $found = true;
524  break;
525  }
526  $offset = strpos($fqdn, ".", $offset);
527  } while (true);
528  if (!$found) {
529  echo "FATAL: didn't found fqdn $fqdn in sub_domaines table !\n";
530  return;
531  }
532  // found and $db point to it:
533  $subdom = $db->Record;
534  $db->query("DELETE FROM certif_hosts WHERE sub=" . $subdom["id"] . ";");
535  }
536  }
$found
Definition: aws_del.php:30
global $db
Definition: bootstrap.php:22
$err
Definition: bootstrap.php:72
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:543
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: