Search code examples
phpopensslcertificate

How do I generate a self-signed certificate using PHP and OpenSSL


I'm trying to make a site that generates a self signed certificate using PHP and openSSL. I'm pretty sure it's some sort of syntax error but I cannot seem to find it.

I've tried the command in the linux terminal and it seems to work, but only in the PHP file, it doesn't work.

This is work.php, it is mainly the function:

<?php

function terminal($command)
{
        //system
        if(function_exists('system'))
        {
                ob_start();
                system($command , $return_var);
                $output = ob_get_contents();
                ob_end_clean();
        }
        //passthru
        else if(function_exists('passthru'))
        {
                ob_start();
                passthru($command , $return_var);
                $output = ob_get_contents();
                ob_end_clean();
        }

        //exec
        else if(function_exists('exec'))
        {
                exec($command , $output , $return_var);
                $output = implode(n , $output);
        }

        //shell_exec
        else if(function_exists('shell_exec'))
        {
                $output = shell_exec($command) ;
        }

        else
        {
                $output = 'Command execution not possible on this system';
                $return_var = 1;
        }

        return array('output' => $output , 'status' => $return_var);
}

?>

And this is index.php which is the main file

<form method="post">
<input type="text" placeholder="domain" name="name"></input>
<input type="submit" value="submit" name="submit"></input>
</form>
<?php

if(isset($_POST['submit']))
{
   $name = $_POST["name"];
   run();
}

function run() {
require "work.php";
$status = 0;
$name = $_POST["name"];


$command1 = "openssl req -x509 -newkey rsa:4096 -nodes -keyout " . $name . ".key -out " . $name . ".pem -days 3650 -subj '/CN=" . $name . "'";
$o = terminal($command1);

echo $o['output'];
echo "<br><br>";
echo "Your certificate >> <a href='" . $name . ".pem'>DOWNLOAD</a>";
echo "<br>";
echo "Your private key >> <a href='" . $name . ".key'>DOWNLOAD</a>";

}

?>

Solution

  • as example how one might potentially generate certificates using native php functions rather than executing a string command

    <?php
        error_reporting( E_ALL );
        $result=false;
    
    
    
        /* 
            configure as appropriate - the root directory
            for all web data
        */
        $rootdir='c:\wwwroot';
        /*
            an aliased directory within web root - select
            an appropriate path
        */
        $certdir=$rootdir . '\content\stack';
        /* 
            to aid correct display of hyperlinks for my environment
            which uses aliases and symbolic links so probably not
            required otherwise
        */
        $displaypath=dirname( $_SERVER['REQUEST_URI'] );
    
    
    
    
    
    
        if( $_SERVER['REQUEST_METHOD']=='POST' && !empty( $_POST['name'] ) ){
    
    
            $name=filter_input( INPUT_POST, 'name', FILTER_SANITIZE_STRING );
    
    
            if( $name ){
    
    
    
                function create( $rootdir='c:/wwwroot', $certdir=false, $certname='certificate', $dn=array(), $passphrase=null, $createpem=true, $overwrite=true ){
                    if( !empty( $certdir ) && !empty( $certname ) && !empty( $dn ) ){
    
                        $out = new stdClass;
                        $days = 3650;
    
                        /* !!! configuration and location of your own openssl.conf file is important !!! */
                        putenv( sprintf( 'OPENSSL_CONF=%s/openssl.cnf', $rootdir ) );
    
                        $config=array(
                            'config'            =>  getenv('OPENSSL_CONF'),
                            'digest_alg'        =>  'AES-128-CBC',
                            'private_key_bits'  =>  4096,
                            'private_key_type'  =>  OPENSSL_KEYTYPE_RSA,
                            'encrypt_key'       =>  false
                        );
    
                        /*
                            Primary configuration is overwritten at runtime
                            by including parameters in the "$dn" argument
                        */
                        $dn=array_merge( array(
                            "countryName"               => "UK",
                            "stateOrProvinceName"       => "Strathclyde",
                            "localityName"              => "Scotland",
                            "organizationName"          => "bonny-scotland.org",
                            "organizationalUnitName"    => "Bonny Scotland",
                            "commonName"                => $certname,
                            "emailAddress"              => "webmaster@bonny-scotland.org"
                        ), $dn );
    
                        $privkey = openssl_pkey_new( $config );
                        $csr = openssl_csr_new( $dn, $privkey, $config );
                        $cert = openssl_csr_sign( $csr, null, $privkey, $days, $config, 0 );
    
                        openssl_x509_export( $cert, $out->pub );
                        openssl_pkey_export( $privkey, $out->priv, $passphrase );
                        openssl_csr_export( $csr, $out->csr );
    
    
    
                        # Create the base private & public directories if they do not exist
                        $privdir = $certdir . sprintf('\\certificates\\%s\\private\\',$certname );
                        $pubdir  = $certdir . sprintf('\\certificates\\%s\\public\\',$certname );
    
                        @mkdir( $privdir, 0777, true );
                        @mkdir( $pubdir, 0777, true );
    
    
                        $pkpath=$privdir . $certname . '.key';
                        $cert=$pubdir . $certname . '.crt';
                        $csr=$privdir . $certname . '.csr';
                        $pem=$pubdir . $certname . '.pem';
    
    
                        if( !file_exists( $pkpath ) or ( $overwrite==true && file_exists( $pkpath ) ) ) {
    
                            openssl_pkey_export_to_file( $privkey, $pkpath, $passphrase, $config );
    
                            file_put_contents( $cert, $out->pub, FILE_TEXT );
                            file_put_contents( $csr, $out->csr, FILE_TEXT );
    
                            if( $createpem ){
                                unset( $out->csr );
                                file_put_contents( $pem, implode( '', get_object_vars( $out ) ) );
                            }
                        }
                        openssl_pkey_free( $privkey );
                        clearstatcache();
    
                        /* return useful stuff for display porpoises */
                        return (object)array(
                            'public'        =>  str_replace( $certdir, '', $pubdir ),
                            'private'       =>  str_replace( $certdir, '', $privdir ),
                            'pubsize'       =>  filesize( $pem ),
                            'privsize'      =>  filesize( $pkpath ),
                            'pkpath'        =>  $pkpath,
                            'cert'          =>  $cert,
                            'csr'           =>  $csr,
                            'pem'           =>  $pem,
                            'certificate'   =>  $certname
                        );
                    }
                    return false;
                }
    
    
    
                /* configure the DN array */
                $dn=array(
                    'countryName'               =>  'GB',
                    'localityName'              =>  'England',
                    'stateOrProvinceName'       =>  'London',
                    'organizationName'          =>  $name,
                    'organizationalUnitName'    =>  'Squirrel Juggling Services',
                    'emailAddress'              =>  sprintf( 'admin-contact@%s', $name )
                );
                $result=create( $rootdir, $certdir, $name, $dn );
            }
        }
    ?>
    <!DOCTYPE html>
    <html lang='en'>
        <head>
            <meta charset='utf-8' />
            <title>Generate Certificates</title>
            <style>
                body,body *{box-sizing:border-box;font-family:calibri,verdana,arial;}
                body{ background:white; width:100%; height:100vh;margin:0;display:flex;flex-direction:column; align-content:center; justify-content:center; align-items:center;}
                form{ border:1px solid rgba(0,0,0,0.25); border-radius:1rem; background:whitesmoke; padding:1rem;width:30%; height:auto; min-height:250px; display:flex; flex-direction:column; align-content:center; justify-content:center; align-items:center; }
                form *{align-self:stretch;flex:1;margin:0.5rem;}
                [type='text']{text-align:center;}
                h1{font-size:1.45rem;text-align:center}
                h2{font-size:1.15rem;text-align:center}
            </style>
        </head>
        <body>
            <form method='post'>
                <h1>Generate Self-Signed SSL Certificate</h1>
                <input type='text' name='name' placeholder='domain' />
                <input type='submit' />
            </form>
            <?php
                if( $_SERVER['REQUEST_METHOD']=='POST' && is_object( $result ) ){
                    printf(
                        '
                        <h2>Certificate for "%s" generated successfully!</h2>
                        <a href="%s" target="_blank">Download Public Certificate ( %s Kb )</a>
                        <a href="%s" target="_blank">Download Private Key ( %s Kb )</a>',
    
                        $result->certificate,
                        sprintf( '%s%s%s.pem', $displaypath, $result->public, $result->certificate ),
                        round( ( $result->pubsize / 1024 ), 2 ),
                        sprintf( '%s%s%s.key', $displaypath, $result->private, $result->certificate ),
                        round( ( $result->privsize / 1024 ), 2 )
                    );
                }
            ?>
        </body>
    </html>