Openssl: cat: /dev/fd/63: No such file or directory - macos

I try to create a Certificate Signing Request (CSR) using
openssl req -new -sha256 -key domain.key -subj "/" \ -reqexts SAN -config <(cat /System/Library/OpenSSL/openssl.cnf \ <(printf "[SAN]\nsubjectAltName=DNS:foo.com,DNS:www.foo.com"))
but getting the following error message on my macbook
cat: /dev/fd/63: No such file or directory
unknown option -reqexts
Any ideas?

Your command is probably copy&paste of a multi-line command where backslashes are used to join lines, however you somehow managed to get newlines converted to spaces.
Remove all occurences of "backslash + space".

I came across this question and in my case I did not have any \ , but I was using sudo so I had to use sudo su -c
$ sudo su -c 'openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/ssl/private/nginx-blah.blah.com.key -new -out /etc/ssl/certs/nginx-blah.blah.com.crt -subj "/O=blah.com/OU=blah/CN=blah.blah.com" -reqexts SAN -extensions SAN -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:blah.blah.com,IP:192.168.174.128")) -sha256'

In some cases not mounted devpts can lead to the same error print. So needed to do:
mount -t devpts devpts /dev/pts

Related

Bash Script working on Tumbleweed but not Kubuntu

We have a virtual Dev-Environment in which we develop a multitude of websites.
We have some scripts that we use to create the environment, one of which handles the creation of the Certificates and pushing them to certain directories.
Said script works for my colleague, who uses Tumbleweed, but not for me (Kubuntu 22.04, Kernel 5.15)
The script is the following:
#!/bin/bash
mkdir -p cert/live/exist.ulb.tu-darmstadt.de
mkdir -p cert/live/purl.ulb.tu-darmstadt.de
mkdir -p cert/live/tueditions.ulb.tu-darmstadt.de
cd cert
openssl req \
-x509 \
-nodes \
-new \
-sha256 \
-days 1024 \
-newkey rsa:2048 \
-keyout ${CertAUTH}.key \
-out ${CertAUTH}.pem \
-subj "/C=DE/CN=Example-Root-CA"
openssl x509 \
-outform pem \
-in ${CertAUTH}.pem \
-out ${CertAUTH}.crt
openssl req \
-outform pem \
-new \
-nodes \
-newkey rsa:2048 \
-keyout privkey.pem \
-out localhost.csr \
-subj "/C=DE/ST=HE/L=Darmstadt/O=ULB/CN=*.localhost"
openssl x509 \
-outform pem \
-req \
-sha256 \
-days 1024 \
-in localhost.csr \
-CA ${CertAUTH}.pem \
-CAkey ${CertAUTH}.key \
-CAcreateserial \
-extfile domains.ext \
-out fullchain.pem
cp fullchain.pem live/exist.ulb.tu-darmstadt.de
cp fullchain.pem live/purl.ulb.tu-darmstadt.de
cp fullchain.pem live/tueditions.ulb.tu-darmstadt.de
cp privkey.pem live/exist.ulb.tu-darmstadt.de
cp privkey.pem live/purl.ulb.tu-darmstadt.de
cp privkey.pem live/tueditions.ulb.tu-darmstadt.de
cd ..
The script is supposed to create directories and create fullchain.pem files, yyou can probably get what it should do.My output is the following:
Can't open "domains.ext" for reading, No such file or directory
4047A01AD37F0000:error:80000002:system library:BIO_new_file:No such file or directory:../crypto/bio/bss_file.c:67:calling fopen(domains.ext, r)
4047A01AD37F0000:error:10000080:BIO routines:BIO_new_file:no such file:../crypto/bio/bss_file.c:75:
cp: Aufruf von stat für 'fullchain.pem' nicht möglich: Datei oder Verzeichnis nicht gefunden
cp: Aufruf von stat für 'fullchain.pem' nicht möglich: Datei oder Verzeichnis nicht gefunden
cp: Aufruf von stat für 'fullchain.pem' nicht möglich: Datei oder Verzeichnis nicht gefunden
nota bene: we have pre-created the domains.ext as current user and entered the necessary information.We're clueless what's happening here, maybe somebody here has a solution for me/us?
all the best
The cp errors are because the script didn't exit after failing the create the previous dependency. Add set -e -o pipefail the top to prevent the script from proceeding after an error.
Next, the domains.ext isn't in the correct location. At the top, your allowing mkdir to fail silently with the -p argument:
-p, --parents
no error if existing, make parent directories as needed
Meaning that it likely created the cert dir too, which is where your script was expecting to find the domains.ext. You can confirm this by testing for your prerequsits first, exiting with a sane failure if it's missing. This is what I would add to the top of the file:
#!/usr/bin/env bash
set -e -o pipefail
[[ -f cert/domains.ext ]] || { echo 'ERROR: ./cert/domains.ext is missing' ; exit 1 ; }

Can I use command substitution in git bash?

I love Git Bash because it puts all the powerful tools on a CLI for windows. I'm trying to use it with openssl to generate a csr and key at the same time. And, I'd like to do it all in one command. Here's what I have so far:
openssl req -new -sha256 \
-newkey ec:<(openssl ecparam -name prime256v1) -keyout site.key \
-batch -out site.csr -utf8 \
-subj '//C=US\ST=State\L=City\O=organization\OU=org unit\CN=site.com\emailAddress=admin#site.com' \
-addext 'subjectAltName=DNS:site.com,DNS:www.site.com'
My problem is that git bash doesn't handle the command substitution properly (or I'm doing it wrong). When I run the above, I get
Can't open parameter file /dev/fd/63
15160:error:02001003:system library:fopen:No such process:../openssl-1.1.1a/crypto/bio/bss_file.c:72:fopen('/dev/fd/63','r')
15160:error:2006D080:BIO routines:BIO_new_file:no such file:../openssl-1.1.1a/crypto/bio/bss_file.c:79:
According to the manual,
All other algorithms support the -newkey alg:file form, where file may be an algorithm parameter file, created by the genpkey -genparam command...
so, I think I'm looking to feed it a file after ec:, I'm just not sure how. (btw, I took direction from this answer. Although it's written for standard bash, I was hoping it would work.)

Syntax error: "(" unexpected error while creating an openssl certificate using a bash command

Using the instructions over here to define the SAN field inside the a openssl certificate, I am using the following commands to generate my own self-signed certificate:
openssl genrsa -out domain.org.key
openssl req -newkey rsa:2048 -nodes -keyout domain.org.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=*.domain.org" -out domain.org.csr
openssl x509 -req -extfile <(printf "subjectAltName=DNS:domain.org,DNS:www.domain.org") -days 365 -in domain.org.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out domain.org.crt
However, I am getting the following error:
Syntax error: "(" unexpected
I don't see anything specifically wrong with the bash syntax used, could anyone help?
That error-message doesn't look like Bash to me; rather, Bash error-messages look like this:
bash: syntax error near unexpected token `('
I recommend double-checking that you're running these commands in Bash, and not a different shell. (Process substitution isn't specified by POSIX, so not all shells support it.)
If it turns out that Bash is not available, you can use a temporary file:
printf "subjectAltName=DNS:domain.org,DNS:www.domain.org" > tmp-ext-file
openssl x509 -req -extfile tmp-ext-file -days 365 -in domain.org.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out domain.org.crt
or standard input:
printf "subjectAltName=DNS:domain.org,DNS:www.domain.org" \
| openssl x509 -req -extfile /dev/stdin -days 365 -in domain.org.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out domain.org.crt

Shell: Capturing output files in variables

Commands like openssl have arguments like -out <file> for output files. I'd like to capture the content of these output files in shell variables for use in other commands without creating temporary files. For example, to generate a self-signed certificate, one can use:
openssl req -new -newkey rsa:2048 -subj / -days 365 -nodes -x509 -keyout KEYFILE -out CERTFILE 2>/dev/null
The closest I've got to capture both output files is to echo them to stdout via process substitution but this is not ideal because one would still have to parse them apart.
openssl req -new -newkey rsa:2048 -subj / -days 365 -nodes -x509 -keyout >(key=$(cat -); echo $key) -out >(cert=$(cat -); echo $cert) 2>/dev/null
Is there a clean way to capture the content of output files in shell variables?
Most modern shells now support /dev/stdout as a file name to redirect to stdout. This is good enough for single file solutions but for two output files you need to go with "process substitution".
eval "$( openssl req -new -newkey rsa:2048 -subj / -days 365 -nodes -x509 -keyout >(echo "keyout='$( cat )'" ) -out >(echo out="'$( cat )'" ) )"
This uses process substitution to direct each "file" to a separate process that prints to stdout an assignment of the calculated values. The whole thing is then passed to an eval to do the actual assignments.
Keeping output of stderr to show any error messages that pops up. Useful to log it in times of troubles.
Edit: incorporating Charles Duffy's good paranoia:
flockf="$(mktemp -t tmp.lock.$$.XXXXXX )" || exit $?;
eval "$( openssl req -new -newkey rsa:2048 -subj / -days 365 -nodes -x509 \
-keyout >( set -x; 99>"$flockf" && \
flock -x "$flockf" printf "keyout=%q " "$( cat )"; ) \
-out >( set -x; 99>"$flockf" && \
flock -x "$flockf" printf "out=%q " "$( cat )"; ) \
)" ;
rm -f "$flockf"
An extension to Gilbert's answer providing additional paranoia:
eval "$( openssl req -new -newkey rsa:2048 -subj / -days 365 -nodes -x509 \
-keyout >(printf 'keyout=%q\n' "$(</dev/stdin)") \
-out >(printf 'out=%q\n' "$(</dev/stdin)") )"
(Note that this is not suitable if your data contains NULs, which bash cannot store in a native shell variable; in that case, you'll want to assign the contents to your variables in base64-encoded form).
Unlike echo "keyout='$(cat)'", printf 'keyout=%q\n' "$(cat)" ensures that even malicious contents cannot be evaluated by the shell as a command substitution, redirection, or otherwise content other than literal data.
To explain why this is necessary, let's take a simplified case:
write_to_two_files() { printf 'one\n' >"$1"; printf 'two\n' >"$2"; }
write_to_two_files >(echo "one='$(cat)'") >(echo "two='$(cat)'")
...we get output akin to (but with no particular ordering):
two='two'
one='one'
...which, when evaled, sets two variables:
$ eval "$(write_to_two_files >(echo "one='$(cat)'") >(echo "two='$(cat)'"))"
$ declare -p one two
declare -- one="one"
declare -- two="two"
However, let's say that our program behaves a bit differently:
## Demonstrate why eval'ing content created by echoing data is dangerous
write_to_two_files() {
printf "'%s'\n" '$(touch /tmp/i-pwned-your-box)' >"$1"
echo "two" >"$2"
}
eval "$(write_to_two_files >(echo "one='$(cat)'") >(echo "two='$(cat)'"))"
ls -l /tmp/i-pwned-your-box
Instead of merely assigning the output to a variable, we evaluated it as code.
If you're further interested in ensuring that the two print operations happen at different times (preventing their output from being intermingled), it's useful to further add locking. This does involve a temporary file, but does not write your keying material to disk (avoidance of which is the most compelling reason to avoid temporary file usage):
lockfile=$(mktemp -t output.lck.XXXXXX)
eval "$( openssl req -new -newkey rsa:2048 -subj / -days 365 -nodes -x509 \
-keyout >(in=$(cat); exec 99>"$lockfile" && flock -x 99 && printf 'keyout=%q\n' "$in") \
-out >(in=$(cat); exec 99>"$lockfile" && flock -x 99 && printf 'out=%q\n' "$in") )"
Note that we're only blocking for the write, not the read, so we can't get into race conditions (ie. where openssl isn't finishing writing to file-A because it's blocked on a write to file-B, which can never complete because the subshell on the read side of the file-A write holds the lock).

entering password into openssl command from shell script

I am trying to convert a p12 to a pem from a shell script without any user input.
I can have the password as a variable within the script.
so when I call:
openssl pkcs12 -in *.p12 -out cert.pem -nodes
The terminal prints "Enter Import Password:" and waits for input.
I tried to pipe the password in with:
echo $PASS | openssl pkcs12 -in *.p12 -out cert.pem -nodes
as well as trying to use a flag with the openssl command but can't figure out how to do this.
This one liner worked for me-
openssl pkcs12 -in certificate.p12 -password pass:<your_password> -nodes | openssl x509 -noout -enddate

Resources