I basically followed the notes on PIV in the manual page of gpg-card except that I generated a nistp256 key instead of an rsa2048 key for the digital signature key, i.e. PIV.9C.
gpg/card> generate --force --algo=nistp256 PIV.9C PIV card no. yk-9074582 detected gpg/card> list Reader ...........: 1050:0407:X:0 Card type ........: yubikey Card firmware ....: 5.1.2 Serial number ....: FF020001008A7796 Application type .: PIV Version ..........: 1.0 Displayed s/n ....: yk-9074582 PIN usage policy .: app-pin PIN retry counter : - [verified] - [?] PIV authentication: EB6A99D61EF3BC7C7934173CD9833376D773E65D keyref .....: PIV.9A (auth) algorithm ..: nistp256 Card authenticat. : 2AD7D08C11E0B8C98FC7BE87A7116427AD589F28 keyref .....: PIV.9E (auth) algorithm ..: nistp256 Digital signature : 541CF278539F78656A5B0176C75D5CAD58A26736 keyref .....: PIV.9C (sign,cert) algorithm ..: nistp256 Key management ...: ED6579C1360100BE92C46ECB1A1826A63614D5AB keyref .....: PIV.9D (encr) algorithm ..: rsa2048 used for ...: X.509 user id ..: CN=Encryption key for yk-9074582,O=example,C=DE user id ..: <otto@example.net> gpg/card>
After generating a self-signed certificate as described on the man page the attempt to write this certificate to the card failed.
$ gpg-card Reader ...........: 1050:0407:X:0 Card type ........: yubikey Card firmware ....: 5.1.2 Serial number ....: FF020001008A7796 Application type .: PIV Version ..........: 1.0 Displayed s/n ....: yk-9074582 PIN usage policy .: app-pin PIN retry counter : - [verified] - [?] PIV authentication: EB6A99D61EF3BC7C7934173CD9833376D773E65D keyref .....: PIV.9A (auth) algorithm ..: nistp256 Card authenticat. : 2AD7D08C11E0B8C98FC7BE87A7116427AD589F28 keyref .....: PIV.9E (auth) algorithm ..: nistp256 Digital signature : 541CF278539F78656A5B0176C75D5CAD58A26736 keyref .....: PIV.9C (sign,cert) algorithm ..: nistp256 used for ...: X.509 user id ..: CN=Signing key for yk-9074582,O=example,C=DE user id ..: <otto@example.net> Key management ...: ED6579C1360100BE92C46ECB1A1826A63614D5AB keyref .....: PIV.9D (encr) algorithm ..: rsa2048 used for ...: X.509 user id ..: CN=Encryption key for yk-9074582,O=example,C=DE user id ..: <otto@example.net> gpg/card> writecert PIV.9C < /home/ingo/dev/g10/sign-nistp256-541CF278539F78656A5B0176C75D5CAD58A26736.crt Command 'writecert' failed: Conflicting use gpg/card>
I have traced down the problem. In do_writecert() (app-piv.c) the public key in the certificate is compared with the public key on the card. The problem is that the representation of the curve differs in the two S-expressions of the public key:
2020-09-10 15:05:54 scdaemon[12280] DBG: orig_pk: (public-key \n (ecc \n (curve nistp256)\n (q #0464ED1D5259833306831FE802E8487F5F5C879ACF671A2DD0A5C134CAC08F66D1429A27BCAFE41042E8A1ECDE2594270CB675D99AF704344ADE9344EA7350A4CD#)\n )\n )\n 2020-09-10 15:05:54 scdaemon[12280] DBG: pk: (public-key \n (ecc \n (curve "1.2.840.10045.3.1.7")\n (q #0464ED1D5259833306831FE802E8487F5F5C879ACF671A2DD0A5C134CAC08F66D1429A27BCAFE41042E8A1ECDE2594270CB675D99AF704344ADE9344EA7350A4CD#)\n )\n )\n 2020-09-10 15:05:54 scdaemon[12280] operation writecert result: Conflicting use
I see that genkey_parse_ecc(), that is used via do_readkey() to read the public key from the card, uses "nistp256" for the curve. OTOH, app_help_pubkey_from_cert() (using ksba_cert_get_public_key()) uses the OID for the curve.