phpki-0.82

This commit is contained in:
2025-09-10 23:01:43 -04:00
parent 02a6566061
commit 66ea908568
78 changed files with 5094 additions and 1 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
*.rpm
*.log
*spec-20*
*.gz

120
root/CHANGELOG Normal file
View File

@@ -0,0 +1,120 @@
v0.01: 03-Mar-21:
- Limited preview release.
v0.02: 03-Mar-22:
- Improved user fiendliness of some terminology.
- Added Unit column to, removed serial column from control panel.
- Added Makefile to make distclean for distribution.
- Improved installation/setup automation with PHP setup script, Makefile
and secure.sh script.
- Added support for NetscapeRevocationURL protocol.
- Minor fixes.
- Minor help file changes.
v0.03:
- Added System Admin module under ca/admin for creating adding/removing users
and updating CRL.
- Fixed NetscapeRevocationURL malformed URL (was missing '?' at end of URL)
- Revoked certificates can now be found with public search, but cannot be
downloaded. Certificate status is shown.
- Added authorityInfoAccess extension to certificates.
- All forms should now load with cursor focus in first field.
- E-mail addresses are now clickable "mailto:" links.
- Added sample crontab CRL update script for use with RedHat style
/etc/cron.monthly crontab layout.
- Probably some minor bug fixes not worth listing separately.
- Updated HELP screenshots
v0.04:
- Fixed a download problem which could cause corrupted certificates and
CRLs. The upload() function was using fpassthru() which automatically
closes the file. A subsequent fclose() error was adding extra junk to
the end of downloads. Switched to readfile().
- Added end-user help screens. More to come.
A brief explanation of PKI and e-mail encryption.
Root certificate installation for Outlook/Express
Personal e-mail certificate installation for Outlook/Express
- Some tweaking of certificate downloads to be more Netscape friendly.
- Some clean-up and reorganization of files, directories, and symlinks.
v0.05
- Added cert status filter to end-user search.
- Cleaned up some double/single quoting.
- SECURITY: Using escapeshellarg() throughout openssl_functions.
- SECURITY: gpvar() adds slashes if magic_quotes_gpc is disabled.
v0.06
- Added EXPERIMENTAL Web server certificate support.
- Added practices & policy statements
- Added descriptions to menu selections.
- SECURITY: Tightened permissions set by secure.sh script.
- SECURITY: Fixed insecure temp file creation in create_user_cnf().
v0.60
- Shifted version number left one digit to signify move to BETA status.
v0.70
- Fixed various typographical errors.
- Fixed updating of DER formatted CRL when using admin menu.
- Added IPSEC/VPN certificate type (reduced size).
- Allow server & VPN certificates with no password.
- Allow password file location to be specified during setup.
- Allow multiple certificates with same e-mail address _OR_ common_name.
- Allow key size selection 512 to 4096 bits.
- Consolidated certificate request forms (select type from dropdown).
- CRL is automatically updated when certificates are revoked.
- Moved CRL update function from admin menu to certificate management menu.
- Changed internal extention for DER files from .crt to .der
- Changed control panel buttons to icons shamelessly stolen from phpMyAdmin & KDE.
- Changed pkcs12 download file extention to "p12". Remains "pfx" internally.
- Changed public certificate download file extention to "cer" (RFC 2585).
- Changed public certificate mime type to "application/pkix-cert" (RFC 2585).
- Changed CRL mime type to "application/pkix-crl" (RFC 2585).
- Some code clean-up and consolidation in openssl_functions.php.
- Updated help file and screenshots.
- This version has not been thoroughly tested. Please log bug report on
sourceforge site.
- Other things I can't remember.
v0.80
- Major restructuring to allow certificates and configuration to be
stored outside of DOCUMENT_ROOT. Some might consider this a
security enhancement.
- Eliminated most of the symbolic links between interfaces.
- Moved the admin interface from ./ca/admin to ./admin
- Removed code to fix DER certificate extensions from secure.sh
You will have to do this manually if you skipped v0.70.
- The secure.sh script will ask the location of the phpkipasswd file
and attempt to create one if necessary.
- Added support for a DEMO mode to allow switching between the
public and private interfaces using the menu. Configure it in
config.php
v0.81 (not a public release)
- Modified VPN certificate extension to work properly with OpenVPN
- Added VPN Client Only, VPN Server Only, VPN Client & Server types
- Removed restrictions on certificate password contents and maximum length
- Fixed duplicate certificate error when requested common name was a
substring of an existing common name
v0.82 (possibly final release)
- Fixed expiry ignored and defaults to one year when renewing certificate
- Fixed missing quotes in CA_generate_crl
- Fixed missing quotes in request_cert.php
- Added documentation regarding method=post error on php5
- Switched on register_long_arrays in .htaccess.
Hope there is no breakage on php4.
- Added support for code signing certificates
- Trimmed some redundant code in CA_create_cert() & CA_renew_cert()
- Fixed "Go Back" button on download form
- Fixed quoting ambiguities when config.php files are created, which
causes warnings to be logged on some web server configurations.
Depending on how much this bugs you and how you upgrade, you may have
to manually fix this by correclty quoting constant definitions within
install_dir/config.php. e.g. define('CONSTANT','somevaluehere')
- Added support for multiple admins. Edit data_store/config/config.php
after installation and configuration. Idea by Micheal Braun.
- secure.sh automatically creates the 'pkiadmin' user.
- Fixed chown in secure.sh for FreeBSD compatibility.
- Fixed quote mismatch in ca/help.php
- Added support for time stamping certificates, Idea by Sebastien Bahlol.

341
root/LICENSE.TXT Normal file
View File

@@ -0,0 +1,341 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

52
root/Makefile Normal file
View File

@@ -0,0 +1,52 @@
VERSION = 0.82
UID = $(shell id -u)
GID = $(shell id -g)
all:
@echo "Read the README file!!"
clean:
find . -name .*.swp -follow -exec rm -f {} \;
find . -name test.php -exec rm -f {} \;
find . -name phpinfo.php -exec rm -f {} \;
find . -name "deleteme*" -exec rm -f {} \;
find . -name "newcert*.???" -exec rm -f {} \;
find . -name "privkey*.???" -exec rm -f {} \;
find . -name "newreq*.???" -exec rm -f {} \;
distclean: clean
find . -type d -follow -exec chmod 2777 {} \;
rm -f ca/index.php
echo -e '<?php\nheader("Location: ./../index.php");\n?>' > ca/index.php
echo '<?php' > config.php
echo 'define(PHPKI_VERSION, "$(VERSION)");' >> config.php
echo '?>' >> config.php
rm -f index.php
ln -sf readme.php index.php
ln -sf setup.php-presetup setup.php
find . ! -type d -follow -exec chown $(UID).$(GID) {} \;
find . ! -type d -follow -exec chmod 0666 {} \;
find . -type d -follow -exec chown $(UID).$(GID) {} \;
find . -type d -follow -exec chmod 2777 {} \;
find . -name .htaccess -follow -exec rm -f {} \;
chmod 700 secure.sh
echo -e 'Options FollowSymLinks' > .htaccess
echo -e 'php_flag register_globals off' >> .htaccess
echo -e 'php_flag register_long_arrays on' >> .htaccess
echo -e 'AddType application/x-x509-ca-cert .crt .pem' >> .htaccess
echo -e 'AddType application/pkix-crl .crl' >> .htaccess
echo -e 'AddType application/pkix-cert .cer .der' >> .htaccess
@echo -e "\n\n=================================================================="
@echo -e "Point your browser to your PHPki installation to configure and"
@echo -e "create your root certificate. (i.e. http://www.domain.com/phpki/)\n"
fixperms:
@./secure.sh

104
root/README Normal file
View File

@@ -0,0 +1,104 @@
NOTICE:
This application is designed to be an easy to use "certificate factory"
requiring minimum human intervention to administer. It is intended for
use within a trusted INTRAnet for the creation and management of x.509
e-mail digital certificates by departmental managers. IT IS NOT INTENDED
FOR USE OVER THE INTERNET.
This application stores private keys within a sub-directory, making them
potentially susceptible to compromise. Extra care has been taken in the
design of this application to protect the security of your certificates,
on the condition that you INSTALL IT AS THE ROOT USER. However, no
software is 100% secure, AND NO PROMISES OR GUARANTEES ARE MADE!
REQUIREMENTS:
PHPki was developed and tested on Mandrake and RedHat GNU/Linux systems.
It requires the Apache web server, PHP, and OpenSSL. I do not as yet
know if it is sensitive to particular versions of those resources.
Your web server must be configured with "AllowOverride All" effective
in the directory where PHPki is installed. If you don't know what this
means, then go Googling.
With PHP 5, make sure register_long_arrays in turn on in php.ini or .htaccess.
Otherwise, you may get an error similar to "method=post was not found on this se
rver.
INSTALLATION:
Make sure "AllowOverride All" is set in your Apache configuration file.
This is necessary because PHPki uses .htaccess files to implement HTTP
authentication and to enforce file access restrictions. If you must
change this Apache setting, don't forget to restart Apache.
Unpack the PHPki tarball onto your web server. For example:
cp phpki.tar.gz /var/tmp
cd /var/www/html
tar -xzvf /var/tmp/phpki.tar.gz
To configure the certificate authority and create your root certificate,
point your browser to where you unpacked PHPki. For example:
http://www.domain.com/phpki/
Enter all the requested information into the web form and click the Submit
button. If all goes well, you should see a page telling you that your
root certificate has been created.
To access the PHPki public content menu, point your browser to your
PHPki installation (i.e. http://www.domain.com/phpki/). To access the
PHPki certificate management menu, point your browser to the "ca"
directory under your PHPki installation (i.e. https://www.domain.com/phpki/ca/).
You must use SSL (https://) to access the PHPki certificate management
menu if you have secured the application using the secure.sh script.
SECURITY & USERS:
From a root user shell prompt, run the "secure.sh" shell script in this
directory to set more restrictive Unix file permissions, and to create
the Apache .htaccess files which are necessary to force SSL access, HTTP
authentication, and directory access restrictions. If you don't do this
you will likely be extremely screwed! Don't say you weren't warned.
The secure.sh script will attempt to create a file for your user list
and passwords. If it fails in that attempt, you will have to use Apache's
htpasswd utility to manually create a "phpkipasswd" file in the location
you specified during setup.
htpasswd -cm /var/www/phpkipasswd username
Normal users may only manage the certificates they create. Administrators
can manage all certificates. The default administrator account is
"pkiadmin". The secure.sh script will attempt to add this user to your
phpkipasswd file when it is first created. Other users can be made
administrators by carefully editing the $PHPki_admins assignment in
config/config.php under your certificate store directory.
You may add additional users and change passwords using your browser after
you have successfully installed PHPki and created your phpkipasswd file with
at least one user. Point your browser to http://www.domain.com/phpki/admin/.
UPGRADING:
Install and configure as if it were a first time installation (see above).
Be sure to specify the same root certificate password and user password file
location you used with the previous version.
From the old installation, copy all certificates, crls, and user defaults
to the store directory specified during setup.
rm -fr store_directory/CA
cp -v --archive oldphpki/CA store_directory
cp -v --archive oldphpki/config/user-*.php newphpki/ca/config
These upgrade instructions have not been thoroughly tested and may be
incomplete. Please be sure to fully backup your old PHPki installation before
upgrading.
CONTACT:
Post all correspondence to the PHPki project page
http://sourceforge.net/projects/phpki/
---END OF FILE---

16
root/TODO Normal file
View File

@@ -0,0 +1,16 @@
TO DO, IN NO PARTICULAR ORDER:
Add CA certificate renewal to sysadmin script (ca/admin/index.php)
Add paging features to Certificate Management Control Panel instead of
having all certificates listed on a single page. This is not really
very necessary unless one will be issuing hundreds of certificates. Even
with 200 certificates, the control panel display is very manageable.
Use a relational database such as MySQL to maintain the certificate database
instead using the built-in OpenSSL CA feature. This will only be necessary
if it turns out that the built in OpenSSL CA doesn't perform well.
More documentation and help files.
Support multi-homed server certificates

44
root/about.php Normal file
View File

@@ -0,0 +1,44 @@
<?php
include('./config.php');
include('./include/my_functions.php');
include('./include/common.php');
printHeader('about');
?>
<p>
PHPki is an <a href=http://www.opensource.org target=_blank>Open Source</a>
Web application for managing a <a href=<?=BASE_URL?>help/glossary.html#PKI target=help/glossary>
Public Key Infrastructure</a> within a small organizations. PHPki acts as a
mechanism for the centralized creation and management of digital certificates.
PHPki is capable of managing certificates for multiple organizations or user
accounts.
<p>
PHPki requires the Apache Web Server, the <href=http://www.php.net target=_blank>PHP</a> Scripting Language, and <href=http://www.openssl.org target=_blank>
OpenSSL</a>, all of which are included with any major
<a href=http://www.linux.org target=_blank> Linux Operating System</a>
<a href=http://www.redhat.com target=_blank>distribution</a>.
<p>
This software may be freely redistributed under the terms of the
<a href=http://www.gnu.org target=_blank>GNU</a> Public
License provided this page and all copyright notices remain completely intact.
<p>
<center><h4>Copyright: 2003, William E. Roadcap</h4>
<form>
<textarea name=gpl cols=80 rows=15 readonly>
<?
readfile("./LICENSE.TXT");
?>
</textarea>
</form>
</center>
<p>
<?
printFooter();
?>

127
root/admin/index.php Normal file
View File

@@ -0,0 +1,127 @@
<?php
include('../config.php');
include(STORE_DIR.'/config/config.php');
include('../include/my_functions.php');
include('../include/common.php') ;
$stage = gpvar('stage');
$login = gpvar('login');
$passwd = gpvar('passwd');
$passwdv = gpvar('passwdv');
switch($stage) {
case 'list_users':
printHeader('admin');
print '<p><h3>Contents of '.htvar($config['passwd_file']).' file:</h3><pre>';
readfile($config['passwd_file'])
?>
</pre>
<form action=<?=$PHP_SELF?> method=post>
<input type=submit name=submit value="Back to Menu">
</form>
<?
printFooter(false);
break;
case 'add_user_form';
printHeader('admin');
?>
<body onLoad="self.focus();document.form.login.focus()">
<form action=<?=$PHP_SELF?> method=post name=form>
<table>
<th colspan=2><h3>Add User or Change Password</h3></th>
<tr><td>User ID</td><td><input type=text name=login value="<?=htvar($login)?>" maxlength=15 size=15></td></tr>
<tr><td>Password </td><td><input type=password name=passwd value='' size=20></td></tr>
<tr><td>Verify Password </td><td><input type=password name=passwdv value='' size=20></td></tr>
</table>
<input type=hidden name=stage value=add_user>
<input type=submit name=submit value='Submit'>
</form>
<?
break;
case 'add_user':
printHeader('admin');
if (! $passwd || ! $passwdv || $passwd != $passwdv || strlen($passwd) < 8) {
print "<center><h2><font color=red>Missing or invalid password or password and password verification do not match.</font></h2></center>"
?>
<p><center>
<form action=<?=$PHP_SELF?> method=post>
<input type=hidden name=stage value=add_user_form>
<input type=hidden name=login value="<?=htvar($login)?>">
<input type=submit name=submit value=Back>
</form></center>
<?
}
else {
$pwdfile = escapeshellarg($config['passwd_file']);
$login = escapeshellarg($login);
$passwd = escapeshellarg($passwd);
print 'Results of htpasswd command:<br>';
system("htpasswd -bm $pwdfile $login $passwd 2>&1")
?>
<p>
<form action=<?=$PHP_SELF?> method=post>
<input type=submit name=submit value="Back to Menu">
</form>
<?
}
printFooter();
break;
case 'del_user_form';
printHeader('admin');
?>
<body onLoad="self.focus();document.form.login.focus()">
<form action=<?=$PHP_SELF?> method=post name=form>
<table>
<th colspan=2><h3>Remove User</h3></th>
<tr><td>User ID</td><td><input type=text name=login value="<?=htvar($login)?>" maxlength=15 size=15></td></tr>
</table>
<input type=hidden name=stage value=del_user>
<input type=submit name=submit value='Submit'>
</form>
<?
printFooter();
break;
case 'del_user':
printHeader('admin');
$pwdfile = escapeshellarg($config['passwd_file']);
$login = escapeshellarg($login);
print 'Results of htpasswd command:<br>';
system("htpasswd -D $pwdfile $login 2>&1")
?>
<p>
<form action=<?=$PHP_SELF?> method=post>
<input type=submit name=submit value="Back to Menu">
</form>
<?
printFooter();
break;
default:
printHeader('admin');
?>
<br>
<br>
<center>
<table class=menu><th class=menu>SYSADMIN MENU</th>
<tr><td class=menu style="padding-left: 1em;"><table>
<tr><td class=menu-pad><a href=<?=$PHP_SELF?>?stage=add_user_form>Add User or Change Password</a></td></tr>
<tr><td class=menu-pad><a href=<?=$PHP_SELF?>?stage=del_user_form>Remove User</a></td></tr>
<tr><td class=menu-pad><a href=<?=$PHP_SELF?>?stage=list_users>List Password File Contents</a></td></tr>
</table></td></tr>
</table>
</center>
<br><br>
<?
printFooter();
}
?>

373
root/ca/help.php Normal file
View File

@@ -0,0 +1,373 @@
<?php
include('../config.php');
include(STORE_DIR.'/config/config.php');
include('../include/my_functions.php');
include('../include/common.php');
printHeader(false);
?>
<p>
<center>
<table class=menu>
<th class=menu style="font-size: 24px;">PHPki HELP FILE<br>TABLE OF CONTENTS</th>
<tr><td class=menu style="padding: 1em;">
<a href=#WHY>Why PHPki</a><br>
<a href=#OVERVIEW>Overview</a><br>
<a href=#MAIN-MENU>Main Menu</a><br>
<a href=#REQUEST-FORM>Requesting a New Certificate</a><br>
<a href=#MANAGE>Managing Your Certificate With The Control Panel</a><br>
<a href=#REVOKE>Revoking a Certificate</a><br>
<a href=#DISPLAY>Displaying Certificate Details</a><br>
<a href=#RENEW>Renewing a Cettificate</a><br>
<a href=#DOWNLOAD>Downloading a Certificate</a><br>
<a href=../help.php target=help>End User Help Documents</a><br>
<a href=#GLOSSARY>The PHPki Glossary of Terms</a><br>
<a href=#GETTING-HELP>Getting Additional Help</a><br>
</td></tr>
</table>
</center>
<br><br><br><br><br><br>
<p>
<h2><a name="WHY">WHY PHPki</a></h2>
<blockquote>
PHPki is an <a href=http://www.opensource.org target=_blank>Open Source</a>
Web based application for managing a
<a href=../help/glossary.html#PKI target=glossary> "Public Key Infrastructure"</a>
within a small organization.
PHPki may be used to create and manage
<a href=../help/glossary.html#CERTIFICATE target=glossary>digital certificates</a>
for use with <a href=../help/glossary.html#SMIME target=glossary>S/MIME</a> enabled
e-mail clients, SSL servers, and VPN applications.
<p>
Most commercial
<a href=../help/glossary.html#CA target=glossary>certificate authorities (CA)</a>
require that certificates be issued to individual workstations, one at a time.
The transaction required to obtain a commercial certificate must usually take
place at the workstation on which the certifcate is to be installed, and can be
complicated, confusing, and time consuming. Such a process does not allow for
easy centralized administration of groups of certificates, where a single
person within an organization or department must request, create, and install
certificates on a number of workstations.
<p>
PHPki creates standard <a href=../help/glossary.html#X509 target=glossary>X.509</a>
digital certificates which should work with most e-mail clients.
It packages private certificates in the <a href=../help/glossary.html#PKCS12 target=glossary>PKCS#12</a> format accepted by Microsoft
e-mail clients <a href=../help/glossary.html#PEM target=glossary>PEM</a> used by certain web servers.
PKCS #12 certificates usually have a <cite>.P12</cite>
filename extension. Since most PKCS #12 certificates usually include the
certificate's private key, they should never be distributed to the general
public. PHPki's publicly distributable certificates are packaged in
standard <a href=../help/glossary.html#DER target=glossary>DER</a> format.
<p>
Server
</blockquote>
<p>
<h2><a name="OVERVIEW">OVERVIEW</a></h2>
<blockquote>
The process of creating and using digital certificates with PHPki is
fairly easy.
<ul>
<li>
First you must download and install our
<a href=../help/glossary.html#ROOT-CERT target=glossary>root certificate</a>
on your computer. Everyone else you intend to exchange encrypted e-mail
with must also install our root certificate.
Everyone who installs our root certificate becomes a member of our
"circle of trust". The PHPki main menu contains an option for downloading
our root certificate. Root certificates are not private and should be widely
distributed and published on the Internet in a conspicuous location.
The more widely published a root certificate is, the more difficult it becomes
to forge.
</li>
<p><li>
You must request and download a digital certificate for each person who will
<strong>RECEIVE</strong> encrypted e-mail at your agency. Remember, having a
digital certificate does not enable one to <strong>send</strong> encrypted
e-mail, but only to <strong>receive</strong> it. Each of the certificates
you download must be installed on the respective users' workstations.
If you wish to send encrypted e-mail to someone, you must install that person's
public certificate on your computer. You can obtain another person's public
certificate simply by having them send you a
<a href=../help/glossary.html#SIGNATURE target=glossary>digitally signed</a> e-mail message. When you receive the message, your e-mail
program should give you the option to add the sender's public key to your
address book or key ring. Once you have installed your digital certificates,
your users should send digitally signed messages to each person who will need
to send encrypted e-mail to them.
</li>
<p><li>
Users come and go, passwords are compromised, and files are lost, such is life.
PHPki includes a certificate management system for handling these situations.
The certificate management control panel gives you the ability to
display certificates in excruciating detail, revoke a certificate when its
e-mail address is no longer valid or its public key has been compromised,
renew certificates which have or will expire, and re-download a previously
issued certificate if you've lost the original.
</li>
<p><li>
There must be a method for letting outside entities know which of your
certificates have been revoked. The mechanism for doing this is the
<cite>Certificate Revocation List</cite> or CRL. A CRL is a digitally signed
list of certificates which have been revoked by a Certificate Authority.
Our CRL is updated periodically, and can be downloaded from the PHPki
Main Menu. Many e-mail clients will automatically download and install CRLs
using information embedded in certificates. However, there is no widely
adopted standard for automatic CRL checking, so it is not unusual to have
to manually install and update CRLs.
</li>
<p><li>
PHPki provides a public interface for Internet users to download our root
certificate and certificate revokation list. A certificate search feature
is also provided to allow easy distribution of public certificates over the
Internet.
</li>
</ul>
</blockquote>
<p>
<h2><a name=MAIN-MENU>THE MAIN MENU</a></h2>
<p>
<blockquote>
<center><img src=../images/main-menu.png width=700 ></center>
<p>
All of the PHPki primary functions can be accessed from the Main Menu.
It is possible to navigate back to the Main Menu from any screen by clicking the
"Menu" link in the upper right corner of each page. Clicking the <cite>Public</cite> link will open a new browser window to the public content menu where
the general public may search for certificates and download the
<a href=../help/glossary.html#ROOT-CERT target=glossary>Root Certificate</a> and <a href=../help/glossary.html#CRL target=glossary>Certificate Revocation List.</a>
</blockquote>
<p>
<h2><a name=REQUEST-FORM>REQUESTING A NEW CERTIFICATE</a></h2>
<blockquote>
When you select "Request a New Certificate" from the Main Menu, you will be
presented with the Certificate Request Form.<br>
<p>
<center><img src=../images/cert-request-form.png width=700 ></center>
<p>
This form is used to collect the minimum necessary information required to
issued a new digital certificate. All fields must be completed.
<blockquote><ul>
<li>
<u>E-mail User's Full Name:</u> Enter the full name of the user for which the certificate will be issued.
</li>
<p><li>
<u>E-mail Address:</u> Enter the e-mail address of the user for which the certificate is to be issued. This field will be checked for proper e-mail address
format, but the e-mail address is not verified otherwise.
</li>
<p><li>
<u>Organization:</u> Enter the full name of your organization (i.e. ACME Shoe Repair).
</li>
<p><li>
<u>Department/Unit:</u> Enter the name of the department or unit in which the
user works. (i.e. Accounting Department).
</li>
<p><li>
<u>Locality:</u> Enter the name of the City or County in which the organization
is located.
</li>
<p><li>
<u>State/Province:</u> Enter the name of the State or Province in which the organization
is located.
</li>
<p><li>
<u>Country:</u> Enter the name of the Country in which the organization
is located.
</li>
<p><li>
<u>Certificate Password:</u> Enter a password to protect the certificate.
If you enter a password, it must ben enter twice for verification.
This password will be used to encrypt the private key which will be packaged
with the completed certificate. It may also be required when installing a PKCS#12
certificate. <strong>This password should be handled with the
utmost security and should never be lost, as it cannot be recovered under
any circumstance.</strong> If this password is lost, you must immediately
revoke the certificate and request/create a new certificate for the user.
</li>
<p><li>
<u>Certificate Life:</u> Select the number of years you want the certificate to
be valid. Although it is common practice to issue certificates which are valid
for only one year, the option to issue certificates for a longer period is
available should you wish to be rebel. The certificate may be revoked or
renewed at any point during its life.
</li>
<p><li>
<u>Key Size:</u> Select this size of your private key in bits. Larger
keys are considered more secure. However, certain VPN applications may
have difficulty with keys larger than 1024 bits.
</li>
<p><li>
<u>Certificate Use:</u> Select the purpose for which the certificate will
be use. E-mail certifcates have different attributes from SSL server
certifcates and may not be interchangeable. Some IPSEC/VPN applications
may be sensitive to large certificates, so those certificates contain less
embedded information to keep them small.
</li>
</ul></blockquote>
<p>
When you have complete filling in the form, click the "Submit Request" button.
The information you submitted will be checked for errors, and a confirmation
screen will be displayed.
<p>
<center><img src=../images/request-confirm-form.png width=700></center>
<p>
Clicking the "Yes! Create and Download" button will cause a file download
window to open in your browser, allowing you to save the certificate on your
computer under whatever name you choose. The default name for each certificate
is derived from the e-mail address provided in the certificate request form.
You may download the certificate as many time as you wish as long as your
browser remains on this page. If you navigate from this page, you will have
to use the <cite>Certificate Management Control Panel</cite> to download the certificate
again. Be sure to save all of your certificates in a safe and secure
place. Doing so will make it easier for you to re-install a certificate on a
user's workstation should the need arise.<br>
<p>
After the download window closes, you may click the "Back" button to return
to the form and request another certificate. All of the data you previously
entered will be retained. This is to allow you to issue a large number of
certificates without having to re-enter much of the form. As well, your
form input will be saved as your default values for the future sessions<br>
</blockquote>
<p>
<h2><a name="MANAGE">MANAGING YOUR CERTIFICATES WITH THE CONTROL PANEL</a></h2>
<blockquote>
PHPki provides one convenient place to manage your certificates.
It is called the <cite>Certificate Management Control Panel</cite>.
<p>
<center><img src=../images/ctrl-panel-before.png width=700></center>
<p>
With the <cite>Control Panel</cite> you can display, download, revoke, and
renew your certificates by simply clicking on the appropriate button to the
right of each certificate entry. Your certificates are listed in columnar
format, with the left-most color coded "Status" column showing whether a
certificate is "<font color=green>Valid</font>" or
"<font color=red>Revoked</font>". The listing can be sorted in any order
by clicking on the column headings. An arrow graphic
&nbsp<img src=../images/uparrow-blue.gif height=12>&nbsp beside a column heading
indicates which column is being used to sort the listing. Clicking on the
arrow graphic will cause the listing to alternate between ascending and
descending sort order. You may find these sort features particularly useful if
you are careful to plan and utilize the <cite>Department/Unit</cite> and
<cite>Locality</cite> fields to categorize your certificates according to
your particular organizational needs.
</blockquote
<p>
<h2><a name="REVOKE">REVOKING A CERTIFICATE</a></h2>
<blockquote>
At times it may become necessary to revoke or invalidate a certificate. This
usually happens when an e-mail address is no longer valid, or the certificate's
private key has been lost or compromised.
<p>
To revoke a certificate, click on the <img src=../images/revoke.png align=top>&nbsp icon next to the certificate entry in the <cite>Control Panel</cite>.
<p>
<center><img src=../images/revoke-confirm.png width=700></center>
<p>
You will then be asked to confirm or cancel the revocation. Be absolutely
sure of what you wish to do before clicking the "Yes" button. Once a
certificate is revoked, it cannot be un-revoked. Well, this isn't completely
true, as a revoked certificate can be renewed. Renewing a revoked certificate
results in a <strong>new</strong> certificate being issued. Certificate
renewal is covererd later.
<p>
<center><img src=../images/ctrl-panel-after-revoke.png width=700></center>
<p>
If you click the "Yes" button, the certificate is revoked with no further
interaction. The certificate's status in the <cite>Control Panel</cite>
will change to <font color=red>Revoked</font>.
</blockquote>
<p>
<h2><a name="DISPLAY">DISPLAYING CERTIFICATE DETAILS</a></h2>
<blockquote>
Certificates may be displayed in full detail by clicking the
<img src=../images/display.png align=top>&nbsp icon next to a certificate's
entry in the <cite>Control Panel</cite>. Although some users may find this
feature useful, many will not find anything of interest in it.
<p>
<center><img src=../images/display-revoked.png width=700></center>
</blockquote>
<p>
<h2><a name="RENEW">RENEWING A CERTIFICATE</a></h2>
<blockquote>
Certificates expire periodically. The usually length a time for which a
certificate is valid is one year. With PHPki, you have the option to
issue certificates with a more extended life span. Regardless, sooner or later
your certificates will begin to expire.
<p>To renew a certificate which has expired or is near expiration, simply click
the <img src=../images/renew.png align=top>&nbsp icon next to the
certifcate's <cite>Control Panel</cite> entry. You will then be presented
with a certificate renewal form.
<p>
<center><img src=../images/renewal-form.png width=700></center>
<p>
The certificate renewal form takes the values for <cite>Common Name,
E-mail Address, Organization, etc.</cite> from the original certificate.
Those fields are disabled in the form, and cannot be changed.
You are required to enter the original certificate's password and select
a life span for the new certificate. If you do not enter the correct
password that was assigned to the original certificate when it was created,
you will not be able to renew the certificate. You may cancel this operation
by clicking the "Back" button, which will take you back to the
<cite>Control Panel</cite>.
<p>
<center><img src=../images/ctrl-panel-after-renew.png width=700></center>
<p>
If you click the "Submit Request" button to renew the certificate, it is
renewed with no further interaction, and you will be returned to the
<cite>Control Panel</cite>. You will notice a new
<font color=green>Valid</font> certificate in the <cite>Control Panel</cite>,
and the old expired certificate is marked <font color=red>Revoked</font>.
</blockquote>
<p>
<h2><a name=DOWNLOAD>DOWNLOADING A CERTIFICATE</a></h2>
<blockquote>
If you lose the original file you downloaded when you first created a
certificate, you may download another copy of a certificate at any time by
clicking the
<img src=../images/download.png align=top>&nbsp icon next to the certificate's entry
in the <cite>Control Panel</cite>. When downloading a certificate, you will
be reminded that the certificate is a
<strong><font color=red>PRIVATE</font> certificate, which <font color=red>
SHOULD NEVER BE DISTRIBUTED TO THE PUBLIC</font></strong>.
You may choose to download <a href=../help/glossary.html#PKCS12 target=glossary>PKCS #12</a> or <a href=../help/glossary.html#PEM target=glossary>PEM</a> formatted bundles.
<p>
<center><img src=../images/confirm-download.png width=700></center>
</blockquote>
<p>
<h2><a name=GLOSSARY>GLOSSARY</a></h2>
<blockquote>
Click <a href=../help/glossary.html#TOP target=glossary>here</a> to view the complete
PHPki glossary of terms.
</blockquote>
<p>
<h2><a name="GETTING-HELP">GETTING ADDITIONAL HELP</a></h2>
<blockquote>
<?=$config[getting_help]?>
</blockquote>
<br>
<?
printFooter();
?>

3
root/ca/index.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
header("Location: ./../index.php");
?>

97
root/ca/main.php Normal file
View File

@@ -0,0 +1,97 @@
<?php
include("../config.php");
include(STORE_DIR.'/config/config.php');
include("../include/my_functions.php");
include("../include/common.php") ;
include("../include/openssl_functions.php");
$stage = gpvar('stage');
switch($stage) {
case 'dl_root':
upload("$config[cacert_pem]", "$config[ca_prefix]cacert.crt", 'application/x-x509-ca-cert');
break;
case 'dl_crl':
upload("$config[cacrl_der]", "$config[ca_prefix]cacrl.crl", 'application/pkix-crl');
break;
case 'gen_crl':
list($ret,$errtxt) = CA_generate_crl();
printHeader(false);
if ($ret) {
?>
<center><h2>Certificate Revocation List Updated</h2></center>
<p>
<form action=<?=$PHP_SELF?> method=post>
<input type=submit name=submit value="Back to Menu">
</form>
<?
print '<pre>'.CA_crl_text().'</pre>';
}
else {
?>
<font color=#ff0000>
<h2>There was an error updating the Certificate Revocation List.</h2></font><br>
<blockquote>
<h3>Debug Info:</h3>
<pre><?=$errtxt?></pre>
</blockquote>
<form action=<?=$PHP_SELF?> method=post>
<p>
<input type=submit name=submit value="Back to Menu">
<p>
</form>
<?
}
break;
default:
printHeader('ca');
?>
<br>
<br>
<center>
<table class=menu width=600><th class=menu colspan=2><big>CERTIFICATE MANAGEMENT MENU</big></th>
<tr><td style="text-align: center; vertical-align: middle; font-weight: bold;" width=33%>
<a href=request_cert.php>Create a New Certificate</a></td>
<td>Use the <strong><cite>Certificate Request Form</cite></strong> to create and download new digital certificates.
You may create certificates in succession without re-entering the entire form
by clicking the "<strong>Go Back</strong>" button after each certificate is created.</td></tr>
<tr><td style="text-align: center; vertical-align: middle; font-weight: bold;">
<a href=manage_certs.php>Manage Certificates</a></td>
<td>Conveniently view, download, revoke, and renew your existing certificates using the
<strong><cite>Certificate Management Control Panel</cite></strong>.</td></tr>
<tr><td style="text-align: center; vertical-align: middle; font-weight: bold;">
<a href=<?=$PHP_SELF?>?stage=gen_crl>Update & View the Certificate Revocation List</a></td>
<td>Some applications automagically reference the Certificate Revocation List to determine
certificate validity. It is not necessary to perform this update function, as the CRL is
updated when certificates are revoked. However, doing so is harmless.
<a href=../help.php target=_help>Read the online help</a> to learn more about this.</td></tr>
<tr><td style="text-align: center; vertical-align: middle; font-weight: bold;">
<a href=<?=$PHP_SELF?>?stage=dl_root>Download the Root Certificate</a></td>
<td>The "Root" certificate must be installed before using any of the
certificates issued here. <a href=../help.php target=_help>Read the online help</a>
to learn more about this.</td></tr>
<tr><td style="text-align: center; vertical-align: middle; font-weight: bold;">
<a href=<?=$PHP_SELF?>?stage=dl_crl>Download the Certificate Revocation List</a></td>
<td>This is the official list of revoked certificates. Using this list with your e-mail or
browser application is optional. Some applications will automagically reference this list. </td></tr>
</table>
</center>
<br><br>
<?
printFooter();
}
?>

408
root/ca/manage_certs.php Normal file
View File

@@ -0,0 +1,408 @@
<?php
include('../config.php');
include(STORE_DIR.'/config/config.php');
include('../include/my_functions.php');
include('../include/common.php');
include('../include/openssl_functions.php');
$stage = gpvar('stage');
$serial = gpvar('serial');
$sortfield = gpvar('sortfield');
$ascdec = gpvar('ascdec');
$passwd = gpvar('passwd');
$expiry = gpvar('expiry');
$submit = gpvar('submit');
$dl_type = gpvar('dl_type');
$search = gpvar('search');
$show_valid = gpvar('show_valid');
$show_revoked = gpvar('show_revoked');
$show_expired = gpvar('show_expired');
# Prevent handling certs that don't belong to user
if ($serial && CAdb_issuer($serial) != $PHPki_user && ! in_array($PHPki_user, $PHPki_admins)) {
$stage = 'goaway';
}
if ( !($show_valid.$show_revoked.$show_expired) ) {
$show_valid = 'V';
$show_revoked = 'R';
$show_expired = 'E';
}
$qstr_filter = 'search='.htvar($search).'&'.
"show_valid=$show_valid&".
"show_revoked=$show_revoked&".
"show_expired=$show_expired&";
$qstr_sort = "sortfield=$sortfield&ascdec=$ascdec";
switch ($stage) {
case 'goaway':
printHeader(false);
?> <p><center><h1><font color=red>YOU ARE A VERY BAD BOY!</font></h2></center> <?
break;
case 'display':
printHeader(false);
?>
<center><h2>Certificate Details</h2></center>
<center><font color=#0000AA><h3>(#<?=$serial?>)<br><?=htvar(CA_cert_cname($serial).' <'.CA_cert_email($serial).'>')?> </h3></font></center>
<?
if ($revoke_date = CAdb_is_revoked($serial))
print '<center><font color=red><h2>REVOKED '.$revoke_date.'</h2></font></center>';
print '<pre>'.CA_cert_text($serial).'</pre>';
break;
case 'dl-confirm':
printHeader('ca');
$rec = CAdb_get_entry($serial);
?>
<h3>You are about to download the <font color=red>PRIVATE</font> certificate key for <?=$rec['common_name'].' &lt;'.$rec['email'].'&gt; '?></h3>
<h3><font color=red>DO NOT DISTRIBUTE THIS FILE TO THE PUBLIC!</font></h3>
<form action="<?=$PHP_SELF.'?stage=download&serial='.$serial.'&'.$qstr_sort.'&'.$qstr_filter?>" method=post>
<strong>File type: </strong>
<td><select name=dl_type>
<option value="PKCS#12">PKCS#12 Bundle</option>
<option value="PEMCERT">PEM Certificate</option>
<option value="PEMKEY">PEM Key</option>
<option value="PEMBUNDLE">PEM Bundle</option>
<option value="PEMCABUNDLE">PEM Bundle w/Root</option>
</select>
<input type=submit name=submit value="Download">
&nbsp; or &nbsp;
<input type=submit name=submit value="Go Back">
</form>
<?
break;
case 'download':
if (strstr($submit, "Back")) $dl_type = '';
$rec = CAdb_get_entry($serial);
switch ($dl_type) {
case 'PKCS#12':
upload("$config[pfx_dir]/$serial.pfx", "$rec[common_name] ($rec[email]).p12", 'application/x-pkcs12');
break;
case 'PEMCERT':
upload("$config[new_certs_dir]/$serial.pem", "$rec[common_name] ($rec[email]).pem",'application/pkix-cert');
break;
case 'PEMKEY':
upload("$config[private_dir]/$serial-key.pem", "$rec[common_name] ($rec[email])-key.pem",'application/octet-stream');
break;
case 'PEMBUNDLE':
upload(array("$config[private_dir]/$serial-key.pem","$config[new_certs_dir]/$serial.pem"), "$rec[common_name] ($rec[email]).pem",'application/octet-stream');
break;
case 'PEMCABUNDLE':
upload(array("$config[private_dir]/$serial-key.pem","$config[new_certs_dir]/$serial.pem",$config['cacert_pem']), "$rec[common_name] ($rec[email]).pem",'application/octet-stream');
break;
default:
header("Location: ${PHP_SELF}?$qstr_sort&$qstr_filter");
}
break;
case 'revoke-form':
$rec = CAdb_get_entry($serial);
printHeader('ca');
?>
<h4>You are about to <font color=red>REVOKE</font> the following certificate:</hr>
<table width=500><tr>
<td width=25% style='white-space: nowrap'>
<p align=right>
Serial Number<br>
User's Name<br>
Email Address<br>
Organization<br>
Department/Unit<br>
Locality<br>
State/Province<br>
Country<br>
</td>
<?
print '
<td>
'.htvar($rec[serial]).'<br>
'.htvar($rec[common_name]).'<br>
'.htvar($rec[email]).'<br>
'.htvar($rec[organization]).'<br>
'.htvar($rec[unit]).'<br>
'.htvar($rec[locality]).'<br>
'.htvar($rec[province]).'<br>
'.htvar($rec[country]).'<br>
</td>
</tr></table>
<h4>Are you sure?</h4>
<p><form action="'.$PHP_SELF.'?'.$qstr_sort.'&'.$qstr_filter.'" method=post>
<input type=hidden name=stage value=revoke >
<input type=hidden name=serial value='.$serial.' >
<input type=submit name=submit value=Yes >&nbsp
<input type=submit name=submit value=Cancel>
</form>';
break;
case 'revoke':
$ret = true;
if ($submit == 'Yes')
list($ret, $errtxt) = CA_revoke_cert($serial);
if (! $ret) {
printHeader('ca');
print "<form action=\"$PHP_SELF?stage=revoke-form&serial=$serial&$qstr_sort&$qstr_filter\" method=post>";
?>
<font color=#ff0000>
<h2>There was an error revoking your certificate
.</h2></font><br>
<blockquote>
<h3>Debug Info:</h3>
<pre><?=$errtxt?></pre>
</blockquote>
<p>
<input type=submit name=submit value=Back>
<p>
</form>
<?
}
else
header("Location: ${PHP_SELF}?$qstr_sort&$qstr_filter");
break;
case 'renew-form':
#
# Get last known values submitted by this user. We only really
# need the expiry value, but the old cert values will override
# the rest.
#
if (! $submit and file_exists("config/user-${PHPki_user}.php"))
include("config/user-${PHPki_user}.php");
#
# Get values from the old certificate.
#
$rec = CAdb_get_entry($serial);
$country = $rec['country'];
$province = $rec['province'];
$locality = $rec['locality'];
$organization = $rec['organization'];
$unit = $rec['unit'];
$common_name = $rec['common_name'];
$email = $rec['email'];
printHeader('ca');
?>
<body onLoad="self.focus();document.form.passwd.focus()">
<form action="<?=$PHP_SELF.'?'.$qstr_sort.'&'.$qstr_filter?>" method=post name=form>
<table width=99%>
<th colspan=2><h3>Certificate Renewal Form</h3></th>
<tr>
<td width=25%>Common Name </td>
<td><input type=text name=common_name value="<?= htvar($common_name)?>" size=50 maxlength=60 disabled></td>
</tr>
<tr>
<td>E-mail Address </td>
<td><input type=text name=email value="<?=htvar($email)?>" size=50 maxlength=60 disabled></td>
</tr>
<tr>
<td>Organization </td>
<td><input type=text name=organization value="<?=htvar($organization)?>" size=60 maxlength=60 disabled></td>
</tr>
<tr>
<td>Department/Unit </td><td><input type=text name=unit value="<?= htvar($unit) ?>" size=40 maxlength=60 disabled></td>
</tr>
<tr>
<td>Locality</td><td><input type=text name=locality value="<?= htvar($locality) ?>" size=30 maxlength=30 disabled></td>
</tr>
<tr>
<td>State/Province</td><td><input type=text name=province value="<?= htvar($province) ?>" size=30 maxlength=30 disabled></td>
</tr>
<tr>
<td>Country</td>
<td><input type=text name=country value="<?= htvar($country) ?>" size=2 maxlength=2 disabled></td>
</tr>
<tr>
<td>Certificate Password </td>
<td><input type=password name=passwd value="<?= htvar($passwd) ?>" size=30></td>
</tr>
<tr>
<td>Certificate Life </td>
<td><select name=expiry>
<?
print "<option value=1 " . ($expiry == 1 ? "selected='selected'" : "") . " >1 Year</option>\n" ;
for ( $i = 2 ; $i < 6 ; $i++ ) {
print "<option value=$i " . ($expiry == $i ? "selected='selected'" : "") . " >$i Years</option>\n" ;
}
?>
</select></td>
</tr>
<tr>
<td>
<center><input type=submit name=submit value="Submit Request">&nbsp
<input type=submit name=submit value="Back"></center>
</td>
<td>
<input type=hidden name=stage value=renew>
<input type=hidden name=serial value=<?=$serial?>>
</td>
</tr>
</table>
</form>
<?
printFooter();
break;
case 'renew':
$ret = true;
if ($submit == "Submit Request")
list($ret, $errtxt) = CA_renew_cert($serial, $expiry, $passwd);
if (! $ret) {
printHeader('ca');
print "<form action=\"$PHP_SELF?stage=renew-form&serial=$serial&$qstr_sort&$qstr_filter\" method=post>";
?>
<font color=#ff0000>
<h2>There was an error creating your certificate
.</h2></font><br>
<blockquote>
<h3>Debug Info:</h3>
<pre><?=$errtxt?></pre>
</blockquote>
<p>
<input type=submit name=submit value=Back>
<p>
</form>
<?
}
else {
header("Location: $PHP_SELF?$qstr_sort&$qstr_filter");
}
break;
default:
printHeader('ca');
?>
<body onLoad="self.focus();document.filter.search.focus()">
<table>
<tr><th colspan=8><big>CERTIFICATE MANAGEMENT CONTROL PANEL</big></th></tr>
<tr><td colspan=8><center>
<form action="<?="$PHP_SELF?$qstr_sort"?>" method=get name=filter>
Search: <input type=text name=search value="<?=htvar($search)?>" style="font-size: 11px;" maxlength=60 size=30>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp<input type=checkbox name=show_valid value="V" <?=($show_valid?'checked'
:'')?>>Valid
&nbsp&nbsp<input type=checkbox name=show_revoked value="R" <?=($show_revoked?'checked':'')?>>Revoked
&nbsp&nbsp<input type=checkbox name=show_expired value="E" <?=($show_expired?'checked':'')?>>Expired
&nbsp&nbsp&nbsp&nbsp&nbsp<input type=submit name=submit value="Apply Filter" style="font-size: 11px;">
</form>
</center></td>
</tr>
<?
if (! $sortfield) {
$sortfield = 'email' ;
$ascdec = 'A';
}
if ($ascdec == 'A') {
$arrow_gif = '../images/uparrow-blue.gif';
$ht_ascdec = 'D';
}
else {
$arrow_gif = '../images/downarrow-blue.gif';
$ht_ascdec = 'A';
}
print '<tr>';
$headings = array(
status=>"Status", issued=>"Issued", expires=>"Expires",
common_name=>"User's Name", email=>"E-mail",
organization=>"Organization", unit=>"Department",
locality=>"Locality"
);
foreach($headings as $field=>$head) {
print '<th><a href="'.$PHP_SELF.'?sortfield='.$field.'&ascdec=A&'.$qstr_filter.'" title="Click to sort on this column."><u>'.$head.'</u></a>';
if ($sortfield == $field) {
print '&nbsp<a href="'.$PHP_SELF.'?sortfield='.$field.'&ascdec='.$ht_ascdec.'&'.$qstr_filter.'" >'.
'<img src='.$arrow_gif.' height=12 alt=\'Change sort order.\' title=\'Click to reverse sort order.\'></a>';
}
print '</th>';
}
print '</tr>';
$x = "^[$show_valid$show_revoked$show_expired]";
if (in_array($PHPki_user, $PHPki_admins)) {
$x = "$x.*$search";
}
else {
$x = "$x.*$search.*$PHPki_user|$x.*$PHPki_user.*$search";
}
$db = csort(CAdb_to_array($x), $sortfield, ($ascdec=='A'?SORT_ASC:SORT_DESC));
$stcolor = array(Valid=>'green',Revoked=>'red',Expired=>'orange');
foreach($db as $rec) {
print '<tr style="font-size: 11px;">
<td><font color='.$stcolor[$rec['status']].'><b>' .$rec[status].'</b></font></td>
<td style="white-space: nowrap">'.$rec[issued].'</td>
<td style="white-space: nowrap">'.$rec[expires].'</td>
<td>'.$rec[common_name].'</td>
<td style="white-space: nowrap"><a href="mailto:' . htvar($rec['common_name']) . ' <' . htvar($rec['email']) . '>" >' . htvar($rec['email']) . '</a></td>
<td>'.htvar($rec[organization]).'</td>
<td>'.htvar($rec[unit]).'</td>
<td>'.htvar($rec[locality]).'</td>
<td><a href="'.$PHP_SELF.'?stage=display&serial='.$rec[serial].'" target=_certdisp>'.
'<img src=../images/display.png alt="Display" title="Display complete certificate details."></a>';
if ($rec['status'] == 'Valid') {
print '
<a href="'.$PHP_SELF.'?stage=dl-confirm&serial='.$rec[serial].'&'.$qstr_sort.'&'.$qstr_filter.'">'.
'<img src=../images/download.png alt="Download" title="Download the PRIVATE certificate. DO NOT DISTRIBUTE THIS TO THE PUBLIC!"></a>
<a href="'.$PHP_SELF.'?stage=revoke-form&serial='.$rec[serial].'&'.$qstr_sort.'&'.$qstr_filter.'">'.
'<img src=../images/revoke.png alt="Revoke" title="Revoke the certificate when the e-mail address is no longer valid or the certificate password or private key has been compromised."></a>';
}
print '
<a href="'.$PHP_SELF.'?stage=renew-form&serial='.$rec[serial].'&'.$qstr_sort.'&'.$qstr_filter.'">'.
'<img src=../images/renew.png alt="Renew" title="Renew the certificate by revoking it, if necessary, and creating a replacement with a new expiration date."></a></td></tr>';
}
print '</table>';
printFooter();
}
?>

78
root/ca/policy.html Normal file
View File

@@ -0,0 +1,78 @@
<html>
<head>
<title>Certificate Authority Agreement</title>
</head>
<body>
<h2 align=center>Certificate Authority Agreement</h2>
<h3 align=center>Policy and Practices</h3>
<br><br>
<p>This is a statement of practices by this Digital Certificate Authority.
Your use of this Certificate Authority constitutes your and/or your agency's
understanding and full acceptance of these practices and all associated risks.
<strong>Please have an authorized person at your agency sign this document and fax it to 000-000-0000</strong>
<p>This document may not be all encompassing, and we reserve the right to modify it at any time.
<ul>
<li> The sole role of this Certificate Authority is
to provide and maintain a password protected software application for the easy
and instant creation and management of standard x.509 personal digital
certificates for e-mail encryption. We assume no responsibility for
verifying the identity of any persons other than that of the limited number of
authorized users of the software.
We accept no liability for damages resulting from the use, misuse,
or compromise of the software application or its host server.
<p><li>As an authorized user of the software, you are in effect <strong>THE</strong> Certificate Authority for your
agency. As such, you are solely
responsible for authenticating the identity of the persons for whom you obtain
certificates. We accept no
responsibility or liability for non-repudiation in any digital certificate
created by this software. You agree that
password protection to the application by authorized certificate managers,
and personal identity management by
those managers is sufficient to create a chain of trust for non-repudiation
in all digital certificates created using the software.
<p><li>No more than two(2)
users at your agency should have access to your agency's Certificate Authority
password. We should be notified
immediately, via e-mail, when the employment of any
authorized user at your agency is terminated so that a new password can be
issued.
<p><li>This Certificate
Authority software application is accessed via the Internet using standard SSL
or Secure Server encryption mechanisms.
Although steps have been taken to protect the security and availability
of the host server and application, its exposure to the Internet as well as any
presently unknown security flaws could lead to potential compromise of the
software and your certificates.
<p><li>No promise is made as
to the availability of the software in the event of hardware, software, or
telecommunications failure or maintenance.<2E>
No advanced notice will be given when the software must be temporarily
taken off line for service.
<p><li>In order to provide
software which can easily create &quot;instant&quot; certificates it is
necessary to store all private keys on the host server. As such, all private keys are potentially exposed
to the Internet and suffer some risk of unauthorized access. However, since all private keys <strong>ARE
ENCRYPTED</strong> using a password provided by you, they are unlikely to be usable by
any intruder.
<p><li>A publicly accessible
web page is provided for interested Internet users to download the Certificate
Authority root certificate, certificate revocation list, and search for the
e-mail addresses and public certificates of users. So as to avoid e-mail address scraping by spammers, no static
content with users' e-mail addresses is available.
</ul>
</body>
</html>

326
root/ca/request_cert.php Normal file
View File

@@ -0,0 +1,326 @@
<?php
include('../config.php');
include(STORE_DIR.'/config/config.php');
include('../include/my_functions.php');
include('../include/common.php') ;
include('../include/openssl_functions.php') ;
# User's preferences file
$user_cnf = "$config[home_dir]/config/user-".strtr($PHPki_user,'/\\','|#').'.php';
# Retrieve GET/POST values
$form_stage = gpvar('form_stage');
$submit = gpvar('submit');
$country = gpvar('country');
$province = gpvar('province');
$locality = gpvar('locality');
$organization = gpvar('organization');
$unit = gpvar('unit');
$common_name = gpvar('common_name');
$email = gpvar('email');
$passwd = gpvar('passwd');
$passwdv = gpvar('passwdv');
$expiry = gpvar('expiry');
$keysize = gpvar('keysize');
$cert_type = gpvar('cert_type');
# To repopulate form after error.
$hidden_fields = '
<input type=hidden name=country value="' . htvar($country) . '">
<input type=hidden name=province value="' . htvar($province) . '">
<input type=hidden name=locality value="' . htvar($locality) . '">
<input type=hidden name=organization value="' . htvar($organization) . '">
<input type=hidden name=unit value="' . htvar($unit) . '">
<input type=hidden name=common_name value="' . htvar($common_name) . '">
<input type=hidden name=email value="' . htvar($email) . '">
<input type=hidden name=passwd value="' . htvar($passwd) . '">
<input type=hidden name=passwdv value="' . htvar($passwdv) . '">
<input type=hidden name=expiry value="' . htvar($expiry) . '">
<input type=hidden name=keysize value="' . htvar($keysize) . '">
<input type=hidden name=cert_type value="' . htvar($cert_type) . '">
';
switch ($form_stage) {
case 'validate':
$er = '';
if (! $country) $er .= 'Missing Country<br>';
if (! $province) $er .= 'Missing State/Province<br>';
if (! $locality) $er .= 'Missing Locality (City/County)<br>';
if (! $organization) $er .= 'Missing Organization (Company/Agency)<br>';
if (! $unit) $er .= 'Missing Unit/Department<br>';
if (! $common_name) $er .= 'Missing E-mail User\'s Full Name<br>';
if (! $email) $er .= 'Missing E-mail Address<br>';
if (($cert_type == 'email' || $cert_type == 'email_signing') && ! $passwd) $er .= 'Missing Certificate Password<br>';
if (($cert_type == 'email' || $cert_type == 'email_signing') && ! $passwdv) $er .= 'Missing Certificate Password Verification "Again"<br>';
if ( $passwd && strlen($passwd) < 8 )
$er .= 'Certificate password is too short.<br>';
if ( $passwd and $passwd != $passwdv )
$er .= 'Password and password verification do not match.<br>';
//if ( ! is_alnum($passwd) or ! is_alnum($passwdv) )
// $er .= 'Password contains invalid characters.<br>';
if ( $email && ! is_email($email) )
$er .= 'E-mail address ('. htvar($email) . ') may be invalid.<br>';
if ( $er )
$er = '<h2>ERROR(S) IN FORM:</h2><h4><blockquote>' . $er . '</blockquote></h4>';
if ($email && ($serial = CAdb_in($email,$common_name))) {
$er = '';
$certtext = CA_cert_text($serial);
$er .= '<h2>A valid certificate already exists for ' . htvar("$common_name <$email>") . '</h2>';
$er .= '</font><blockquote><pre> ' . htvar($certtext) . ' </pre></blockquote>';
}
if ($er) {
printHeader();
?>
<form action='<?=$PHP_SELF?>' method=post>
<input type=submit name=submit value='Go Back'>
<font color=#ff0000><?=$er?></font>
<br><input type=submit name=submit value='Go Back'>
<?
print $hidden_fields;
print "</form>";
printFooter();
break;
}
case 'confirm':
printHeader();
?>
<h4>You are about to create a certificate using the following information:</h4>
<table width=500><tr>
<td width=25% style='white-space: nowrap'>
<p align=right>
User's Name<br>
E-mail Address<br>
Organization<br>
Department/Unit<br>
Locality<br>
State/Province<br>
Country<br>
Certificate Life<br>
Key Size<br>
Certificate Use<br>
</td>
<td>
<?
print htvar($common_name) . '<br>';
print htvar($email) . '<br>';
print htvar($organization) . '<br>';
print htvar($unit) . '<br>';
print htvar($locality) . '<br>';
print htvar($province) . '<br>';
print htvar($country) . '<br>';
print htvar($expiry). ' Year'.($expiry == 1 ? '' : 's').'<br>';
print htvar($keysize). ' bits<br>';
print htvar($cert_type). '<br>';
?>
</td>
</tr></table>
<h4>Are you sure?</h4>
<p><form action='<?=$PHP_SELF?>' method=post>
<?= $hidden_fields ?>
<input type=hidden name=form_stage value=final>
<input type=submit name=submit value='Yes! Create and Download' >&nbsp;
<input type=submit name=submit value='Go Back'>
</form>
<?
printFooter();
# Save user's defaults
$fp = fopen($user_cnf,'w');
$x = '<?php
$country = \''.addslashes($country).'\';
$locality = \''.addslashes($locality).'\';
$province = \''.addslashes($province).'\';
$organization = \''.addslashes($organization).'\';
$unit = \''.addslashes($unit).'\';
$expiry = \''.addslashes($expiry).'\';
$keysize = \''.addslashes($keysize).'\';
?>';
fwrite($fp,$x);
fclose($fp);
break;
case 'final':
if ($submit == "Yes! Create and Download") {
if (! $serial = CAdb_in($email,$common_name)) {
list($ret,$errtxt) = CA_create_cert($cert_type,$country, $province, $locality, $organization, $unit, $common_name, $email, $expiry, $passwd, $keysize);
if (! $ret) {
printHeader();
?>
<form action=<?=$PHP_SELF?> method=post>
<font color=#ff0000>
<h2>There was an error creating your certificate.</h2></font><br>
<blockquote>
<h3>Debug Info:</h3>
<pre><?=$errtxt?></pre>
</blockquote>
<p>
<?=$hidden_fields?>
<input type=submit name=submit value=Back>
<p>
</form>
<?
printFooter();
break;
}
else {
$serial = $errtxt;
}
}
switch($cert_type) {
case 'server':
upload(array("$config[private_dir]/$serial-key.pem","$config[new_certs_dir]/$serial.pem",$config['cacert_pem']), "$common_name ($email).pem",'application/pkix-cert');
break;
case 'email':
case 'email_signing':
case 'time_stamping':
case 'vpn_client_server':
case 'vpn_client':
case 'vpn_server':
upload("$config[pfx_dir]/$serial.pfx", "$common_name ($email).p12", 'application/x-pkcs12');
break;
}
break;
}
default:
#
# Default fields to reasonable values if necessary.
#
if (! $submit and file_exists($user_cnf)) include($user_cnf);
if (! $country) $country = $config['country'];
if (! $province) $province = $config['province'];
if (! $locality) $locality = "";
if (! $organization) $organization = "";
if (! $unit) $unit = "";
if (! $email) $email = "";
if (! $expiry) $expiry = 1;
if (! $keysize) $keysize = 1024;
if (! $cert_type) $cert_type = 'email';
printHeader();
?>
<body onLoad="self.focus();document.request.common_name.focus()">
<form action="<?=$PHP_SELF?>" method=post name=request>
<table width=99%>
<th colspan=2><h3>Certificate Request Form</h3></th>
<tr>
<td width=30%>Common Name<br>(i.e. User real name or computer hostname) </td>
<td><input type=text name=common_name value="<?= htvar($common_name)?>" size=50 maxlength=60></td>
</tr>
<tr>
<td>E-mail Address </td>
<td><input type=text name=email value="<?=htvar($email)?>" size=50 maxlength=60></td>
</tr>
<tr>
<td>Organization (Company/Agency)</td>
<td><input type=text name=organization value="<?=htvar($organization)?>" size=60 maxlength=60></td>
</tr>
<tr>
<td>Department/Unit </td><td><input type=text name=unit value="<?= htvar($unit) ?>" size=40 maxlength=60></td>
</tr>
<tr>
<td>Locality (City/County)</td><td><input type=text name=locality value="<?= htvar($locality) ?>" size=30 maxlength=30></td>
</tr>
<tr>
<td>State/Province</td><td><input type=text name=province value="<?= htvar($province) ?>" size=30 maxlength=30></td>
</tr>
<tr>
<td>Country</td>
<td><input type=text name=country value="<?= htvar($country) ?>" size=2 maxlength=2></td>
</tr>
<tr>
<td>Certificate Password </td>
<td><input type=password name=passwd value="<?= htvar($passwd) ?>" size=30>&nbsp;&nbsp; Again <input type=password name=passwdv value="<?= htvar($passwdv) ?>" size=30></td>
</tr>
<tr>
<td>Certificate Life </td>
<td><select name=expiry>
<?
print "<option value=1 " . ($expiry == 1 ? "selected='selected'" : "") . " >1 Year</option>\n" ;
for ( $i = 2 ; $i < 6 ; $i++ ) {
print "<option value=$i " . ($expiry == $i ? "selected='selected'" : "") . " >$i Years</option>\n" ;
}
?>
</select></td>
</tr>
<tr>
<td>Key Size </td>
<td><select name=keysize>
<?
for ( $i = 512 ; $i < 4096 ; $i+= 512 ) {
print "<option value=$i " . ($keysize == $i ? "selected='selected'" : "") . " >$i bits</option>\n" ;
}
?>
</select></td>
</tr>
<tr>
<td>Certificate Use: </td>
<td><select name=cert_type>
<?
print '<option value="email" '.($cert_type=='email'?'selected':'').'>E-mail, SSL Client</option>';
print '<option value="email_signing" '.($cert_type=='email_signing'?'selected':'').'>E-mail, SSL Client, Code Signing</option>';
print '<option value="server" '.($cert_type=='server'?'selected':'').'>SSL Server</option>';
print '<option value="vpn_client" '.($cert_type=='vpn_client'?'selected':'').'>VPN Client Only</option>';
print '<option value="vpn_server" '.($cert_type=='vpn_server'?'selected':'').'>VPN Server Only</option>';
print '<option value="vpn_client_server" '.($cert_type=='vpn_client_server'?'selected':'').'>VPN Client, VPN Server</option>';
print '<option value="time_stamping" '.($cert_type=='time_stamping'?'selected':'').'>Time Stamping</option>';
?>
</select></td>
</tr>
<tr>
<td><center><input type=submit name=submit value='Submit Request'></center><input type=hidden name=form_stage value='validate'></td><td><font color=red size=3>* All fields are required</td>
</tr>
</table>
</form>
<?
printFooter();
}
?>

3
root/config.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
define(PHPKI_VERSION, "0.82");
?>

172
root/css/style.css Normal file
View File

@@ -0,0 +1,172 @@
h1 {
font-size: 32px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 18px;
}
body {
margin: 10px;
padding: 0;
background: #fafaff;
font-family: Arial, Veranda, Helvetica, sans-serif;
font-size: 12px;
}
img {
border: 0;
}
a {
color: #00F;
background-color: transparent;
}
a:link, a:active, a:visited {
color: #00F;
background-color: transparent;
}
a.headermenu:link, a.headermenu:active, a.headermenu:visited {
text-decoration: underline;
color: #00F;
background-color: transparent;
padding-left: 8px;
}
form {
padding: 0;
margin: 0;
}
fieldset {
border: 2px solid black;
margin-left: 10px;
padding: 10px;
width: 700px;
font-size: 10px;
}
legend {
background-color: rgb(200, 220, 240);
border: 2px solid black;
padding: 0.25em;
padding-top: 0.1em;
font-size: 12px;
}
table {
font-size: 12px;
margin-right: .1in;
}
th {
font-weight: bold;
background-color: #AFC3E4;
padding: 3px;
color: #323C4D;
text-align: center;
vertical-align: middle;
border: 1px solid #606060;
white-space: nowrap;
}
td {
background-color: #DEE3EC;
padding: 3px;
text-align: left;
vertical-align: middle;
border: 1px solid #a0a0a0;
}
.menu {
height: 22px;
font-size: 13px;
text-align: center;
vertical-align: bottom;
border: 1px solid #808080;
border-left: 2px solid #808080;
border-bottom: 2px solid #808080;
color: #000000;
}
.menu-pad {
height: 22px;
font-size: 13px;
text-align: center;
padding-left: 1em;
padding-right: 1em;
vertical-align: bottom;
border: 1px solid #808080;
border-left: 2px solid #808080;
border-bottom: 2px solid #808080;
color: #000000;
}
.menu a {
vertical-align: bottom;
text-decoration: none;
font-size: 13px;
}
.headermenu-ie {
text-align: right;
margin-right: 0.1in;
margin-top: -0.20in;
}
.headermenu-konq {
text-align: right;
margin-right: 0.1in;
margin-top: -0.25in;
}
.logo-ie {
font-family: 'impact', sans-serif;
font-size: 60pt;
font-weight: bold;
color: #99caff;
margin-top: -0.20in;
margin-bottom: 0;
margin-right: 0.2in;
text-align: left;
}
.title-ie {
font-family: 'impact', sans-serif;
font-size: 22pt;
font-weight: bold;
font-style: italic;
margin-right: 0.4in;
margin-top: -0.52in;
margin-bottom: 0;
text-align: left; }
.logo-konq {
font-family: 'impact', sans-serif;
font-size: 62pt;
font-weight: bold;
color: #99caff;
margin-top: -0.20in;
margin-bottom: 0;
margin-right: 0.2in;
text-align: left;
}
.title-konq {
font-family: 'impact', 'sans-serif';
font-size: 24pt;
font-weight: bold;
font-style: italic;
margin-right: 0.4in;
margin-top: -0.55in;
margin-bottom: 0;
text-align: left;
}

16
root/help.php Normal file
View File

@@ -0,0 +1,16 @@
<?php
include('./config.php');
include('./include/my_functions.php');
include('./include/common.php');
printHeader(about);
?>
<center><h1>PHPki HELP FILES</h1>
<a href=<?=BASE_URL?>help/PKI_basics.html><h3>PKI and E-mail Encryption - A Brief Explanation</h3></a>
<a href=<?=BASE_URL?>help/cacert_install_ie.html><h3>Installing Our Root Certificate For Use With Outlook and Outlook Express</h3></a>
<p><a href=<?=BASE_URL?>help/usercert_install_ie.html><h3>Installing Your Personal E-mail Certificate For Use With Outlook and Outlook Express</h3></a>
<p><a href=<?=BASE_URL?>help/glossary.html><h3>Glossary</h3></a>
</center>
<?
printFooter();
?>

64
root/help/PKI_basics.html Normal file
View File

@@ -0,0 +1,64 @@
<html>
<head>
<link rel='stylesheet' type='text/css' href='../css/style.css'>
<title>PKI and E-mail Encryption - A Brief Explanation</title>
</head>
<body>
<center><h1>PKI and E-mail Encryption - A Brief Explanation</h2></center>
PKI stands for <cite>Public Key Infrastructure</cite>. PKI is Information
Technology infrastructure that enables users of a basically unsecure public
network (such as the Internet) to securely and privately exchange data through
the use of a <a href=glossary.html#KEYS target=glossary>public and a private
cryptographic key pair</a> that is obtained and shared through a
<a href=glossary.html#CA target=glossary>trusted Authority</a>.
<p>
Public and private keys are like two halves of a single key. PKI encryption
algorithms are designed such that a public key is used to encrypt or
"lock" a message, and only the complementary private key can "unlock" that
message.
Think of a bank vault or safe that can only be unlocked by two individuals
using two different but complementary keys. Neither of those keys can be used
by itself to unlock the vault.
<p>
In practice, individuals wishing to exchange encrypted e-mail
will agree to mutually trust one or more <a href=glossary.html#CA target=glossary>
Certificate Authorities(CA)</a> by downloading and installing each trusted Authority's
<a href=glossary.html#ROOT-CERT target=glossary>root certificate</a> on their computers.
They will each obtain their own personal
<a href=glossary.html#CERTIFICATE target=glossary>digital certificate</a>
from a trusted Certificate Authority, and install them on their
respective computers.
Because they mutually trust the Certificate Authorities, they trust each other's
digital certificates. More specifically, they trust the
<a href=glossary.html#KEYS target=glossary>public keys</a> contained within
their personal digital certificates which have been
<a href=glossary.html#SIGNATURE target=glossary>digitally signed</a> by a
trusted Certificate Authority.
They will then exchange their trusted public keys by sending each other
digitally signed e-mail messages. Once each party has the other's public key,
they may exchange trusted and encrypted messsages.
<p>
Public key exchange and encryption is like exchanging notarized documents.
One trusts a notarized document because a trusted third party, the Notary
Public, has signed it. The Certificate Authority is the Notary Public, and
the public keys are the documents.
<p>
Remember, having a personal digital certificate alone does <strong>not</strong>
give one the ability to send encrypted e-mail to others, but only allows the
<strong>receipt</strong> of encrypted e-mail. PKI is a cooperative encryption
standard. Both parties who are exchanging encrypted messages must have
personal digital certificates, they must trust the Certificate Authority
which issued the other persons certificate, and they must exchange
public keys with each other, as described above.
<p>
The process of installing certificates and exchanging public keys is dependent
upon the e-mail application one uses, and is beyond the scope of this document.
</body>
</html>

View File

@@ -0,0 +1,29 @@
<html>
<head>
<title>Root Certificate Installation for Outlook & Outlook Express</title>
<link rel='stylesheet' type='text/css' href='../css/style.css'>
</head>
<body>
<center><h1>Root Certificate Installation for Outlook & Outlook Express</h1>
<h2>A Step-by-Step Guide</h2></center><br>
<h4>
<p><img src=../images/right-click-install-cacert.jpg>
<p>Open the folder which holds the certificates you have downloaded.<br>
Right-click on the certificate you wish to install, and select
<cite>Install Certificate</cite> from the context menu.
<p><br><img src=../images/cert-wizard1-welcome.jpg >
<p>Click the <cite>Next</cite> button in the <cite>Certificate Wizard</cite>
welcome window.
<p><br><img src=../images/cert-wizard4-select-store.jpg>
<p>Click the <cite>Next</cite> button in the <cite>Select a Certificate Store</cite> window.
<p><br><img src=../images/cert-wizard5-root-final.jpg>
<p>Click the <cite>Finish</cite> button in the <cite>Complete the Certificate..</cite> window.
<p><br><img src=../images/confirm-install-cacert.jpg>
<p>You may be asked to confirm the root certificate installation. Click the <cite>Yes</cite> button if a window like this appears.
<p><br><img src=../images/import-successful.jpg>
<p>Windows confirms the root certificate was successfully imported.<br>
You may now <a href=usercert_install_ie.html>install your personal e-mail certificate</a>.
</h4>
</body>
</html>

144
root/help/glossary.html Normal file
View File

@@ -0,0 +1,144 @@
<html>
<head>
<title>PHPki Glossary</title>
<link rel='stylesheet' type='text/css' href='../css/style.css'>
</head>
<body>
<a name=TOP></a>
<a name=PKI></a><p>
<table>
<th><h2>PUBLIC KEY INFRASTRUCTURE</h2></th>
<tr><td>
PKI stands for <cite>Public Key Infrastructure</cite>. PKI is IT infrastructure that enables users of a basically unsecure public network (such as the Internet) to securely and privately exchange data through the use of a public and a private <a href=#KEYS>cryptographic key pair</a> that is obtained and shared through a trusted authority.
PKI is not only software or hardware. It is an infrastructure. So, PKI is a combination of products, services, facilities, policies, procedures, agreements, and people. All of these elements work together to provide for secure interactions on the Internet and other open networks. PKI is not a single monolithic entity, but a distributed system. The component elements may include multiple organization-specific public key infrastructures that are interoperable and interconnected.
</td></tr>
</table>
<a name=CERTIFICATE></a><p>
<table>
<th><h2>DIGITAL CERTIFICATE</h2></th>
<tr><td>
<p>
An attachment to an electronic message used for security purposes. The most common use of a digital certificate is to verify that a user sending a message is who he or she claims to be, and to provide the receiver with the means to encode a reply.
<p>An individual wishing to send an encrypted message applies for a digital certificate from a <a href=#CA>Certificate Authority (CA)</a>. The CA issues an encrypted digital certificate containing the applicant's <a href=#KEYS>public key</a> and a variety of other identification information. The CA makes its own public key readily available through print publicity or perhaps on the Internet.
<p>The recipient of an encrypted message uses the CA's public key to decode the digital certificate attached to the message, verifies it as issued by the CA and then obtains the sender's public key and identification information held within the certificate. With this information, the recipient can send an encrypted reply.
<p>The most widely used standard for digital certificates is X.509.
</td></tr>
</table>
<a name=CA></a><p>
<table>
<th><h2>CERTIFICATE AUTHORITY</h2></th>
<tr><td>
A trusted third-party organization or company that issues digital certificates used to create digital signatures and <a href=#KEYS>public-private key pairs</a>. The role of the CA in this process is to guarantee that the individual granted the unique certificate is, in fact, who he or she claims to be. Usually, this means that the CA has an arrangement with a financial institution, such as a credit card company, which provides it with information to confirm an individual's claimed identity. CAs are a critical component in data security and electronic commerce because they guarantee that the two parties exchanging information are really who they claim to be.
</td></tr>
</table>
<a name=KEYS></a><p>
<table>
<th><h2>PUBLIC KEY ENCRYPTION</h2></th>
<tr><td>
A cryptographic system that uses two keys -- a public key known to everyone and a private or secret key known only to the recipient of the message. When John wants to send a secure message to Jane, he uses Jane's public key to encrypt the message. Jane then uses her private key to decrypt it.
<p>An important element to the public key system is that the public and private keys are related in such a way that only the public key can be used to encrypt messages and only the corresponding private key can be used to decrypt them. Moreover, it is virtually impossible to deduce the private key if you know the public key.
</td></tr>
</table>
<a name=SMIME></a><p>
<table>
<th><h2>S/MIME</h2></th>
<tr><td>
S/MIME (Secure Multi-Purpose Internet Mail Extensions) is a secure method of sending e-mail that uses the <a href=#RSA>RSA</a> encryption system. S/MIME is included in the latest versions of the Web browsers from Microsoft and Netscape and has also been endorsed by other vendors that make messaging products. RSA has proposed S/MIME as a standard to the Internet Engineering Task Force (IETF).
</td></tr>
</table>
<a name=RSA></a><p>
<table>
<th><h2>RSA</h2></th>
<tr><td>
RSA is an Internet encryption and authentication system that uses an algorithm developed in 1977 by Ron Rivest, Adi Shamir, and Leonard Adleman. The RSA algorithm is the most commonly used encryption and authentication algorithm and is included as part of the Web browsers from Microsoft and Netscape. It's also part of Lotus Notes, Intuit's Quicken, and many other products. The encryption system was owned by RSA Security, but a recent patent expiration placed it into the public domain. The technologies are part of existing or proposed Web, Internet, and computing standards.
</td></tr>
</table>
<a name=ROOT-CERT></a><p>
<table>
<th><h2>ROOT CERTIFICATE</h2></th>
<tr><td>
A root certificate is like a MASTER
<a href=#CERTIFICATE>digital certificate</a>.
You must install a <a href=#CA>certificate authority's</a> root certificate
before you can trust other certificates issued by that same certificate
authority. Root certificates are used to "sign" other certificates.
A signature by a root certificate is somewhat analogous to "notarizing" a
document in the physical world. When you install a root certificate on your
computer, you are saying you "trust" that certification authority and all
certificates it signs.
</td></tr>
</table>
<a name=SIGNATURE></a><p>
<table>
<th><h2>DIGITAL SIGNATURE</h2></th>
<tr><td>
A digital code that can be attached to an electronically transmitted message
that uniquely identifies the sender. Like a written signature, the purpose of
a digital signature is to guarantee that the individual sending the message
really is who he or she claims to be. Digital certificates inherently provide
digital signature capability to most S/MIME enable e-mail clients. Digitally
signing an e-mail usually provides the recipient the with the sender's public
key, so the recipient may then send encrypted e-mail back to the sender.
</td></tr>
</table>
<a name=X509></a><p>
<table>
<th><h2>X.509</h2></th>
<tr><td>
The most widely used standard for defining digital certificates. X.509 is
actually an ITU Recommendation, which means that has not yet been officially
defined or approved. As a result, companies have implemented the standard in
different ways. For example, both Netscape and Microsoft use X.509 certificates
to implement SSL in their web servers and browsers. But an X.509 certificate
generated by Netscape may not be readable by Microsoft products, and vice
versa.
</td></tr>
</table>
<a name=PEM></a><p>
<table>
<th><h2>PEM</h2></th>
<tr><td>
PEM is a widely used standard for storing digital certificates.
A PEM encoded file can contain all of private keys, public keys, and
<a href=#X509>(x.509)</a> certificates. It is the default format for OpenSSL.
It stores data in Base64 encoded format, surrounded by ascii headers, so it is
suitable for text mode transfers between systems. PEM files usually end with
a <cite>.PEM</cite> extension.
</td></tr>
</table>
<a name=DER></a><p>
<table>
<th><h2>DER</h2></th>
<tr><td>
DER is a widely used standard for storing digital certificates. A DER encoded
file can contain all of private keys, public keys, and <a href=#X509>(x.509)</a>
certificates. DER is a binary encoded headerless format. DER files usually
end with a <cite>.CRT</cite> or <cite>.CER</cite> extension.
</td></tr>
</table>
<a name=PKCS12></a><p>
<table>
<th><h2>PKCS #12</h2></th>
<tr><td>
PKCS #12 (a.k.a. Personal Information Exchange Standard) is a standard for storing private keys and certificates securely (well sort of). It is used in (among other things) Netscape and Microsoft Internet Explorer with their import and export options. PKCS12 files usually end with a <cite>.PFX</cite> extension.
</td></tr>
</table>
<br><br></body></html>

View File

@@ -0,0 +1,40 @@
<html>
<head>
<title>Personal E-mail Certificate Installation for Outlook & Outlook Express</title>
<link rel='stylesheet' type='text/css' href='../css/style.css'>
</head>
<body>
<center><h1>Personal E-mail Certificate Installation for Outlook & Outlook Express</h1>
<h2>A Step-by-Step Guide</h2></center><br>
<h4>
<p><img src=../images/right-click-install-usercert.jpg>
<p>Open the folder which holds the certificates you have downloaded.<br>
Right-click on the certificate you wish to install, and select
<cite>Install PFX</cite> from the context menu.
<p><br><img src=../images/cert-wizard1-welcome.jpg >
<p>Click the <cite>Next</cite> button in the <cite>Certificate Wizard</cite>
welcome window.
<p><br><img src=../images/cert-wizard2-select-file.jpg>
<p>Click the <cite>Next</cite> button in the <cite>Select File to Import</cite> window.
<p><br><img src=../images/cert-wizard3-password.jpg>
<p>The personal e-mail certificate files created by PHPki contain an encrypted
copy of your private key. When your certficate was created, a password was
given to PHPki to encrypt the private key. The same password is used to
decrypt your private key and install the certificate. Do not forget or lose
this password as it cannot be recovered under any circumstance.
Select the <cite>Enable strong private key protection</cite> option if you
would like Windows to add an additional layer of password protection to use
your certificate. This is not necessary, and will not be covered further here.
There is no need to select the <cite>Mark the private key as exportable</cite>
option. Enter your certificate password and click the <cite>Next</cite> button
in the <cite>Password Protection for Private Keys</cite> window.
<p><br><img src=../images/cert-wizard4-select-store.jpg>
<p>Click the <cite>Next</cite> button in the <cite>Select a Certificate Store</cite> window.
<p><br><img src=../images/cert-wizard5-user-final.jpg>
<p>Click the <cite>Finish</cite> button in the <cite>Complete the Certificate..</cite> window.
<p><br><img src=../images/import-successful.jpg>
<p>Windows confirms the root certificate was successfully imported.<br>
</h4>
</body>
</html>

BIN
root/images/bt0009.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

BIN
root/images/display.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 B

BIN
root/images/down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
root/images/download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
root/images/edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

BIN
root/images/grey-bullet.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
root/images/main-menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

BIN
root/images/public-menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
root/images/public_menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

BIN
root/images/renew.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
root/images/revoke.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
root/images/search-form.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
root/images/start-menu.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

130
root/include/common.php Normal file
View File

@@ -0,0 +1,130 @@
<?php
umask(0007);
if ($HTTP_SERVER_VARS['PHP_AUTH_USER'])
$PHPki_user = md5($HTTP_SERVER_VARS['PHP_AUTH_USER']);
else
$PHPki_user = md5('default');
$PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
function printHeader($withmenu="default") {
global $config;
$title = ($config['header_title']?$config['header_title']:'PHPki Certificate Authority');
switch ($withmenu) {
case 'public':
case 'about':
case 'setup':
$style_css = './css/style.css';
break;
case 'ca':
case 'admin':
default:
$style_css = '../css/style.css';
break;
}
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Expires: -1");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
?>
<html>
<head>
<title>PHPki: <?=$title?> </title>
<link rel="stylesheet" type="text/css" href="<?=$style_css?>">
</head>
<body>
<?
if (isKonq()) {
$logoclass = 'logo-konq';
$titleclass = 'title-konq';
$menuclass = 'headermenu-konq';
}
else {
$logoclass = 'logo-ie';
$titleclass = 'title-ie';
$menuclass = 'headermenu-ie';
}
?>
<div class=<?=$logoclass?>>PHPki</div>
<div class=<?=$titleclass?>><?=$title?></div>
<?
switch ($withmenu) {
case false:
case 'about':
break;
case 'setup':
?>
<div class=<?=$menuclass?>>
<a class=<?=$menuclass?> href=readme.php>ReadMe</a>
<a class=<?=$menuclass?> href=setup.php>Setup</a>
<a class=<?=$menuclass?> href=about.php target=_about>About</a>
</div>
<?
break;
case 'public':
print "<div class=$menuclass>";
if (DEMO) {
print "<a class=$menuclass href=index.php>Public</a>";
print "<a class=$menuclass href=ca/ >Manage</a>";
}
else {
print "<a class=$menuclass href=index.php>Menu</a>";
}
if (file_exists('policy.html')) {
print '<a class='.$menuclass.' style="color: red" href=policy.html target=help>Policy</a>';
}
?>
<a class=<?=$menuclass?> href=help.php target=_help>Help</a>
<a class=<?=$menuclass?> href=about.php target=_about>About</a>
</div>
<?
break;
case 'ca':
default:
print "<div class=$menuclass>";
if (DEMO) {
print "<a class=$menuclass href=../index.php>Public</a>";
print "<a class=$menuclass href=../ca/index.php>Manage</a>";
}
else {
print "<a class=$menuclass href=index.php>Menu</a>";
}
if (file_exists('../policy.html')) {
print '<a class='.$menuclass.' style="color: red" href=../policy.html target=help>Policy</a>';
}
?>
<a class=<?=$menuclass?> href=../help.php target=_help>Help</a>
<a class=<?=$menuclass?> href=../about.php target=_about>About</a>
</div>
<?
}
?><hr width=99% align=left color=#99caff><?
}
function printFooter() {
?>
<br>
<hr width=99% align=left color=#99caff>
<center style='margin-top: -5px; font-size: 8pt'>PHPki v<?=PHPKI_VERSION?> - Copyright 2003 - William E. Roadcap</center><br>
</body>
</html>
<?
}
?>

View File

@@ -0,0 +1,207 @@
<?php
$PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
#
# Returns TRUE if browser is Internet Explorer.
#
function isIE() {
global $HTTP_SERVER_VARS;
return strstr($HTTP_SERVER_VARS['HTTP_USER_AGENT'], 'MSIE');
}
function isKonq() {
global $HTTP_SERVER_VARS;
return strstr($HTTP_SERVER_VARS['HTTP_USER_AGENT'], 'Konqueror');
}
function isMoz() {
global $HTTP_SERVER_VARS;
return strstr($HTTP_SERVER_VARS['HTTP_USER_AGENT'], 'Gecko');
}
#
# Force upload of specified file to browser.
#
function upload($source, $destination, $content_type="application/octet-stream") {
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Expires: -1");
# header("Cache-Control: no-store, no-cache, must-revalidate");
# header("Cache-Control: post-check=0, pre-check=0", false);
# header("Pragma: no-cache");
header("Content-Type: $content_type");
if (is_array($source)) {
$fsize = 0;
foreach($source as $f) $fsize += filesize($f);
}
else {
$fsize = filesize($source);
}
header("Content-length: " . $fsize);
# header("Content-Disposition: attachment; filename=\"" . $destination ."\"");
header("Content-Disposition: filename=\"" . $destination ."\"");
if (is_array($source))
foreach($source as $f) $ret = readfile($f);
else
$ret=readfile($source);
# $fd=fopen($source,'r');
# fpassthru($fd);
# fclose($fd);
}
#
# Returns a value from the GET/POST global array referenced
# by field name. POST fields have precedence over GET fields.
# Quoting/Slashes are stripped if magic quotes gpc is on.
#
function gpvar($v) {
global $HTTP_GET_VARS, $HTTP_POST_VARS;
$x = "";
if ($HTTP_GET_VARS[$v]) $x = $HTTP_GET_VARS[$v];
if ($HTTP_POST_VARS[$v]) $x = $HTTP_POST_VARS[$v];
if (get_magic_quotes_gpc()) $x = stripslashes($x);
return $x;
}
#
# Sort a two multidimensional array by one of it's columns
#
function csort($array, $column, $ascdec=SORT_ASC){
if (sizeof($array) == 0) return $array;
foreach($array as $x) $sortarr[]=$x[$column];
array_multisort($sortarr, $ascdec, $array);
return $array;
}
#
# Returns a value suitable for display in the browser.
# Strips slashes if second argument is true.
#
function htvar($v, $strip=false) {
if ($strip)
return htmlentities(stripslashes($v));
else
return htmlentities($v);
}
#
# Returns a value suitable for use as a shell argument.
# Strips slashes if magic quotes is on, surrounds
# provided strings with single-quotes and quotes any
# other dangerous characters.
#
function escshellarg($v, $strip=false) {
if ($strip)
return escapeshellarg(stripslashes($v));
else
return escapeshellarg($v);
}
#
# Similar to escshellarg(), but doesn't surround provided
# string with single-quotes.
#
function escshellcmd($v, $strip=false) {
if ($strip)
return escapeshellcmd(stripslashes($v));
else
return escapeshellarg($v);
}
#
# Recursively strips slashes from a string or array.
#
function stripslashes_array(&$a) {
if (is_array($a)) {
foreach($a as $k => $v) {
my_stripslashes($a[$k]);
}
}
else {
$a = stripslashes($a);
}
}
#
# Don't use this.
#
function undo_magic_quotes(&$a) {
if(get_magic_quotes_gpc()) {
global $HTTP_POST_VARS, $HTTP_GET_VARS;
foreach($HTTP_POST_VARS as $k => $v) {
stripslashes_array($HTTP_POST_VARS[$k]);
global $$k;
stripslashes_array($$k);
}
foreach($HTTP_GET_VARS as $k => $v) {
stripslashes_array($HTTP_GET_VARS[$k]);
global $$k;
stripslashes_array($$k);
}
}
}
#
# Returns TRUE if argument contains only alphabetic characters.
#
function is_alpha($v) {
return (eregi('[^A-Z]',$v) ? false : true) ;
}
#
# Returns TRUE if argument contains only numeric characters.
#
function is_num($v) {
return (eregi('[^0-9]',$v) ? false : true) ;
}
#
# Returns TRUE if argument contains only alphanumeric characters.
#
function is_alnum($v) {
return (eregi('[^A-Z0-9]',$v) ? false : true) ;
}
#
# Returns TRUE if argument is in proper e-mail address format.
#
function is_email($v) {
return (eregi('^[^@ ]+\@[^@ ]+\.[A-Z]{2,3}$',$v) ? true : false);
}
#
# Checks regexp in every element of an array, returns TRUE as soon
# as a match is found.
#
function eregi_array($regexp, $a) {
foreach($a as $e) {
if (eregi($regexp,$e)) return true;
}
return false;
}
#
# Reads entire file into a string
# Same as file_get_contents in php >= 4.3.0
#
function my_file_get_contents($f) {
return implode('', file($f));
}
?>

View File

@@ -0,0 +1,779 @@
<?php
//
// Creates a temporary openssl config file specific to given parameters.
// File name is placed in ./tmp with a random name. It lingers unless
// removed manually.
//
function CA_create_cnf($country='',$province='',$locality='',$organization='',$unit='',$common_name='',$email='',$keysize=1024) {
global $config, $PHPki_user;
$issuer = $PHPki_user;
$cnf_contents = "
HOME = $config[home_dir]
RANDFILE = $config[random]
dir = $config[ca_dir]
certs = $config[cert_dir]
crl_dir = $config[crl_dir]
database = $config[index]
new_certs_dir = $config[new_certs_dir]
private_dir = $config[private_dir]
serial = $config[serial]
certificate = $config[cacert_pem]
crl = $config[cacrl_pem]
private_key = $config[cakey]
crl_extentions = crl_ext
default_days = 365
default_crl_days = 30
preserve = no
default_md = md5
[ req ]
default_bits = $keysize
string_mask = nombstr
prompt = no
distinguished_name = req_name
req_extensions = req_ext
[ req_name]
C=$country
ST=$province
L=$locality
0.O=$organization
1.O='$issuer'
OU=$unit
CN=$common_name
emailAddress=$email
[ ca ]
default_ca = email_cert
[ root_cert ]
x509_extensions = root_ext
default_days = 3650
policy = policy_supplied
[ email_cert ]
x509_extensions = email_ext
default_days = 365
policy = policy_supplied
[ email_codesigning_cert ]
x509_extensions = email_codesigning_ext
default_days = 365
policy = policy_supplied
[ server_cert ]
x509_extensions = server_ext
default_days = 365
policy = policy_supplied
[ vpn_cert ]
x509_extensions = vpn_client_server_ext
default_days = 365
policy = policy_supplied
[ time_stamping_cert ]
x509_extensions = time_stamping_ext
default_days = 365
policy = policy_supplied
[ policy_supplied ]
countryName = supplied
stateOrProvinceName = supplied
localityName = supplied
organizationName = supplied
organizationalUnitName = supplied
commonName = supplied
emailAddress = supplied
[ req_ext]
basicConstraints = CA:false
[ crl_ext ]
issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always,issuer:always
[ root_ext ]
basicConstraints = CA:true
keyUsage = cRLSign, keyCertSign
nsCertType = sslCA, emailCA, objCA
subjectKeyIdentifier = hash
subjectAltName = email:copy
crlDistributionPoints = URI:$config[base_url]index.php?stage=dl_crl
nsComment = \"PHPki/OpenSSL Generated Root Certificate\"
#nsCaRevocationUrl = ns_revoke_query.php?
nsCaPolicyUrl = $config[base_url]policy.html
[ email_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = critical, emailProtection, clientAuth
nsCertType = critical, client, email
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:$config[base_url]index.php?stage=dl_crl
nsComment = \"PHPki/OpenSSL Generated Personal Certificate\"
nsBaseUrl = $config[base_url]
nsRevocationUrl = ns_revoke_query.php?
nsCaPolicyUrl = $config[base_url]policy.html
[ email_codesigning_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = critical, emailProtection, clientAuth, codeSigning
nsCertType = critical, client, email
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:$config[base_url]index.php?stage=dl_crl
nsComment = \"PHPki/OpenSSL Generated Personal Certificate\"
nsBaseUrl = $config[base_url]
nsRevocationUrl = ns_revoke_query.php?
nsCaPolicyUrl = $config[base_url]policy.html
[ server_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature, keyEncipherment
nsCertType = critical, server
extendedKeyUsage = critical, serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = DNS:$common_name,email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:$config[base_url]index.php?stage=dl_crl
nsComment = \"PHPki/OpenSSL Generated Server Certificate\"
nsBaseUrl = $config[base_url]
nsRevocationUrl = ns_revoke_query.php?
nsCaPolicyUrl = $config[base_url]policy.html
[ time_stamping_ext ]
basicConstraints = CA:false
keyUsage = critical, nonRepudiation, digitalSignature
extendedKeyUsage = timeStamping
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = DNS:$common_name,email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:$config[base_url]index.php?stage=dl_crl
nsComment = \"PHPki/OpenSSL Generated Time Stamping Certificate\"
nsBaseUrl = $config[base_url]
nsRevocationUrl = ns_revoke_query.php?
[ vpn_client_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, clientAuth
nsCertType = critical, client
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = DNS:$common_name,email:copy
[ vpn_server_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth
nsCertType = critical, server
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = DNS:$common_name,email:copy
[ vpn_client_server_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth, clientAuth
nsCertType = critical, server, client
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = DNS:$common_name,email:copy
";
# Write out the config file.
$cnf_file = tempnam('./tmp','cnf-');
$handle = fopen($cnf_file,"w");
fwrite($handle, $cnf_contents);
fclose($handle);
return($cnf_file);
}
//
// Search the certificate index and return resulting
// records in array[cert_serial_number][field_name].
// Fields: serial, country, province, locality, organization,
// issuer, unit, common_name, email
//
function CAdb_to_array($search = '.*') {
global $config;
# Prepend a default status to search string if missing.
if (! ereg('^\^\[.*\]', $search)) $search = '^[VRE].*'.$search;
# Include valid certs?
if (ereg('^\^\[.*V.*\]',$search)) $inclval = true;
# Include revoked certs?
if (ereg('^\^\[.*R.*\]',$search)) $inclrev = true;
# Include expired certs?
if (ereg('^\^\[.*E.*\]',$search)) $inclexp = true;
# There isn't really a status of 'E' in the openssl index.
# Change (E)xpired to (V)alid within the search string.
$search = ereg_replace('^(\^\[.*)E(.*\])','\\1V\\2',$search);
$db = array();
exec('egrep -i '.escshellarg($search).' '.$config['index'], $x);
foreach($x as $y) {
$i = CAdb_explode_entry($y);
if (($i['status'] == "Valid" && $inclval) || ($i['status'] == "Revoked" && $inclrev) || ($i['status'] == "Expired" && $inclexp))
$db[$i['serial']] = $i;
}
return($db);
}
//
// Returns an array containing the index record for
// certificate $serial.
//
function CAdb_get_entry($serial) {
global $config;
$regexp = "^[VR]\t.*\t.*\t$serial\t.*\t.*$";
$x = exec('egrep '.escshellarg($regexp).' '.$config['index']);
if ($x)
return CAdb_explode_entry($x);
else {
return false;
}
}
//
// Returns the serial number of a VALID certificate matching
// $email and/or $name. Returns FALSE if no match is found.
//
function CAdb_in($email="", $name="") {
global $config;
$email = escshellcmd($email);
$name = escshellcmd($name);
$regexp = "^[V].*CN=$name/(Email|emailAddress)=$email";
$x =exec("egrep '$regexp' $config[index]");
if ($x) {
list($j,$j,$j,$serial,$j,$j) = explode("\t", $x);
return "$serial";
}
else
return false;
}
//
// Alias for CAdb_in()
//
function CAdb_serial($email, $name='') {
return CAdb_in($email, $name='');
}
//
// Alias for CAdb_in()
//
function CAdb_exists($email, $name='') {
return CAdb_in($email, $name='');
}
//
// Returns the certificate 'issuer'
//
function CAdb_issuer($serial) {
global $config;
$rec = CAdb_get_entry($serial);
return $rec['issuer'];
}
//
// Returns an array containing the respective fields given a
// a raw line ($dbentry) from the certificate index.
// Fields: serial, country, province locality, organization,
// issuer, unit, common_name, email
//
function CAdb_explode_entry($dbentry) {
$a = explode("\t", $dbentry);
$b = preg_split('/\/([A-Z]|[a-z])+=/', $a[5]);
switch ($a[0]) {
case "V":
$db['status'] = "Valid";
break;
case "R":
$db['status'] = "Revoked";
break;
}
sscanf(CA_cert_startdate($a[3]),"%s %s %s %s", $mm,$dd,$tt,$yy);
$db['issued'] = strftime("%y-%b-%d", strtotime("$dd $mm $yy"));
sscanf($a[1], "%2s%2s%2s",$yy,$mm,$dd);
$db['expires'] = strftime("%y-%b-%d", strtotime("$mm/$dd/$yy"));
if (time() > strtotime("$mm/$dd/$yy"))
$db['status'] = "Expired";
$db['serial'] = $a[3];
$db['country'] = $b[1];
$db['province'] = $b[2];
$db['locality'] = $b[3];
$db['organization'] = $b[4];
$db['issuer'] = $b[5];
$db['unit'] = $b[6];
$db['common_name'] = $b[7];
$db['email'] = $b[8];
return $db;
}
//
// Returns the date & time a specified certificate is revoked,
// Returns FALSE if the certificate is not revoked.
//
function CAdb_is_revoked($serial) {
global $config;
$regexp = "^R\t.*\t.*\t$serial\t.*\t.*$";
$x = exec('egrep '.escshellarg($regexp).' '.$config['index']);
if ($x) {
list($j,$j,$revoke_date,$j,$j,$j) = explode("\t", $x);
sscanf($revoke_date, "%2s%2s%2s",$yy,$mm,$dd);
return strftime("%b %d, %Y", strtotime("$mm/$dd/$yy"));
}
else
return false;
}
//
// Returns TRUE if a certificate is valid, otherwise FALSE.
//
function CAdb_is_valid($serial) {
global $config;
$regexp = "^V\t.*\t.*\t$serial\t.*\t.*$";
if (exec('egrep '.escshellarg($regexp).' '.$config['index']))
return true;
else
return false;
}
//
// Returns the long-form certificate description as output by
// openssl x509 -in certificatefile -text -purpose
//
function CA_cert_text($serial) {
global $config;
$certfile = $config['new_certs_dir'] . '/' . $serial . '.pem';
return(shell_exec(X509.' -in '.escshellarg($certfile).' -text -purpose 2>&1'));
}
//
// Returns the long-form text of the Certificate Revocation List
// openssl crl -in crlfile -text
//
function CA_crl_text() {
global $config;
$crlfile = $config['cacrl_pem'];
return(shell_exec(CRL.' -in '.escshellarg($crlfile).' -text 2>&1'));
}
//
// Returns the subject of a certificate.
//
function CA_cert_subject($serial) {
global $config;
$certfile = $config['new_certs_dir'] . '/' . $serial . '.pem';
$x = exec(X509.' -in '.escshellarg($certfile).' -noout -subject 2>&1');
return(str_replace('subject=', '', $x));
}
//
// Returns the common name of a certificate.
//
function CA_cert_cname($serial) {
global $config;
return(ereg_replace('^.*/CN=(.*)/.*','\\1',CA_cert_subject($serial)));
}
//
// Returns the email address of a certificate.
//
function CA_cert_email($serial) {
global $config;
$certfile = $config['new_certs_dir'] . '/' . $serial . '.pem';
$x = exec(X509.' -in '.escshellarg($certfile).' -noout -email 2>&1');
return($x);
}
//
// Returns the effective date of a certificate.
//
function CA_cert_startdate($serial) {
global $config;
$certfile = $config['new_certs_dir'] . '/' . $serial . '.pem';
$x = exec(X509.' -in '.escshellarg($certfile).' -noout -startdate 2>&1');
return(str_replace('notBefore=','',$x));
}
//
// Returns the expiration date of a certificate.
//
function CA_cert_enddate($serial) {
global $config;
$certfile = $config['new_certs_dir'] . '/' . $serial . '.pem';
$x = exec(X509.' -in '.escshellarg($certfile).' -noout -enddate 2>&1');
return(str_replace('notAfter=','',$x));
}
//
// Revokes a specified certificate.
//
function CA_revoke_cert($serial) {
global $config;
$fd = fopen($config['index'],'a');
flock($fd, LOCK_EX);
$certfile = "$config[new_certs_dir]/$serial.pem";
$cmd_output[] = 'Revoking the certificate.';
exec(CA." -config '$config[openssl_cnf]' -revoke ".escshellarg($certfile)." -passin pass:'$config[ca_pwd]' 2>&1", $cmd_output, $ret);
if ($ret == 0) {
unset($cmd_output);
list($ret, $cmd_output[]) = CA_generate_crl();
}
fclose($fd);
return array(($ret == true || $ret == 0 ? true : false), implode('<br>',$cmd_output));
}
//
// Creates a new certificate request, and certificate in various formats
// according to specified parameters. PKCS12 bundle files contain the
// private key, certificate, and CA certificate.
//
// Returns an array containing the output of failed openssl commands.
//
function CA_create_cert($cert_type='email',$country,$province,$locality,$organization,$unit,$common_name,$email,$expiry,$passwd,$keysize=1024) {
global $config;
# Wait here if another user has the database locked.
$fd = fopen($config['index'],"a");
flock($fd, LOCK_EX);
# Get the next available serial number
$serial = trim(implode('',file($config['serial'])));
$userkey = $config['private_dir'].'/'.$serial.'-key.pem';
$userreq = $config['req_dir'].'/'.$serial.'-req.pem';
$usercert = $config['new_certs_dir'].'/'.$serial.'.pem';
$userder = $config['cert_dir'].'/'.$serial.'.der';
$userpfx = $config['pfx_dir'].'/'.$serial.'.pfx';
$expiry_days = round($expiry * 365.25, 0);
$cnf_file = CA_create_cnf($country,$province,$locality,$organization,$unit,$common_name,$email,$keysize);
# Escape certain dangerous characters in user input
$email = escshellcmd($email);
$passwd = escshellarg($passwd);
$friendly_name = escshellarg($common_name);
$extensions = escshellarg($cert_type.'_ext');
# Create the certificate request
unset($cmd_output);
$cmd_output[] = 'Creating certifcate request.';
if ($passwd) {
exec(REQ." -new -newkey rsa:$keysize -keyout '$userkey' -out '$userreq' -config '$cnf_file' -days '$expiry_days' -passout pass:$passwd 2>&1", $cmd_output, $ret);
}
else {
exec(REQ." -new -newkey rsa:$keysize -keyout '$userkey' -out '$userreq' -config '$cnf_file' -days '$expiry_days' -nodes 2>&1", $cmd_output, $ret);
}
# Sign the certificate request and create the certificate
if ($ret == 0) {
unset($cmd_output);
$cmd_output[] = "Signing $cert_type certifcate request.";
exec(CA." -config '$cnf_file' -in '$userreq' -out /dev/null -notext -days '$expiry_days' -passin pass:'$config[ca_pwd]' -batch -extensions $extensions 2>&1", $cmd_output, $ret);
};
# Create DER format certificate
if ($ret == 0) {
unset($cmd_output);
$cmd_output[] = "Creating DER format certifcate.";
exec(X509." -in '$usercert' -out '$userder' -inform PEM -outform DER 2>&1", $cmd_output, $ret);
};
# Create a PKCS12 certificate file for download to Windows
if ($ret == 0) {
unset($cmd_output);
$cmd_output[] = "Creating PKCS12 format certifcate.";
if ($passwd) {
$cmd_output[] = "infile: $usercert keyfile: $userkey outfile: $userpfx pass: $passwd";
exec(PKCS12." -export -in '$usercert' -inkey '$userkey' -certfile '$config[cacert_pem]' -caname '$config[organization]' -out '$userpfx' -name $friendly_name -rand '$config[random]' -passin pass:$passwd -passout pass:$passwd 2>&1", $cmd_output, $ret);
}
else {
$cmd_output[] = "infile: $usercert keyfile: $userkey outfile: $userpfx";
exec(PKCS12." -export -in '$usercert' -inkey '$userkey' -certfile '$config[cacert_pem]' -caname '$config[organization]' -out '$userpfx' -name $friendly_name -passout pass: 2>&1", $cmd_output, $ret);
}
};
#Unlock the CA database
fclose($fd);
#Remove temporary openssl config file.
if (file_exists($cnf_file)) unlink($cnf_file);
if ($ret == 0) {
# Successful!
# Return status=true and serial number of issued certificate.
return array(true, $serial);
}
else {
# Not successful. :-(
# Clean up our loose ends.
# Return status=false and openssl output/errors for debug.
CA_remove_cert($serial);
$cmd_output[] = 'Click on the "Help" link above for information on how to report this problem.';
return array(false, implode("<br>",$cmd_output));
}
}
//
// Renews a specified certificate, revoking any existing valid versions.
// Uses old certificate request to Creates a new request, and certificate
// in various formats.
//
// Returns an array containing the output of failed openssl commands.
//
// FIXME: Yes, I know... This functions contains much duplicative code
// from CA_create_cert(). Bleh!
//
function CA_renew_cert($old_serial,$expiry,$passwd) {
global $config;
# Don't renew a revoked certificate if a valid one exists for this
# URL. Find and renew the valid certificate instead.
if (CAdb_is_revoked($old_serial)) {
$ret = CAdb_in(CA_cert_email($old_serial),CA_cert_cname($old_serial));
if ($ret && $old_serial != $ret) $old_serial = $ret;
}
# Valid certificates must be revoked prior to renewal.
if (CAdb_is_valid($old_serial)) {
$ret = CA_revoke_cert($old_serial);
if (! $ret[0]) return $ret;
}
$cert_type = CA_cert_type($old_serial);
$extensions = $cert_type.'_ext';
# Get common_name from old certificate for use as the
# "friendly name" of PKCS12 certificate.
$rec = CAdb_get_entry($old_serial);
$country = $rec['country'];
$province = $rec['province'];
$locality = $rec['locality'];
$organization = $rec['organiztion'];
$unit = $rec['unit'];
$common_name = $rec['common_name'];
$email = $rec['email'];
# Wait here if another user has the database locked.
$fd = fopen($config['index'],"a");
flock($fd, LOCK_EX);
# Get the next available serial number
$serial = trim(implode('',file($config['serial'])));
$old_userkey = $config['private_dir'].'/'.$old_serial.'-key.pem';
$old_userreq = $config['req_dir'].'/'.$old_serial.'-req.pem';
$userkey = $config['private_dir'].'/'.$serial.'-key.pem';
$userreq = $config['req_dir'].'/'.$serial.'-req.pem';
$usercert = $config['new_certs_dir'].'/'.$serial.'.pem';
$userder = $config['cert_dir'].'/'.$serial.'.der';
$userpfx = $config['pfx_dir'].'/'.$serial.'.pfx';
$expiry_days = round($expiry * 365.25, 0);
$cmd_output = array();
$ret = 0;
# Create a new certificate request by copying the old request.
if (! file_exists($old_userreq) || ! copy($old_userreq,$userreq)) {
$cmd_output[] = 'Could not create new certificate request file.';
$ret = 1;
}
# Copy private key to new file.
if ($ret == 0 && (! file_exists($old_userkey) || ! copy($old_userkey,$userkey))) {
$cmd_output[] = "Could not update private key file.";
$ret = 1;
}
$cnf_file = CA_create_cnf($country,$province,$locality,$organization,$unit,$common_name,$email);
# "friendly name" of PKCS12 certificate.
$friendly_name = escshellarg($rec['common_name']);
# Escape dangerous characters in user input.
$passwd = escshellarg($passwd);
# Sign the certificate request and create the certificate.
if ($ret == 0) {
unset($cmd_output);
$cmd_output[] = "Signing the $cert_type certificate request.";
exec(CA." -config '$cnf_file' -in '$userreq' -out /dev/null -notext -days '$expiry_days' -passin pass:'$config[ca_pwd]' -batch -extensions $extensions 2>&1", $cmd_output, $ret);
};
# Create DER format certificate
if ($ret == 0) {
unset($cmd_output);
$cmd_output[] = "Creating DER format certificate.";
exec(X509." -in '$usercert' -out '$userder' -inform PEM -outform DER 2>&1", $cmd_output, $ret);
};
# Create a PKCS12 certificate file for download to Windows
if ($ret == 0) {
unset($cmd_output);
$cmd_output[] = "Creating PKCS12 format certificate.";
if ($passwd) {
$cmd_output[] = "infile: $usercert keyfile: $userkey outfile: $userpfx pass: $passwd";
exec(PKCS12." -export -in '$usercert' -inkey '$userkey' -certfile '$config[cacert_pem]' -caname '$config[organization]' -out '$userpfx' -name $friendly_name -rand '$config[random]' -passin pass:$passwd -passout pass:$passwd 2>&1", $cmd_output, $ret);
}
else {
$cmd_output[] = "infile: $usercert keyfile: $userkey outfile: $userpfx";
exec(PKCS12." -export -in '$usercert' -inkey '$userkey' -certfile '$config[cacert_pem]' -caname '$config[organization]' -out '$userpfx' -name $friendly_name -passout pass: 2>&1", $cmd_output, $ret);
}
};
#Unlock the CA database
fclose($fd);
#Remove temporary openssl config file.
if (file_exists($cnf_file)) unlink($cnf_file);
if ($ret == 0) {
return array(true, $serial);
}
else {
# Not successful, so clean up before exiting.
CA_remove_cert($serial);
if (eregi_array('.*private key.*',$cmd_output))
$cmd_output[] = '<strong>This was likely caused by entering the wrong certificate password.</strong>';
else
$cmd_output[] = '<strong>Click on the "Help" link above for information on how to report this problem.</strong>';
return array(false, implode('<br>',$cmd_output));
}
}
//
// Creates a new Certificate Revocation List and copies it the the approriate
// locations. Returns error messages from failed commands.
//
function CA_generate_crl() {
global $config;
$ret = 0;
$cmd_output[] = "Generating Certificate Revocation List.";
exec(CA. " -gencrl -config '$config[openssl_cnf]' -out '$config[cacrl_pem]' -passin pass:'$config[ca_pwd]' 2>&1", $cmd_output, $ret);
if ($ret == 0) {
unset($cmd_output);
$cmd_output[] = "Creating DER format Certificate Revocation List.";
exec(CRL." -in '$config[cacrl_pem]' -out '$config[cacrl_der]' -inform PEM -outform DER 2>&1", $cmd_output, $ret);
}
return array(($ret == 0 ? true : false), implode('<br>',$cmd_output));
}
//
// Removes a specified certificate from the certificate index,
// and all traces of it from the file system.
//
function CA_remove_cert($serial) {
global $config;
$userreq = $config['req_dir'].'/'.$serial.'-req.pem';
$userkey = $config['private_dir'].'/'.$serial.'-key.pem';
$usercert = $config['new_certs_dir'].'/'.$serial.'.pem';
$userder = $config['cert_dir'].'/'.$serial.'.der';
$userpfx = $config['pfx_dir'].'/'.$serial.'.pfx';
# Wait here if another user has the database locked.
$fd = fopen($config['index'],'a');
flock($fd, LOCK_EX);
if( file_exists($userreq)) unlink($userreq);
if( file_exists($userkey)) unlink($userkey);
if( file_exists($usercert)) unlink($usercert);
if( file_exists($userder)) unlink($userder);
if( file_exists($userpfx)) unlink($userpfx);
$tmpfile = $config['index'].'.tmp';
copy($config['index'], $tmpfile);
$regexp = "^[VR]\t.*\t.*\t".$serial."\t.*\t.*$";
exec('egrep -v '.escshellarg($regexp)." $tmpfile > $config[index] 2>/dev/null");
unlink($tmpfile);
fclose($fd);
}
//
// Returns the likely intended use for a specified certificate
// (email, server, vpn).
//
function CA_cert_type($serial) {
$certtext = CA_cert_text($serial);
if (ereg('OpenSSL.* (E.?mail|Personal) .*Certificate', $certtext) && ereg('Code Signing', $certtest)) {
$cert_type = 'email_codesigning';
}
if (ereg('OpenSSL.* (E.?mail|Personal) .*Certificate', $certtext)) {
$cert_type = 'email';
}
elseif (ereg('OpenSSL.* Server .*Certificate', $certtext)) {
$cert_type = 'server';
}
elseif (ereg('timeStamping|Time Stamping', $certtext)) {
$cert_type = 'time_stamping';
}
elseif (ereg('TLS Web Client Authentication', $certtext) && ereg('TLS Web Server Authentication', $certtext)) {
$cert_type = 'vpn_client_server';
}
elseif (ereg('TLS Web Client Authentication', $certtext)) {
$cert_type = 'vpn_client';
}
elseif (ereg('TLS Web Server Authentication', $certtext)) {
$cert_type = 'vpn_server';
}
else {
$cert_type = 'vpn_client_server';
}
return $cert_type;
}
?>

1
root/index.php Symbolic link
View File

@@ -0,0 +1 @@
readme.php

52
root/main.php Normal file
View File

@@ -0,0 +1,52 @@
<?php
include('./config.php');
include(STORE_DIR.'/config/config.php');
include('./include/common.php');
include('./include/my_functions.php');
$stage = gpvar('stage');
switch($stage) {
case 'dl_root':
upload("$config[cacert_pem]", "$config[ca_prefix]cacert.crt", 'application/x-x509-ca-cert');
break;
case 'dl_crl':
upload("$config[cacrl_der]", "$config[ca_prefix]cacrl.crl", 'application/pkix-crl');
break;
default:
printHeader('public');
?>
<br>
<br>
<center>
<table class=menu width=500><th class=menu colspan=2><big>PUBLIC CONTENT MENU<big></th>
<tr><td style="text-align: center; vertical-align: middle; font-weight: bold;" width=35%>
<a href=search.php>Search for a Certificate</a></td>
<td>Find a digital certificate to download and install in your e-mail or browser application.</td></tr>
<tr><td style="text-align: center; vertical-align: middle; font-weight: bold;">
<a href=<?=$PHP_SELF?>?stage=dl_root>Download Our Root Certificate</a></td>
<td>You must install our "Root" certificate before you can use any of the
certificates issued here. <a href=help.php target=_help>Read the online help</a>
to learn more about this.</td></tr>
<tr><td style="text-align: center; vertical-align: middle; font-weight: bold;">
<a href=<?=$PHP_SELF?>?stage=dl_crl>Download Our Certificate Revocation List</a></td>
<td>The official list of certificates revoked by this site. Installation and use of
this list is optional. Some e-mail programs will reference this list automagically. </td></tr>
</table>
</center>
<br><br>
<?
printFooter();
}
?>

27
root/ns_revoke_query.php Normal file
View File

@@ -0,0 +1,27 @@
<?php
#
# This is to support the NetscapeRevocationURL extension that can
# be used to check the validity of certificates issued by this CA.
# The URL to this script is embeded in all certificates issued by
# this CA.
#
# PROTOCOL:
# The client should issue an HTTP GET request using a URL that is
# the concatenation of the revocation url and certificate serial
# number. (i.e. http://www.host.dom/phpki/ns_revoke_query.php?10A5F2)
#
# The server should return a document of type
# application/x-netscape-revocation containing a single character
# '1' if the certificate is revoked, '0' if it is valid.
#
include('./config.in.php');
include(STORE_DIR.'/config/config.php');
$serial = escapeshellcmd(trim($HTTP_SERVER_VARS['QUERY_STRING']));
header("Content-type: application/x-netscape-revocation");
$regexp = "^R\t.*\t.*\t$serial\t.*\t.*$";
if (exec("egrep '$regexp' ca/$config[index]"))
print '1';
else
print '0';
?>

183
root/openssl.cnf Normal file
View File

@@ -0,0 +1,183 @@
HOME = /var/www/phpki-store
RANDFILE = /var/www/phpki-store/CA/.rnd
dir = /var/www/phpki-store/CA
certs = /var/www/phpki-store/CA/certs
crl_dir = /var/www/phpki-store/CA/crl
database = /var/www/phpki-store/CA/index.txt
new_certs_dir = /var/www/phpki-store/CA/newcerts
private_dir = /var/www/phpki-store/CA/private
serial = /var/www/phpki-store/CA/serial
certificate = /var/www/phpki-store/CA/certs/cacert.pem
crl = /var/www/phpki-store/CA/crl/cacrl.pem
private_key = /var/www/phpki-store/CA/private/cakey.pem
crl_extensions = crl_ext
default_days = 365
default_crl_days = 30
preserve = no
default_md = md5
[ ca ]
default_ca = email_cert
[ root_cert ]
x509_extensions = root_ext
default_days = 3650
policy = policy_supplied
[ email_cert ]
x509_extensions = email_ext
default_days = 365
policy = policy_supplied
[ email_codesigning_cert ]
x509_extensions = email_codesigning_ext
default_days = 365
policy = policy_supplied
[ server_cert ]
x509_extensions = server_ext
default_days = 365
policy = policy_supplied
[ vpn_cert ]
x509_extensions = vpn_client_server_ext
default_days = 365
policy = policy_supplied
[ policy_supplied ]
countryName = supplied
stateOrProvinceName = supplied
localityName = supplied
organizationName = supplied
organizationalUnitName = supplied
commonName = supplied
emailAddress = supplied
[ root_ext ]
basicConstraints = CA:true
keyUsage = cRLSign, keyCertSign
nsCertType = sslCA, emailCA, objCA
subjectKeyIdentifier = hash
subjectAltName = email:copy
crlDistributionPoints = URI:http://www.somewhere.com/phpki/index.php?stage=dl_crl
nsComment = "PHPki/OpenSSL Generated Root Certificate Authority"
#nsCaRevocationUrl = ns_revoke_query.php?
nsCaPolicyUrl = http://www.somewhere.com/phpki/policy.html
[ email_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = critical, emailProtection, clientAuth
nsCertType = critical, client, email
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:http://www.somewhere.com/phpki/index.php?stage=dl_crl
nsComment = "PHPki/OpenSSL Generated Personal Certificate"
nsBaseUrl = http://www.somewhere.com/phpki/
nsRevocationUrl = ns_revoke_query.php?
#nsRenewalUrl =
nsCaPolicyUrl = http://www.somewhere.com/phpki/policy.html
#nsSslServerName =
[ email_codesigning_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = critical, emailProtection, clientAuth, codeSigning
nsCertType = critical, client, email
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:http://www.somewhere.com/phpki/index.php?stage=dl_crl
nsComment = "PHPki/OpenSSL Generated Personal Certificate"
nsBaseUrl = http://www.somewhere.com/phpki/
nsRevocationUrl = ns_revoke_query.php?
#nsRenewalUrl =
nsCaPolicyUrl = http://www.somewhere.com/phpki/policy.html
#nsSslServerName =
[ server_ext ]
basicConstraints = CA:false
keyUsage = critical, digitalSignature, keyEncipherment
nsCertType = critical, server
extendedKeyUsage = critical, serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:http://www.somewhere.com/phpki/index.php?stage=dl_crl
nsComment = "PHPki/OpenSSL Generated Secure Server Certificate"
nsBaseUrl = http://www.somewhere.com/phpki/
nsRevocationUrl = ns_revoke_query.php?
nsCaPolicyUrl = http://www.somewhere.com/phpki/policy.html
[ vpn_client_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, clientAuth
nsCertType = critical, client
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = email:copy
[ vpn_server_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth
nsCertType = critical, server
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = email:copy
[ vpn_client_server_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth, clientAuth
nsCertType = critical, server, client
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = email:copy
[ crl_ext ]
issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always,issuer:always
[ req ]
default_bits = 1024
default_keyfile = privkey.pem
distinguished_name = req_name
string_mask = nombstr
req_extensions = req_ext
[ req_name]
countryName = Country Name (2 letter code)
countryName_default = US
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default =
localityName = Locality Name (eg, city)
localityName_default =
0.organizationName = Organization Name (eg, company)
0.organizationName_default =
1.organizationName = Second Organization Name (eg, company)
1.organizationName_default =
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default =
commonName = Common Name (eg, YOUR name)
emailAddress = Email Address or Web URL
[ req_ext ]
basicConstraints = critical, CA:false

14
root/policy.html Normal file
View File

@@ -0,0 +1,14 @@
<html>
<head>
<title>Certificate Authority Issuer's Statement</title>
</head>
<body>
<h1 align=center>Certificate Authority Issuer's Statement</h2>
<p>
This is a private Limited Liability certificate authority for use by member
non-profit agencies.
<p>
Certificate non-repudiation is achieved via identity verification by password
authorized certificate managers from each member agency.
</body>
</html>

13
root/readme.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
include('./config.php');
include('./include/my_functions.php');
include('./include/common.php');
printHeader('setup');
print '<center><font color=red><h1>READ ME</h1></font></center>';
print '<pre>';
readfile('./README');
print '</pre>';
printFooter();
?>

140
root/search.php Normal file
View File

@@ -0,0 +1,140 @@
<?php
include('./config.php');
include(STORE_DIR.'/config/config.php');
include('./include/common.php');
include('./include/my_functions.php');
include('./include/openssl_functions.php');
$stage = gpvar('stage');
$submit = gpvar('submit');
$search = gpvar('search');
$serial = gpvar('serial');
$show_valid = gpvar('show_valid');
$show_revoked = gpvar('show_revoked');
$show_expired = gpvar('show_expired');
# Force stage back to search form if search string is empty.
if ($stage == "search" && ! $search) $stage = "";
# Force filter to (V)alid certs if no search status is selected.
if ( !($show_valid.$show_revoked.$show_expired) ) $show_valid = 'V';
switch ($stage) {
case display:
printHeader('about');
print '
<center><h2>Certificate Details</h2></center>
<center><font color=#0000AA><h3>(#'.htvar($serial).')<br>'.htvar(CA_cert_cname($serial).' <'.CA_cert_email($serial).'>').'</h3></font></center>';
if ($revoke_date = CAdb_is_revoked($serial))
print '<center><font color=red><h2>REVOKED '.htvar($revoke_date).'</h2></font></center>';
print '<pre>'.htvar(CA_cert_text($serial)).'</pre>';
break;
case 'download':
$rec = CAdb_get_entry($serial);
upload("$config[cert_dir]/$serial.der", "$rec[common_name] ($rec[email]).cer", 'application/pkix-cert');
break;
case search:
printHeader('public');
$db = CAdb_to_array("^[${show_valid}${show_revoked}${show_expired}].*$search");
print '<body onLoad="self.focus();document.form.submit.focus()">';
if (sizeof($db) == 0) {
?>
<center>
<h2>Nothing Found</h2>
<form action=<?=$PHP_SELF?> method=post name=form>
<input type=hidden name=search value="<?=htvar($search)?>">
<input type=hidden name=show_valid value="<?=htvar($show_valid)?>">
<input type=hidden name=show_revoked value="<?=htvar($show_revoked)?>">
<input type=hidden name=show_expired value="<?=htvar($show_expired)?>">
<input type=submit name=submit value="Go Back">
</form>
</center>
<?
printFooter();
break;
}
print '<table>';
print '<th colspan=9><big>CERTIFICATE SEARCH RESULTS</big></th>';
$headings = array(
status=>"Status", issued=>"Issued", expires=>"Expires",
common_name=>"User's Name", email=>"E-mail",
organization=>"Organization", unit=>"Department",
locality=>"Locality", province=>"State"
);
print '<tr>';
foreach($headings as $field=>$head) {
print '<th>'.htvar($head). '</th>';
}
print '</tr>';
foreach($db as $rec) {
$stcolor = array(Valid=>'green',Revoked=>'red',Expired=>'orange');
?>
<tr style="font-size: 11px;">
<td style="color: <?=$stcolor[$rec['status']]?>; font-weight: bold"><?=htvar($rec['status'])?></td>
<td style="white-space: nowrap"><?=htvar($rec['issued'])?></td>
<td style="white-space: nowrap"><?=htvar($rec['expires'])?></td>
<td><?=htvar($rec[common_name])?></td>
<td style="white-space: nowrap"><a href="mailto:<?=htvar($rec['common_name']).' <'.htvar($rec['email']).'>"'?>><?=htvar($rec['email'])?></a></td>
<td><?=htvar($rec['organization'])?></td>
<td><?=htvar($rec['unit'])?></td>
<td><?=htvar($rec['locality'])?></td>
<td><?=htvar($rec['province'])?></td>
<td><a href=<?=$PHP_SELF?>?stage=display&serial=<?=htvar($rec['serial'])?> target=_certdisp><img src=images/display.png alt="Display" title="Display the certificate in excruciating detail"></a>
<?
if ($rec['status'] != 'Revoked') {
?>
<a href=<?=$PHP_SELF?>?stage=download&serial=<?=htvar($rec['serial'])?>><img src=images/download.png alt="Download" title="Download the certificate so that you may send encrypted e-mail"></a>
<?
}
print '</td></tr>';
}
?>
</table>
<form action=<?=$PHP_SELF?> method=post name=form>
<input type=submit name=submit value="Another Search">
<input type=hidden name=search value="<?=htvar($search)?>">
<input type=hidden name=show_valid value="<?=htvar($show_valid)?>">
<input type=hidden name=show_revoked value="<?=htvar($show_revoked)?>">
<input type=hidden name=show_expired value="<?=htvar($show_expired)?>">
</form>
<?
printFooter();
break;
default:
printHeader('public');
?>
<body onLoad="self.focus();document.search.search.focus()">
<center><h2>Certificate Search</h2>
<form action=<?=$PHP_SELF?> method=post name=search>
<input type=text name=search value="<?=htvar($search)?>" maxlength=60 size=40>
<input type=submit name=submit value="Find It!"><br>
<input type=checkbox name=show_valid value="V" <?=($show_valid?'checked':'')?>>Valid
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type=checkbox name=show_revoked value="R" <?=($show_revoked?'checked':'')?>>Revoked
&nbsp;&nbsp;&nbsp;&nbsp;<input type=checkbox name=show_expired value="E" <?=($show_expired?'checked':'')?>>Expired
<input type=hidden name=stage value=search>
</form></center>
<br><br>
<?
printFooter();
}
?>

102
root/secure.sh Executable file
View File

@@ -0,0 +1,102 @@
#!/bin/bash
owner="`id -nu`"
cat <<EOM
This application is designed to be an easy to use "certificate factory"
requiring minimum human intervention to administer. It is intended for
use within a trusted INTRAnet for the creation and management of x.509
e-mail digital certificates by departmental managers. IT IS NOT INTENDED
FOR USE OVER THE INTERNET.
This application stores private keys within a sub-directory, making them
potentially susceptible to compromise. Extra care has been taken in the
design of this application to protect the security of your certificates,
on the condition that you INSTALL IT AS THE ROOT USER. However, no
software is 100% secure.
EOM
read -p "Enter the location of your PHPki password (i.e. /etc/phpkipasswd): " passwd_file
echo
if [ ! -f "$passwd_file" ]
then
echo "The file you specified does not yet exist."
echo "Let's create it and add your first user."
echo
read -p "Enter a user id: " $user_id
echo "Creating the '$user_id' user account..."
htpasswd -m "$passwd_file" "$user_id" || exit
echo "Creating the administrator account..."
echo "See the README file for more information about the"
echo "'pkiadmin' user."
htpasswd -c -m "$passwd_file" 'pkiadmin' || exit
fi
echo
if [ ! "${owner}_" = "root_" ]
then
cat <<EOM
YOU ARE NOT LOGGED ON AS ROOT!
If you choose to proceed anyway, and you plan to make this application
available over the Internet, you increase the risk of compromising the
security of your certifcates and your server.
This script may not run correctly if you are not the ROOT user.
EOM
fi
echo -n "Enter the user ID your web server runs as [apache]: " ; read x
echo
echo -n "Enter the group ID your web server runs as [apache]: " ; read z
echo
echo "Enter the IP or subnet address [192.168.0.0/16] which will be allowed access"
echo -n "to the user admin module in under ./admin: " ; read y
user=${x:-apache}
group=${z:-apache}
subnet=${y:-'192.168.0.0/16'}
subnet="${subnet} 127.0.0.1"
echo "Working..."
for i in ./include
do
echo "deny from all" >$i/.htaccess
done
cat <<EOS >> ./ca/.htaccess
AuthName "Restricted Area"
AuthType Basic
AuthUserFile "$passwd_file"
require valid-user
SSLRequireSSL
EOS
cat <<EOS > ./admin/.htaccess
AuthName "Restricted Area"
AuthType Basic
AuthUserFile "$passwd_file"
require valid-user
SSLRequireSSL
Order Allow,Deny
Allow from $subnet
EOS
# Start with web server getting read-only access to everything.
# Directories have sticky bits set.
find . -exec chown $owner:$group {} \;
find . ! -type d -exec chmod 640 {} \;
find . -type d -exec chmod 3750 {} \;
echo "Done."

1
root/setup.php Symbolic link
View File

@@ -0,0 +1 @@
setup.php-presetup

886
root/setup.php-presetup Normal file
View File

@@ -0,0 +1,886 @@
<?php
include('./config.php');
include('./include/my_functions.php');
include('./include/common.php');
function flush_exec($command, $line_length=200) {
$handle = popen("$command 2>&1",'r');
$line = '';
while (! feof($handle)) {
$chr = fread($handle, 1);
$line .= $chr;
if ($chr == "\n") {
print str_replace("\n", "<br>\n", $line);
$line = '';
flush();
}
elseif (strlen($line) > $line_length) {
print $line."<br>\n";
$line = '';
flush();
}
}
print $line."<br>\n";
flush;
return;
}
$version = PHPKI_VERSION;
# Who does the webserver run as (apache,www-data,etc)?
$uid = posix_getuid();
$pwdinfo = posix_getpwuid($uid);
$uname = $pwdinfo['name'];
# Permissions on the file store.
$store_perms=0770;
# Where are we?
$here = dirname($_SERVER['SCRIPT_FILENAME']);
$submit = gpvar('submit');
$stage = gpvar('stage');
$organization = gpvar('organization');
$unit = gpvar('unit');
$contact = gpvar('contact');
$locality = gpvar('locality');
$province = gpvar('province');
$country = gpvar('country');
$common_name = gpvar('common_name');
$passwd = gpvar('passwd');
$passwdv = gpvar('passwdv');
$expiry = gpvar('expiry');
$keysize = gpvar('keysize');
$base_url = gpvar('base_url');
$openssl_bin = gpvar('openssl_bin');
$passwd_file = gpvar('passwd_file');
$getting_help = gpvar('getting_help');
$ca_prefix = gpvar('ca_prefix');
$header_title = gpvar('header_title');
$store_dir = gpvar('store_dir');
if ($base_url && substr($base_url,-1) != '/') $base_url .= '/';
$hidden_fields = '
<input type=hidden name=country value="' . htvar($country) . '">
<input type=hidden name=province value="' . htvar($province) . '">
<input type=hidden name=locality value="' . htvar($locality) . '">
<input type=hidden name=organization value="' . htvar($organization) . '">
<input type=hidden name=unit value="' . htvar($unit) . '">
<input type=hidden name=contact value="' . htvar($contact) . '">
<input type=hidden name=common_name value="' . htvar($common_name) . '">
<input type=hidden name=passwd value="' . htvar($passwd) . '">
<input type=hidden name=passwdv value="' . htvar($passwdv) . '">
<input type=hidden name=expiry value="' . htvar($expiry) . '">
<input type=hidden name=keysize value="' . htvar($keysize) . '">
<input type=hidden name=base_url value="' . htvar($base_url) . '">
<input type=hidden name=openssl_bin value="' . htvar($openssl_bin) . '">
<input type=hidden name=getting_help value="' . htvar($getting_help) . '">
<input type=hidden name=ca_prefix value="' . htvar($ca_prefix) . '">
<input type=hidden name=header_title value="' . htvar($header_title) . '">
<input type=hidden name=passwd_file value="' . htvar($passwd_file) . '">
<input type=hidden name=store_dir value="' . htvar($store_dir) . '">
';
switch ($stage) {
case 'validate':
$er = '';
if (! $country) $er .= 'Missing Country<br>';
if (! $province) $er .= 'Missing State/Province<br>';
if (! $locality) $er .= 'Missing Locality<br>';
if (! $organization) $er .= 'Missing Organization<br>';
if (! $unit) $er .= 'Missing Unit/Department<br>';
if (! $contact) $er .= 'Missing Contact E-mail Address<br>';
if (! $common_name) $er .= 'Missing Common Name<br>';
if (! $passwd) $er .= 'Missing Certificate Password<br>';
if (! $passwdv) $er .= 'Missing Certificate Password Verification "Again"<br>';
if (! $header_title) $er .= 'Missing Header Title<br>';
if (! $passwd_file) $er .= 'Missing User Password File Location';
if (! $store_dir) $er .= 'Missing Storage Directory<br>';
if ( $passwd && strlen($passwd) < 8 )
$er .= 'Certificate password is too short.<br>';
if ( $passwd and $passwd != $passwdv )
$er .= 'Password and password verification do not match.<br>';
if ( $email && ! is_email($contact) )
$er .= 'E-mail address ('. htvar($contact) . ') may be invalid.<br>';
if (strpos($store_dir,$_SERVER['DOCUMENT_ROOT']) === 0)
$er .= 'Store directory must exist somewhere outside of DOCUMENT_ROOT ('.$_SERVER['DOCUMENT_ROOT'].').<br>';
if (strpos($store_dir,dirname($_SERVER['SCRIPT_FILENAME'])) === 0)
$er .= 'Store directory cannot exist within the PHPki installation directory ('.dirname($_SERVER['SCRIPT_FILENAME']).').<br>';
if (! $er) {
if (! file_exists($store_dir) ) {
if ( ! mkdir("$store_dir",$store_perms)) $er .= "Could not create the store directory \"$store_dir\"<br>";
}
if (file_exists($store_dir)) {
if (! chmod($store_dir, $store_perms)) $er .= "Could not change permissions on the store directory \"$store_dir\"<br>";
if (! is_readable($store_dir)) $er .= "The store directory \"$store_dir\" is not readable by the web server user \"$uname\"<br>";
if (! is_writeable($store_dir)) $er .= "The store directory \"$store_dir\: is not writeable by the web server user \"$uname\"<br>";
}
else {
$er .= "Store directory \"$store_dir\" does not exist. You will have to manually create it as desribed in the setup form.<br>";
}
}
if ( $er )
$er = '<h2>ERROR(S) IN FORM:</h2><h4><blockquote>' . $er . '</blockquote></h4>';
if ($er) {
printHeader('setup');
?>
<form action='<?=$PHP_SELF?>' method=post>
<input type=submit name=Submit value='Go Back'>
<font color=#ff0000><?=$er?></font>
<br><input type=submit name=Submit2 value='Go Back'>
<?
print $hidden_fields;
print "</form>";
printFooter();
break;
}
case 'write':
printHeader('about');
#
#Create the file store directory structure.
#
print '<strong>Creating PHPki file store...</strong><br>';
flush();
if (! file_exists("$store_dir/config")) mkdir("$store_dir/config",$store_perms);
if (! file_exists("$store_dir/tmp")) mkdir("$store_dir/tmp",$store_perms);
if (! file_exists("$store_dir/CA")) mkdir("$store_dir/CA",$store_perms);
if (! file_exists("$store_dir/CA/certs")) mkdir("$store_dir/CA/certs",$store_perms);
if (! file_exists("$store_dir/CA/private")) mkdir("$store_dir/CA/private",$store_perms);
if (! file_exists("$store_dir/CA/newcerts")) mkdir("$store_dir/CA/newcerts",$store_perms);
if (! file_exists("$store_dir/CA/requests")) mkdir("$store_dir/CA/requests",$store_perms);
if (! file_exists("$store_dir/CA/crl")) mkdir("$store_dir/CA/crl",$store_perms);
if (! file_exists("$store_dir/CA/pfx")) mkdir("$store_dir/CA/pfx",$store_perms);
#
# Create the PHPki CA configuration.
#
print '<strong>Writing configuration files...</strong><br>';
flush();
$config_txt = <<<EOS
<?php
# PHPki CONFIGURATION FILE
# Automatically generated by PHPki. Edit at your own peril.
#
\$config['organization'] = '$organization';
\$config['unit'] = '$unit';
\$config['contact'] = '$contact';
\$config['locality'] = '$locality';
\$config['province'] = '$province';
\$config['country'] = '$country';
\$config['common_name'] = '$common_name';
# Store Directory
\$config['store_dir'] = '$store_dir';
# Location HTTP Password File
\$config['passwd_file'] = '$passwd_file';
# Password for CA root certificate.
\$config['ca_pwd'] = '$passwd';
# Number of years the root certificate is good.
\$config['expiry'] = '$expiry';
# CA certificate key size
\$config['keysize'] = '$keysize';
# This is superimposed over the PHPki logo on each page.
\$config['header_title'] = '$header_title';
# String to prefix cer and crl uploads
\$config['ca_prefix'] = '$ca_prefix';
# Location of your OpenSSL binary.
\$config['openssl_bin'] = '$openssl_bin';
# Base URL
\$config['base_url'] = '$base_url';
# Who users should contact if they have technical difficulty with
# your certificate authority site.
\$config['getting_help'] = '$getting_help';
#
# You shouldn't change anything below this line. If you do, don't
# ask for help!
#
\$config['home_dir'] = \$config['store_dir'];
\$config['ca_dir'] = \$config['home_dir'] . '/CA';
\$config['private_dir'] = \$config['ca_dir'] . '/private';
\$config['new_certs_dir'] = \$config['ca_dir'] . '/newcerts';
\$config['cert_dir'] = \$config['ca_dir'] . '/certs';
\$config['req_dir'] = \$config['ca_dir'] . '/requests';
\$config['crl_dir'] = \$config['ca_dir'] . '/crl';
\$config['pfx_dir'] = \$config['ca_dir'] . '/pfx';
\$config['index'] = \$config['ca_dir'] . '/index.txt';
\$config['serial'] = \$config['ca_dir'] . '/serial';
\$config['random'] = \$config['ca_dir'] . '/.rnd';
\$config['cacert_pem'] = \$config['cert_dir'] . '/cacert.pem';
\$config['cacrl_pem'] = \$config['crl_dir'] . '/cacrl.pem';
\$config['cacrl_der'] = \$config['crl_dir'] . '/cacrl.crl';
\$config['cakey'] = \$config['private_dir'] . '/cakey.pem';
# Default OpenSSL Config File.
\$config['openssl_cnf'] = \$config['home_dir'] . '/config/openssl.cnf';
\$PHPki_admins = Array(md5('pkiadmin'));
define('OPENSSL',\$config['openssl_bin'].' ');
define('X509', OPENSSL . ' x509 ');
define('PKCS12', "RANDFILE='\$config[random]' " . OPENSSL . ' pkcs12 ');
define('CA', OPENSSL . ' ca ');
define('REQ', OPENSSL . ' req ');
define('CRL', OPENSSL . ' crl ');
?>
EOS;
#
# Write out the CA configuration file.
#
$fd = fopen("$store_dir/config/config.php",'w');
fwrite($fd, $config_txt);
fclose($fd);
#
# Create the bootstrap configuration
#
$config_txt = <<<EOS
<?php
define('PHPKI_VERSION','$version');
define('STORE_DIR','$store_dir');
define('DEMO',FALSE);
define('BASE_URL','$base_url');
?>
EOS;
#
# Write out the bootstrap config
#
$fd = fopen('./config.php','w');
fwrite($fd, $config_txt);
fclose($fd);
# Re-read the CA config file so the openssl_functions
# can be used to create a CA root certificate.
include("$store_dir/config/config.php");
#
# Now create a temporary openssl.cnf for creating a self-signed
# CA root certificate, and create a generic openssl.cnf file
# in the CA home
#
$config_txt1 = <<< EOS
HOME = $config[home_dir]
RANDFILE = $config[random]
dir = $config[ca_dir]
certs = $config[cert_dir]
crl_dir = $config[crl_dir]
database = $config[index]
new_certs_dir = $config[new_certs_dir]
private_dir = $config[private_dir]
serial = $config[serial]
certificate = $config[cacert_pem]
crl = $config[cacrl_pem]
private_key = $config[cakey]
crl_extensions = crl_ext
default_days = 365
default_crl_days = 30
preserve = no
default_md = md5
[ ca ]
default_ca = email_cert
[ root_cert ]
x509_extensions = root_ext
default_days = 3650
policy = policy_supplied
[ email_cert ]
x509_extensions = email_ext
default_days = 365
policy = policy_supplied
[ email_signing_cert ]
x509_extensions = email_signing_ext
default_days = 365
policy = policy_supplied
[ server_cert ]
x509_extensions = server_ext
default_days = 365
policy = policy_supplied
[ vpn_cert ]
x509_extensions = vpn_client_server_ext
default_days = 365
policy = policy_supplied
[ time_stamping_cert ]
x509_extensions = time_stamping_ext
default_days = 365
policy = policy_supplied
[ policy_supplied ]
countryName = supplied
stateOrProvinceName = supplied
localityName = supplied
organizationName = supplied
organizationalUnitName = supplied
commonName = supplied
emailAddress = supplied
[ root_ext ]
basicConstraints = CA:true
keyUsage = cRLSign, keyCertSign
nsCertType = sslCA, emailCA, objCA
subjectKeyIdentifier = hash
subjectAltName = email:copy
crlDistributionPoints = URI:$config[base_url]index.php?stage=dl_crl
nsComment = "PHPki/OpenSSL Generated Root Certificate Authority"
#nsCaRevocationUrl = ns_revoke_query.php?
nsCaPolicyUrl = $config[base_url]policy.html
[ email_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = critical, emailProtection, clientAuth
nsCertType = critical, client, email
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:$config[base_url]index.php?stage=dl_crl
nsComment = "PHPki/OpenSSL Generated Personal Certificate"
nsBaseUrl = $config[base_url]
nsRevocationUrl = ns_revoke_query.php?
#nsRenewalUrl =
nsCaPolicyUrl = $config[base_url]policy.html
#nsSslServerName =
[ email_signing_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = critical, emailProtection, clientAuth, codeSigning
nsCertType = critical, client, email
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:$config[base_url]index.php?stage=dl_crl
nsComment = "PHPki/OpenSSL Generated Personal Certificate"
nsBaseUrl = $config[base_url]
nsRevocationUrl = ns_revoke_query.php?
#nsRenewalUrl =
nsCaPolicyUrl = $config[base_url]policy.html
#nsSslServerName =
[ server_ext ]
basicConstraints = CA:false
keyUsage = critical, digitalSignature, keyEncipherment
nsCertType = critical, server
extendedKeyUsage = critical, serverAuth, 1.3.6.1.5.5.7.3.1
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = DNS:$common_name,email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:$config[base_url]index.php?stage=dl_crl
nsComment = "PHPki/OpenSSL Generated Secure Server Certificate"
nsBaseUrl = $config[base_url]
nsRevocationUrl = ns_revoke_query.php?
nsCaPolicyUrl = $config[base_url]policy.html
[ time_stamping_ext ]
basicConstraints = CA:false
keyUsage = critical, nonRepudiation, digitalSignature
extendedKeyUsage = timeStamping
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = DNS:$common_name,email:copy
issuerAltName = issuer:copy
crlDistributionPoints = URI:$config[base_url]index.php?stage=dl_crl
nsComment = \"PHPki/OpenSSL Generated Time Stamping Certificate\"
nsBaseUrl = $config[base_url]
nsRevocationUrl = ns_revoke_query.php?
nsCaPolicyUrl = $config[base_url]policy.html
[ vpn_client_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, clientAuth
nsCertType = critical, client
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = DNS:$common_name,email:copy
[ vpn_server_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth
nsCertType = critical, server
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = DNS:$common_name,email:copy
[ vpn_client_server_ext ]
basicConstraints = critical, CA:false
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth, clientAuth
nsCertType = critical, server, client
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer:always
subjectAltName = DNS:$common_name,email:copy
[ crl_ext ]
issuerAltName=issuer:copy
authorityKeyIdentifier=keyid:always,issuer:always
EOS;
$config_txt2 = <<< EOS
[ req ]
default_bits = 1024
default_keyfile = privkey.pem
distinguished_name = req_name
string_mask = nombstr
req_extensions = req_ext
[ req_name]
countryName = Country Name (2 letter code)
countryName_default = US
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default =
localityName = Locality Name (eg, city)
localityName_default =
0.organizationName = Organization Name (eg, company)
0.organizationName_default =
1.organizationName = Second Organization Name (eg, company)
1.organizationName_default =
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default =
commonName = Common Name (eg, YOUR name)
emailAddress = Email Address or Web URL
[ req_ext ]
basicConstraints = critical, CA:false
EOS;
$config_txt3 = <<< EOS
[ req ]
default_bits = 1024
default_keyfile = privkey.pem
distinguished_name = req_name
string_mask = nombstr
req_extensions = req_ext
prompt = no
[ req_name ]
C = $config[country]
ST = $config[province]
L = $config[locality]
O = $config[organization]
OU = $config[unit]
CN = $config[common_name]
emailAddress = $config[contact]
[ req_ext ]
basicConstraints = critical, CA:true
EOS;
#
# Write the permanent OpenSSL config
#
$fd = fopen($config['openssl_cnf'],'w');
fwrite($fd, $config_txt1 . $config_txt2);
fclose($fd);
#
# Write the temporary OpenSSL config
#
$tmp_cnf = "$config[home_dir]/tmp/openssl.cnf";
$fd = fopen($tmp_cnf,'w');
fwrite($fd, $config_txt1 . $config_txt3);
fclose($fd);
#
# Intialize index.txt and serial files
#
$fd = fopen($config['index'],'w');
fwrite($fd, "");
fclose($fd);
#
$fd = fopen($config['serial'],'w');
fwrite($fd, "100001");
fclose($fd);
#
# Convert expiry years to approximate days.
#
$days = $config['expiry'] * 365.25;
#
# Create a new self-signed CA certificate in PEM format.
#
print '<strong>Creating root certificate...</strong><br>';
flush();
exec(REQ . " -x509 -config $tmp_cnf -extensions root_ext -newkey rsa:$keysize -keyout $config[cakey] -out $config[cacert_pem] -passout pass:'$config[ca_pwd]' -days $days 2>&1");
# **** DISABLED *****
# It appears that both IE and Netscape accept PEM formatted root certificates
#
# Create a copy of the CA certificate in DER format.
#
#exec(X509 . " -in ca/$config[cacert_pem] -inform PEM -out ca/$config[cacert_der] -outform DER 2>&1");
#
# Generate the initial CRL.
#
print '<strong>Generating certificate revocation list...</strong><br>';
flush();
exec(CA . " -gencrl -config $config[openssl_cnf] -out $config[cacrl_pem] -passin pass:'$config[ca_pwd]'");
# Make a copy of the CRL in DER format.
#
exec(CRL . " -in $config[cacrl_pem] -out $config[cacrl_der] -inform PEM -outform DER");
#
# Clean up.
#
if (! unlink("$store_dir/tmp/openssl.cnf")) print "Can't unlink $store_dir/tmp/openssl.cnf";
#
# Create dhparam files for OpenVPN and others.
#
print '<p><strong>Creating 1024 bit Diffie-Hellman parameters used by OpenVPN.<br>';
print "Saving to $store_dir/dhparam1024.pem.</strong><br>";
$cmd = "openssl dhparam -rand '$config[random]' -out '$config[private_dir]/dhparam1024.pem' 1024";
print $cmd.'<br>';
flush();
flush_exec($cmd,100);
#print '<p><strong>Creating 2048 bit Diffie-Hellman parameters used by OpenVPN.<br>';
#print "Saving to $store_dir/dhparam2048.pem.</strong><br>";
#$cmd = "openssl dhparam -rand '$config[random]' -out '$config[private_dir]/dhparam2048.pem' 2048";
#print $cmd.'<br>';
#flush();
#flush_exec($cmd,200);
#
# Step aside and let the users in (create index.php files).
#
if (! unlink('index.php')) print "Can't unlink index.php";
if (! unlink('setup.php')) print "Can't unlink setup.php";;
if (! unlink('ca/index.php')) print "Can't unlink ca/index.php";
if (! symlink('main.php','index.php')) print "Can't symlink main.php";
if (! symlink('main.php','ca/index.php')) print "Can't symlink ca/main.php";;
?>
<center>
<h2>Setup is complete. Your CA root certificate as been created.</h2>
<h3><font color=red>SECURITY WARNING!&nbsp;&nbsp; Be sure to run the <cite>secure.sh</cite> shell script as the <strong>root</strong> user.</font></h3>
<p><br><br>
<form action=index.php>
<input type=submit name=submit value="Proceed To The PHPki Main Menu">
</form>
</center>
<?
printFooter();
break;
default:
if (! $country) $country = $config['country'];
if (! $province) $province = $config['province'];
if (! $locality) $locality = $config['locality'];
if (! $organization) $organization = $config['organization'];
if (! $contact) $contact = $config['contact'];
if (! $expiry) $expiry = $config['expiry'];
if (! $expiry) $expiry = 10;
if (! $keysize) $keysize = $config['keysize'];
if (! $keysize) $keysize = 1024;
if (! $passwd) $passwd = $config['ca_pwd'];
if (! $passwdv) $passwdv = $passwd;
if (! $unit) $unit = $config['unit'];
if (! $unit) $unit = "Certificate Authority";
if (! $common_name) $common_name = $config['common_name'];
if (! $common_name) $common_name = "PHPki Certificate Authority";
if (! $getting_help) $getting_help = $config['getting_help'];
if (! $getting_help) $getting_help = '
<b>Contact:</b><br>
First-Name Last-Name<br>
Company/Organization Name<br>
Address Line #1<br>
Address Line #2<br>
City, State, ZipCode<br>
<br>
Phone: (000) 000-0000<br>
E-mail: <a href=mailto:someone@somewhere.com>someone@somewhere.com</a>&nbsp;&nbsp;&nbsp;<i><b>E-mail is preferred.</b></i><br>';
if (! $store_dir) $store_dir = dirname($_SERVER['DOCUMENT_ROOT']).'/phpki-store';
if (! $base_url) $base_url = $config['base_url'];
if (! $base_url) $base_url = 'http://www.somewhere.com/phpki/';
if (! $ca_prefix) $ca_prefix = $config['ca_prefix'];
if (! $openssl_bin) $openssl_bin = $config['openssl_bin'];
if (! $openssl_bin) $openssl_bin = '/usr/bin/openssl';
if (! $passwd_file) $passwd_file = $config['passwd_file'];
if (! $passwd_file) $passwd_file = dirname($_SERVER['DOCUMENT_ROOT']).'/phpkipasswd';
if (! $header_title) $header_title = $config['header_title'];
if (! $header_title) $header_title = 'Certificate Authority';
printHeader('setup');
?>
<form action=<?=$PHP_SELF?> method=post>
<center><h2>Certificate Authority Initial Setup</h2></center>
<table width=99%>
<tr>
<th colspan=2><h3>Root Certificate Data</h3></th>
</tr>
<tr>
<td width=35%><strong>Organization</strong> <font color=red>*</font></td>
<td><input type=text name=organization value="<?=htvar($organization)?>" maxlength=60 size=50></td>
</tr>
<tr>
<td><strong>Department/Unit</strong> <font color=red>*</font></td>
<td><input type=text name=unit value="<?=htvar($unit)?>" maxlength=60 size=30></td>
</tr>
<tr>
<td>
<strong>Common Name</strong> <font color=red>*</font>
This is embeded in certificates, and is most often displayed in
e-mail clients as the <cite>Issued By:</cite> text. This is usually
the full name of your certificate authority (i.e. ACME Certificate Authority).
</td>
<td><input type=text name=common_name value="<?=htvar($common_name)?>" maxlength=60 size=60></td>
</tr>
<tr>
<td>
<strong>Technical Contact E-mail Address</strong> <font color=red>*</font><br>
Enter an e-mail address where users should send correspondence
regarding your certificate authority and the certificates you issue.
</td>
<td><input type=text name=contact value="<?=htvar($contact)?>" maxlength=60 size=30></td>
</tr>
<tr>
<td><strong>Locality</strong> <font color=red>*</font></td>
<td><input type=text name=locality value="<?=htvar($locality)?>" maxlength=60 size=30></td>
</tr>
<tr>
<td><strong>State/Province</strong> <font color=red>*</font></td>
<td><input type=text name=province value="<?=htvar($province)?>" maxlength=60 size=20></td>
</tr>
<tr>
<td><strong>Country</strong> <font color=red>*</font></td>
<td><input type=text name=country value="<?=htvar($country)?>" maxlength=2 size=2></td>
</tr>
<tr>
<td>
<strong>Password</strong> <font color=red>*</font><br>
This password will be used to protect your root certificate private
key. <strong><font color=red>Do not lose or forget this password.</font></strong>
</td>
<td><input type=password name=passwd value="<?=htvar($passwd)?>" size=30>&nbsp;&nbsp; Again <input type=password name=passwdv value="<?=htvar($passwdv)?>" size=30></td>
</tr>
<tr>
<td>
<strong>Certificate Life</strong> <font color=red>*</font><br>
Enter the number of years you wish your root certificate to be valid.
</td>
<td><select name=expiry>
<?
for ( $i = 5 ; $i < 20 ; $i+=5 ) {
print "<option value=$i " . ($expiry == $i ? "selected='selected
'" : "") . " >$i Years</option>\n" ;
}
?>
</select></td>
</tr>
<tr>
<td>
<strong>Key Size</strong> <font color=red>*</font><br>
Enter the size of your certificate key.
</td>
<td><select name=keysize>
<?
for ( $i = 512 ; $i <= 4096 ; $i+=512 ) {
print "<option value=$i " . ($keysize == $i ? "selected='selected
'" : "") . " >$i bits</option>\n" ;
}
?>
</select></td>
</tr>
<tr>
<td>
<strong>Certificate Authority Base URL</strong><br>
Enter the public Web address where your Certificate Authority will
reside. The address should end with a trailing slash (/) character.
This address will be embeded in all certficates issued
by your CA, for informational purposes.
</td>
<td>
<input type=text name=base_url value="<?=htvar($base_url)?>" size=50>
</td>
</tr>
</table>
<p>
<table width=99%>
<tr>
<th colspan=2><h3>Configuration Options</h3></th>
</tr>
<tr>
<td width=35%>
<strong>Storage Directory <font color=red>*</font></strong><br>
Enter the location where PHPki will store its files. This should be a directory where
the web server has full read/write access (chown <?=$uname?> ; chmod 700), and is preferably
outside of DOCUMENT_ROOT (<?=$_SERVER['DOCUMENT_ROOT']?>). You may have to manually create the directory before completing this form.
</td>
<td>
<input type=text name=store_dir value="<?=htvar($store_dir)?>" size=35>
</td>
</tr>
<tr>
<td width=35%>
<strong>Location of OpenSSL Executable <font color=red>*</font></strong><br>
Enter the location of your OpenSSL binary. The default is usually ok.
</td>
<td>
<input type=text name=openssl_bin value="<?=htvar($openssl_bin)?>" size=35>
</td>
</tr>
<tr>
<td width=35%>
<strong>Location of HTTP password file <font color=red>*</font></strong><br>
Enter the location of your PHPki user password file. The default is usually ok.
</td>
<td>
<input type=text name=passwd_file value="<?=htvar($passwd_file)?>" size=35>
</td>
</tr>
<tr>
<td>
<strong>File Upload Prefix</strong><br>
This is an optional prefix which will be added to root certificate
and certificate revocation list file uploads. Normally the root
certificate is uploaded as caroot.crt. With a prefix like
<cite style="white-space: nowrap">"acme_"</cite>, the root certificate would be uploaded as
<cite>"acme_caroot.crt"</cite>.
</td>
<td>
<input type=text name=ca_prefix value="<?=htvar($ca_prefix)?>" maxlength=10 size=10>
</td>
</tr>
<tr>
<td>
<strong>Page Header Title</strong><br>
This title will be displayed superimposed over the PHPki logo at the
top of every page.
</td>
<td>
<input type=text name=header_title value="<?=htvar($header_title)?>" maxlength=40 size=40>
</td>
</tr>
<tr>
<td>
<strong>Help Document Contact Info</strong><br>
This text will be inserted into the online help document
under the "Getting Additional Help" section. Include full
contact info for the convenience of your users. Use HTML
tags to improve presentation.
</td>
<td>
<textarea name=getting_help cols=50 rows=15><?=htvar($getting_help)?></textarea>
</td>
</tr>
</table>
<font color=red>* Required field</font>
<p>
<center><input type=submit name=submit value=Submit></center></td>
<input type=hidden name=stage value='validate'>
</form>
<?
printFooter();
break;
}
function create_ca_cnf($email, $expiry) {
}
?>