gpg-agent/scdaemon/gnuk unable to sign ssh certificate (Couldn't certify key … via agent: agent refused operation)
Testing, NormalPublic

Description

I tried to use Gnuk (Nitrokey Start) keychain with Ed25519/Cv25519 keys to secure SSH setup using gpg-agent's --enable-ssh-support option to let it talk the ssh-agent protocol with ssh and ssh-keygen.
This works very well for signing authentication tokens (ssh public key authentication) but it turns out signing anything larger than 255 bytes fails.
This results in ssh-keygen -U … invocation failing with:

Couldn't certify key ssh_host_ed25519_key.pub via agent: agent refused operation

I traced down the passing of payload to be signed through gpg-agent to scdaemon:

< SETDATA <hex-payload>
> OK
< PKAUTH  OPENPGP.3
> scdaemon[14551]: app_auth failed: Invalid value
> ERR 100663351 Invalid value <SCD>
< RESTART

and further down to iso7816_internal_authenticate() and apdu_send_le() in scdaemon itself.
What I find baffling is that the payload is at not point hashed (SSH Ed25519 uses SHA-512 pre-hash as per rfc8709) so it seems it's sent to the keycard in full.
Furthermore PKAUTH command isn't documented in Scdaemon manual's protocol section.
Since GPG can generally sign larger amounts of data I suspect this issue is due to gpg-agent or scdaemon mishandling the card rather than inherent limitation of Gnuk tokens.
Specifically I think it should be possible to pre-hash the payload in gpg-agent and ask smartcard to use signature version without pre-hash. (I haven't been able to find OpenPGP SmartCard specification covering Ed25519 to ascertain that is the case though.)

Details

Version
gpg (GnuPG) 2.2.17 / libgcrypt 1.8.4

Related Objects

ccx created this task.Tue, Sep 1, 1:51 PM
ccx updated the task description. (Show Details)Tue, Sep 1, 2:20 PM
werner added a project: ssh.Tue, Sep 1, 2:47 PM
werner added a subscriber: werner.

gpg-agent has only very limited support for ssh certificates which is the reason that your command fails.

Why did you mention OpenSC? It is not related or used by GnuPG.

I would also suggest to take your questions to the gnupg-users mailing list so that you can get input from other users.
Bug reports are rarely read by a wider audience.

Mikaela added a subscriber: Mikaela.Tue, Sep 1, 3:58 PM
ccx added a comment.Tue, Sep 1, 4:23 PM

I've meant scdaemon rather than OpenSC. I'll correct the descritpion.

This issue is unrelated to any certificate support in gpg-agent - that is keypairs with associated certificates being made available via ssh-agent protocol.
This issue is about using ssh-agent signing with "regular" keypair (as opposed to one with attached certificate) when the data to be signed is itself a certificate.
I believe it just happens that signing of certificates using ssh-keygen's switch to use ssh-agent (all certificate-handling code residing in OpenSSH's ssh-keygen) exceeds some size limit in the keychain setup, while it works correctly with regular ssh-agent from OpenSSH with private key in memory.

What gpg-agent receives via the ssh-agent protocol is just data blob to sign, as per https://tools.ietf.org/html/draft-miller-ssh-agent-04#section-4.5 and does not require any support of certificates on side of gpg-agent.
Sorry for the confusion.

ccx updated the task description. (Show Details)Tue, Sep 1, 4:24 PM
gniibe added a subscriber: gniibe.Wed, Sep 2, 5:11 AM

Please show us concrete example of debug output by scdaemon, when you run ssh-keygen.
You can have a setup in .gnupg/scdaemon.conf like:

debug-level guru
debug-all
verbose
verbose
verbose
log-file /run/user/1000/scd.log

Please note that your PIN interaction is also recorded in the debug output. It's good if you just use factory setting passphrase, not the real one in use, so that exposure of PIN information doesn't matter.

gniibe added a comment.EditedWed, Sep 2, 5:40 AM

I just confirmed that Gnuk has a limitation for the input length is less than or equals to 256.
So, this is the issue of Gnuk, not GnuPG (or at least, Gnuk has the problem).

gniibe claimed this task.Wed, Sep 2, 5:42 AM
gniibe added a comment.Thu, Sep 3, 3:14 AM

Well, from the viewpoint of card specification, "a message M of arbitrary size" for Ed25519/Ed448 in RFC8032 is not good, because card has a limit for buffer size and the protocol in the OpenPGP card specification requires the steps of (1) the message M is buffered and then (2) the compute the signature.

I'm curious that how large is your message to be signed?

In OpenPGP and normal SSH signing, the length of message M is small (For OpenPGP, because it is prehashed).

ccx added a comment.Thu, Sep 3, 5:14 PM

In case of Ed25519 certificate signed by Ed25519 key with only few names and flags it seems to be just below 500 bytes. This could of course grow if names are added or larger public key is being signed.

The requirement of OpenPGP card specification to buffer and hash sounds weird to me. But then I'm not a cryptologist. Without that it could just feed the incoming data to the SHA-512 function as it receives them without any buffer overhead, as long as it can keep up computationally.

On the other hand I don't see a reason to invoke a version of the signing algorithm that does hashing on the OpenPGP card if one that uses identity function instead is available. I assume that's what PGP uses for signing it's data.

Is the debug dump still useful? I can get a device to make one but it seems the cause has been identified.

gniibe added a comment.EditedFri, Sep 4, 1:53 AM

Thanks for your information. No debug output any more, as I already figured out things.

In the process of hashing (when PH function does nothing, the case of Ed25519), private key information is required. That is, it can be only done the card side (not host side). See RFC 8032.

Anyway, I fixed Gnuk. In next release, it will be fixed.

When Ed448 signing will be implemented to OpenSSH, it would be good to use Ed448ph, so that we can avoid "a message M of arbitrary size" will be passed to device.

gniibe triaged this task as Normal priority.Fri, Sep 11, 2:19 AM
gniibe changed the task status from Open to Testing.

Fixed in Gnuk 1.2.16, although it still has a limitation by the I/O buffer size.