Dude Where's My Output?
Dec 6, 2024I recently had to build a simple project simulating a certificate authority, CRL distribution point, web server and client host. The web server ran Apache with a simple HTML page in conjunction with some PHP code. The purpose of the web server was to verify some messages signed by user x509 certificates that were, in turn, signed by the CA. The web server needed to display the output from some OpenSSL verification checks after getting the user x509, message signature and message file.
The command I wanted to run and show output from was:1
openssl verify -verbose -crl_check -CRLfile project.crl.pem -trusted CARootCert.cer user.cer
I needed to test some cases where the user certificate could be revoked or expired. In these cases, when the command is run in the terminal, it returns a multi-line output such as:
C = Country, ST = State, L = City, O = Organization, OU = Unit, CN = Common Name, emailAddress = email@email.com
error 23 at 0 depth lookup: certificate revoked
error uploads/user.cer: verification failed
I combined with the PHP code to execute and display the command output:
$cmd = openssl verify -verbose -crl_check -CRLfile project.crl.pem -trusted CARootCert.cer u.cer
$res = shell_exec($cmd);
echo nl2br(htmlspecialchars($res);
However, the output to the webpage was:
error uploads/user.cer: verification failed
Why is it only returning the last line of the output? In my debugging process I tried to run other multi-line commands to see if they print properly. Commands like ls -l print perfectly find using the same code.
This stumped me super hard, mainly because the only way to search for the solution to this problem was to know the answer already. It was also a bit tricky, as the fact that I was still able to echo the last line of output made it harder for me to reach the correct diagnosis.
It turns out that the problem was that the first two lines of this output are written to stderr and not stdout. The shell_exec command will only print out the stdout response. This output provided by OpenSSL is a little bit misleading as the stdout response starts with error. Due to my inexperience in bash, the thought of stdout vs stderr never crossed my mind.
To fix this, it is as simple as appending:
$res = shell_exec($cmd." 2>&1");
The snippet " 2>&1" is a shell construct that takes file descriptor 1, which is stdout and combines it with file descriptor 2, which is the stderr into one merged output using >&.2
Finally, I’ve found the entire output. This displays the entire stderr along with stdout.
-
The whole reason why I even need to execute this command instead of using the OpenSSL PHP library is because there is no way to perform a CRL check using the library! ↩︎
-
https://stackoverflow.com/questions/818255/what-does-21-mean ↩︎