easy-rsa
easy-rsa copied to clipboard
Older certs for a CN cannot be revoked
With the unique_subject set to no, it is possible to add unlimited certs for a CN. EasyRSA only maintains all info for the last issued cert for a CN. Earlier created certs for a CN are tracked by their serial and serial.pem is available. This makes it not so easy to manage.
EasyRSA has no function to list all issued certs and to revoke the older issued certs for a CN. List can be done with cat | grep index.txt, revoke is almost impossible.
This problem is created with the work_in_progress for renewal (#286).
IMHO, because EasyRSA is updated to manage multiple issued certs for a CN, it must keep track of all of these and not only the last issued cert.
One method solving the issue would be to restructure the database, with a single copy of items which will be kept forever and usage of symbolic links in various folders. This could be difficult to implement for non-*x systems.
Or just use current data for list and revoke. Maybe index.txt is enough to support commands like list-certs [ all | valid | revoked ] (instead of cat index.txt or egrep ^V index.txt / egrep ^R index.txt). And the revoke-all < filename_base > and revoke-older < filename_base > commands to revoke all or the older certs for a CN. Maybe add a revoke-serial < serial > .
Meanwhile, unique_subject = yes has to be supported. For users that want to keep the EasyRSA2 behaviour can put it on yes. So maybe implement a unique_subject yes | no command and keep it on yes until the issues are fixed..
From version 3.1, there is a new renew mechanism, which does not keep the renewed files by serial number.
There is also a new command revoke-renewed, which can revoke renewed certificates.
There is also another new command rewind-renew, which undoes the old renew mechanism and then allows certificates to be revoked by using revoke-renewed.
I do not know what the plans are for EasyRSA versions prior to version 3.1 to correct the revoking of renewed certificates problem.
I do not expect there to be a way to switch between unique_subject mode yes or no. Once upgraded, your PKI will function as required.
@tecoboot would you consider testing version 3.1.1, which is currently git/master ?
That would help us a great deal.
To test, simply make a copy of your current PKI and download git/master/easyrsa into your copy PKI.
To save your currently renewed certificates you need to use:
rewind-renew <serial-number>. This can be done for each uniquecommonNameof your certificates.
Then you can revoke a renewed certificate by using:
revoke-renewed <commonName>.
Finally, update your Certificate Revocation List [CRL]:
gen-crlAnd upload the new CRL to your OpenVPN Server.
EasyRSA version 3.1.1 (git/master) now includes these status reports:
show-expire- List certificates which will expire soon.show-revoke- List certificates which are revoked.show-renew- List certificates which have been renewed.
Tempting tools for upgrading .. :cake: :beer:
Linking #609
OK, I'll produce test results. Attached test result with master. Issue 626 - problem.txt
Couple of findings:
- vars handling is different in v3.0.6 and current master;
- with unique_subject = no, it is not possible to add same client-1 with build-client-full, but it is possible with sign-req;
- with easyrsa, current status of ollder issues certs cannot be shown;
- with multiple certs for client-1, it is hard or impossible to revoke the older. Now I'll try the new rewind functions, please wait for results.
There is an issue with show-expire caused by the older but still valid certs:
.. show-expire: ./easyrsa: 3478: [: Illegal number: ./easyrsa: 3478: [: Illegal number:
Line is: if [ "$cert_expire_date_s" -lt "$cutoff_date_s" ]; then
Error (with bash -x): + '[' '' -lt 1667721397 ']'
Before: + cert_expire_date_s=
So $cert_expire_date_s is empty. The older certs were indeed not expired.
These are the certs that I want to see with show-older (or a better command).
The rewind-renew doesn't work for these older certs. Issue 626 - revoke-renewed.txt
Easy-RSA error: Unable to revoke as no renewed certificate was found. Certificate was expected at: /root/easy-rsa/easyrsa3/pki/renewed/issued/17F4A03B99101C17986D7CC955855B86.crt
The problem is that the certs were not renewed but added with sign-req's.
Here first attempt to fix show-expire or basics for show-older:
root@host:~/easy-rsa/easyrsa3# git diff easyrsa
diff --git a/easyrsa3/easyrsa b/easyrsa3/easyrsa
index 256c878..1464a03 100755
--- a/easyrsa3/easyrsa
+++ b/easyrsa3/easyrsa
@@ -3475,10 +3475,17 @@ expire_status() {
cert_date_to_timestamp_s "$cert_type_date" # Assigns timestamp_s
cutoff_date_s="$timestamp_s"
- if [ "$cert_expire_date_s" -lt "$cutoff_date_s" ]; then
- # Cert expires in less than grace period
- printf '%s%s\n' "$db_status | Serial: $db_serial | " \
+ if [ ! -z "$cert_expire_date_s" ]; then
+ if [ "$cert_expire_date_s" -lt "$cutoff_date_s" ]; then
+ # Cert expires in less than grace period
+ printf '%s%s\n' "$db_status | Serial: $db_serial | " \
"Expires: $cert_not_after_date | CN: $db_cn"
+ fi
+ else
+ # FIXME - show older certs
+ printf '%s%s\n' "FIXME - $db_status | Serial: $db_serial | " \
+ "Expires: $(openssl x509 -in ./pki/certs_by_serial/$db_serial.pem -text | \
+ awk -F\: '/Not After/{print $2":"$3":"$4}') | CN: $db_cn"
fi
} # => expire_status()
root@host:~/easy-rsa/easyrsa3# ./easyrsa show-expire
Notice
------
* Showing certificates which expire in less than 90 days (--renew-days):
FIXME - V | Serial: 37D51BF4F7FA5A987F4730A3F3D255CD | Expires: Nov 10 08:48:54 2024 GMT | CN: client-1
FIXME - V | Serial: 17F4A03B99101C17986D7CC955855B86 | Expires: Nov 10 08:48:54 2024 GMT | CN: client-1
root@host:~/easy-rsa/easyrsa3#
@tecoboot thanks for testing.
- vars handling is different in v3.0.6 and current master
True - However, the only serious difference is that the preferred location of vars is now to be within the PKI folder.
- with unique_subject = no, it is not possible to add same client-1 with build-client-full,
That is correct functionality.
but it is possible with sign-req
That must be a bug, I'll have to take a closer look. Edit: Fixed via 5b4fd2b484adc6e2f506b62eb54fc38adc802766
- with easyrsa, current status of ollder issues certs cannot be shown
That can be addressed and fixed.
- with multiple certs for client-1, it is hard or impossible to revoke the older
From what I can gather here; You created your client-1 multiple certificates in a completely unsupported way, on a PKI that should not allow you to create duplicate CN certificates.
- Now I'll try the new rewind functions
rewind-renew only works for certificates which were renewed the old way, using easyrsa version 3.0.x.
rewind-renew will not work on a certificate which has been renewed using easyrsa version 3.1.x (git/master).
To test, simply make a copy of your current PKI and download
git/master/easyrsainto your copy PKI.
For rewind-renew to work, you must use this copy of your old PKI.
Here first attempt to fix show-expire or basics for show-older
Thanks for your work, I'll take a closer look soon.
Your work for show-older is based on certificates which should not exist, so I cannot proceed with that option.
- vars handling is different in v3.0.6 and current master
True - However, the only serious difference is that the preferred location of
varsis now to be within the PKI folder.
OK now. I started with Debian Bullseye, with easyrsa 3.0.8. Then the file was copied, not moved. This change needs an update in my install scripts.
Your work for
show-olderis based on certificates which should not exist, so I cannot proceed with that option.
OK, with the protection by https://github.com/OpenVPN/easy-rsa/commit/5b4fd2b484adc6e2f506b62eb54fc38adc802766 it is not needed.
With the patch, the to be revoked certs also cannot exists.
I'm a bit concerned on installed easyrsa, that lacks the protection. Updating in for example Debian takes some time (years).
@tecoboot good point.
@ecrist should https://github.com/OpenVPN/easy-rsa/commit/5b4fd2b484adc6e2f506b62eb54fc38adc802766 be applied to 3.0 series ?
EasyRSA version
3.1.1(git/master) now includes these status reports:
show-expire- List certificates which will expire soon.show-revoke- List certificates which are revoked.show-renew- List certificates which have been renewed.Tempting tools for upgrading .. 🍰 🍺
The show-all function: ./easyrsa --renew-days=99999 show-expire
Have a fix for the "corrupt" PKI? Now I have:
root@host:~/easy-rsa/easyrsa3# ./easyrsa --renew-days=99999 show-expire
Notice
------
* Showing certificates which expire in less than 99999 days (--renew-days):
V | Serial: F8959E69B85CE56299006C3EA2F600C7 | Expires: Apr 6 14:27:17 2077 GMT | CN: server
V | Serial: 036D8E15DFC0AF9F5E68CB4DA34A45FD | Expires: Apr 6 18:58:54 2077 GMT | CN: client-x
V | Serial: D812344919EAFF9B4C5FE26040356463 | Expires: Apr 6 18:58:55 2077 GMT | CN: client-y
./easyrsa: 3483: [: Illegal number:
./easyrsa: 3483: [: Illegal number:
./easyrsa: 3483: [: Illegal number:
./easyrsa: 3483: [: Illegal number:
./easyrsa: 3483: [: Illegal number:
The Illegal number can be fixed but it is important to understand why it is happening that either cert_expire_date_s and/or cutoff_date_s are empty values.
I would need to see your index.txt file and find pki/issued pki/revoked.
I revoked the fix and reran the testscript. Result:
root@host:~/easy-rsa/easyrsa3# cat pki/index.txt
V 241110155612Z A347D033EBB501418145AC840E2E4A5B unknown /CN=client-1
V 241110155612Z A6FAE9867E46635386C490CAF91F81FC unknown /CN=client-1
R 241110155612Z 220808155612Z A08D3B46F37861CDEF1804E02276C484 unknown /CN=client-1
root@host:~/easy-rsa/easyrsa3# find pki/issued pki/revoked
pki/issued
pki/revoked
pki/revoked/private_by_serial
pki/revoked/private_by_serial/A08D3B46F37861CDEF1804E02276C484.key
pki/revoked/reqs_by_serial
pki/revoked/reqs_by_serial/A08D3B46F37861CDEF1804E02276C484.req
pki/revoked/certs_by_serial
pki/revoked/certs_by_serial/A08D3B46F37861CDEF1804E02276C484.crt
root@host:~/easy-rsa/easyrsa3#
Here 2 errors:
... show-expire:
./easyrsa: 3482: [: Illegal number:
./easyrsa: 3482: [: Illegal number:
From your index.txt file, there are three known certificates:
A3..,A6..andA0...
However, there exists only one certificate file:
pki/revoked/certs_by_serial/A08D3B46F37861CDEF1804E02276C484.crt
You have over-written your original certificate twice.
Obviously, easyrsa needs to handle this situation correctly. I'll take a closer look.
Thanks for your time and feedback :+1:
This turned out to be a bug in my busybox date input.
The correct command is:
busybox date -u \
-D "%Y-%m-%d %H:%M:%S%Z" \
-d "$in_date" "+%b %d %H:%M:%S %Y %Z"
-D was incorrectly formatted.
https://github.com/OpenVPN/easy-rsa/blob/5b4fd2b484adc6e2f506b62eb54fc38adc802766/easyrsa3/easyrsa#L3298-L3309
There is still something going wrong though, otherwise it should fail for all dates ... weird. Still working on this one ..
I'll have made a revoke-untracked-certs cleanup script. It revokes all "untracked" serials. Please confirm that easyrsa3 keeps all certs in pki subfolders. I'm not so sure such a script should be made available with std distribution, or even integrate in easyrsa itself. Opinions?
#!/bin/bash -e
# Bypass for https://github.com/OpenVPN/easy-rsa/issues/626
# Revoke untracked certs, e.g. created with multiple sign-req's for same CN, before
# fix https://github.com/OpenVPN/easy-rsa/commit/5b4fd2b484adc6e2f506b62eb54fc38adc802766
#
# With EasyRSA 3, all generated valid certs are kept in the PKI folder
# So the serials of the valid certs in the openssl index.txt MUST be present in one of
# the cert files maintained by easyrsa3.
# If a serial in index.txt is not backed in a cert file, it is untracked.
# This scripts revokes all such untracked certs
echo -n "Do you want to revoke untracked certs in $(pwd) ?
Warning, use at your own risk !!
Say yes: "
read response
if [ "$response" != yes ]; then
echo "You didn't give permission"
exit 1
fi
# Housekeeping
run_date=$(date +%y%m%d%H%M%SZ)
found_untracked_serials=no
tracked_serials_file=tracked-serials-$run_date
# Find tracked serials
rm -f $tracked_serials_file # just to be sure
find pki/*/ -type f -regex ".*crt" -exec bash -c \
"openssl x509 -noout -serial -in {} | cut -d'=' -f2 >>$tracked_serials_file" \;
# Save current index.txt
cp pki/index.txt pki/index.txt.$run_date
# Revoke untracked certs
for cert_serial in $(egrep "^V.*$cert_serial" pki/index.txt | cut -f4)
do
if grep -q "$cert_serial" $tracked_serials_file; then
: # found, this is OK
else
cert_expiration=$(grep "$cert_serial" pki/index.txt | cut -f2)
cert_filename=$(grep "$cert_serial" pki/index.txt| cut -f5)
cert_DN=$(grep "$cert_serial" pki/index.txt | cut -f6)
printf -v new_index_line "R\t$cert_expiration\t$run_date,cessationOfOperation\t$cert_serial\t$cert_filename\t$cert_DN"
sed -i "s|.*$cert_serial.*|$new_index_line|" pki/index.txt
found_untracked_serials=yes
echo "Untracked certificate with serial $cert_serial revoked"
fi
done
# Cleanup
if [ "$found_untracked_serials" = yes ]; then
echo "Do not forget to generate a new CRL and push it to your systems"
echo "Old index.txt is saved as pki/index.txt.$run_date"
echo "Current tracked serials file is saved as $tracked_serials_file"
else
echo "No untracked serials found"
rm -f pki/index.txt.$run_date $tracked_serials_file
fi
exit 0
Results:
root@host:~/easy-rsa/easyrsa3# ./revoke-untracked-certs
Do you want to revoke untracked certs in /root/easy-rsa/easyrsa3 ?
Warning, use at your own risk !!
Say yes: yes
Untracked certificate with serial AAABBBCCC7B1FE1723C1F663C2F59800 revoked
Untracked certificate with serial A83EBCEE029D62C931D95FB51F381548 revoked
Untracked certificate with serial 1B4FA7A3CEB1A7DA6CEB5C7EEDDE6152 revoked
Do not forget to generate a new CRL and push it to your systems
Old index.txt is saved as pki/index.txt.220811094830Z
Current tracked serials file is saved as tracked-serials-220811094830Z
root@host:~/easy-rsa/easyrsa3#
root@host:~/easy-rsa/easyrsa3# ./revoke-untracked-certs
Do you want to revoke untracked certs in /root/easy-rsa/easyrsa3 ?
Warning, use at your own risk !!
Say yes: yes
No untracked serials found
root@host:~/easy-rsa/easyrsa3#
root@host:~/easy-rsa/easyrsa3# find -regex ".*220811094830Z" -exec ls -al '{}' +
-rw------- 1 root root 930 Aug 11 09:48 ./pki/index.txt.220811094830Z
-rw-r--r-- 1 root root 330 Aug 11 09:48 ./tracked-serials-220811094830Z
root@host:~/easy-rsa/easyrsa3#
root@host:~/easy-rsa/easyrsa3# grep 220811094830Z pki/index.txt
R 241112062921Z 220811094830Z,cessationOfOperation AAABBBCCC7B1FE1723C1F663C2F59800 unknown /CN=client-a
R 241112064104Z 220811094830Z,cessationOfOperation A83EBCEE029D62C931D95FB51F381548 unknown /CN=client-b
R 241112105107Z 220811094830Z,cessationOfOperation 1B4FA7A3CEB1A7DA6CEB5C7EEDDE6152 unknown /CN=client-3
root@host:~/easy-rsa/easyrsa3#
root@host:~/easy-rsa/easyrsa3# ./easyrsa gen-crl
Using configuration from /root/easy-rsa/easyrsa3/pki/8c6e51af/temp.c7bcee00
root@host:~/easy-rsa/easyrsa3#
root@host:~/easy-rsa/easyrsa3# ./easyrsa show-crl | grep -A 4 AAABBBCCC7B1FE1723C1F663C2F59800
Serial Number: AAABBBCCC7B1FE1723C1F663C2F59800
Revocation Date: Aug 11 09:48:30 2022 GMT
CRL entry extensions:
X509v3 CRL Reason Code:
Cessation Of Operation
root@host:~/easy-rsa/easyrsa3#
For the record:
-
Version
3.1.xof Easy-RSArewind-renewmoves a certificate (etc) from therenewed/certs_by_serialfolder to therenewed/issuedfolder and names it back to itscommonName.This is done so that the certificate can then be revoked with
revoke-renewed commonName. -
The reason to
rewind-renewindividual certificates only is because: If a certificate has been renewed more than once the old way then a subsequent collision ofcommonNamewill occur, if all renewed certificates are rewound at the same time. -
This new mechanism does not allow for any certificate to be renewed more than one time, until the previous renewed certificate is revoked. This is a complete solution, which is considerably better than the old way.
-
Version
3.0.xof Easy-RSA can not revoke renewed certificates at all.
I will not consider any code to change this new method. If bugs are found then they can be fixed but that is all.
What to do with this one? I'm still not happy with the possibility having PKI's around that are not healthy but where easyrsa doesn't complain. I can think of an in-depth verify function where index.txt is verified with all certs in pki subfolders.
The solution is to back-port version 3.1 renew, revoke-renewed and rewind-renew to version 3.0. That would also include the *_move_*() and undo *_move_*() capabilities ..
I do not know what the plan is or even if a plan exists.
@ecrist Any comment ?
My answer is simple: Upgrade your easyrsa to version 3.1.1.