Page MenuHome GnuPG

gpgme X.509 certificates have unknown validity in offline mode unless `disable-crl-checks` is set
Open, LowPublic

Description


This simple test program sets a CMS gpgme context into offline mode then tries to learn the validity of the identity of alice.crt, based on trusting ca.crt (certs are from the LAMPS sample certificates.

Despite explicitly asking for offline mode and certificate validation, the certificate validity check fails unless the user has manually set disable-crl-checks in gpgsm.conf.

Here is a transcript of me testing without disable-crl-checks and then with disable-crl-checks. Note that the validity goes from UNKNOWN to FULL:

0 $ make
gcc -O2 -g -Wall -Werror -pedantic -o test test.c -lgpgme -lassuan -lgpg-error
echo "4D:E0:FF:63:C0:E9:EC:01:29:11:C8:7A:EE:DA:3A:9A:7F:6E:C1:0D S relax" > ghome/trustlist.txt
gpgsm --import ca.crt
gpgsm: total number processed: 1
gpgsm:              unchanged: 1
gpgsm --import alice.crt
gpgsm: total number processed: 1
gpgsm:              unchanged: 1
printf disable-crl-checks:16: | gpgconf --change-options gpgsm
gpgsm:S/MIME:/usr/bin/gpgsm:1:1:
./test
version: 1.13.1-unknown
validity: UNKNOWN
    name: 
   email: 
  userid: CN=Alice Lovelace
validity: UNKNOWN
    name: 
   email: <alice@smime.example>
  userid: <alice@smime.example>
printf disable-crl-checks::1 | gpgconf --change-options gpgsm
gpgsm:S/MIME:/usr/bin/gpgsm:1:1:
./test
version: 1.13.1-unknown
validity: FULL
    name: 
   email: 
  userid: CN=Alice Lovelace
validity: FULL
    name: 
   email: <alice@smime.example>
  userid: <alice@smime.example>
0 $

I'm testing this with gpgsm 2.2.19.

(this was the original bug i was trying to track down when i filed T4881, as it is getting in the way of a robust test suite for notmuch to handle S/MIME (via GMime's wrapper around gpgme))

Details

Version
1.13.1

Event Timeline

werner added a subscriber: werner.

I can see no bug here. See my comment over at T4881.

I think what you're saying that there is *no way* to use GPGME in offline mode to validate x.509 certificates, and this is by design. Am I understanding that right?

As far as i can tell, there is no way to set disable-crl-checks via GPGME itself.

The conclusion i draw from this is that any user of GPGME who wants to use offline mode should also (outside of the GPGME API) fiddle with gpgsm.conf manually. Is that the intent?

I would have thought that gpgme_set_offline (ctx, 1); would make it clear that CRL checks and OCSP checks were to be disabled.

That option does the same as --disable-dirmngr which in trun has the same effect as disable-crl-checks; see gnupg/sm/server.c#option_handler. If you want to check the validity of the cert you check the TRUST status lines. This is what gpgme does for you. An example is gpgme.tests/gpgsm/t-verify. You can run the tests also manually, I do this as follows:

First I always use a little script to make things easy (~/bin/gnupg.setup-tests):

#!/bin/sh
SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
export SSH_AUTH_SOCK
cat >setup-tests.ini <<'EOF'
PS1="$(echo "$PS1" | sed 's,\\\$ $,(GnuPGTest)\\\$ ,')"
export HISTCONTROL=ignoreboth
export HISTFILE=$(pwd)/.bash_history
EOF
exec bash --init-file setup-tests.ini

I usually create then empty test directories but in this case I use the tests/gpgsm directory.

After cd-ing to the test dir, I start an agent:

GNUPGHOME=`pwd` gpg-agent --daemon ~/bin/gnupg-setup-tests

and now I have an interactive environment. If you ever ran the test before you should already have a gpgsm.conf in the test directory:

#disable-crl-checks
faked-system-time 1008241200
agent-program /usr/local/bin/gpg-agent|--debug-quick-random

Here I commented the disable-crl-checks; the agent-program thing is not used here becuase we already have an agent running. The signature taken from t-verify is

-----BEGIN CMS OBJECT-----
MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAA
MYIBOTCCATUCAQEwcDBrMQswCQYDVQQGEwJERTETMBEGA1UEBxQKRPxzc2VsZG9y
ZjEWMBQGA1UEChMNZzEwIENvZGUgR21iSDEZMBcGA1UECxMQQWVneXB0ZW4gUHJv
amVjdDEUMBIGA1UEAxMLdGVzdCBjZXJ0IDECAQAwBwYFKw4DAhqgJTAjBgkqhkiG
9w0BCQQxFgQU7FC/ibH3lC9GE24RJJxa8zqP7wEwCwYJKoZIhvcNAQEBBIGAA3oC
DUmKERmD1eoJYFw38y/qnncS/6ZPjWINDIphZeK8mzAANpvpIaRPf3sNBznb89QF
mRgCXIWcjlHT0DTRLBf192Ve22IyKH00L52CqFsSN3a2sajqRUlXH8RY2D+Al71e
MYdRclgjObCcoilA8fZ13VR4DiMJVFCxJL4qVWI=
-----END CMS OBJECT-----

call it x.sig. Use

echo Hallo Leute! >x.data

to create the data file. Now we can run the test:

$ ../run-verify --cms --status --verbose x.sig x.data
status_cb: NEWSIG 
status_cb: GOODSIG 3CF405464F66ED4A7DF45BBDD1E4282E33BDB76E /CN=test cert 1/OU=Aegypten Project/O=g10 Code GmbH/L=D%C3%BCsseldorf/C=DE
status_cb: VALIDSIG 3CF405464F66ED4A7DF45BBDD1E4282E33BDB76E none 0 20021203T093638 0 0 1 2 00
status_cb: TRUST_UNDEFINED 115
Original file name .: [none]
MIME flag ..........: no
Signature ...: 0
  status ....: Success
  summary ...:
  fingerprint: 3CF405464F66ED4A7DF45BBDD1E4282E33BDB76E
  created ...: 0
  expires ...: 1038908198
  validity ..: unknown
  val.reason : Success
  pubkey algo: 1 (RSA)
  digest algo: 2 (SHA1)
  pka address: [none]
  pka trust .: n/a
  other flags:

What we get is the expected outcome due to the missing CRL. After disabling the CRL check again in gpgsm.conf we see

$ ../run-verify --cms --status --verbose x.sig x.data
status_cb: NEWSIG 
status_cb: GOODSIG 3CF405464F66ED4A7DF45BBDD1E4282E33BDB76E /CN=test cert 1/OU=Aegypten Project/O=g10 Code GmbH/L=D%C3%BCsseldorf/C=DE
status_cb: VALIDSIG 3CF405464F66ED4A7DF45BBDD1E4282E33BDB76E none 0 20021203T093638 0 0 1 2 00
status_cb: TRUST_UNDEFINED 115
Original file name .: [none]
MIME flag ..........: no
Signature ...: 0
  status ....: Success
  summary ...:
  fingerprint: 3CF405464F66ED4A7DF45BBDD1E4282E33BDB76E
  created ...: 0
  expires ...: 1038908198
  validity ..: unknown
  val.reason : Success
  pubkey algo: 1 (RSA)
  digest algo: 2 (SHA1)
  pka address: [none]
  pka trust .: n/a
  other flags:

Which shows that disable-crl-checks does what you expected. I don't known why it did not worked for you but by using the run-verify program you should have an easy way to debug this.

I see no difference between the last two example stanzas that show you running ../run-verify. Are they supposed to have different output?

After disabling the CRL check again in gpgsm.conf

Which means that I edited gpgsm.conf and renmove the comment before disable-crl-checks.

Hi,

I think what you're saying that there is *no way* to use GPGME in offline mode to validate x.509 certificates, and this is by design. Am I understanding that right?

so Kleopatra does it in the way that it uses "GPGME_KEYLIST_MODE_VALIDATE" with the offline flag set for the initial keylisting.
This takes a while but afterwards Kleoaptra has a "decent idea" of the validity of the certificates and no online / crl checks are done.

Only when the certificate is going to be used or when it is opened in the certificate details it does an online check.

I think that you are just missing the "--with-validation" or KEYLIST_MODE_VALIDATE to get the results that you would expect. Otherwise the trust is indeed unknown.

@werner wrote:

If you want to check the validity of the cert you check the TRUST status lines

and then in both examples (which show identical runs), we see:

status_cb: TRUST_UNDEFINED 115

So this seems to be saying that regardless of whether you set disable-crl-checks, the certificate is *never* validated. While this is indeed consistent, this is not what I want. I want to be able to actually validate a certificate that i should be able to validate. And I want to be able to validate it in an offline context.

@aheinecke wrote:

so Kleopatra does it in the way that it uses "GPGME_KEYLIST_MODE_VALIDATE" with the offline flag set for the initial keylisting.
This takes a while but afterwards Kleoaptra has a "decent idea" of the validity of the certificates and no online / crl checks are done.

If you read test.c (attached in the initial bug report), you can see:

gpgme_set_offline (ctx, offline);
gtry (gpgme_set_keylist_mode (ctx, gpgme_get_keylist_mode (ctx) | GPGME_KEYLIST_MODE_VALIDATE));

gtry (gpgme_get_key (ctx, fpr, &key, secret));

So i think i'm doing the same thing that you are proposing, no? The only think i can see that's different from the GpgOL code (thanks for the pointer!) is that i'm modifying the existing keylist mode while GpgOL is explicitly setting it to local | validate (this goes against the manual guidance about "future binary compatibility", but whatever). I tried changing test.c to just use GPGME_KEYLIST_MODE_VALIDATE | GPGME_KEYLIST_MODE_VALIDATE instead, and i got the same results, though ☹.

As you can see in my demonstration in the initial report, the validity is always "unknown" unless i explicitly set disable-crl-checks in gpgsm.conf.

Do you expect the test.c example to be able to determine that the alice cert is valid without setting disable-crl-checks in gpgsm.conf ?

(also, I really don't understand what "This takes a while" means -- is there some additional latency induced by *not* querying the network? Or do you mean that verifying the signatures takes a while?)

Is there some sort of caching that i need to be aware of in order to use this API properly? If so, how do I manage that cache?

That option does the same as --disable-dirmngr which in trun has the same effect as disable-crl-checks

I think "That option" is intended to refer to gpgme_set_offline (ctx, 1);. Is that right?

I believe the initial bug report demonstrates that gpgme_set_offline is *not* the same effect as disable-crl-checks. In particular, the same code produces different results depending on the setting of disable-crl-checks. When disable-crl-checks is set, the certificate's validity is FULL. When disable-crl-checks is not set, the certificate's validity is UNKNOWN.