New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Certificate validation fails when the last certificate of the chain is signed by an expired CA (DST Root CA X3) #606
Comments
|
I assume that it is easy to reproduce this cert chain? In regards to scripts, There is #126 it has been said that the current scripts are not in a state that is suitable to be made public, but hopefully that has changed. |
Yes, any Let's Encrypt certificate deployed with
I'll see what I can do tomorrow.
If you have control over the server, I'd suggest switching to the shorter trust chain (for Line 54 in 1192edf
Or you could host your own copy of the cross-signed certificates but that requires significantly more work. |
With the Intermediate Certificates R3 it works, for a workaround. The fix will be:
|
|
I think in crosscert we may sign the
if we sign the |
|
I doubt the signature of the CA matters, if you dump the contents of the existing certificate, you'll see that the whole signature section is lost, only the modulus remains the same: diff -u <(openssl x509 -in isrg-root-x1-cross-signed.pem -noout -text) <(openssl x509 -in c92eb62f.1.der -inform der -noout -text)
--- /dev/fd/63 2022-03-03 10:55:18.633285391 +0100
+++ /dev/fd/62 2022-03-03 10:55:18.633285391 +0100
@@ -1,13 +1,12 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number:
- 40:01:77:21:37:d4:e9:42:b8:ee:76:aa:3c:64:0a:b7
+ Serial Number: 107880616886351 (0x621de9d9004f)
Signature Algorithm: sha256WithRSAEncryption
- Issuer: O = Digital Signature Trust Co., CN = DST Root CA X3
+ Issuer: C = GB, ST = Cambridgeshire, L = Cambridge, O = Fen Systems Ltd, OU = ipxe.org, CN = iPXE cross-signing CA
Validity
- Not Before: Jan 20 19:14:03 2021 GMT
- Not After : Sep 30 18:14:03 2024 GMT
+ Not Before: Mar 1 09:39:43 2022 GMT
+ Not After : May 30 09:39:43 2022 GMT
Subject: C = US, O = Internet Security Research Group, CN = ISRG Root X1
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
@@ -55,36 +54,14 @@
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
Authority Information Access:
- CA Issuers - URI:http://apps.identrust.com/roots/dstrootcax3.p7c
+ OCSP - URI:http://ocsp.ipxe.org/ocsp/cross/
- X509v3 Authority Key Identifier:
- keyid:C4:A7:B1:A4:7B:2C:71:FA:DB:E1:4B:90:75:FF:C4:15:60:85:89:10
-
- X509v3 Certificate Policies:
- Policy: 2.23.140.1.2.1
- Policy: 1.3.6.1.4.1.44947.1.1.1
- CPS: http://cps.root-x1.letsencrypt.org
-
- X509v3 CRL Distribution Points:
-
- Full Name:
- URI:http://crl.identrust.com/DSTROOTCAX3CRL.crl
-
- X509v3 Subject Key Identifier:
- 79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E
Signature Algorithm: sha256WithRSAEncryption
- 0a:73:00:6c:96:6e:ff:0e:52:d0:ae:dd:8c:e7:5a:06:ad:2f:
- a8:e3:8f:bf:c9:0a:03:15:50:c2:e5:6c:42:bb:6f:9b:f4:b4:
- 4f:c2:44:88:08:75:cc:eb:07:9b:14:62:6e:78:de:ec:27:ba:
- 39:5c:f5:a2:a1:6e:56:94:70:10:53:b1:bb:e4:af:d0:a2:c3:
- 2b:01:d4:96:f4:c5:20:35:33:f9:d8:61:36:e0:71:8d:b4:b8:
- b5:aa:82:45:95:c0:f2:a9:23:28:e7:d6:a1:cb:67:08:da:a0:
- 43:2c:aa:1b:93:1f:c9:de:f5:ab:69:5d:13:f5:5b:86:58:22:
- ca:4d:55:e4:70:67:6d:c2:57:c5:46:39:41:cf:8a:58:83:58:
- 6d:99:fe:57:e8:36:0e:f0:0e:23:aa:fd:88:97:d0:e3:5c:0e:
- 94:49:b5:b5:17:35:d2:2e:bf:4e:85:ef:18:e0:85:92:eb:06:
- 3b:6c:29:23:09:60:dc:45:02:4c:12:18:3b:e9:fb:0e:de:dc:
- 44:f8:58:98:ae:ea:bd:45:45:a1:88:5d:66:ca:fe:10:e9:6f:
- 82:c8:11:42:0d:fb:e9:ec:e3:86:00:de:9d:10:e3:38:fa:a4:
- 7d:b1:d8:e8:49:82:84:06:9b:2b:e8:6b:4f:01:0c:38:77:2e:
- f9:dd:e7:39
+ 96:a6:19:ea:17:99:e4:5d:12:c3:d7:95:15:96:36:70:0b:e8:
+ a3:ed:d7:16:8f:44:7b:64:03:e7:3f:3a:11:8e:bd:c6:cf:e0:
+ 05:38:d1:25:02:8e:61:af:e4:15:7c:53:dc:eb:8b:7c:c6:fd:
+ af:d5:c1:3a:4f:85:c4:f6:fc:ff:27:b2:5f:54:bb:a0:8d:ba:
+ e4:f8:b0:4b:f5:48:5b:ac:e9:92:2c:9e:ac:1a:40:c1:b6:6d:
+ 5a:93:57:32:e4:1b:e4:e7:c0:43:2f:7a:08:f9:de:ba:c7:63:
+ 5c:f2:14:95:3d:1b:9e:97:d8:67:b2:0a:85:67:a4:77:af:54:
+ f8:2bWhere #!/usr/bin/env python3
import argparse
import pathlib
import subprocess
import sys
import pyasn1
from pyasn1.codec.der import decoder
from pyasn1.codec.der import encoder
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("der", type=pathlib.Path, help="iPXE cross-signed DER file", nargs="+")
parser.add_argument("-w", "--write", help="write individual DER files that make up the input DER file", action="store_true", default=False)
args = parser.parse_args()
for der in args.der:
with der.open("rb") as f:
data = decoder.decode(f.read())
for element in data:
if isinstance(element, pyasn1.type.univ.SetOf):
for index, set_element in enumerate(element, start=1):
out_name = der.with_suffix(f".{index}.der")
encoded = encoder.encode(set_element)
if args.write:
with out_name.open("wb") as f:
f.write(encoded)
saved = f", saved as {out_name}" if args.write else ""
print(f"Set element {index} from {der}{saved}:")
# subprocess seems to use unbuffered output, we want our print to appear
# before openssl's output
sys.stdout.flush()
subprocess.run(["openssl", "x509", "-inform", "der", "-noout", "-text"], input=encoded)
breakAlso the example command from the documentation expects a self-signed certificate: |
Please try the following script: |
This comment was marked as abuse.
This comment was marked as abuse.
|
@stappersg I'm not sure what your test does. $ curl -sSL https://downloads.sourceforge.net/project/refind/0.13.2/refind-bin-0.13.2.zip | bsdtar Oxf - refind-bin-0.13.2/refind/refind_x64.efi | sha512sum
79d9bca3fff15b219eabe66b82d0f46e4b0d980913ad94e0d09d0fffbe1bf5fe1eb4e64e15cf9f84fb87302cf244534337ec29b9e920a468ee03c1843e2f9a96 -
$ curl -sS https://sbraz.xyz/refind/refind_x64.efi | sha512sum
79d9bca3fff15b219eabe66b82d0f46e4b0d980913ad94e0d09d0fffbe1bf5fe1eb4e64e15cf9f84fb87302cf244534337ec29b9e920a468ee03c1843e2f9a96 -And I found another way of dumping the #!/bin/bash
while getopts "w" opt; do
case "$opt" in
w)
write=1
;;
?)
exit 1
;;
esac
done
shift $((OPTIND -1))
for certificate in "${@}"; do
# Find offset of all elements at depth 1
openssl asn1parse -inform der -in "$certificate" | sed -En 's/^\s+([0-9]+):d=1\s.*/\1/p' | nl | while read index offset; do
echo "Set element $index from $certificate:"
command=(openssl asn1parse -inform der -in "$certificate" -strparse "$offset" -noout -out)
"${command[@]}" - | openssl x509 -inform der -noout -text
if [[ "$write" ]]; then
"${command[@]}" "${certificate%.der}.$index.der"
fi
done
done |
|
I can also confirm this issue. This is a picture of the failed ipxe boot with error https://ipxe.org/0216e43c (I rebuilt my ipxe payloads with DEBUG=x509) For reference, my certificate chain is: Which matches @sbraz. I can also confirm @sbraz sugestion of using This website is also a nice tool to check if you have the If you can't change your https server, a workaround that I also tried, but is quite extreme. I removed the expiration check in |
|
Fastly uses the For me, it was easier to rebuild ipxe than to stand up a custom host with the "right" front-end certificate. I used the I was surprised to learn the fingerprint is different between the self-signed cert (https://letsencrypt.org/certs/isrgrootx1.pem) and the cross-signed cert (https://letsencrypt.org/certs/lets-encrypt-r3.pem). I would've though the fingerprint would depend only on modulus, and thus be the same for both certificates, but that's not the case. LetsEncrypt's announcement about this says that older Android devices will continue to reference the |
This is definitely still an issue for LetsEncrypt certificates. The linked workaround still works, but it would be good to get this properly fixed. For completeness, output from a build with the workaround applied |
This comment was marked as outdated.
This comment was marked as outdated.
Manually built from 1d1cf74 |
That is current git master, and matching your output from working test? If so it is already properly fixed? |
Both are builds of current git master (at least at time of filing.) The first, with the connection failure, was built with The second, so called "working test" was using the workaround from the intentionally linked #606 (comment) : I suppose I have worded #606 (comment) a bit more clearly / could have been explicit about exactly what I tried since this is an older bug. To summarize: The bug as initially reported still seems to exist. Is everything clearer now? |


Hi,
It looks like iPXE behaves like older OpenSSL versions when encountering an expired CA at the end of a chain of trust.
When it attempts to download an image from a server with this chain (which I believe is still Let's Encrypt's default because of Android devices), it will fail:
I would expect iPXE to check that the
R3certificate was signed by a trusted authority (theX1CA is present in the official list of cross-signed certificate asc92eb62f.der) and therefore consider that the chain is valid.Instead, it downloads the cross-signed
X3CA (0e4aff85.der, which was last cross-signed on 2021-12-01 and expired on 2022-03-01) and fails validation.Logs:
As a side note, would it be possible to publish the scripts used to create the cross-signed
DERfiles? The documentation does not mention the fact that ASN.1 sets are used.I eventually found a way to dump the
DERfiles thanks to an old ML thread but a similar question had been left unanswered on the forums.The text was updated successfully, but these errors were encountered: