Is there any way to get openssl s_client to read from stdin?

Looking at the source code it seems that s_client only reads from console or TTY devices and not from just any stdin.

You can work around that by interposing a program that wraps a (pseudo)TTY around the command.

screen can do that, but it makes it a bit hard, I sometimes use the ssh trick.

Also there is the goto for interactive console programs (expect): https://linux.die.net/man/1/expect, but never tried that.

with SSH

echo -e 'GET / HTTP/1.0\nHost: www.example.com\n\n' | ssh -tt user@localhost 'openssl s_client -crlf -servername www.example.com -brief -connect www.example.com:443'

The -tt forces TTY allocation, which ssh by default wouldn't do, if it detects a pipe.

Disadvantage is that you have to set this loopback SSH connection to logon automatically to use it in a script.

This is NOT binary safe. For simple ASCII it will do.

with Screen

Somewhat harder, but minus the logon hassle.

Prepare a file query with lines for input to the server.

For example:

GET / HTTP/1.0
Host: www.example.com

Make a detached screen with name myscreen and save output to ./out.log

screen -d -m -S myscreen -L -Logfile ./out.log

Send the openssl connection command (-X stuff) to the first window (-p 0) of the screen named myscreen (-S myscreen) and then immediately send the data from file ./query. Note that the $(cat..) process substitution will chomp any trailing newlines in file ./query and the openssl command MUST have -crlf in case of HTTP protocol. The query data MUST be send not long after opening the connection or the s_client will timeout.

screen -S myscreen -p 0 -X stuff "openssl s_client -crlf -servername www.example.com -brief -connect www.example.com:443^M";screen -S myscreen -p 0 -X stuff "$(cat ./query)^M^M"

Finally exit the screen, to erase the myscreen session (This assumes the preceding query made the server already drop the connection and s_client exited itself):

screen -S myscreen -p 0 -X stuff "exit^M"

Output including the query and exit and s_client output is now in ./out.log

If s_client does not exit after the query you could first send an interrupt signal.

screen -S myscreen -p 0 -X stuff "^C"