Process substitution working in zsh but not is bash

175 views Asked by At

I'm attempting to sign some content using a certificate with the following command which uses process substitution to deliver the certificate content to openssl (since it requires either a file or uri):

echo "something to sign" \
| openssl dgst -binary -sha256 -sign <(echo "certificate to sign with")

This runs flawlessly in zsh but when I try to run this via bash I get an error:

Could not read private key from /dev/fd/63

What am I doing wrong here?

2

There are 2 answers

2
Hrafn On BEST ANSWER

It turns out this was all due to new line \n sequences in the credentials payload and echo requiring interpretation of backslash escapes to be turned on when using bash.

echo "something to sign" \
| openssl dgst -binary -sha256 -sign <(echo -e "certificate to sign with")

When using zsh the backslashes are seemingly interpreted automatically making me believe the issue was with the process substitution but not the contents of the credentials.

It feels silly to not have realized this sooner, but I hope this will help someone in the future also gets lost in the weeds.

1
remcycles On

It seems that openssl doesn't like to read from a named pipe. Named pipes can be used for implementing process substitution and operate like a FIFO that doesn't support fseek().

More info here: https://unix.stackexchange.com/questions/164107/why-does-bash-process-substitution-not-work-with-some-commands

On my Linux system, both bash and zsh fail with Could not read private key from /dev/fd/63, and Could not read private key from /proc/self/fd/12, respectively. But perhaps zsh implements process substitution another way on your machine.

The "Process Substitution" section of man zshexpn has more to say about the possible pitfalls of <(). It also says that =() uses a temporary file instead of a named pipe, so it will work with programs that want to seek. But Bash does not have =().