Mangled path fax send (#7515)
[openemr.git] / interface / usergroup / ssl_certificates_admin.php
blob4707755f402f2f1d37f1e3d8fc408a602f0a1a06
1 <?php
3 /**
4 * This page is used to setup https access to OpenEMR with client certificate authentication.
5 * If enabled, the browser must connect to OpenEMR using a client SSL certificate that is
6 * generated by OpenEMR. This page is used to create the Certificate Authority and
7 * Apache SSL server certificate.
9 * @package OpenEMR
10 * @link http://www.open-emr.org
11 * @author Visolve <vicareplus_engg@visolve.com>
12 * @author Brady Miller <brady.g.miller@gmail.com>
13 * @author Jerry Padgett <sjpadgett@gmail.com>
14 * @copyright Copyright (c) Visolve <vicareplus_engg@visolve.com>
15 * @copyright Copyright (c) 2018-2020 Brady Miller <brady.g.miller@gmail.com>
16 * @copyright Copyright (c) 2020 Jerry Padgett <sjpadgett@gmail.com>
17 * @license https://github.com/openemr/openemr/blob/master/LICENSE CNU General Public License 3
20 require_once("../globals.php");
21 require_once("../../library/create_ssl_certificate.php");
23 use OpenEMR\Common\Acl\AclMain;
24 use OpenEMR\Common\Csrf\CsrfUtils;
25 use OpenEMR\Common\Session\SessionUtil;
26 use OpenEMR\Common\Twig\TwigContainer;
27 use OpenEMR\Core\Header;
29 if (!empty($_POST)) {
30 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
31 CsrfUtils::csrfNotVerified();
35 if (!AclMain::aclCheckCore('admin', 'users')) {
36 echo (new TwigContainer(null, $GLOBALS['kernel']))->getTwig()->render('core/unauthorized.html.twig', ['pageTitle' => xl("SSL Certificate Administration")]);
37 exit;
40 /* This string contains any error messages if generating
41 * certificates fails.
43 $error_msg = "";
45 /**
46 * Send an http reply so that the browser downloads the given file.
47 * Delete the file once the download is completed.
48 * @param $filename - The file to download.
49 * @param $filetype - The type of file.
51 function download_file($filename, $filetype)
54 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
55 header("Cache-Control: private");
56 header("Content-Type: application/" . $filetype);
57 header("Content-Disposition: attachment; filename=" . basename($filename) . ";");
58 header("Content-Transfer-Encoding: binary");
59 header("Content-Length: " . filesize($filename));
60 readfile($filename);
61 exit;
62 flush();
63 @unlink($filename);
66 /* This function is called when the "Create Client Certificate" button is clicked.
67 * Create and download a client certificate, given the following form inputs:
68 * client_cert_user - The username to store in the certificate
69 * client_cert_email - The email to store in the certificate
70 * A temporary certificate will be written to /tmp/openemr_client_cert.p12.
71 * If an error occurs, set the $error_msg (which is displayed later below).
73 function create_client_cert()
75 global $error_msg;
77 if (!$GLOBALS['is_client_ssl_enabled']) {
78 $error_msg .= xl('Error, User Certificate Authentication is not enabled in OpenEMR');
79 return;
81 if (!file_exists($GLOBALS['certificate_authority_crt'])) {
82 $error_msg .= xl('Error, the CA Certificate File doesn\'t exist');
83 return;
85 if (!file_exists($GLOBALS['certificate_authority_key'])) {
86 $error_msg .= xl('Error, the CA Key File doesn\'t exist');
87 return;
90 if ($_POST["client_cert_user"]) {
91 $user = trim($_POST['client_cert_user']);
94 if ($_POST["client_cert_email"]) {
95 $email = trim($_POST['client_cert_email']);
98 if ($_POST["clientPassPhrase"]) {
99 $clientPassPhrase = trim($_POST['clientPassPhrase']);
102 $serial = 0;
103 $data = create_user_certificate(
104 $user,
105 $email,
106 $serial,
107 $GLOBALS['certificate_authority_crt'],
108 $GLOBALS['certificate_authority_key'],
109 $GLOBALS['client_certificate_valid_in_days']
111 if ($data === false) {
112 $error_msg .= xl('Error, unable to create client certificate.');
113 return;
116 $filename = $GLOBALS['temporary_files_dir'] . "/openemr_client_cert.p12";
117 $handle = fopen($filename, 'w');
118 fwrite($handle, $data);
119 fclose($handle);
121 download_file($filename, "p12");
124 /* Delete the following temporary certificate files, if they exist:
125 * /tmp/CertificateAuthority.key
126 * /tmp/CertificateAuthority.crt
127 * /tmp/Server.key
128 * /tmp/Server.crt
129 * /tmp/admin.p12
130 * /tmp/ssl.zip
132 function delete_certificates()
134 $tempDir = $GLOBALS['temporary_files_dir'];
135 $files = array("CertificateAuthority.key", "CertificateAuthority.crt",
136 "Server.key", "Server.crt", "admin.p12", "ssl.zip");
138 foreach ($files as $file) {
139 if (file_exists($file)) {
140 unlink($file);
146 * Create and download the following certificates:
147 * - CertificateAuthority.key
148 * - CertificateAuthority.crt
149 * - Server.key
150 * - Server.crt
151 * - admin.p12
152 * The following form inputs are used:
154 function create_and_download_certificates()
156 global $error_msg;
157 $tempDir = $GLOBALS['temporary_files_dir'];
159 $zipName = $tempDir . "/ssl.zip";
160 if (file_exists($zipName)) {
161 unlink($zipName);
164 $commonName = false;
165 $emailAddress = false;
166 $countryName = false;
167 $stateOrProvinceName = false;
168 $localityName = false;
169 $organizationName = false;
170 $organizationalUnitName = false;
171 $clientCertValidity = false;
172 $clientPassPhrase = null;
174 /* Retrieve the certificate name settings from the form input */
175 if ($_POST["commonName"]) {
176 $commonName = trim($_POST['commonName']);
179 if ($_POST["emailAddress"]) {
180 $emailAddress = trim($_POST['emailAddress']);
183 if ($_POST["countryName"]) {
184 $countryName = trim($_POST['countryName']);
187 if ($_POST["stateOrProvinceName"]) {
188 $stateOrProvinceName = trim($_POST['stateOrProvinceName']);
191 if ($_POST["localityName"]) {
192 $localityName = trim($_POST['localityName']);
195 if ($_POST["organizationName"]) {
196 $organizationName = trim($_POST['organizationName']);
199 if ($_POST["organizationalUnitName"]) {
200 $organizationName = trim($_POST['organizationalUnitName']);
203 if ($_POST["clientCertValidity"]) {
204 $clientCertValidity = trim($_POST['clientCertValidity']);
207 if ($_POST["clientPassPhrase"]) {
208 $clientPassPhrase = trim($_POST['clientPassPhrase']);
211 /* Create the Certficate Authority (CA) */
212 $arr = create_csr(
213 "OpenEMR CA for " . $commonName,
214 $emailAddress,
215 $countryName,
216 $stateOrProvinceName,
217 $localityName,
218 $organizationName,
219 $organizationalUnitName
222 if ($arr === false) {
223 $error_msg .= xl('Error, unable to create the Certificate Authority certificate.');
224 delete_certificates();
225 return;
228 $ca_csr = $arr[0];
229 $ca_key = $arr[1];
230 $ca_crt = create_crt($ca_csr, null, $ca_key);
231 if ($ca_crt === false) {
232 $error_msg .= xl('Error, unable to create the Certificate Authority certificate.');
233 delete_certificates();
234 return;
237 openssl_pkey_export_to_file($ca_key, $tempDir . "/CertificateAuthority.key", null);
238 openssl_x509_export_to_file($ca_crt, $tempDir . "/CertificateAuthority.crt");
240 /* Create the Server certificate */
241 $arr = create_csr(
242 $commonName,
243 $emailAddress,
244 $countryName,
245 $stateOrProvinceName,
246 $localityName,
247 $organizationName,
248 $organizationalUnitName
250 if ($arr === false) {
251 $error_msg .= xl('Error, unable to create the Server certificate.');
252 delete_certificates();
253 return;
256 $server_csr = $arr[0];
257 $server_key = $arr[1];
258 $server_crt = create_crt($server_csr, $ca_crt, $ca_key);
260 if ($server_crt === false) {
261 $error_msg .= xl('Error, unable to create the Server certificate.');
262 delete_certificates();
263 return;
266 openssl_pkey_export_to_file($server_key, $tempDir . "/Server.key", null);
267 openssl_x509_export_to_file($server_crt, $tempDir . "/Server.crt");
269 /* Create the client certificate for the 'admin' user */
270 $serial = 0;
271 $res = sqlStatement("select id from users where username='admin'");
272 if ($row = sqlFetchArray($res)) {
273 $serial = $row['id'];
276 $user_cert = create_user_certificate(
277 "admin",
278 $emailAddress,
279 $serial,
280 $tempDir . "/CertificateAuthority.crt",
281 $tempDir . "/CertificateAuthority.key",
282 $clientCertValidity
284 if ($user_cert === false) {
285 $error_msg .= xl('Error, unable to create the admin.p12 certificate.');
286 delete_certificates();
287 return;
290 $adminFile = $tempDir . "/admin.p12";
291 $handle = fopen($adminFile, 'w');
292 fwrite($handle, $user_cert);
293 fclose($handle);
295 /* Create a zip file containing the CertificateAuthority, Server, and admin files */
296 try {
297 if (! (class_exists('ZipArchive'))) {
298 SessionUtil::setSession('zip_error', xl("Error, Class ZipArchive does not exist"));
299 return;
302 $zip = new ZipArchive();
303 if (!($zip)) {
304 SessionUtil::setSession('zip_error', xl("Error, Could not create file archive"));
305 return;
308 if ($zip->open($zipName, ZipArchive::CREATE)) {
309 $files = array("CertificateAuthority.key", "CertificateAuthority.crt",
310 "Server.key", "Server.crt", "admin.p12");
311 foreach ($files as $file) {
312 $zip->addFile($tempDir . "/" . $file, $file);
314 } else {
315 SessionUtil::setSession('zip_error', xl("Error, unable to create zip file with all the certificates"));
316 return;
319 $zip->close();
321 if (ini_get('zlib.output_compression')) {
322 ini_set('zlib.output_compression', 'Off');
324 } catch (Exception $e) {
325 SessionUtil::setSession('zip_error', xl("Error, Could not create file archive"));
326 return;
329 download_file($zipName, "zip");
332 /*if ($_POST["mode"] == "save_ssl_settings") {
333 save_certificate_settings();
336 if (!empty($_POST["mode"]) && ($_POST["mode"] == "create_client_certificate")) {
337 create_client_cert();
338 } elseif (!empty($_POST["mode"]) && ($_POST["mode"] == "download_certificates")) {
339 create_and_download_certificates();
342 if (!empty($_SESSION["zip_error"])) {
343 $zipErrorOutput = '<div><table align="center"><tr valign="top"><td rowspan="3"><font class="redtext">' . text($_SESSION["zip_error"]) . '</td></tr></table></div>';
344 SessionUtil::unsetSession('zip_error');
349 <html>
350 <head>
351 <script>
353 //check whether email id is valid or not
354 function checkEmail(email) {
355 var str=email;
356 var at="@";
357 var dot=".";
358 var lat=str.indexOf(at);
359 var lstr=str.length;
360 var ldot=str.indexOf(dot);
361 if (str.indexOf(at)==-1){
362 return false;
365 if (str.indexOf(at)==-1 || str.indexOf(at)==0 || str.indexOf(at)==lstr){
366 return false;
369 if (str.indexOf(dot)==-1 || str.indexOf(dot)==0 || str.indexOf(dot)==lstr){
370 return false;
373 if (str.indexOf(at,(lat+1))!=-1){
374 return false;
377 if (str.substring(lat-1,lat)==dot || str.substring(lat+1,lat+2)==dot){
378 return false;
381 if (str.indexOf(dot,(lat+2))==-1){
382 return false;
385 if (str.indexOf(" ")!=-1){
386 return false;
389 return true;
391 function download_click(){
392 if (document.ssl_certificate_frm.commonName.value == "") {
393 alert (<?php echo xlj('Host Name cannot be empty'); ?>);
394 document.ssl_certificate_frm.commonName.focus();
395 return false;
398 if (document.ssl_certificate_frm.emailAddress.value) {
399 //call checkEmail function
400 if(checkEmail(document.ssl_certificate_frm.emailAddress.value) == false){
401 alert (<?php echo xlj('Provide valid Email Address'); ?>);
402 return false;
406 if (document.ssl_certificate_frm.countryName.value.length > 2) {
407 alert (<?php echo xlj('Country Name should be represent in two letters. (Example: United States is US)'); ?>);
408 document.ssl_certificate_frm.countryName.focus();
409 return false;
411 if (document.ssl_certificate_frm.clientCertValidity.value < 1) {
412 alert (<?php echo xlj('Client certificate validity should be a valid number.'); ?>);
413 document.ssl_certificate_frm.clientCertValidity.focus();
414 return false;
417 function create_client_certificate_click(){
419 /*if(document.ssl_frm.isClientAuthenticationEnabled[1].checked == true)
421 alert (<?php echo xlj('User Certificate Authentication is disabled'); ?>);
422 return false;
425 if (document.client_cert_frm.client_cert_user.value == "") {
426 alert (<?php echo xlj('User name or Host name cannot be empty'); ?>);
427 document.ssl_certificate_frm.commonName.focus();
428 return false;
430 if (document.client_cert_frm.client_cert_email.value) {
431 //call checkEmail function
432 if(checkEmail(document.client_cert_frm.client_cert_email.value) == false){
433 alert (<?php echo xlj('Provide valid Email Address'); ?>);
434 return false;
439 function isNumberKey(evt) {
440 var charCode = (evt.which) ? evt.which : evt.keyCode
441 if (charCode > 31 && (charCode < 48 || charCode > 57))
442 return false;
443 else
444 return true;
447 </script>
449 <?php Header::setupHeader(); ?>
451 <style>
452 div.borderbox {
453 margin: 5px 5px;
454 padding: 5px 5px;
455 border: solid 1px;
456 width: 60%;
458 </style>
460 </head>
461 <body class="body_top">
462 <span class='title'><b><?php echo xlt('SSL Certificate Administration'); ?></b></span>
463 <br /> <br />
464 <?php if (!empty($zipErrorOutput)) {
465 echo $zipErrorOutput;
466 } else { ?>
467 <span class='text'>
468 <?php
469 if ($error_msg != "") {
470 echo "<font class='redtext'>" . text($error_msg) . "</font><br /><br />";
473 <?php echo xlt('To setup https access with client certificate authentication, do the following'); ?>
474 <ul>
475 <li><?php echo xlt('Create the SSL Certificate Authority and Server certificates.'); ?>
476 <li><?php echo xlt('Configure Apache to use HTTPS.'); ?>
477 <li><?php echo xlt('Configure Apache and OpenEMR to use Client side SSL certificates.'); ?>
478 <li><?php echo xlt('Import certificate to the browser.'); ?>
479 <li><?php echo xlt('Create a Client side SSL certificate for each user or client machine.'); ?>
480 </ul>
481 <br />
482 <?php
483 if ($GLOBALS['certificate_authority_crt'] != "" && $GLOBALS['is_client_ssl_enabled']) {
484 echo xlt('OpenEMR already has a Certificate Authority configured.');
487 <form method='post' name=ssl_certificate_frm action='ssl_certificates_admin.php'>
488 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
489 <input type='hidden' name='mode' value='download_certificates'>
490 <div class='borderbox'>
491 <b><?php echo xlt('Create the SSL Certificate Authority and Server certificates.'); ?></b><br />
492 <br />
493 1. <?php echo xlt('Fill in the values below'); ?><br />
494 2. <?php echo xlt('Click Download Certificate to download the certificates in the file ssl.zip'); ?> <br />
495 3. <?php echo xlt('Extract the zip file');
496 echo ": ssl.zip "; ?><br /><br />
497 <?php echo xlt('The zip file will contain the following items'); ?> <br />
498 <ul>
499 <li>Server.crt : <?php echo xlt('The Apache SSL server certificate and public key'); ?>
500 <li>Server.key : <?php echo xlt('The corresponding private key'); ?>
501 <li>CertificateAuthority.crt : <?php echo xlt('The Certificate Authority certificate'); ?>
502 <li>CertificateAuthority.key : <?php echo xlt('The corresponding private key'); ?>
503 <li>admin.p12 : <?php echo xlt('A client certificate for the admin user'); ?>
504 </ul>
505 <table border=0>
506 <tr class='text'>
507 <td><?php echo xlt('Host Name'); ?> *:</td>
508 <td><input name='commonName' type='text' value=''></td>
509 <td><?php echo xlt('Example') ;
510 echo ': hostname.domain.com'; ?></td>
511 </tr>
512 <tr class='text'>
513 <td><?php echo xlt('Email Address'); ?>:</td>
514 <td><input name='emailAddress' type='text' value=''></td>
515 <td><?php echo xlt('Example') ;
516 echo ': web_admin@domain.com'; ?></td>
517 </tr>
518 <tr class='text'>
519 <td><?php echo xlt('Organization Name'); ?>:</td>
520 <td><input name='organizationName' type='text' value=''></td>
521 <td><?php echo xlt('Example');
522 echo ': My Company Ltd'; ?></td>
523 </tr>
524 <tr class='text'>
525 <td><?php echo xlt('Organizational Unit Name'); ?>:</td>
526 <td><input name='organizationalUnitName' type='text' value=''></td>
527 <td><?php echo xlt('Example');
528 echo ': OpenEMR'; ?></td>
529 </tr>
530 <tr class='text'>
531 <td><?php echo xlt('Locality'); ?>:</td>
532 <td><input name='localityName' type='text' value=''></td>
533 <td><?php echo xlt('Example') ;
534 echo ': City'; ?></td>
535 </tr>
536 <tr class='text'>
537 <td><?php echo xlt('State Or Province'); ?>:</td>
538 <td><input name='stateOrProvinceName' type='text' value=''></td>
539 <td><?php echo xlt('Example') ;
540 echo ': California'; ?></td>
541 </tr>
542 <tr class='text'>
543 <td><?php echo xlt('Country'); ?>:</td>
544 <td><input name='countryName' type='text' value='' maxlength='2'></td>
545 <td><?php echo xlt('Example');
546 echo ': US';
547 echo ' (';
548 echo xlt('Should be two letters');
549 echo ')'; ?></td>
550 </tr>
551 <tr class='text'>
552 <td><?php echo xlt('Client certificate validation period'); ?>:</td>
553 <td><input name='clientCertValidity' type='text' onkeypress='return isNumberKey(event)' value='365'></td>
554 <td><?php echo xlt('days'); ?></td>
555 </tr>
556 <tr class='text'>
557 <td><?php echo xlt('Client certificate passphrase'); ?>:</td>
558 <td><input name='clientPassPhrase' type='text' value=''></td>
559 <td><?php echo xlt('Not required. This password is for generated admin.p12'); ?></td>
560 </tr>
561 <tr>
562 <td colspan=3 align='center'>
563 <input name='sslcrt' type='submit' onclick='return download_click();' value='<?php echo xla('Download Certificates'); ?>'>
564 </td>
565 </tr>
566 </table>
567 </div>
568 </form>
569 <br />
571 <div class="borderbox">
572 <b><?php echo xlt('Configure Apache to use HTTPS.'); ?></b><br />
573 <br />
574 <?php echo xlt('Add new certificates to the Apache configuration file'); ?>:<br />
575 <br />
576 SSLEngine on<br />
577 SSLCertificateFile /path/to/Server.crt<br />
578 SSLCertificateKeyFile /path/to/Server.key<br />
579 SSLCACertificateFile /path/to/CertificateAuthority.crt<br />
580 <br />
581 <?php echo xlt('Note'); ?>:
582 <ul>
583 <li><?php echo xlt('To Enable only HTTPS, perform the above changes and restart Apache server. If you want to configure client side certificates also, please configure them in the next section.'); ?><br />
584 <li> <?php echo xlt('To Disable HTTPS, comment the above lines in Apache configuration file and restart Apache server.'); ?>
585 <ul/>
586 </div>
588 <br />
589 <div class="borderbox">
590 <form name='ssl_frm' method='post'>
591 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
592 <b><?php echo xlt('Configure Apache to use Client side SSL certificates'); ?> </b>
593 <br /><br />
594 <?php echo xlt('Add following lines to the Apache configuration file'); ?>:<br />
595 <br />
596 SSLVerifyClient require<br />
597 SSLVerifyDepth 2<br />
598 SSLOptions +StdEnvVars<br />
599 <br /> <b><?php echo xlt('Configure Openemr to use Client side SSL certificates'); ?> </b><br />
600 <input type='hidden' name='clientCertValidity_hidden' value=''>
601 <br />
603 <?php echo xlt('Update the following settings in Administration->Globals->Security'); ?>:<br />
604 <?php echo xlt('Turn on Enable Client SSL'); ?><br />
605 <?php echo xlt('Provide absolute path of following file in Path to CA Certificate File'); ?> CertificateAuthority.crt<br />
606 <?php echo xlt('Provide absolute path of following file in Path to CA Key File'); ?> CertificateAuthority.key<br />
607 <br />
608 <br /><?php echo xlt('Note'); ?>:
609 <ul>
610 <li><?php echo xlt('To Enable Client side SSL certificates authentication, HTTPS should be enabled.'); ?>
611 <li><?php echo xlt('After performing above configurations, import the admin client certificate to the browser and restart Apache server (empty password).'); ?>
612 <li><?php echo xlt('To Disable client side SSL certificates, comment above lines in Apache configuration file and turn off the \'Enable Client SSL\' global setting in OpenEMR and restart Apache server.'); ?>
613 </form>
614 </div>
615 <br />
616 <div class="borderbox">
617 <b><?php echo xlt('Create Client side SSL certificates'); ?></b><br />
618 <br />
619 <?php echo xlt('Create a client side SSL certificate for either a user or a client hostname.'); ?>
620 <br />
621 <?php
622 if (
623 !$GLOBALS['is_client_ssl_enabled'] ||
624 $GLOBALS['certificate_authority_crt'] == ""
626 echo "<font class='redtext'>" . xlt('OpenEMR must be configured to use certificates before it can create client certificates.') . "</font><br />";
629 <form name='client_cert_frm' method='post' action='ssl_certificates_admin.php'>
630 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
631 <input type='hidden' name='mode' value='create_client_certificate'>
632 <table>
633 <tr class='text'>
634 <td><?php echo xlt('User or Host name'); ?>*:</td>
635 <td><input type='text' name='client_cert_user' size=20 />
636 </tr>
637 <tr class='text'>
638 <td><?php echo xlt('Email'); ?>:</td>
639 <td><input type='text' name='client_cert_email' size=20 />
640 </tr>
641 <tr class='text'>
642 <td><?php echo xlt('Client certificate passphrase'); ?>:</td>
643 <td><input name='clientPassPhrase' type='password' value=''></td>
644 <td><?php echo xlt('Not required.'); ?></td>
645 </tr>
646 </table>
647 <br /> <input type='submit' onclick='return create_client_certificate_click();' value='<?php echo xla('Create Client Certificate'); ?>'>
648 </form>
649 </div>
650 <br />
651 <br />&nbsp;
652 <br />&nbsp;
653 </span>
654 <?php } ?>
655 </body>
656 </html>