Trying to create OpenVPN user certs manually
-
I need to be able to create a (large) set of user certs for OpenVPN, so I want to be able to run a local script to do this. The basic code I'm using is:
$CA_CERT = "VPN-CA.crt"; $CA_KEY = "VPN-CA.key"; $digest_alg = "sha512"; $keylen = 4096; $args = array ( "x509_extensions" => "usr_cert", "digest_alg" => $digest_alg, "private_key_bits" => (int)$keylen, "private_key_type" => OPENSSL_KEYTYPE_RSA, "encrypt_key" => false ); $req_key = openssl_pkey_new( $args ); if( openssl_pkey_export ( $req_key, $out_key ) ) { $dn = array( "countryName" => "GB", "stateOrProvinceName" => "...", "localityName" => "...", "organizationName" => "...", "emailAddress" => "...", "commonName" => "..." ); $req_csr = openssl_csr_new ( $dn, $req_key, $args ); $req_cert = openssl_csr_sign ( $req_csr, "file://$CA_CERT", "file://$CA_KEY", 365, $args ); if( openssl_x509_export ( $req_cert, $out_cert ) ) { $umask = umask(0066); if ( ! openssl_pkcs12_export_to_file( $req_cert, "user.p12", $req_key, "" ) ) { echo "Failed p12\n"; } }
Where "VPN-CA" is a self-signed CA generated using the pfSense Cert Manager. This is also used to create a server certificate for use by the OpenVPN server.
I'm then using the .p12 this produces to replace the one in a client export produced using the OpenVPN Client Export package.
The exported package (unmodified) works as expected and I can connect and create a tunnel.
However, when I use the .p12 generated using my script I am seeing the following in the logs (Tunnelblick):
2016-08-09 10:10:39 TLS: Initial packet from [AF_INET]xx.xx.xx.xxx:1194, sid=54773c0c d9fca608 2016-08-09 10:10:39 VERIFY ERROR: depth=1, error=self signed certificate in certificate chain: C=..., ST=..., L=..., O=..., emailAddress=..., CN=... 2016-08-09 10:10:39 OpenSSL: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed 2016-08-09 10:10:39 TLS_ERROR: BIO read tls_read_plaintext error 2016-08-09 10:10:39 TLS Error: TLS object -> incoming plaintext read error 2016-08-09 10:10:39 TLS Error: TLS handshake failed
I think my code has the same behaviour as the code pfSense uses to create the user cert (system_certmanager.php), but I must be missing something. Can anyone see what I'm doing wrong?
-
Should add that running:
openssl verify -verbose -CAfile VPN-CA.crt user.crt
where 'user.cdt' was extracted from 'user.p12' reports that the user cert is valid.
-
Ok, this:
if ( ! openssl_pkcs12_export_to_file( $req_cert, "user.p12", $req_key, "" ) )
is the problem. The .p12 produced only contains the user cert - I need to add the CA cert as well.
However, it doesn't look like there's a php openssl_ function to do this - which is probably why the openVPN Client Export Plugin uses:
exec("/usr/bin/openssl pkcs12 -export -in {$ecrtpath} -inkey {$ekeypath} -certfile {$ecapath} -out {$eoutpath} -passout pass:{$eoutpass}");