5 Annexe
5.1 Fichier des fonctions de gestion des certificats
<?php
define('PUBLIC_CERTIFICATE_DIR','/etc/ssl/php-certs');
define('PUBLIC_CERTIFICATE_SSLDIR','/etc/ssl/certs');
define('PUBLIC_CERTIFICATE_NEWDIR','/etc/ssl/newcerts');
define('PRIVATE_CERTIFICATE_DIR','/etc/ssl/php-private');
define('PRIVATE_CERTIFICATE_SSLDIR','/etc/ssl/private');
define('CERTIFICATE_SUFFIX','.pem');
define('CERTIFICATE_SERIAL_PATH','/etc/ssl/php-serial');
define('CERTIFICATE_INITSERIAL_PATH','/etc/ssl/php-initial-serial');
/****************************************************************************/
/* */
/* Fonction permettant de lister les certificats suivant des criteres sur */
/* le cn et l'email. */
/* $cn_filter => filtre sur le common name */
/* $email_filter => filtre sur l'email */
/* */
/****************************************************************************/
function list_certificates(
$dir,
$ca_cn_filter='.*',$ca_email_filter='.*',
$cn_filter='.*',$email_filter='.*'
){
if(!is_dir($dir)) return;
$certificates = scandir($dir);
foreach($certificates as $cert)
if(!is_link("$dir/$cert") && ereg(".*".CERTIFICATE_SUFFIX,$cert)){
$infos = openssl_x509_parse("file://$dir/$cert",TRUE);
$ca_cn = $infos['issuer']['CN'];
$ca_email = $infos['issuer']['emailAddress'];
$cn = $infos['subject']['CN'];
$email = $infos['subject']['emailAddress'];
if($ca_cn_filter && !eregi($ca_cn_filter,$ca_cn)) continue;
if($ca_email_filter && !eregi($ca_email_filter,$ca_email)) continue;
if($cn_filter && !eregi($cn_filter,$cn)) continue;
if($email_filter && !eregi($email_filter,$email)) continue;
$serial = $infos['serialNumber'];
$validfrom = date("F d Y H:i:s",$infos['validFrom_time_t']);
$validto = date("F d Y H:i:s",$infos['validTo_time_t']);
$capurposes = $infos['purposes']; $capurplabel = array();
foreach($capurposes as $purpose) if($purpose[1]) $capurplabel[] = $purpose[2];
$purposes = $infos['purposes']; $purplabel = array();
foreach($purposes as $purpose) if($purpose[0]) $purplabel[] = $purpose[2];
echo "----\nCertificat #$serial ($dir/$cert).\n";
echo " CA CN:\t$ca_cn\n CA e-mail:\t$ca_email\n";
echo " Common Name:\t$cn\n e-mail:\t$email\n";
echo " Validity:\t[$validfrom => $validto]\n";
echo " CA Purposes:\t".implode(',',$capurplabel)."\n";
echo " Purposes:\t".implode(',',$purplabel)."\n";
}
}
/****************************************************************************/
/* */
/* Fonction permettant de purger les certificats invalides */
/* $cert_dir => repertoire des certificats */
/* $private_dir => repertoire des clefs privees */
/* */
/****************************************************************************/
function purge_certificates($cert_dir,$private_dir){
if(!is_dir($cert_dir)) return;
$current=time();
$certificates = scandir($cert_dir);
foreach($certificates as $cert){
$cert_path="$cert_dir/$cert";
$paths=array($cert_path);
if($private_dir){
$private_path="$private_dir/$cert";
array_push($paths,$private_path);
}
foreach($paths as $path)
if(is_link($path))
if(!is_readable($path)) @unlink($path);
if(!is_readable($cert_path)) continue;
$infos = @openssl_x509_parse("file://$cert_path",TRUE);
if(!$infos) continue;
$validto = $infos['validTo_time_t'];
if($validto>$current) continue;
foreach($paths as $path) @unlink($path);
}
}
/****************************************************************************/
/* */
/* Fonction permettant de supprimer un certificat */
/* $cert_dir => repertoire des certificats */
/* $private_dir => repertoire des clefs privees */
/* $cert_name => nom du certificat */
/* */
/****************************************************************************/
function delete_certificate($cert_dir,$private_dir,$cert_name){
$cert_path="$cert_dir/$cert_name".CERTIFICATE_SUFFIX;
$paths=array($cert_path);
if($private_dir){
$private_path="$private_dir/$cert_name".CERTIFICATE_SUFFIX;
array_push($paths,$private_path);
}
foreach($paths as $path){
if(is_link($path)){
$dir=dirname($path);
$file=readlink($path);
if($file && $file[0]!='/') $file="$dir/$file";
if($file) @unlink($file);
}
@unlink($path);
}
}
/****************************************************************************/
/* */
/* Fonction permettant de copier un certificat sur une machine distante */
/* $cert_name => nom du certificat */
/* $server => nom de la machine */
/* */
/****************************************************************************/
function copy_certificate($cert_name,$server){
$cert_path=PUBLIC_CERTIFICATE_DIR."/$cert_name".CERTIFICATE_SUFFIX;
$private_path=PRIVATE_CERTIFICATE_DIR."/$cert_name".CERTIFICATE_SUFFIX;
system("scp $cert_path $server:".PUBLIC_CERTIFICATE_SSLDIR);
system("scp $private_path $server:".PRIVATE_CERTIFICATE_SSLDIR);
}
/****************************************************************************/
/* */
/* Fonction permettant de lister les no de serie des certificats revoques */
/* $dir => repertoire des certificats */
/* */
/****************************************************************************/
function list_revocated($dir){
$first = trim(file_get_contents(CERTIFICATE_INITSERIAL_PATH));
$last = trim(file_get_contents(CERTIFICATE_SERIAL_PATH));
$serials = array();
for($i=$first;$i<$last;$i++) $serials[$i] = true;
$certificates = scandir($dir);
foreach($certificates as $cert)
if(!is_link("$dir/$cert") && ereg(".*".CERTIFICATE_SUFFIX,$cert)){
$infos = openssl_x509_parse("file://$dir/$cert",TRUE);
$serial = $infos['serialNumber'];
$serials[$serial] = false;
}
foreach($serials as $serial => $bool) if($bool) echo "$serial\n";
}
/****************************************************************************/
/* */
/* Fonction permettant de trouver le numero de serie d'un certificat */
/* $cert_name => nom du certificat */
/* */
/****************************************************************************/
function get_serial($cert_name){
$cert_path=PUBLIC_CERTIFICATE_DIR."/$cert_name".CERTIFICATE_SUFFIX;
$infos = openssl_x509_parse("file://$cert_path",TRUE);
$serial = $infos['serialNumber'];
echo "$serial\n";
}
/************************************************************************/
/* */
/* Fonction analysant les paramètres et appelant les bonnes actions. */
/* */
/************************************************************************/
function usage($base,$cansign){
fputs(STDERR,"Syntax:\n");
if($cansign){
fputs(STDERR," $base new_ca <name> <cn> <email> [<CA cert name>|.]\n");
fputs(STDERR," $base new <name> <cn> <email> [<CA cert name>]\n");
}
foreach(array('list','list_ssl','list_new') as $label)
fputs(STDERR," $base $label [<CA cn filter> [<CA email filter> [<cn filter> [<email filter]]]]\n");
foreach(array('purge','purge_ssl','purge_new') as $label)
fputs(STDERR," $base $label\n");
foreach(array('delete','delete_ssl','delete_new') as $label)
fputs(STDERR," $base $label <name>\n");
fputs(STDERR," $base copy <name> <server>\n");
fputs(STDERR," $base crl\n");
fputs(STDERR," $base get_serial <name>\n");
die();
}
function main($argc,$argv,$cansign){
/* Parameters analysis */
$base=basename($argv[0]);
if($argc<2) usage($base,$cansign);
$action=$argv[1];
switch($action){
case 'new':
case 'new_ca':
if($cansign && $argc<5) usage($base,$cansign);
break;
case 'purge':
case 'purge_ssl':
case 'purge_new':
if($argc!=2) usage($base,$cansign);
break;
case 'delete':
case 'delete_ssl':
case 'delete_new':
if($argc!=3) usage($base,$cansign);
break;
case 'copy':
if($argc!=4) usage($base,$cansign);
break;
}
/* Execution of requested action */
switch($action){
case 'new_ca':
case 'new':
if(!cansign) break;
$cert_name=$argv[2];
$common_name=$argv[3];
$mail_address=$argv[4];
$ca_name=$argv[5];
if($action=='new_ca') $is_ca=true; else $is_ca=false;
$serial=create_certificate($cert_name,$common_name,$mail_address,$is_ca,$ca_name);
break;;
case 'list':
case 'list_ssl':
case 'list_new':
$ca_cn_filter=$argv[2];
$ca_email_filter=$argv[3];
$cn_filter=$argv[4];
$email_filter=$argv[5];
if($action=='list') $dir=PUBLIC_CERTIFICATE_DIR;
else if($action=='list_ssl') $dir=PUBLIC_CERTIFICATE_SSLDIR;
else if($action=='list_new') $dir=PUBLIC_CERTIFICATE_NEWDIR;
list_certificates($dir,$cn_filter,$email_filter);
break;;
case 'purge':
case 'purge_ssl':
case 'purge_new':
if($action=='purge'){
$cert_dir=PUBLIC_CERTIFICATE_DIR; $private_dir=PRIVATE_CERTIFICATE_DIR; }
else if($action=='purge_ssl'){
$cert_dir=PUBLIC_CERTIFICATE_SSLDIR; $private_dir=PRIVATE_CERTIFICATE_SSLDIR; }
else if($action=='purge_new'){
$cert_dir=PUBLIC_CERTIFICATE_NEWDIR; $private_dir=false; }
purge_certificates($cert_dir,$private_dir);
break;
case 'delete':
case 'delete_ssl':
case 'delete_new':
$name=$argv[2];
if($action=='delete'){
$cert_dir=PUBLIC_CERTIFICATE_DIR; $private_dir=PRIVATE_CERTIFICATE_DIR; }
else if($action=='delete_ssl'){
$cert_dir=PUBLIC_CERTIFICATE_SSLDIR; $private_dir=PRIVATE_CERTIFICATE_SSLDIR; }
else if($action=='delete_new'){
$cert_dir=PUBLIC_CERTIFICATE_NEWDIR; $private_dir=false; }
delete_certificate($cert_dir,$private_dir,$name);
break;
case 'copy':
$name=$argv[2];
$server=$argv[3];
copy_certificate($name,$server);
break;
case 'crl':
list_revocated(PUBLIC_CERTIFICATE_DIR);
break;
case 'get_serial':
$name=$argv[2];
get_serial($name);
break;
default:
fputs(STDERR,"Illegal action !\n");
break;
}
}
5.2 Fichier principal de gestion des certificats
#!/usr/bin/php
<?php
require('certfunctions.php');
define('PRIVATE_CERTIFICATE_DIR','/etc/ssl/php-private');
define('PUBLIC_CERTIFICATE_CADIR','file:///etc/ssl/php-certs/');
define('PRIVATE_CERTIFICATE_CADIR','file:///etc/ssl/php-private/');
define('DEFAULT_CANAME','Organisation');
define('PASSPHRASE_SIGN','MotDePasse');
define('COUNTRY_NAME','FR');
define('STATE_OR_PROVINCE_NAME','Nord');
define('LOCALITY_NAME','Villeneuve d Ascq');
define('ORGANIZATION_NAME','Universite de Lille 1');
define('ORGANIZATIONAL_UNIT_NAME','Polytech Lille');
define('CERTIFICATE_DURATION','5');
/****************************************************************************/
/* */
/* Fonction permettant de creer les certificats */
/* $common_name => nom du destinataire du certificat (nom ou domaine) */
/* $mail_address => email du destinataire du certificat */
/* */
/****************************************************************************/
function create_certificate($cert_name,$common_name,$mail_address,$is_ca,$ca_name) {
$dn = array(
"countryName" => COUNTRY_NAME,
"stateOrProvinceName" => STATE_OR_PROVINCE_NAME,
"localityName" => LOCALITY_NAME,
"organizationName" => ORGANIZATION_NAME,
"organizationalUnitName" => ORGANIZATIONAL_UNIT_NAME,
"commonName" => $common_name,
"emailAddress" => $mail_address
);
/* Set the correct openssl section (CA or mere certificate) */
if($is_ca){
$config = array('config_section_name' => 'req_custom_ca');
$keypass = PASSPHRASE_SIGN;
}
else{
$config = array('config_section_name' => 'req_custom');
$keypass = null;
}
/* Get serial number for this certificate */
$fp = fopen(CERTIFICATE_SERIAL_PATH,'r+');
if(flock($fp,LOCK_EX,$block=TRUE)) { // do an exclusive lock
$serial = trim(fgets($fp)); $newserial=$serial+1;
rewind($fp);
fputs($fp,"$newserial\n");
}
else die("System Error: couldn't lock the file !");
fclose($fp);
/* Twin keys generation */
$privkey = openssl_pkey_new($config);
if(!$privkey){ while($msg = openssl_error_string()) echo $msg."\n"; die(); }
/* Generate CSR */
$csr = openssl_csr_new($dn, $privkey, $config);
if(!$csr){ while($msg = openssl_error_string()) echo $msg."\n"; die(); }
/* Retreive CA informations */
if($ca_name!="."){
if(!$ca_name) $ca_name = DEFAULT_CANAME;
$pub_capath = PUBLIC_CERTIFICATE_CADIR."$ca_name.pem";
$priv_capath = PRIVATE_CERTIFICATE_CADIR."$ca_name.pem";
$privatekey = array($priv_capath, PASSPHRASE_SIGN);
}
else{
$pub_capath = null;
$privatekey = $privkey;
}
/* Sign the CSR */
$days = CERTIFICATE_DURATION*365 ;
$sscert = openssl_csr_sign($csr, $pub_capath, $privatekey, $days, $config, $serial);
if(!$sscert){ while($msg = openssl_error_string()) echo $msg."\n"; die(); }
$certpath = PUBLIC_CERTIFICATE_DIR."/$serial.pem";
$keypath = PRIVATE_CERTIFICATE_DIR."/$serial.pem";
$certlink = PUBLIC_CERTIFICATE_DIR."/$cert_name.pem";
$keylink = PRIVATE_CERTIFICATE_DIR."/$cert_name.pem";
openssl_x509_export_to_file ($sscert,$certpath);
openssl_pkey_export_to_file ($privkey,$keypath,$keypass);
symlink($certpath,$certlink);
symlink($keypath,$keylink);
return $serial;
}
main($argc,$argv,true);
?>
?>