Page MenuHome GnuPG

gpgsm fails to find path to valid X.509 root when cross-signed intermediate certificate is present
Open, NormalPublic

Description

When an intermediate certificate is available in the keyring, gpgsm tries to use it for path finding, even if a shorter path to a root cert is available. This causes signature validation failure.

This demonstration uses certificates from draft-ietf-lamps-samples-04, plus a novel cross-certifying CA.

If we assign the sample RSA CA (ca.rsa.crt) as a valid root authority, then the verification of a PKCS#7 signedData object succeeds (TRUST_FULLY).

If we then *also* load the cross-signed intermediate (ca.rsa.cross2.crt) into the homedir, then verification of the same signedData object will fail with invalid certification chain: Missing issuer certificate (TRUST_UNDEFINED 185).

Here's the reproducer:

workdir=$(mktemp -d)
mkdir -m 0700 "$workdir/gpg"
export GNUPGHOME="$workdir/gpg"
echo C4:C7:D3:DF:10:C5:C9:F8:D2:34:1D:8C:69:B7:30:D6:EB:BE:9E:DD S relax > "$workdir/gpg/trustlist.txt"
gpgsm --import ca.rsa.crt
gpgsm --verify --status-fd 3 3>without-intermediate-cert.status <signed-data.p7
gpgsm --import ca.rsa.cross2.crt
gpgsm --verify --status-fd 3 3>with-intermediate-cert.status <signed-data.p7

The different status descriptions look like:

$ head -v *.status
==> with-intermediate.status <==
[GNUPG:] NEWSIG
[GNUPG:] VERIFICATION_COMPLIANCE_MODE 23
[GNUPG:] GOODSIG 32933B035357A3D852DB338B1F27DA2405548976 /CN=Alice Lovelace/OU=LAMPS WG/O=IETF
[GNUPG:] VALIDSIG 32933B035357A3D852DB338B1F27DA2405548976 2021-02-20 20210220T150102 20520927T065418 0 0 1 8 00
[GNUPG:] TRUST_UNDEFINED 185

==> without-intermediate.status <==
[GNUPG:] NEWSIG
[GNUPG:] VERIFICATION_COMPLIANCE_MODE 23
[GNUPG:] GOODSIG 32933B035357A3D852DB338B1F27DA2405548976 /CN=Alice Lovelace/OU=LAMPS WG/O=IETF
[GNUPG:] VALIDSIG 32933B035357A3D852DB338B1F27DA2405548976 2021-02-20 20210220T150102 20520927T065418 0 0 1 8 00
[GNUPG:] TRUST_FULLY 0 shell
$

Note that ca.rsa.crt and ca.rsa.cross2.crt share the same subject key. But ca.rsa.crt is a self-signed root, and ca.rsa.cross2.crt is cross-signed by a different CA. As the draft explains, the signing key can be validated against two root CA certs, either directly by the issuing authority:

╔════════════╗  ┌────────────────┐
║ ca.rsa.crt ╟─→│ alice.sign.crt │
╚════════════╝  └────────────────┘

Or by a cross-signed intermediate CA certificate:

╔═════════════╗  ┌───────────────────┐  ┌────────────────┐
║ ca.rsa2.crt ╟─→│ ca.rsa.cross2.crt ├─→│ alice.sign.crt │
╚═════════════╝  └───────────────────┘  └────────────────┘

In the reproducer above, ca.rsa2.crt is unknown to gpgsm, but the mere presence of ca.rsa.cross2.crt in the keyring prevents successful signature validation.

gpgsm should not consider a signature less valid just because it knows of an unusable cross-signed intermediate CA certificate.




(edited to simplify the steps to reproduce; edited again to avoid bringing ed25519 into the mix)

Details

Version
2.2.27

Event Timeline

dkg renamed this task from gpgsm fails to find shortest certificate path to valid X.509 root to gpgsm fails to find path to valid X.509 root when cross-signed intermediate certificate is present.May 21 2021, 3:08 AM
dkg updated the task description. (Show Details)
dkg updated the task description. (Show Details)
dkg updated the task description. (Show Details)
dkg updated the task description. (Show Details)
dkg updated the task description. (Show Details)
werner triaged this task as Normal priority.May 25 2021, 9:45 AM
werner added a subscriber: werner.

I do not have the time to analyse this in the context of our approved versions and to compare it to the NIST test suite. We also do not yet have support for ed25519 certificates.

Which NIST test suite are you referring to? It might not cover certificate pathfinding in the face of multiple cross-signed authorities.

I don't think you need any ed25519 certificates to replicate the problem. If it would help, i can probably replicate it with a cross-signed RSA-based intermediate CA certificate. let me know if that would be useful.

OK, i have replicated this successfully with no ed25519 involved. here's the new intermediate cert:

I'll update the task description to show the same problem, but with no mention of ed25519. This issue tries to document gpgsm's pathfinding failure, not anything related to unimplemented algorithms.

dkg updated the task description. (Show Details)

Attached is an even worse PKCS7 blob, that should be validatable given reliance on ca.rsa.crt, but it will be rejected by gpgsm because the PKCS#7 bundle includes ca.rsa.cross2.crt in it.

By comparison, certtool from GnuTLS can validate it against ca.rsa.crt:

$ certtool --load-ca-certificate ca.rsa.crt --p7-verify --p7-show-data --inder < signed-data-worse.p7
Loaded CAs (1 available)
eContent Type: 1.2.840.113549.1.7.1
Signers:
	Signer's issuer DN: CN=Sample LAMPS RSA Certification Authority,OU=LAMPS WG,O=IETF
	Signer's serial: 37410579ed757f42a9a25c3af4f86ace9aa9d7
	Signing time: Tue May 25 21:41:11 UTC 2021
	Signature Algorithm: RSA-SHA256

	Signature status: ok
$

and NSS's utilities also validate it successfully:

$ mkdir -m 0700 nss
$ certutil -d sql:nss -A  -n rsaca -t ,C, < ca.rsa.crt 
$ p7content -d sql:nss < signed-data-worse.p7 
Content printed between bars (newline added before second bar):
---------------------------------------------
hi there

---------------------------------------------
Content was not encrypted.
Signature is valid.
The signer's common name is Alice Lovelace
The signer's email address is alice@smime.example
Signing time: Tue May 25 21:41:11 2021
There were certs or crls included.
$