From 5796878203b16c6777ba9b3b08f5dd0fb496f57a Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sun, 14 Apr 2019 23:12:51 +0000 Subject: [PATCH] Convert final article --- ...27-ec-ca-redux-now-with-more-nitrokey.html | 141 ++++---- 2016-05-17-wifi-bridging-redux.html | 2 +- ...3-27-ec-ca-redux-now-with-more-nitrokey.md | 302 ++++++++++++++++++ markdown/2016-05-17-wifi-bridging-redux.md | 2 +- 4 files changed, 386 insertions(+), 61 deletions(-) create mode 100644 markdown/2016-03-27-ec-ca-redux-now-with-more-nitrokey.md diff --git a/2016-03-27-ec-ca-redux-now-with-more-nitrokey.html b/2016-03-27-ec-ca-redux-now-with-more-nitrokey.html index 259e920..8ec1303 100644 --- a/2016-03-27-ec-ca-redux-now-with-more-nitrokey.html +++ b/2016-03-27-ec-ca-redux-now-with-more-nitrokey.html @@ -15,17 +15,18 @@

Create directory structure

-mkdir ca +
mkdir ca
 cd ca
 mkdir -p {root,intermediate}/{certs,crl,csr,newcerts}
 mkdir -p {client,server}/{certs,csr,pfx,private}
 touch {root,intermediate}/database
 echo 1000 | tee {root,intermediate}/{serial,crlnumber}
-chmod 700 {client,server}/private
+chmod 700 {client,server}/private
+

Create openssl.cnf

-cat > openssl.cnf <<'END' +
cat > openssl.cnf &lt;&lt;'END'
 openssl_conf = openssl_init
 [ openssl_init ]
 engines = engines
@@ -138,93 +139,105 @@ engine_id     = pkcs11
 dynamic_path  = /usr/lib/arm-linux-gnueabihf/openssl-1.0.0/engines/libpkcs11.so
 MODULE_PATH   = /usr/local/lib/pkcs11/opensc-pkcs11.so
 init          = 0
-END
+END
+

Tell future commands to use your new conf file

-export OPENSSL_CONF=openssl.cnf +
export OPENSSL_CONF=openssl.cnf
+

Create a root key

Insert your root HSM.

-/usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --keypairgen --key-type EC:prime256v1 --label root -# Enter PIN +
/usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --keypairgen --key-type EC:prime256v1 --label root
+# Enter PIN
+

Create a self-signed root cert

-openssl req -engine pkcs11 -keyform engine -key label_root -new -extensions ext_root -out root/certs/root.cert.pem -x509 -subj '/C=US/ST=California/O=XXXX/OU=XXXX Certificate Authority/CN=XXXX Root CA' -days 7300 +
openssl req -engine pkcs11 -keyform engine -key label_root -new -extensions ext_root -out root/certs/root.cert.pem -x509 -subj '/C=US/ST=California/O=XXXX/OU=XXXX Certificate Authority/CN=XXXX Root CA' -days 7300
 # Enter PIN
-chmod 444 root/certs/root.cert.pem
+chmod 444 root/certs/root.cert.pem
+

Verify root cert

-openssl x509 -noout -text -in root/certs/root.cert.pem +
openssl x509 -noout -text -in root/certs/root.cert.pem
+

Check:

Import root cert onto HSM

-openssl x509 -in root/certs/root.cert.pem -out root/certs/root.cert.der -outform der +
openssl x509 -in root/certs/root.cert.pem -out root/certs/root.cert.der -outform der
 /usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --write-object root/certs/root.cert.der --type cert --label root
-# Enter PIN
+# Enter PIN
+

Create an intermediate key

Insert your intermediate HSM

-/usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --keypairgen --key-type EC:prime256v1 --label intermediate -# Enter PIN +
/usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --keypairgen --key-type EC:prime256v1 --label intermediate
+# Enter PIN
+

Create an intermediate certificate signing request (CSR)

-openssl req -engine pkcs11 -keyform engine -new -key label_intermediate -out intermediate/csr/intermediate.csr.pem -subj '/C=US/ST=California/O=XXXX/OU=XXXX Certificate Authority/CN=XXXX Intermediate' -# Enter PIN +
openssl req -engine pkcs11 -keyform engine -new -key label_intermediate -out intermediate/csr/intermediate.csr.pem  -subj '/C=US/ST=California/O=XXXX/OU=XXXX Certificate Authority/CN=XXXX Intermediate'
+# Enter PIN
+

Sign intermediate cert with root key

Insert your root HSM

-openssl ca -engine pkcs11 -keyform engine -name ca_root -extensions ext_intermediate -notext -in intermediate/csr/intermediate.csr.pem -out intermediate/certs/intermediate.cert.pem +
openssl ca -engine pkcs11 -keyform engine -name ca_root -extensions ext_intermediate -notext -in intermediate/csr/intermediate.csr.pem -out intermediate/certs/intermediate.cert.pem
 # Enter PIN
-chmod 444 intermediate/certs/intermediate.cert.pem
+chmod 444 intermediate/certs/intermediate.cert.pem
+

Verify intermediate cert

-openssl x509 -noout -text -in intermediate/certs/intermediate.cert.pem -openssl verify -CAfile root/certs/root.cert.pem intermediate/certs/intermediate.cert.pem +
openssl x509 -noout -text -in intermediate/certs/intermediate.cert.pem
+openssl verify -CAfile root/certs/root.cert.pem intermediate/certs/intermediate.cert.pem
+

Check:

-

Import root & intermediate certs onto HSM

+

Import root & intermediate certs onto HSM

Insert your intermediate HSM

-openssl x509 -in intermediate/certs/intermediate.cert.pem -out intermediate/certs/intermediate.cert.der -outform der +
openssl x509 -in intermediate/certs/intermediate.cert.pem -out intermediate/certs/intermediate.cert.der -outform der
 /usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --write-object root/certs/root.cert.der --type cert --label root
 # Enter PIN
 /usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --write-object intermediate/certs/intermediate.cert.der --type cert --label intermediate
-# Enter PIN
+# Enter PIN
+

Create a chain certificate file

-cat intermediate/certs/intermediate.cert.pem root/certs/root.cert.pem > intermediate/certs/chain.cert.pem -chmod 444 intermediate/certs/chain.cert.pem +
cat intermediate/certs/intermediate.cert.pem root/certs/root.cert.pem > intermediate/certs/chain.cert.pem
+chmod 444 intermediate/certs/chain.cert.pem
+

CA setup done!

@@ -236,75 +249,85 @@ chmod 444 intermediate/certs/chain.cert.pem

You can substitute “server” for “client” for a server cert.

-openssl ecparam -name secp384r1 -genkey | openssl ec -aes-256-cbc -out client/private/test1.key.pem +
openssl ecparam -name secp384r1 -genkey | openssl ec -aes-256-cbc -out client/private/test1.key.pem
 # Create client key password
-chmod 400 client/private/test1.key.pem
+chmod 400 client/private/test1.key.pem
+

Create a client certificate signing request (CSR)

-openssl req -new -key client/private/test1.key.pem -out client/csr/test1.csr.pem -subj '/C=US/ST=California/O=XXXX/OU=XXXX Test/CN=XXXX Test 1' +
openssl req -new -key client/private/test1.key.pem -out client/csr/test1.csr.pem  -subj '/C=US/ST=California/O=XXXX/OU=XXXX Test/CN=XXXX Test 1'
+

Sign client cert with intermediate key

-openssl ca -engine pkcs11 -keyform engine -extensions ext_client -notext -in client/csr/test1.csr.pem -out client/certs/test1.cert.pem +
openssl ca -engine pkcs11 -keyform engine -extensions ext_client -notext -in client/csr/test1.csr.pem -out client/certs/test1.cert.pem
 # Enter PIN
-chmod 444 client/certs/test1.cert.pem
+chmod 444 client/certs/test1.cert.pem
+

Verify client cert

-openssl x509 -noout -text -in client/certs/test1.cert.pem -openssl verify -CAfile intermediate/certs/chain.cert.pem client/certs/test1.cert.pem +
openssl x509 -noout -text -in client/certs/test1.cert.pem
+openssl verify -CAfile intermediate/certs/chain.cert.pem client/certs/test1.cert.pem
+

Check:

Create a PKCS#12 bundle for the client

-

This is an easy(er) way to get all the necessary keys & certs to the client in one package.

+

This is an easy(er) way to get all the necessary keys & certs to the client in one package.

-openssl pkcs12 -export -out client/pfx/test1.pfx -inkey client/private/test1.key.pem -in client/certs/test1.cert.pem -certfile intermediate/certs/chain.cert.pem -# Enter both the client key password, and a new password for the export; you'll need to give the latter to the client +
openssl pkcs12 -export -out client/pfx/test1.pfx -inkey client/private/test1.key.pem -in client/certs/test1.cert.pem -certfile intermediate/certs/chain.cert.pem
+# Enter both the client key password, and a new password for the export; you'll need to give the latter to the client
+

Generate a certificate revocation list (CRL)

Initially empty. You can also do this for your root CA (with its HSM inserted).

-openssl ca -engine pkcs11 -keyform engine -gencrl -out intermediate/crl/intermediate.crl.pem +
openssl ca -engine pkcs11 -keyform engine -gencrl -out intermediate/crl/intermediate.crl.pem
+

Verify certificate revocation list

-openssl crl -in intermediate/crl/intermediate.crl.pem -noout -text +
openssl crl -in intermediate/crl/intermediate.crl.pem -noout -text
+

Check:

Revoke a certificate

Only do this if you need to. Find the certificate:

-cat intermediate/database +
cat intermediate/database
 # You'll need the hex-formatted serial number, in the third field.
-# Substitute serial number for YYYY below.
+# Substitute serial number for YYYY below.
+

Revoke it:

-openssl ca -engine pkcs11 -keyform engine -revoke intermediate/newcerts/YYYY.pem -# Enter PIN +
openssl ca -engine pkcs11 -keyform engine -revoke intermediate/newcerts/YYYY.pem
+# Enter PIN
+

Generate a new CRL file:

-openssl ca -engine pkcs11 -keyform engine -gencrl -out intermediate/crl/intermediate.crl.pem -# Enter PIN +
openssl ca -engine pkcs11 -keyform engine -gencrl -out intermediate/crl/intermediate.crl.pem
+# Enter PIN
+
diff --git a/2016-05-17-wifi-bridging-redux.html b/2016-05-17-wifi-bridging-redux.html index d98c2db..674920a 100644 --- a/2016-05-17-wifi-bridging-redux.html +++ b/2016-05-17-wifi-bridging-redux.html @@ -85,7 +85,7 @@ iface br0 inet dhcp pre-up /sbin/start-stop-daemon --start --pidfile=/var/run/wpa_supplicant.wlan0.pid --exec=/usr/local/sbin/wpa_supplicant --user=root -- -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf -C /var/run/wpa_supplicant -P /var/run/wpa_supplicant.wlan0.pid -b $IFACE bridge_ports eth0 eth1 wlan0 post-down /sbin/start-stop-daemon --stop --pidfile=/var/run/wpa_supplicant.wlan0.pid --exec=/usr/local/sbin/wpa_supplicant --user=root - post-down /sbin/iw dev wlan0 set 4addr off</code></p> + post-down /sbin/iw dev wlan0 set 4addr off

We use start-stop-daemon because it provides idempotence and safety from stale PID files.

diff --git a/markdown/2016-03-27-ec-ca-redux-now-with-more-nitrokey.md b/markdown/2016-03-27-ec-ca-redux-now-with-more-nitrokey.md new file mode 100644 index 0000000..a42a97c --- /dev/null +++ b/markdown/2016-03-27-ec-ca-redux-now-with-more-nitrokey.md @@ -0,0 +1,302 @@ + + + + + +This is a revisit on my doc on [how to set up an EC CA](https://medium.com/where-the-flamingcow-roams/elliptic-curve-certificate-authority-bbdb9c3855f7#.4z3bzvz6e). In this version, we’re using the [Nitrokey HSM](https://shop.nitrokey.com/shop/product/nitrokey-hsm-7) for key generation, storage, and operations. You’ll need two Nitrokey HSMs. You can get away with one, but there’s not a lot of point to splitting root and intermediate certs if you then keep them on the same device. You’ll also need a [system set up](https://medium.com/where-the-flamingcow-roams/nitrokey-hsm-ec-setup-6ed9b9e43c36#.pgal18rvh) to talk to the Nitrokey, which is a bit tricky. + +If you do this right, you can set up a CA where the keys never touched computer that you’re using to host the CA; they only ever reside protected in the Nitrokey. + +You have a choice between making the keys unexportable, or supporting a [backup scheme](https://github.com/OpenSC/OpenSC/wiki/SmartCardHSM#using-key-backup-and-restore). Choose wisely, because you can’t change later. If you’re choosing the former, make sure you can answer “what is my plan if the Nitrokey breaks?”. + +There’s one material difference from the other instructions: the Nitrokey HSM only supports up to 320-bit EC keys, so we can’t use P-384 (secp384r1) as we did in the other instructions. We’ll be using P-256 (prime256v1) instead. + +XXXX is still our placeholder of choice. + +### Create directory structure + + mkdir ca + cd ca + mkdir -p {root,intermediate}/{certs,crl,csr,newcerts} + mkdir -p {client,server}/{certs,csr,pfx,private} + touch {root,intermediate}/database + echo 1000 | tee {root,intermediate}/{serial,crlnumber} + chmod 700 {client,server}/private + +### Create openssl.cnf + + cat > openssl.cnf <<'END' + openssl_conf = openssl_init + [ openssl_init ] + engines = engines + [ ca ] + default_ca = ca_intermediate + [ ca_root ] + dir = root + certs = $dir/certs + crl_dir = $dir/crl + new_certs_dir = $dir/newcerts + database = $dir/database + serial = $dir/serial + crlnumber = $dir/crlnumber + private_key = label_root + certificate = $dir/certs/root.cert.pem + crl = $dir/crl/root.crl.pem + crl_extensions = ext_crl + default_md = sha256 + name_opt = ca_default + cert_opt = ca_default + default_crl_days = 30 + default_days = 3650 + preserve = no + policy = policy_strict + [ ca_intermediate ] + dir = intermediate + certs = $dir/certs + crl_dir = $dir/crl + new_certs_dir = $dir/newcerts + database = $dir/database + serial = $dir/serial + crlnumber = $dir/crlnumber + private_key = label_intermediate + certificate = $dir/certs/intermediate.cert.pem + crl = $dir/crl/intermediate.crl.pem + crl_extensions = ext_crl + default_md = sha256 + name_opt = ca_default + cert_opt = ca_default + default_crl_days = 30 + default_days = 375 + preserve = no + policy = policy_loose + [ policy_strict ] + countryName = match + stateOrProvinceName = match + organizationName = match + organizationalUnitName = optional + commonName = supplied + emailAddress = optional + [ policy_loose ] + countryName = optional + stateOrProvinceName = optional + localityName = optional + organizationName = optional + organizationalUnitName = optional + commonName = supplied + emailAddress = optional + [ req ] + default_bits = 2048 + string_mask = utf8only + default_md = sha256 + distinguished_name = req_distinguished_name + [ req_distinguished_name ] + countryName = Country Name (2 letter code) + stateOrProvinceName = State or Province Name + localityName = Locality Name + 0.organizationName = Organization Name + organizationalUnitName = Organizational Unit Name + commonName = Common Name + emailAddress = Email Address + [ ext_root ] + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid:always, issuer + basicConstraints = critical, CA:true + keyUsage = critical, digitalSignature, cRLSign, keyCertSign + [ ext_intermediate ] + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid:always, issuer + basicConstraints = critical, CA:true, pathlen:0 + keyUsage = critical, digitalSignature, cRLSign, keyCertSign + [ ext_client ] + basicConstraints = CA:FALSE + nsCertType = client, email + nsComment = "OpenSSL Generated Client Certificate" + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid, issuer + keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment + extendedKeyUsage = clientAuth, emailProtection + [ ext_server ] + basicConstraints = CA:FALSE + nsCertType = server + nsComment = "OpenSSL Generated Server Certificate" + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid, issuer:always + keyUsage = critical, digitalSignature, keyEncipherment + extendedKeyUsage = serverAuth + [ ext_crl ] + authorityKeyIdentifier = keyid:always + [ ext_ocsp ] + basicConstraints = CA:FALSE + subjectKeyIdentifier = hash + authorityKeyIdentifier = keyid, issuer + keyUsage = critical, digitalSignature + extendedKeyUsage = critical, OCSPSigning + [ engines ] + pkcs11 = engine_pkcs11 + [ engine_pkcs11 ] + engine_id = pkcs11 + dynamic_path = /usr/lib/arm-linux-gnueabihf/openssl-1.0.0/engines/libpkcs11.so + MODULE_PATH = /usr/local/lib/pkcs11/opensc-pkcs11.so + init = 0 + END + +### Tell future commands to use your new conf file + + export OPENSSL_CONF=openssl.cnf + +### Create a root key + +Insert your root HSM. + + /usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --keypairgen --key-type EC:prime256v1 --label root + # Enter PIN + +### Create a self-signed root cert + + openssl req -engine pkcs11 -keyform engine -key label_root -new -extensions ext_root -out root/certs/root.cert.pem -x509 -subj '/C=US/ST=California/O=XXXX/OU=XXXX Certificate Authority/CN=XXXX Root CA' -days 7300 + # Enter PIN + chmod 444 root/certs/root.cert.pem + +### Verify root cert + + openssl x509 -noout -text -in root/certs/root.cert.pem + +Check: + +* Expiration date (20 years in future) +* Signature algorithm (ecdsa-with-SHA256) +* Public key size (256 bit) +* CA:TRUE + +### Import root cert onto HSM + + openssl x509 -in root/certs/root.cert.pem -out root/certs/root.cert.der -outform der + /usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --write-object root/certs/root.cert.der --type cert --label root + # Enter PIN + +### Create an intermediate key + +Insert your intermediate HSM + + /usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --keypairgen --key-type EC:prime256v1 --label intermediate + # Enter PIN + +### Create an intermediate certificate signing request (CSR) + + openssl req -engine pkcs11 -keyform engine -new -key label_intermediate -out intermediate/csr/intermediate.csr.pem -subj '/C=US/ST=California/O=XXXX/OU=XXXX Certificate Authority/CN=XXXX Intermediate' + # Enter PIN + +### Sign intermediate cert with root key + +Insert your root HSM + + openssl ca -engine pkcs11 -keyform engine -name ca_root -extensions ext_intermediate -notext -in intermediate/csr/intermediate.csr.pem -out intermediate/certs/intermediate.cert.pem + # Enter PIN + chmod 444 intermediate/certs/intermediate.cert.pem + +### Verify intermediate cert + + openssl x509 -noout -text -in intermediate/certs/intermediate.cert.pem + openssl verify -CAfile root/certs/root.cert.pem intermediate/certs/intermediate.cert.pem + +Check: + +* Expiration date (10 years in future) +* Signature algorithm (ecdsa-with-SHA256) +* Public key size (256 bit) +* CA:TRUE +* OK + +### Import root & intermediate certs onto HSM + +Insert your intermediate HSM + + openssl x509 -in intermediate/certs/intermediate.cert.pem -out intermediate/certs/intermediate.cert.der -outform der + /usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --write-object root/certs/root.cert.der --type cert --label root + # Enter PIN + /usr/local/bin/pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so --login --write-object intermediate/certs/intermediate.cert.der --type cert --label intermediate + # Enter PIN + +### Create a chain certificate file + + cat intermediate/certs/intermediate.cert.pem root/certs/root.cert.pem > intermediate/certs/chain.cert.pem + chmod 444 intermediate/certs/chain.cert.pem + +### CA setup done! + +Take your root HSM, if you have a separate one, and lock it in a safe somewhere; you won’t need it for regular use. + +The following steps are examples of how to use your new CA. + +### Create a client key + +You can substitute “server” for “client” for a server cert. + + openssl ecparam -name secp384r1 -genkey | openssl ec -aes-256-cbc -out client/private/test1.key.pem + # Create client key password + chmod 400 client/private/test1.key.pem + +### Create a client certificate signing request (CSR) + + openssl req -new -key client/private/test1.key.pem -out client/csr/test1.csr.pem -subj '/C=US/ST=California/O=XXXX/OU=XXXX Test/CN=XXXX Test 1' + +### Sign client cert with intermediate key + + openssl ca -engine pkcs11 -keyform engine -extensions ext_client -notext -in client/csr/test1.csr.pem -out client/certs/test1.cert.pem + # Enter PIN + chmod 444 client/certs/test1.cert.pem + +### Verify client cert + + openssl x509 -noout -text -in client/certs/test1.cert.pem + openssl verify -CAfile intermediate/certs/chain.cert.pem client/certs/test1.cert.pem + +Check: + +* Expiration date (1 year in future) +* Signature algorithm (ecdsa-with-SHA256) +* Public key size (384 bit) +* CA:FALSE +* OK + +### Create a PKCS#12 bundle for the client + +This is an easy(er) way to get all the necessary keys & certs to the client in one package. + + openssl pkcs12 -export -out client/pfx/test1.pfx -inkey client/private/test1.key.pem -in client/certs/test1.cert.pem -certfile intermediate/certs/chain.cert.pem + # Enter both the client key password, and a new password for the export; you'll need to give the latter to the client + +### Generate a certificate revocation list (CRL) + +Initially empty. You can also do this for your root CA (with its HSM inserted). + + openssl ca -engine pkcs11 -keyform engine -gencrl -out intermediate/crl/intermediate.crl.pem + +### Verify certificate revocation list + + openssl crl -in intermediate/crl/intermediate.crl.pem -noout -text + +Check: + +* Expiration date (30 days in future) +* Signature algorithm (ecdsa-with-SHA256) + +### Revoke a certificate + +Only do this if you need to. Find the certificate: + + cat intermediate/database + # You'll need the hex-formatted serial number, in the third field. + # Substitute serial number for YYYY below. + +Revoke it: + + openssl ca -engine pkcs11 -keyform engine -revoke intermediate/newcerts/YYYY.pem + # Enter PIN + +Generate a new CRL file: + + openssl ca -engine pkcs11 -keyform engine -gencrl -out intermediate/crl/intermediate.crl.pem + # Enter PIN + + diff --git a/markdown/2016-05-17-wifi-bridging-redux.md b/markdown/2016-05-17-wifi-bridging-redux.md index b8f4ff7..e88c3fc 100644 --- a/markdown/2016-05-17-wifi-bridging-redux.md +++ b/markdown/2016-05-17-wifi-bridging-redux.md @@ -75,7 +75,7 @@ Because of the ordering issues, it’s easier to treat this all as one interface pre-up /sbin/start-stop-daemon --start --pidfile=/var/run/wpa_supplicant.wlan0.pid --exec=/usr/local/sbin/wpa_supplicant --user=root -- -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf -C /var/run/wpa_supplicant -P /var/run/wpa_supplicant.wlan0.pid -b $IFACE bridge_ports eth0 eth1 wlan0 post-down /sbin/start-stop-daemon --stop --pidfile=/var/run/wpa_supplicant.wlan0.pid --exec=/usr/local/sbin/wpa_supplicant --user=root - post-down /sbin/iw dev wlan0 set 4addr off

+ post-down /sbin/iw dev wlan0 set 4addr off We use start-stop-daemon because it provides idempotence and safety from stale PID files.