Previous Contents

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);

?>
?>


Previous Contents