aa6e1002ac072352401963c07b10344a5332cafe
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

1) <?php
Bernd Wurst Added license tags for CC0,...

Bernd Wurst authored 12 years ago

2) /*
3) This file belongs to the Webinterface of schokokeks.org Hosting
4) 
Bernd Wurst Copyright year update

Bernd Wurst authored 6 years ago

5) Written 2008-2018 by schokokeks.org Hosting, namely
Bernd Wurst Added license tags for CC0,...

Bernd Wurst authored 12 years ago

6)   Bernd Wurst <bernd@schokokeks.org>
7)   Hanno Böck <hanno@schokokeks.org>
8) 
9) To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
10) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

11) You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see
Bernd Wurst Added license tags for CC0,...

Bernd Wurst authored 12 years ago

12) http://creativecommons.org/publicdomain/zero/1.0/
13) 
14) Nevertheless, in case you use a significant part of this code, we ask (but not require, see the license) that you keep the authors' names in place and return your changes to the public. We would be especially happy if you tell us what you're going to do with this code.
15) */
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

16) 
17) require_once('inc/base.php');
bernd CSR-Erstellung

bernd authored 15 years ago

18) require_once('inc/security.php');
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

19) 
20) define("CERT_OK", 0);
21) define("CERT_INVALID", 1);
22) define("CERT_NOCHAIN", 2);
23) 
24) function user_certs()
25) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

26)     $uid = (int) $_SESSION['userinfo']['uid'];
27)     $result = db_query("SELECT id, valid_from, valid_until, subject, cn FROM vhosts.certs WHERE uid=? ORDER BY cn", array($uid));
28)     $ret = array();
29)     while ($i = $result->fetch()) {
30)         $ret[] = $i;
31)     }
32)     #DEBUG($ret);
33)     return $ret;
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

34) }
35) 
bernd CSR-Erstellung

bernd authored 15 years ago

36) function user_csr()
37) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

38)     $uid = (int) $_SESSION['userinfo']['uid'];
39)     $result = db_query("SELECT id, created, hostname, bits FROM vhosts.csr WHERE uid=? ORDER BY hostname", array($uid));
40)     $ret = array();
41)     while ($i = $result->fetch()) {
42)         $ret[] = $i;
43)     }
44)     #DEBUG($ret);
45)     return $ret;
bernd CSR-Erstellung

bernd authored 15 years ago

46) }
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

47) 
Bernd Wurst Interface für Zertifikate i...

Bernd Wurst authored 8 years ago

48) function user_has_manual_certs()
49) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

50)     foreach (user_certs() as $c) {
51)         if (!cert_is_letsencrypt($c['id'])) {
52)             return true;
53)         }
54)     }
55)     foreach (user_csr() as $c) {
56)         return true;
Bernd Wurst Interface für Zertifikate i...

Bernd Wurst authored 8 years ago

57)     }
58) }
59) 
60) 
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

61) function cert_details($id)
62) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

63)     $id = (int) $id;
64)     $uid = (int) $_SESSION['userinfo']['uid'];
Hanno remove whitespace in empty...

Hanno authored 6 years ago

65) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

66)     $result = db_query("SELECT id, lastchange, valid_from, valid_until, subject, cn, chain, cert, `key` FROM vhosts.certs WHERE uid=:uid AND id=:id", array(":uid" => $uid, ":id" => $id));
67)     if ($result->rowCount() != 1) {
68)         system_failure("Ungültiges Zertifikat #{$id}");
69)     }
70)     return $result->fetch();
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

71) }
72) 
Bernd Wurst Status der letsencrypt-Opti...

Bernd Wurst authored 9 years ago

73) function cert_is_letsencrypt($id)
74) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

75)     $details = cert_details($id);
76)     #DEBUG($details);
77)     if (strpos($details['subject'], "Let's Encrypt autogenerated") > 0) {
78)         return true;
79)     }
80)     return false;
Bernd Wurst Status der letsencrypt-Opti...

Bernd Wurst authored 9 years ago

81) }
82) 
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

83) 
bernd CSR-Erstellung

bernd authored 15 years ago

84) function csr_details($id)
85) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

86)     $id = (int) $id;
87)     $uid = (int) $_SESSION['userinfo']['uid'];
Hanno remove whitespace in empty...

Hanno authored 6 years ago

88) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

89)     $result = db_query("SELECT id, created, hostname, bits, `replace`, csr, `key` FROM vhosts.csr WHERE uid=:uid AND id=:id", array(":uid" => $uid, ":id" => $id));
90)     if ($result->rowCount() != 1) {
91)         system_failure("Ungültiger CSR");
92)     }
93)     return $result->fetch();
bernd CSR-Erstellung

bernd authored 15 years ago

94) }
95) 
96) 
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

97) function get_available_CAs()
98) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

99)     $path = '/etc/apache2/certs/cabundle/';
100)     $ret = glob($path.'*.pem');
101)     if (! $ret) {
102)         system_failure("Konnte die CA-Zertifikate nicht laden");
103)     }
104)     DEBUG($ret);
105)     return $ret;
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

106) }
107) 
108) 
bernd Cert-Chain erkennen und ben...

bernd authored 14 years ago

109) function get_chain($cert)
110) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

111)     $certdata = openssl_x509_parse($cert, true);
112)     if ($certdata === false) {
113)         system_failure("Das Zertifikat konnte nicht gelesen werden");
114)     }
115)     if (! isset($certdata['issuer']['CN'])) {
116)         return null;
117)     }
118)     $result = db_query("SELECT id FROM vhosts.certchain WHERE cn=?", array($certdata['issuer']['CN']));
119)     if ($result->rowCount() > 0) {
120)         $c = $result->fetch();
121)         //$chainfile = '/etc/apache2/certs/chains/'.$c['id'].'.pem';
122)         DEBUG("identified fitting certificate chain #".$c['id']);
123)         return $c['id'];
124)     }
bernd Cert-Chain erkennen und ben...

bernd authored 14 years ago

125) }
126) 
127) 
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

128) function validate_certificate($cert, $key)
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

129) {
130)     // Lade private key
131)     $seckey = openssl_get_privatekey($key);
132)     if ($seckey === false) {
133)         system_failure("Der private Schlüssel konnte (ohne Passwort) nicht gelesen werden.");
134)     }
135)     // Lade public key
136)     $pubkey = openssl_get_publickey($cert);
137)     if ($pubkey === false) {
138)         system_failure("In dem eingetragenen Zertifikat wurde kein öffentlicher Schlüssel gefunden.");
139)     }
140)     // Parse Details über den pubkey
141)     $certinfo = openssl_pkey_get_details($pubkey);
142)     DEBUG($certinfo);
143)     if ($certinfo === false) {
144)         system_failure("Der öffentliche Schlüssel des Zertifikats konnte nicht gelesen werden");
145)     }
146) 
147)     // Apache unterstützt nur Schlüssel vom Typ RSA oder DSA
148)     if (! in_array($certinfo['type'], array(OPENSSL_KEYTYPE_RSA, OPENSSL_KEYTYPE_DSA))) {
149)         system_failure("Dieser Schlüssel nutzt einen nicht unterstützten Algorithmus.");
150)     }
Hanno remove whitespace in empty...

Hanno authored 6 years ago

151) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

152)     // Bei ECC-Keys treten kürzere Schlüssellängen auf, die können wir aktuell aber sowieso nicht unterstützen
153)     if ($certinfo['bits'] < 2048) {
154)         warning("Dieser Schlüssel hat eine sehr geringe Bitlänge und ist daher als nicht besonders sicher einzustufen!");
155)     }
156) 
157)     // Prüfe ob Key und Zertifikat zusammen passen
158)     if (openssl_x509_check_private_key($cert, $key) !== true) {
159)         DEBUG("Zertifikat und Key passen nicht zusammen: ".openssl_x509_check_private_key($cert, $key));
160)         return CERT_INVALID;
161)     }
162) 
163)     $cacerts = array('/etc/ssl/certs');
164)     $chain = (int) get_chain($cert);
165)     if ($chain) {
166)         $result = db_query("SELECT content FROM vhosts.certchain WHERE id=?", array($chain));
167)         $tmp = $result->fetch();
168)         $chaincert = $tmp['content'];
169)         $chainfile = tempnam(sys_get_temp_dir(), 'webinterface');
170)         $f = fopen($chainfile, "w");
171)         fwrite($f, $chaincert);
172)         fclose($f);
173)         $cacerts[] = $chainfile;
174)     }
175) 
176)     $valid = openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_SERVER, $cacerts);
177)     if ($chain) {
178)         unlink($chainfile);
179)     }
180)     if ($valid !== true) {
181)         DEBUG('certificate was not validated as a server certificate with the available chain');
182)         return CERT_NOCHAIN;
183)     }
184) 
185)     return CERT_OK;
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

186) }
187) 
188) 
189) function parse_cert_details($cert)
190) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

191)     $certdata = openssl_x509_parse($cert, true);
192)     /*
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

193) name => /CN=*.bwurst.org
194) validFrom_time_t => 1204118790
195) validTo_time_t => 1267190790
196) 
197) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

198)     */
199)     DEBUG($certdata);
200)     DEBUG("SAN: ".$certdata['extensions']['subjectAltName']);
201)     //return array('subject' => $certdata['name'], 'cn' => $certdata['subject']['CN'], 'valid_from' => date('Y-m-d', $certdata['validFrom_time_t']), 'valid_until' => date('Y-m-d', $certdata['validTo_time_t']));
202)     $issuer = $certdata['issuer']['CN'];
203)     if (isset($certdata['issuer']['O'])) {
204)         $issuer = $certdata['issuer']['O'];
205)     }
206)     $san = array();
207)     $raw_san = explode(', ', $certdata['extensions']['subjectAltName']);
208)     foreach ($raw_san as $name) {
209)         if (! substr($name, 0, 4) == 'DNS:') {
210)             warning('Unparsable SAN: '.$name);
211)             continue;
212)         }
213)         $san[] = str_replace('DNS:', '', $name);
Bernd Wurst Verarbeite und Speichere SA...

Bernd Wurst authored 7 years ago

214)     }
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

215)     $san = implode("\n", $san);
216)     DEBUG("SAN: <pre>".$san."</pre>");
217)     return array('subject' => $certdata['subject']['CN'].' / '.$issuer, 'cn' => $certdata['subject']['CN'], 'valid_from' => date('Y-m-d', $certdata['validFrom_time_t']), 'valid_until' => date('Y-m-d', $certdata['validTo_time_t']), 'issuer' => $certdata['issuer']['CN'], 'san' => $san);
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

218) }
219) 
220) 
221) function save_cert($info, $cert, $key)
222) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

223)     openssl_pkey_export($key, $key);
224)     openssl_x509_export($cert, $cert);
225)     $uid = (int) $_SESSION['userinfo']['uid'];
226) 
227)     db_query(
228)       "INSERT INTO vhosts.certs (uid, subject, cn, san, valid_from, valid_until, chain, cert, `key`) VALUES (:uid, :subject, :cn, :san, :valid_from, :valid_until, :chain, :cert, :key)",
229)         array(":uid" => $uid, ":subject" => filter_input_general($info['subject']), ":cn" => filter_input_general($info['cn']), ":san" => $info['san'], ":valid_from" => $info['valid_from'],
230)               ":valid_until" => $info['valid_until'], ":chain" => get_chain($cert), ":cert" => $cert, ":key" => $key)
231)   );
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

232) }
233) 
bernd Cert-Refresh

bernd authored 15 years ago

234) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

235) function refresh_cert($id, $info, $cert, $key = null)
bernd Cert-Refresh

bernd authored 15 years ago

236) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

237)     openssl_x509_export($cert, $cert);
238)     $chain = get_chain($cert);
bernd Bugfix: Beim Eintragen eine...

bernd authored 13 years ago

239) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

240)     $id = (int) $id;
241)     $oldcert = cert_details($id);
242)     $args = array(":subject" => filter_input_general($info['subject']),
Bernd Wurst Einige Statements auf Prepa...

Bernd Wurst authored 10 years ago

243)                 ":cn" => filter_input_general($info['cn']),
Bernd Wurst Fix SAN for refreshed certs

Bernd Wurst authored 5 years ago

244)                 ":san" => $info['san'],
Bernd Wurst Einige Statements auf Prepa...

Bernd Wurst authored 10 years ago

245)                 ":cert" => $cert,
246)                 ":valid_from" => $info['valid_from'],
247)                 ":valid_until" => $info['valid_until'],
248)                 ":chain" => get_chain($cert),
249)                 ":id" => $id);
250) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

251)     $keyop = '';
252)     if ($key) {
253)         openssl_pkey_export($key, $key);
254)         $keyop = ", `key`=:key";
255)         $args[":key"] = $key;
256)     }
257)     db_query("UPDATE vhosts.certs SET subject=:subject, cn=:cn, san=:san, cert=:cert{$keyop}, valid_from=:valid_from, valid_until=:valid_until, chain=:chain WHERE id=:id", $args);
bernd Cert-Refresh

bernd authored 15 years ago

258) }
259) 
260) 
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

261) function delete_cert($id)
262) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

263)     $uid = (int) $_SESSION['userinfo']['uid'];
264)     $id = (int) $id;
Hanno remove whitespace in empty...

Hanno authored 6 years ago

265) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

266)     db_query("DELETE FROM vhosts.certs WHERE uid=? AND id=?", array($uid, $id));
bernd Neue Zertifikatsverwaltung

bernd authored 15 years ago

267) }
268) 
bernd CSR-Erstellung

bernd authored 15 years ago

269) function delete_csr($id)
270) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

271)     $uid = (int) $_SESSION['userinfo']['uid'];
272)     $id = (int) $id;
Hanno remove whitespace in empty...

Hanno authored 6 years ago

273) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

274)     db_query("DELETE FROM vhosts.csr WHERE uid=? AND id=?", array($uid, $id));
bernd CSR-Erstellung

bernd authored 15 years ago

275) }
276) 
277) 
Bernd Wurst * Ermögliche SAN bei CSRs *...

Bernd Wurst authored 9 years ago

278) function split_cn($cn)
279) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

280)     $domains = array();
281)     if (strstr($cn, ',') or strstr($cn, "\n")) {
282)         $domains = preg_split("/[, \n]+/", $cn);
283)         DEBUG("Domains:");
284)         DEBUG($domains);
285)     } else {
286)         $domains[] = $cn;
287)     }
288)     for ($i=0;$i!=count($domains);$i++) {
289)         $domains[$i] = filter_input_hostname($domains[$i], true);
290)     }
291)     return $domains;
Bernd Wurst * Ermögliche SAN bei CSRs *...

Bernd Wurst authored 9 years ago

292) }
293) 
bernd CSR-Erstellung

bernd authored 15 years ago

294) function create_csr($cn, $bits)
295) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

296)     $domains = split_cn($cn);
297)     $tmp = array();
298)     foreach ($domains as $dom) {
299)         $tmp[] = 'DNS:'.$dom;
300)     }
301)     $SAN = "[ v3_req ]\nsubjectAltName = ".implode(', ', $tmp);
302)     DEBUG($SAN);
303)     $cn = $domains[0];
304)     $bits = (int) $bits;
305)     if ($bits == 0) {
306)         $bits = 4096;
307)     }
308) 
309)     $keyfile = tempnam(ini_get('upload_tmp_dir'), 'key');
310)     $csrfile = tempnam(ini_get('upload_tmp_dir'), 'csr');
311)     $config = tempnam(ini_get('upload_tmp_dir'), 'config');
312) 
313)     DEBUG("key: ".$keyfile." / csr: ".$csrfile." / config: ".$config);
314) 
315)     $c = fopen($config, "w");
316)     fwrite($c, "[req]
bernd CSR-Erstellung

bernd authored 15 years ago

317) default_bits = {$bits}
318) default_keyfile = {$keyfile}
319) encrypt_key = no
320) distinguished_name      = req_distinguished_name
Bernd Wurst * Ermögliche SAN bei CSRs *...

Bernd Wurst authored 9 years ago

321) req_extensions = v3_req
bernd CSR-Erstellung

bernd authored 15 years ago

322) 
323) [ req_distinguished_name ]
324) countryName                     = Country Name (2 letter code)
Bernd Wurst Leere Vorgaben für CSR-Details

Bernd Wurst authored 10 years ago

325) countryName_default             = 
bernd CSR-Erstellung

bernd authored 15 years ago

326) stateOrProvinceName             = State or Province Name (full name)
Bernd Wurst Leere Vorgaben für CSR-Details

Bernd Wurst authored 10 years ago

327) stateOrProvinceName_default     = 
bernd CSR-Erstellung

bernd authored 15 years ago

328) localityName                    = Locality Name (eg, city)
Bernd Wurst Leere Vorgaben für CSR-Details

Bernd Wurst authored 10 years ago

329) localityName_default            = 
bernd CSR-Erstellung

bernd authored 15 years ago

330) 0.organizationName              = Organization Name (eg, company)
Bernd Wurst Leere Vorgaben für CSR-Details

Bernd Wurst authored 10 years ago

331) 0.organizationName_default      = 
bernd CSR-Erstellung

bernd authored 15 years ago

332) 
333) commonName = Common Name
334) commonName_default = {$cn}
Bernd Wurst * Ermögliche SAN bei CSRs *...

Bernd Wurst authored 9 years ago

335) {$SAN}
bernd CSR-Erstellung

bernd authored 15 years ago

336) ");
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

337)     fclose($c);
338) 
339)     $output = '';
340)     $cmdline = "openssl req -sha256 -new -batch -config {$config} -out {$csrfile}";
341)     $retval = 0;
342)     exec($cmdline, $output, $retval);
343)     DEBUG($output);
344)     DEBUG($retval);
345)     if ($retval != 0) {
346)         system_failure("Die Erzeugung des CSR ist fehlgeschlagen. Ausgabe des OpenSSL-Befehls: ".print_r($output, true));
347)     }
Hanno remove whitespace in empty...

Hanno authored 6 years ago

348) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

349)     $csr = file_get_contents($csrfile);
350)     $key = file_get_contents($keyfile);
bernd CSR-Erstellung

bernd authored 15 years ago

351) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

352)     unlink($csrfile);
353)     unlink($keyfile);
354)     unlink($config);
bernd CSR-Erstellung

bernd authored 15 years ago

355) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

356)     return array($csr, $key);
bernd CSR-Erstellung

bernd authored 15 years ago

357) }
358) 
359) 
360) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

361) function save_csr($cn, $bits, $replace=null)
bernd CSR-Erstellung

bernd authored 15 years ago

362) {
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

363)     if (! $cn) {
364)         system_failure("Sie müssen einen Domainname eingeben!");
365)     }
366)     $domains = split_cn($cn);
367)     $cn = $domains[0];
368)     $san = implode("\n", $domains);
369)     $csr = null;
370)     $key = null;
371)     list($csr, $key) = create_csr(implode(',', $domains), $bits);
Hanno remove whitespace in empty...

Hanno authored 6 years ago

372) 
Hanno Fix coding style with php-c...

Hanno authored 6 years ago

373)     $uid = (int) $_SESSION['userinfo']['uid'];
374)     db_query(
375)       "INSERT INTO vhosts.csr (uid, hostname, san, bits, `replace`, csr, `key`) VALUES (:uid, :cn, :san, :bits, :replace, :csr, :key)",
376)            array(":uid" => $uid, ":cn" => $cn, ":san" => $san, ":bits" => $bits,
377)                  ":replace" => $replace, ":csr" => $csr, ":key" => $key)
378)   );
379)     $id = db_insert_id();
380)     return $id;