Page MenuHome GnuPG

WKD fail: gpg/dimngr fails to retrieve public key
Open, NormalPublic

Description

Tests run on arch linux:
The following fails to get public key via WKD:

gpg -v --auto-key-locate clear,wkd,nodefault --locate-external-keys arch@sapience.com
gpg: error retrieving 'arch@sapience.com' via WKD: Network error

Turning on logging for dirnmgr shows:

DBG: Using TLS library: GNUTLS 3.8.3
detected interfaces: IPv4 IPv6
DBG: http.c:connect_server: trying name='openpgpkey.sapience.com' port=443
DBG: dns: resolve_dns_name(openpgpkey.sapience.com): Success
DBG: http.c:2899:socket_new: object 0x00007f235401fc40 for fd 7 created
TLS handshake failed: Illegal parameter (alert 47)
error connecting to 'https://openpgpkey.sapience.com/.well-known/openpgpkey/sapience.com/hu/me5xnfhbf3w9djpmxa3keq5q8s3rcgf1?l=arch': Network error
command 'WKD_GET' failed: Network error <Unspecified source>

While on same machine manually pulling the file given in log succeeds just fine:

curl https://openpgpkey.sapience.com/.well-known/openpgpkey/sapience.com/hu/me5xnfhbf3w9djpmxa3keq5q8s3rcgf1?l=arch -o xxx

And indeed this is valid public key:

file xxx
xxx: OpenPGP Public Key Version 4...

Check using sequoia works fine:

sq wkd get arch@sapience.com

Importing 1 certificate into the certificate store:

  1. 7CCA1BA66669F3273DB52678E5B81343AB9809E1 ...

Details

Version
2.4.4

Event Timeline

It looks like a failure of GnuTLS negotiation.

$ wget --server-response --spider https://openpgpkey.sapience.com/.well-known/openpgpkey/sapience.com/hu/me5xnfhbf3w9djpmxa3keq5q8s3rcgf1?l=arch 
Spider mode enabled. Check if remote file exists.
--2024-01-29 11:35:15--  https://openpgpkey.sapience.com/.well-known/openpgpkey/sapience.com/hu/me5xnfhbf3w9djpmxa3keq5q8s3rcgf1?l=arch
Resolving openpgpkey.sapience.com (openpgpkey.sapience.com)... 72.84.236.69
Connecting to openpgpkey.sapience.com (openpgpkey.sapience.com)|72.84.236.69|:443... connected.
GnuTLS: A TLS fatal alert has been received.
GnuTLS: received alert [47]: Illegal parameter
Unable to establish SSL connection.

Here is what I observe:

Client sends Client Hello, specifying TLS 1.0.
Server sends back Hello Retry Request with version TLS 1.3 specified. IIUC, it is a request to change to TLS 1.3.
Server sends also Change Cipher Spec with version TLS 1.2. IIUC, this might contradict version specified in the Hello Retry Request.
Client sends Client Hello with TLS 1.2.
Server sends Fatal Alert. (Possibly, it expects TLS 1.3 version in client's Client Hello.)

After the original fail - one of the things I tried was changing nginx server to allow TLSv1.2:

ssl_protocols to TLSv1.2 TLSv1.3 ;

But it didn't help and still failed. I forgot to set it back to TLSv1.3 only. Its now set to 1.3 only again.

Sorry if that muddied waters.

Please configure your server so that an application with GnuTLS can interoperate. It is not GnuPG specific.

In my testing, I don't see any problem on client side.

I can do correct handshake with GnuTLS, if specified.

$  gnutls-cli --verbose --port=443 --priority=SECURE192 openpgpkey.sapience.com

The command line above works. But following (or no --priority option) fails.

$ gnutls-cli --verbose --port=443 --priority=SECURE128 openpgpkey.sapience.com
Processed 140 CA certificate(s).
Resolving 'openpgpkey.sapience.com:443'...
Connecting to '72.84.236.69:443'...
*** Fatal error: A TLS fatal alert has been received.
*** Received alert [47]: Illegal parameter

Thanks for taking time to look into this. You have clearly identified the issue.

If I understand correctly, the client tests confirm that all is fine as long as the connection is sufficiently secure (above "128" bits" ).

gpg , when fetching WKD, is unable to negotiate when server uses TLSv1.3 (or TLSv1.2) which requires connection be too secure?

Can you suggest what gpg compatible settings for server might be or do you think gpg should be able to work with servers set to use TLSv1.3?

Thank you again.

AFAIK, we don't have any option to control the lower-level detail of GnuTLS for dirmngr of GnuPG.

I also test with OpenSSL (the version 3.0.9-1 on Debian). With TLS1.3 only setting, it works for me.

What I did:

(1) Create self-signed certificate of secp384r1 for testing (I use Common Name = ex.gniibe.org).

$ openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-384 -noenc -keyout key.pem -out cert.pem -days 365

(2) Run the server with secp384r1 TLS1.3 only

$ openssl s_server -key privkey.pem -cert cert.pem -accept 8080 -www -ciphersuites TLS_AES_256_GCM_SHA384 -security_debug_verbose -tlsextdebug -named_curve secp384r1 -tls1_3

(3) Connect the server by GnuTLS

$ gnutls-cli --verbose --port=8080 --no-ca-verification localhost

The gnutls-cli says:

- Description: (TLS1.3-X.509)-(ECDHE-SECP384R1)-(ECDSA-SECP384R1-SHA384)-(AES-256-GCM)
- Session ID: EE:ED:7C:27:26:AB:29:13:45:44:D1:98:C0:F6:E8:50:EB:C7:CD:6C:29:AC:26:F8:80:3E:52:84:CC:97:73:9A
- Ephemeral EC Diffie-Hellman parameters
 - Using curve: SECP384R1
 - Curve size: 384 bits
- Version: TLS1.3
- Server Signature: ECDSA-SECP384R1-SHA384
- Cipher: AES-256-GCM
- MAC: AEAD
- Options:
- Channel bindings
 - 'tls-unique': not available
 - 'tls-server-end-point': 436b2f031b63b3538d88f1ee8bfc925f1a4ac5ac715ab2a0b75dc702808e403e
 - 'tls-exporter': 91dbb4ab8b77ee4b7f24704af703eb7c1c4622623875b34616ae3e8806879a2d
- Handshake was completed

- Simple Client Mode:

That is, handshake success.

So, I think that it is possible to configure a server with TLS1.3 only which can inter-operate normal configuration of GnuTLS client.

Server is nginx with the following settings

ssl_protocols TLSv1.3 ;
ssl_prefer_server_ciphers off;
http3 on;
http2 on; 
quic_retry on;        
ssl_early_data off;

I have tried with prefer_server_ciphers on and off - makes no difference to gpg.
The cipher in your test is one of the 3 standard TLSv1.3 ones and is available on webserver.

sq continues to work either way - curl works, browser works. Only gpg fails.
ssllabs test is A with the only miss being the 1.3 cipher TLS_AES_128_GCM_SHA256 being deemed weak due its "128" bits.

My apologies but not sure what else to try - thanks for all your help.

I'm afraid that your particular configuration would cause the problem of the negotiation.

I can't replicate the failure by my environment with nginx. I did with following settings (I tried to interpret your preferences, limiting the curve in use):

##                                                                                                                                                                                                
# SSL Settings                                                                                                                                                                                    
##                                                                                                                                                                                                
                                                                                                           
ssl_protocols TLSv1.3;
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384;
ssl_ciphers SUITEB192;
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on;

(No other settings in openssl.cnf)

And it works well with GnuTLS library.

Actually, I can't find a way to remove TLS_AES_128_GCM_SHA256 cipher for OpenSSL, so I added limiting the curve.

It should not be removed as I believe it is required to be compliant:

RFC-8446

Thanks for all the help @gniibe.

The following nginx config seems to now work fine with gpg :

ssl_ecdh_curve secp384r1:X25519;
ssl_protocols TLSv1.3 ;
ssl_session_tickets off;
ssl_prefer_server_ciphers on;
http3 on;
http2 on; 
quic_retry on;        
ssl_early_data off;
gc100 claimed this task.

Fixed by changing server as noted above.

An update FYI

The hacky workarounds only lasted a while and problem came back.
As before both curl and sq work fine - its only gpg that fails. So sure seems like something
is not right with gnupg and wkd.

These Work fine:

  curl https://openpgpkey.sapience.com/.well-known/openpgpkey/sapience.com/hu/me5xnfhbf3w9djpmxa3keq5q8s3rcgf1?l=arch -o xxx

  sq network wkd fetch arch@sapience.com

Browsers work fine using same URL as well.

But this Fails:

gpg --no-default-keyring --keyring /tmp/gpg-$$ --auto-key-locate clear,wkd,nodefault --locate-keys arch@sapience.com
gpg: error retrieving 'arch@sapience.com' via WKD: Network error

nginx settings are same as above