jorgelbg / pinentry-touchid Goto Github PK
View Code? Open in Web Editor NEWCustom GPG pinentry program for macOS that allows using Touch ID for fetching the password from the macOS keychain.
License: Apache License 2.0
Custom GPG pinentry program for macOS that allows using Touch ID for fetching the password from the macOS keychain.
License: Apache License 2.0
I tested running a build of this (from commit 45ffb97) in my 2015 Macbook Pro that lacks the Touch ID sensor and the program just seems to hang when the call to touchid.Authenticate
happens.
This is also reproducible when running the sample code from https://github.com/lox/go-touchid/blob/master/cli/main.go.
I set up pinentry-touchid at the start of a new machine before creating a new GPG key, I was never asked for a passphrase when going through key generation and was left very confused. Only after disabling the configuration (commenting out the gpg-agent.conf configuration line) was I prompted for a GPG key passphrase.
I'm not informed enough on the particulars of GPG to offer a documentation change, but I am left feeling like it should be made clear that pinentry-touchid should only be configured after creating a new / importing an existing key, and that the key must have a passphrase, hence the whole purpose of pinentry.
The key info is parsed to obtain a key grip and fails for key descriptions that don't conform to the format. The pinentry documentation states that the key identifier must be considered opaque.
Although --clear
may be passed here for unidentified keys, they should not set the allow-external-password-cache
option and the key identifier shouldn't be mapped to any cache.
When running echo "GETPIN" | pinentry-touchid
I get the following response
OK Hi from pinentry-touchid!
OK
2022/06/06 10:54:16 Pinentry Serve returned error: EOF
pinentry-mac runs as expected - I have tried to unsinstall & re-install pinentry-mac & pinentry-touchid with no sucess at this point. I have also been looking for similar issues but haven't found a solution as of yet.
macOS
GPG
gpg --version
gpg (GnuPG) 2.3.6
libgcrypt 1.10.1
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Home: /Users/<USER>/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
CAMELLIA128, CAMELLIA192, CAMELLIA256
AEAD: EAX, OCB
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
Yes.
Configuration
gpgconf
.gpg:OpenPGP:/usr/local/Cellar/gnupg/2.3.6/bin/gpg
gpgsm:S/MIME:/usr/local/Cellar/gnupg/2.3.6/bin/gpgsm
keyboxd:Public Keys:/usr/local/Cellar/gnupg/2.3.6/libexec/keyboxd
gpg-agent:Private Keys:/usr/local/Cellar/gnupg/2.3.6/bin/gpg-agent
scdaemon:Smartcards:/usr/local/Cellar/gnupg/2.3.6/libexec/scdaemon
dirmngr:Network:/usr/local/Cellar/gnupg/2.3.6/bin/dirmngr
pinentry:Passphrase Entry:/usr/local/opt/pinentry/bin/pinentry
cat /Users/<USERNAME>/.gnupg/gpg-agent.conf
debug-level basic
log-file /Users/<USERNAME>.gnupg/gpg-agent.log
pinentry-program /usr/local/opt/pinentry-touchid/bin/pinentry-touchid
Logs
gpg-agent
:
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 -> OK Pleased to meet you, process 36805
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 <- RESET
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 -> OK
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 <- OPTION ttyname=/dev/ttys004
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 -> OK
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 <- OPTION ttytype=xterm-256color
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 -> OK
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 <- OPTION lc-ctype=UTF-8
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 -> OK
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 <- reloadagent
2022-06-06 10:53:55 gpg-agent[36329] SIGHUP received - re-reading configuration and flushing cache
2022-06-06 10:53:55 gpg-agent[36329] reading options from '/Users/<USERNAME>/.gnupg/gpg-agent.conf'
2022-06-06 10:53:55 gpg-agent[36329] enabled debug flags: ipc
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 -> OK
2022-06-06 10:53:55 gpg-agent[36329] DBG: chan_8 <- [eof]
pinentry-touchid
:
2022/06/06 10:49:49 main.go:105: Ready!
2022/06/06 10:49:49 main.go:211: Confirm was called!
2022/06/06 10:49:50 main.go:105: Ready!
2022/06/06 10:49:50 main.go:211: Confirm was called!
2022/06/06 10:50:15 main.go:105: Ready!
2022/06/06 10:51:10 main.go:105: Ready!
2022/06/06 10:51:45 main.go:105: Ready!
2022/06/06 10:54:16 main.go:105: Ready!
2022/06/06 10:57:46 main.go:105: Ready!
2022/06/06 10:57:59 main.go:105: Ready!
Hi,
I've been able to configure pinentry-mac to work and store the key's passphrase in the keychain, no issue whatsoever.
But once I switch my ~/.gnupg/gpg-agent.conf to
default-cache-ttl 1
max-cache-ttl 1
#pinentry-program /usr/local/bin/pinentry-mac
pinentry-program /usr/local/bin/pinentry-touchid
It never brings the touchID prompt.
I have looked into allowing pinentry-touchid in the access control of the keychain entry as mentionned.
to add /usr/local/bin/pinentry-touchid
But this doesn't work either, my git debug output tells me:
15:17:57.787749 run-command.c:668 trace: run_command: /usr/local/bin/gpg --status-fd=2 -bsau xxxxxx
error: gpg failed to sign the data
And if I retry this command in another terminal, it hangs infinitely.
[GNUPG:] KEY_CONSIDERED xxxxx 2
[GNUPG:] BEGIN_SIGNING H10
Even something as simple as echo "test" | gpg -vvv --clearsign
will fail
gpg: using character set 'utf-8'
gpg: Note: RFC4880bis features are enabled.
gpg: Note: signature key A0D8xxxx expired Dim 1 nov 19:31:02 2020 CET
gpg: using pgp trust model
gpg: key <mykey>: accepted as trusted key
gpg: writing to stdout
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
test
gpg: signing failed: Operation cancelled
gpg: [stdin]: clear-sign failed: Operation cancelled
Tried generating binaries for the M1 Macs via goreleaser, but it fails with:
⨯ release failed after 6.02s error=failed to build for darwin_arm64: package command-line-arguments
imports github.com/lox/go-touchid: build constraints exclude all Go files in /Users/jbetancourt/dev/go/pkg/mod/github.com/lox/[email protected]
There seems to be a build constraint in https://github.com/lox/go-touchid.
Happens when I run $ echo "1234" | gpg -as -
Reset Passphrase used from TouchID?
(using) M1 Mac
GPG
$ gpg --version
gpg (GnuPG) 2.3.7
libgcrypt 1.10.1
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later https://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Home: /Users/truckerbug/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
CAMELLIA128, CAMELLIA192, CAMELLIA256
AEAD: EAX, OCB
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
Configuration
gpg:OpenPGP:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/gpg
gpgsm:S/MIME:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/gpgsm
keyboxd:Public Keys:/opt/homebrew/Cellar/gnupg/2.3.7_1/libexec/keyboxd
gpg-agent:Private Keys:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/gpg-agent
scdaemon:Smartcards:/opt/homebrew/Cellar/gnupg/2.3.7_1/libexec/scdaemon
dirmngr:Network:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/dirmngr
pinentry:Passphrase Entry:/opt/homebrew/opt/pinentry/bin/pinentry
Logs
gpg-agent
:
/.gnupg/gpg-agent.log:
pinentry-touchid
also generates its own log which you can find in $TMPDIR/pinentry-touchid.log
:
2022/09/06 11:29:15 main.go:118: Ready!
2022/09/06 11:31:17 main.go:118: Ready!
2022/09/06 11:38:37 main.go:118: Ready!
2022/09/06 11:39:20 main.go:118: Ready!
2022/09/06 11:40:08 main.go:118: Ready!
2022/09/06 20:41:06 main.go:118: Ready!
2022/09/06 20:41:43 main.go:118: Ready!
2022/09/06 20:45:47 main.go:118: Ready!
2022/09/06 20:50:07 main.go:118: Ready!
2022/09/06 20:50:11 main.go:118: Ready!
2022/09/06 20:50:13 main.go:348: Failed to authenticate
2022/09/06 20:50:30 main.go:118: Ready!
2022/09/06 20:50:32 main.go:348: Failed to authenticate
2022/09/06 20:50:34 main.go:118: Ready!
2022/09/06 20:51:58 main.go:118: Ready!
2022/09/06 20:54:09 main.go:118: Ready!
2022/09/06 20:54:30 main.go:118: Ready!
2022/09/06 20:54:34 main.go:348: Failed to authenticate
2022/09/06 20:54:35 main.go:118: Ready!
2022/09/06 20:54:37 main.go:348: Failed to authenticate
2022/09/06 20:55:47 main.go:118: Ready!
2022/09/06 20:58:17 main.go:118: Ready!
2022/09/06 20:58:19 main.go:348: Failed to authenticate
2022/09/06 20:58:21 main.go:118: Ready!
2022/09/06 20:58:22 main.go:348: Failed to authenticate
2022/09/06 20:58:36 main.go:118: Ready!
2022/09/06 21:00:16 main.go:118: Ready!
2022/09/06 21:00:21 main.go:118: Ready!
2022/09/06 21:00:29 main.go:118: Ready!
2022/09/06 21:01:37 main.go:118: Ready!
2022/09/06 21:01:40 main.go:348: Failed to authenticate
2022/09/06 21:01:41 main.go:118: Ready!
2022/09/06 21:01:42 main.go:348: Failed to authenticate
2022/09/06 21:01:47 main.go:118: Ready!
2022/09/06 21:01:50 main.go:348: Failed to authenticate
2022/09/06 21:04:48 main.go:118: Ready!
that's all I can say for right now
I managed to configure pinentry-mac
to work nicely, but when I try to switch to pinentry-touchid
I am unable to find a proper way of solving this problem. After I follow the steps provided after installation, I keep getting the following error message:
gpg: signing failed: No passphrase given
gpg: [stdin]: clear-sign failed: No passphrase given
Simplest test to reproduce:
echo "test" | gpg -vvv --clearsign
I have generated keys which have passphrases of course, but now I am unsure how to provide these passphrases to the pinentry.
macOS
GPG
gpg (GnuPG) 2.3.6
Configuration
gpg:OpenPGP:/opt/homebrew/Cellar/gnupg/2.3.6/bin/gpg
gpgsm:S/MIME:/opt/homebrew/Cellar/gnupg/2.3.6/bin/gpgsm
keyboxd:Public Keys:/opt/homebrew/Cellar/gnupg/2.3.6/libexec/keyboxd
gpg-agent:Private Keys:/opt/homebrew/Cellar/gnupg/2.3.6/bin/gpg-agent
scdaemon:Smartcards:/opt/homebrew/Cellar/gnupg/2.3.6/libexec/scdaemon
dirmngr:Network:/opt/homebrew/Cellar/gnupg/2.3.6/bin/dirmngr
pinentry:Passphrase Entry:/opt/homebrew/opt/pinentry/bin/pinentry
Logs
2022-07-01 16:50:14 gpg-agent[16600] enabled debug flags: ipc
2022-07-01 16:50:14 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:14 gpg-agent[16600] DBG: chan_7 <- [eof]
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK Pleased to meet you, process 16934
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- RESET
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- OPTION ttyname=/dev/ttys000
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- OPTION ttytype=xterm-256color
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- OPTION lc-ctype=UTF-8
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- GETINFO version
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> D 2.3.6
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- OPTION allow-pinentry-notify
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- OPTION agent-awareness=2.1.0
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- SCD SERIALNO
2022-07-01 16:50:19 gpg-agent[16600] new connection to /opt/homebrew/Cellar/gnupg/2.3.6/libexec/scdaemon daemon established (reusing)
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_8 -> SERIALNO
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_8 <- ERR 100696144 Operation not supported by device <SCD>
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> ERR 100696144 Operation not supported by device <SCD>
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- HAVEKEY --list=1000
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_8 -> KEYINFO --list
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_8 <- OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> [ 44 20 52 af 5d 47 8d 4d a5 13 0e da d2 c4 ee a5 ...(26 byte(s) skipped) ]
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- KEYINFO XXXXXX
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_8 -> KEYINFO --list
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_8 <- OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> S KEYINFO XXXXXX D - - - P - - -
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- RESET
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- SIGKEY XXXXXX
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- SETKEYDESC Please+enter+the+passphrase+to+unlock+the+OpenPGP+secret+key:%0A%22nemscep_at_github+(key+to+rule+them+all)+<[email protected]>%22%0A4096-bit+RSA+key,+ID+XXXXXX,%0Acreated+2022-07-01.%0A
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- SETHASH 8 XXXXXXX
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:50:19 gpg-agent[16600] DBG: chan_7 <- PKSIGN
2022-07-01 16:50:19 gpg-agent[16600] starting a new PIN Entry
2022-07-01 16:50:19 gpg-agent[16600] DBG: connection to PIN entry established
2022-07-01 16:50:19 gpg-agent[16600] You may want to update to a newer pinentry
2022-07-01 16:50:20 gpg-agent[16600] DBG: error calling pinentry: No passphrase given <GPG Agent>
2022-07-01 16:50:20 gpg-agent[16600] failed to unprotect the secret key: No passphrase given
2022-07-01 16:50:20 gpg-agent[16600] failed to read the secret key
2022-07-01 16:50:20 gpg-agent[16600] command 'PKSIGN' failed: No passphrase given
2022-07-01 16:50:20 gpg-agent[16600] DBG: chan_7 -> ERR 67109041 No passphrase given <GPG Agent>
2022-07-01 16:50:20 gpg-agent[16600] DBG: chan_7 <- [eof]
2022-07-01 16:50:20 gpg-agent[16600] DBG: chan_8 -> RESTART
2022-07-01 16:50:20 gpg-agent[16600] DBG: chan_8 <- OK
2022-07-01 16:52:03 gpg-agent[16600] DBG: chan_7 -> OK Pleased to meet you, process 17044
2022-07-01 16:52:03 gpg-agent[16600] DBG: chan_7 <- RESET
2022-07-01 16:52:03 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:52:03 gpg-agent[16600] DBG: chan_7 <- OPTION ttyname=not a tty
2022-07-01 16:52:03 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:52:03 gpg-agent[16600] DBG: chan_7 <- NOP
2022-07-01 16:52:03 gpg-agent[16600] DBG: chan_7 -> OK
2022-07-01 16:52:03 gpg-agent[16600] DBG: chan_7 <- [eof]
Thanks for creating this tool!
I'm using M1 Mac, OS X 12.1, gpg 2.3.4, pinentry-mac 1.1.1.1, pinentry-touchid 0.0.2. My GPG private key is on my Yubikey 5C NFC.
If I use pinentry-touchid in ~/.gnupg/gpg-agent.conf
pinentry-program /opt/homebrew/opt/pinentry-touchid/bin/pinentry-touchid
and run echo 1234 | gpg -as -
, I see
gpg: signing failed: Bad PIN
-----BEGIN PGP MESSAGE-----
gpg: signing failed: Bad PIN
I'm not prompted for a PIN or for touch ID.
To be prompted for touch ID, then get encrypted message.
/tmp/pinentry-touchid.log
says 2022/02/06 18:19:49 main.go:105: Ready!
gpg-agent.log says
2022-02-06 18:19:49 gpg-agent[95746] starting a new PIN Entry
2022-02-06 18:19:49 gpg-agent[95746] DBG: connection to PIN entry established
2022-02-06 18:19:49 gpg-agent[95746] You may want to update to a newer pinentry
2022-02-06 18:19:50 gpg-agent[95746] DBG: chan_9 -> [ 44 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...(76 byte(s) skipped) ]
2022-02-06 18:19:50 gpg-agent[95746] DBG: chan_9 -> END
2022-02-06 18:19:50 gpg-agent[95746] DBG: chan_9 <- ERR 100663383 Bad PIN <SCD>
2022-02-06 18:19:50 gpg-agent[95746] smartcard signing failed: Bad PIN
2022-02-06 18:19:50 gpg-agent[95746] command 'PKSIGN' failed: Bad PIN <SCD>
2022-02-06 18:19:50 gpg-agent[95746] DBG: chan_8 -> ERR 100663383 Bad PIN <SCD>
2022-02-06 18:19:50 gpg-agent[95746] DBG: chan_8 <- [eof]
2022-02-06 18:19:50 gpg-agent[95746] DBG: chan_9 -> RESTART
2022-02-06 18:19:50 gpg-agent[95746] DBG: chan_9 <- OK
I know my Yubikey and pinentry-mac are working because if I use pinentry-mac in ~/.gnupg/gpg-agent.conf
pinentry-program /opt/homebrew/bin/pinentry-mac
and run echo 1234 | gpg -as -
, I'm prompted for my PIN, then the encrypted message shows up in my terminal.
pinentry-touchid
doesn't save the password into the Keychain.
As a result, I get the password/confirm password popup every time I use my GPG key which is really quite annoying 😅
macOS
GPG
gpg --version
gpg (GnuPG) 2.3.7
libgcrypt 1.10.1
Copyright (C) 2021 Free Software Foundation, Inc.
Configuration
gpgconf
.❯ gpgconf
gpg:OpenPGP:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/gpg
gpgsm:S/MIME:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/gpgsm
keyboxd:Public Keys:/opt/homebrew/Cellar/gnupg/2.3.7_1/libexec/keyboxd
gpg-agent:Private Keys:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/gpg-agent
scdaemon:Smartcards:/opt/homebrew/Cellar/gnupg/2.3.7_1/libexec/scdaemon
dirmngr:Network:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/dirmngr
pinentry:Passphrase Entry:/opt/homebrew/opt/pinentry/bin/pinentry
Logs
gpg-agent
:
It would be very useful for us if you could enable the basic
debug info for your gpg-agent
and attach the generated log. Add the following to your ~/.gpg-agent.conf
:
debug-level basic
log-file /Users/<USERNAME>/.gnupg/gpg-agent.log
Reload gpg-agent
with the following command:
$ gpg-connect-agent reloadagent /bye
Add/attach the relevant section of the log to this issue (feel free to redact your key IDs).
pinentry-touchid
:
pinentry-touchid
also generates its own log which you can find in $TMPDIR/pinentry-touchid.log
.
❯ cat $TMPDIR/pinentry-touchid.log
2022/10/12 13:15:22 main.go:118: Ready!
2022/10/12 13:52:16 main.go:118: Ready!
2022/10/12 15:03:37 main.go:118: Ready!
2022/10/12 15:19:26 main.go:118: Ready!
2022/10/12 16:29:32 main.go:118: Ready!
2022/10/12 16:44:35 main.go:118: Ready!
2022/10/12 17:01:53 main.go:118: Ready!
2022/10/12 17:12:30 main.go:118: Ready!
2022/10/13 00:01:17 main.go:118: Ready!
2022/10/13 00:16:21 main.go:118: Ready!
2022/10/13 10:43:06 main.go:118: Ready!
2022/10/13 10:49:28 main.go:118: Ready!
2022/10/13 10:50:56 main.go:118: Ready!
2022/10/13 10:52:42 main.go:118: Ready!
Allow installation without downloading the binary directly or compiling from the source (which needs the entire Go toolchain)
I have been trying to set up pinentry-touchid
the whole day. First I run into the problem of the pinentry
symlink using pinentry-curse
that I have fixed using forcing the symlink to use pinentry-touchid
, but that still has not resolved the issue.
It was obvious that gpg-agent
uses pinetrny-touchid
but between gpg-agent
restarts no Touch ID prompt showed up and instead pinentry-mac
was always shown.
I used a custom build from latest master with adding some more logging to see what is going on and discovered that the main function GetPin()
is not invoked thanks to the condition
Line 208 in 3ebb30f
KeyInfo
is passed.
Looking at the gpg-agent.log
I noticed that gpg-agent
sents: SETKEYINFO --clear
which might be the issue, yet I have no clue why is that. I have been even digging in the source code of gpg-agent
itself and this happens only if the cache mode is in ignore mode. I am not sure how is that set, one case is when gpg-agent
's flag ignore-cache-for-signing
is enabled which I don't have (see bellow in configuration) or if !ctrl->server_local->use_cache_for_signing
which I don't know how to verify.
Some pointers in gpg-agent
code:
If anybody would have some pointers then I would be very happy, but now I have spent way too long on this so I am putting it to the ice and maybe returning to it sometime later.
macOS
GPG
gpg --version
: 2.3.3Configuration
gpg-agent
:
$ gpg-agent --gpgconf-list
gpg-agent[88475]: enabled debug flags: mpi crypto memory cache memstat hashing ipc
gpg-agent[88475]: random usage: poolsize=600 mixed=0 polls=0/0 added=0/0
outmix=0 getlvl1=0/0 getlvl2=0/0
gpg-agent[88475]: rndjent stat: collector=0x0000000000000000 calls=0 bytes=0
gpg-agent[88475]: secmem usage: 0/32768 bytes in 0 blocks
debug-level:16:"none:
default-cache-ttl:16:600:
default-cache-ttl-ssh:16:1800:
max-cache-ttl:16:7200:
max-cache-ttl-ssh:16:7200:
min-passphrase-len:16:8:
min-passphrase-nonalpha:16:1:
check-passphrase-pattern:16:
check-sym-passphrase-pattern:16:
max-passphrase-days:16:0:
ssh-fingerprint-digest:16:"sha256:
$ gpgconf
gpg:OpenPGP:/opt/homebrew/Cellar/gnupg/2.3.3_1/bin/gpg
gpgsm:S/MIME:/opt/homebrew/Cellar/gnupg/2.3.3_1/bin/gpgsm
keyboxd:Public Keys:/opt/homebrew/Cellar/gnupg/2.3.3_1/libexec/keyboxd
gpg-agent:Private Keys:/opt/homebrew/Cellar/gnupg/2.3.3_1/bin/gpg-agent
scdaemon:Smartcards:/opt/homebrew/Cellar/gnupg/2.3.3_1/libexec/scdaemon
dirmngr:Network:/opt/homebrew/Cellar/gnupg/2.3.3_1/bin/dirmngr
pinentry:Passphrase Entry:/opt/homebrew/opt/pinentry/bin/pinentry
Logs
gpg-agent
:
2021-12-30 18:43:04 gpg-agent[83616] listening on socket '/Users/adam/.gnupg/S.gpg-agent'
2021-12-30 18:43:04 gpg-agent[83616] listening on socket '/Users/adam/.gnupg/S.gpg-agent.extra'
2021-12-30 18:43:04 gpg-agent[83616] listening on socket '/Users/adam/.gnupg/S.gpg-agent.browser'
2021-12-30 18:43:04 gpg-agent[83616] listening on socket '/Users/adam/.gnupg/S.gpg-agent.ssh'
2021-12-30 18:43:04 gpg-agent[83617] gpg-agent (GnuPG) 2.3.3 started
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK Pleased to meet you, process 83615
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- RESET
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- OPTION ttytype=xterm-256color
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- GETINFO version
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> D 2.3.3
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- OPTION allow-pinentry-notify
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- OPTION agent-awareness=2.1.0
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- SCD SERIALNO
2021-12-30 18:43:04 gpg-agent[83617] no running /opt/homebrew/Cellar/gnupg/2.3.3_1/libexec/scdaemon daemon - starting it
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK GNU Privacy Guard's Smartcard server ready
2021-12-30 18:43:04 gpg-agent[83617] first connection to daemon /opt/homebrew/Cellar/gnupg/2.3.3_1/libexec/scdaemon established
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> GETINFO socket_name
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- D /Users/adam/.gnupg/S.scdaemon
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: additional connections at '/Users/adam/.gnupg/S.scdaemon'
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> OPTION event-signal=31
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> SERIALNO
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S SERIALNO D2760001240100000006163835350000
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> S SERIALNO D2760001240100000006163835350000
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- SCD SERIALNO
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> SERIALNO
2021-12-30 18:43:04 gpg-agent[83617] SIGUSR2 received - updating card event counter
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S SERIALNO D2760001240100000006163835350000
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> S SERIALNO D2760001240100000006163835350000
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- SCD GETATTR KEY-FPR
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> GETATTR KEY-FPR
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S KEY-FPR 1 EA3C2C2034B196194C10DC081D17A9E81F76155B
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> S KEY-FPR 1 EA3C2C2034B196194C10DC081D17A9E81F76155B
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S KEY-FPR 2 734DFF91532DE1CF3B0F263F98CC64154DD31AAD
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> S KEY-FPR 2 734DFF91532DE1CF3B0F263F98CC64154DD31AAD
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S KEY-FPR 3 B43793807EE335D308A45766F0D3C75EE7FC9DE7
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> S KEY-FPR 3 B43793807EE335D308A45766F0D3C75EE7FC9DE7
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- READKEY --card --no-data -- $SIGNKEYID
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> GETATTR SERIALNO
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S SERIALNO D2760001240100000006163835350000
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> GETATTR $SIGNKEYID
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S $SIGNKEYID OPENPGP.1
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> READKEY -- OPENPGP.1
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- [ 44 20 28 31 30 3a 70 75 62 6c 69 63 2d 6b 65 79 ...(554 byte(s) skipped) ]
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- READKEY --card --no-data -- $ENCRKEYID
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> GETATTR SERIALNO
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S SERIALNO D2760001240100000006163835350000
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> GETATTR $ENCRKEYID
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S $ENCRKEYID OPENPGP.2
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> READKEY -- OPENPGP.2
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- [ 44 20 28 31 30 3a 70 75 62 6c 69 63 2d 6b 65 79 ...(552 byte(s) skipped) ]
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- KEYINFO 7A98B54F7AF5896A1C7D77A98728BD9C03F1E374
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> KEYINFO --list
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S KEYINFO A633F40D9DF82B626C5F7DAF1E277641E937F115 T D2760001240100000006163835350000 OPENPGP.1
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S KEYINFO BF19A7ED2BC1F76B40DCDCEEFA00973731139FF6 T D2760001240100000006163835350000 OPENPGP.2
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S KEYINFO B62091485C283939115550D8E71449A5845FFF7F T D2760001240100000006163835350000 OPENPGP.3
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> ERR 67108891 Not found <GPG Agent>
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- KEYINFO 917685F020531A9B27B0520C21F7355FCFE56A6C
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> ERR 67108891 Not found <GPG Agent>
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- KEYINFO 5A50BD15E71E9202511CA4FDED8D124ACD1A98DF
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> ERR 67108891 Not found <GPG Agent>
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- KEYINFO B01772F781C80DC733FF18953A8AD350BDC06B38
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> S KEYINFO B01772F781C80DC733FF18953A8AD350BDC06B38 T D2760001240100000006077988180000 OPENPGP.3 - - - - -
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- HAVEKEY --list=1000
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> [ 44 20 bf 19 a7 ed 2b c1 f7 6b 40 dc dc ee fa 00 ...(132 byte(s) skipped) ]
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- KEYINFO 917685F020531A9B27B0520C21F7355FCFE56A6C
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> ERR 67108891 Not found <GPG Agent>
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- KEYINFO 8D102F6474372F1B81B0F641E01184800E45E712
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> ERR 67108891 Not found <GPG Agent>
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- KEYINFO A633F40D9DF82B626C5F7DAF1E277641E937F115
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> S KEYINFO A633F40D9DF82B626C5F7DAF1E277641E937F115 T D2760001240100000006163835350000 OPENPGP.1 - - - - A
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- KEYINFO A633F40D9DF82B626C5F7DAF1E277641E937F115
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> S KEYINFO A633F40D9DF82B626C5F7DAF1E277641E937F115 T D2760001240100000006163835350000 OPENPGP.1 - - - - A
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- RESET
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- SIGKEY A633F40D9DF82B626C5F7DAF1E277641E937F115
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- SETKEYDESC Please+enter+the+passphrase+to+unlock+the+OpenPGP+secret+key:%0A%22...
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- SETHASH 10 03D1EAF118C87C9CA260D562C972FDC73E8D44315A21E576A78F0C0CE2D20098E1686DC544001300CC1452ADCEA5E994A52416C3BF4E6CB14EE160C5320C4870
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_8 <- PKSIGN
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> SERIALNO --all
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S SERIALNO D2760001240100000006163835350000
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> KEYINFO A633F40D9DF82B626C5F7DAF1E277641E937F115
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- S KEYINFO A633F40D9DF82B626C5F7DAF1E277641E937F115 T D2760001240100000006163835350000 OPENPGP.1
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> SETDATA 3051300D06096086480165030402030500044003D1EAF118C87C9CA260D562C972FDC73E8D44315A21E576A78F0C0CE2D20098E1686DC544001300CC1452ADCEA5E994A52416C3BF4E6CB14EE160C5320C4870
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 -> PKSIGN --hash=sha512 A633F40D9DF82B626C5F7DAF1E277641E937F115
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_9 <- [ 49 4e 51 55 49 52 45 20 4e 45 45 44 50 49 4e 20 ...(88 byte(s) skipped) ]
2021-12-30 18:43:04 gpg-agent[83617] starting a new PIN Entry
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK Hi from pinentry-touchid!
2021-12-30 18:43:04 gpg-agent[83617] DBG: connection to PIN entry established
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION no-grab
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION ttytype=xterm-256color
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION allow-external-password-cache
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION default-ok=_OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION default-cancel=_Cancel
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION default-yes=_Yes
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION default-no=_No
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION default-prompt=PIN:
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION default-pwmngr=_Save in password manager
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION default-cf-visi=Do you really want to make your passphrase visible on the screen?
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION default-tt-visi=Make passphrase visible
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION default-tt-hide=Hide passphrase
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION default-capshint=Caps Lock is on
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION touch-file=/Users/adam/.gnupg/S.gpg-agent
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> OPTION owner=83615/501 MacyTwo.local
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> GETINFO flavor
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- ERR 251658515 unknown IPC command <assuan>
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> GETINFO version
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- ERR 251658515 unknown IPC command <assuan>
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> GETINFO ttyinfo
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- ERR 251658515 unknown IPC command <assuan>
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> GETINFO pid
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- ERR 251658515 unknown IPC command <assuan>
2021-12-30 18:43:04 gpg-agent[83617] You may want to update to a newer pinentry
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> SETKEYINFO --clear
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> SETDESC Please unlock the card%0A%0ANumber: 16 383 535%0AHolder: Adam Uhlir%0ACounter: 114
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> SETPROMPT PIN
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 <- OK
2021-12-30 18:43:04 gpg-agent[83617] DBG: chan_10 -> [[Confidential data not shown]]
2021-12-30 18:43:10 gpg-agent[83617] DBG: chan_10 <- [[Confidential data not shown]]
2021-12-30 18:43:10 gpg-agent[83617] DBG: chan_10 <- [[Confidential data not shown]]
2021-12-30 18:43:10 gpg-agent[83617] DBG: chan_10 -> BYE
2021-12-30 18:43:10 gpg-agent[83617] DBG: chan_9 -> [ 44 20 6d 30 6e 44 21 6b 33 6c 26 00 00 00 00 00 ...(76 byte(s) skipped) ]
2021-12-30 18:43:10 gpg-agent[83617] DBG: chan_9 -> END
2021-12-30 18:43:10 gpg-agent[83617] DBG: chan_9 <- S PINCACHE_PUT 0/openpgp/1 E8C978EA60984183A2C8B7E698BB1C9014341346245A9170
2021-12-30 18:43:10 gpg-agent[83617] DBG: handle_pincache_put: caching '0/openpgp/1'->'E8C978EA60984183A2C8B7E698BB1C9014341346245A9170'
2021-12-30 18:43:13 gpg-agent[83617] DBG: chan_9 <- [ 44 20 49 d9 b5 94 46 82 57 0f 32 90 b3 5e 9a d2 ...(502 byte(s) skipped) ]
2021-12-30 18:43:13 gpg-agent[83617] DBG: chan_9 <- OK
2021-12-30 18:43:13 gpg-agent[83617] DBG: chan_8 -> [ 44 20 28 37 3a 73 69 67 2d 76 61 6c 28 33 3a 72 ...(529 byte(s) skipped) ]
2021-12-30 18:43:13 gpg-agent[83617] DBG: chan_8 -> OK
2021-12-30 18:43:13 gpg-agent[83617] DBG: chan_8 <- [eof]
2021-12-30 18:43:13 gpg-agent[83617] DBG: chan_9 -> RESTART
2021-12-30 18:43:13 gpg-agent[83617] DBG: chan_9 <- OK
pinentry-touchid
:
2021/12/30 18:43:04 main.go:109: Ready!
2021/12/30 18:43:04 main.go:213: Not meeting criteria to use pinentry-touchid, falling back to pinentry-mac
2021/12/30 18:43:04 main.go:214: len(s.Error): 0, len(s.RepeatPrompt): 0, s.Opts.AllowExtPasswdCache: true, len(s.KeyInfo): 0
I've been trying to use this gpg-agent for a while now. Finally got it working on the M1 chip mac.
However, now im running into a new issue related to gpg comments and regex.
Seems like pinentry-mac stores the key in the keychain without the comment, so when pinentry-touchid is looking for it, it isnt found -> tries to create -> duplicate key error.
macOS
GPG
gpg (GnuPG) 2.3.7
libgcrypt 1.10.1
Homebrew: yes
Configuration
gpg:OpenPGP:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/gpg
gpgsm:S/MIME:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/gpgsm
keyboxd:Public Keys:/opt/homebrew/Cellar/gnupg/2.3.7_1/libexec/keyboxd
gpg-agent:Private Keys:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/gpg-agent
scdaemon:Smartcards:/opt/homebrew/Cellar/gnupg/2.3.7_1/libexec/scdaemon
dirmngr:Network:/opt/homebrew/Cellar/gnupg/2.3.7_1/bin/dirmngr
pinentry:Passphrase Entry:/opt/homebrew/opt/pinentry/bin/pinentry
Logs
(I added some logs)
2022/08/30 09:18:23 main.go:119: Ready!
2022/08/30 09:18:23 main.go:260: description: pinentry.Settings{Desc:"Please enter the passphrase to unlock the OpenPGP secret key:\n"Brandon Ryan (brandonryan.dev) [email protected]"\n4096-bit RSA key, ID C39ECBC9739CCB93,\ncreated 2021-11-24.\n", Prompt:"Passphrase:", Error:"", OkBtn:"", NotOkBtn:"", CancelBtn:"", Title:"", Timeout:0, RepeatPrompt:"", RepeatError:"", QualityBar:"", PasswordQuality:(func(string) int)(nil), KeyInfo:"n/D25BB7218F89E807AAF8A055340843E8FDAC1A0B", Opts:pinentry.Options{Grab:false, AllowExtPasswdCache:true, Display:"", TTYType:"xterm-256color", TTYName:"/dev/ttys000", TTYAlert:"", LCCtype:"en_US.UTF-8", LCMessages:"en_US.UTF-8", Owner:"23826/501 Brandons-MacBook-Pro.local", TouchFile:"/Users/brandonryan/.gnupg/S.gpg-agent", ParentWID:"", InvisibleChar:""}}
2022/08/30 09:18:23 main.go:285: matches: []string{"ID C39ECBC9739CCB93,", "C39ECBC9739CCB93"}
2022/08/30 09:18:23 main.go:291: KeyID: "C39ECBC9739CCB93"
2022/08/30 09:18:23 main.go:298: keychain label: "Brandon Ryan (brandonryan.dev) [email protected] (C39ECBC9739CCB93)"
2022/08/30 09:18:23 main.go:305: key exists: false
2022/08/30 09:18:23 main.go:348: Duplicated entry in the keychain
gpg-agent
:
#pinentry-program /opt/homebrew/bin/pinentry-mac
#pinentry-program /opt/homebrew/opt/pinentry-touchid/bin/pinentry-touchid
pinentry-program /Users/brandonryan/Development/pinentry-touchid/pinentry-touchid
I'm not sure about this, but I will put it here just to keep track of the issue:
It would be nice to support devices without Touch ID by using the Apple Watch instead of Touch ID. My 2015 Macbook pro does this for a few different scenarios.
I was trying to export my keys and found that it's not possible in the command line using gpg --armor --export-secret-keys
I end up using something like this:
echo mypassphrase | gpg --output private_keys.backup --armor --export-secret-keys --passphrase-fd 0 --pinentry-mode loopback
Is this expected?
I was trying to test the pinentry
command as described in the installation section, but it failed eventually.
$ echo GETPIN | pinentry
OK Pleased to meet you
S ERROR curses.isatty 83918950
ERR 83918950 Inappropriate ioctl for device <Pinentry>
Then I installed the pinentry-mac, and it seems this fixed the issue. It had better notice this detail in the README.
It would be nice to store the password in the Secure Enclave similar to how https://github.com/maxgoedjen/secretive does.
I didn't find a Golang library that allowed this and for now it is stored as an issue/would be nice to have at some point. This would also imply not being compatible with the normal pinentry-mac.
Why not just abandon the pinentry-mac, and getting the password by yourself?
I have freshly installed the pinentry-touchid from homebrew. The configuration didn't work well. I would appreciate it if you can locate what the problem is.
I tried: pinentry-touchid
returns: OK Hi from pinentry-touchid!
When pinentry program is set to pinentry-mac
, running echo "test" | gpg -vvv clearsign
returns:
❯ echo "test" | gpg -vvv --clearsign
gpg: using character set 'utf-8'
gpg: Note: RFC4880bis features are enabled.
gpg: no running gpg-agent - starting '/opt/homebrew/Cellar/gnupg/2.3.4/bin/gpg-agent'
gpg: waiting for the agent to come up ... (5s)
gpg: connection to the agent established
gpg: using pgp trust model
gpg: writing to stdout
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
test
gpg: pinentry launched (61958 mac 1.1.1 - xterm-256color /private/tmp/com.apple.launchd.N7eC4KL1mw/org.xquartz:0 - 501/20 0)
gpg: RSA/SHA256 signature from: "??? SunsetYe66"
-----BEGIN PGP SIGNATURE-----
iQGzBAEBCAAdFiEE3HGm3LzMJDi5MmgVmWNPzt9VFbcFAmHnokQACgkQmWNPzt9V
Fbc8rgwAsyhMRA3gk+KZtNkhND5++ag8cLMkfSW5xFEYScNMp5EHPATM5aagTbhG
ZS2DvBKOhWoo2oLZR7C1Kt5TOU4u92rgrjppBs5273Map27KQYKF0bYlo/5+mBzf
DGd9ffdvhmcm/IMReyV5ABSPTDUNPi2He9CVzpT5gxTYceHe39aiR5Ij+7e5cy3j
ZHtihlGJULSj8AaV6VuyCJO3vef1/4DVkjHKjy8pZR66IrcBin4dBMeQ1RkIPmkA
hqqziORwY7c7zhQRB7qDp/l3xP76WgKwMFFQ3vkufl+GPr/+e0GT778EUaUxRxvr
A0CVCibgFQWQSE2/CVSrRkgPzdwfDOzQ3Dy8T+RS6eISHi3eVv2BUQjWipM+7U8u
8QyZOsR0zE+9T/8rPTJGmkC6zlVCEnebxMjfWxY30sKVIezSxhtkeCcmArqxKuVr
58guXJB4fFHZ+D2spKVmodmWzubfNzN/vItbfxozPjSibraj5NEeNFCphXLMBbmX
EUwQ0zcj
=xfL3
-----END PGP SIGNATURE-----
But if set to pinentry-touchid
, it fails:
gpg: using character set 'utf-8'
gpg: Note: RFC4880bis features are enabled.
gpg: using pgp trust model
gpg: writing to stdout
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
test
gpg: signing failed: No pinentry
gpg: [stdin]: clear-sign failed: No pinentry
macOS
GPG
gpg --version
gpg (GnuPG) 2.3.4
libgcrypt 1.9.4
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Home: /Users/shawn.ye/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
CAMELLIA128, CAMELLIA192, CAMELLIA256
AEAD: EAX, OCB
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
Configuration
gpgconf
.gpg:OpenPGP:/opt/homebrew/Cellar/gnupg/2.3.4/bin/gpg
gpgsm:S/MIME:/opt/homebrew/Cellar/gnupg/2.3.4/bin/gpgsm
keyboxd:Public Keys:/opt/homebrew/Cellar/gnupg/2.3.4/libexec/keyboxd
gpg-agent:Private Keys:/opt/homebrew/Cellar/gnupg/2.3.4/bin/gpg-agent
scdaemon:Smartcards:/opt/homebrew/Cellar/gnupg/2.3.4/libexec/scdaemon
dirmngr:Network:/opt/homebrew/Cellar/gnupg/2.3.4/bin/dirmngr
pinentry:Passphrase Entry:/opt/homebrew/opt/pinentry/bin/pinentry
Logs
gpg-agent
:
❯ cat .gnupg/gpg-agent.log
2022-01-19 13:26:38 gpg-agent[61089] listening on socket '/Users/shawn.ye/.gnupg/S.gpg-agent'
2022-01-19 13:26:38 gpg-agent[61089] listening on socket '/Users/shawn.ye/.gnupg/S.gpg-agent.extra'
2022-01-19 13:26:38 gpg-agent[61089] listening on socket '/Users/shawn.ye/.gnupg/S.gpg-agent.browser'
2022-01-19 13:26:38 gpg-agent[61089] listening on socket '/Users/shawn.ye/.gnupg/S.gpg-agent.ssh'
2022-01-19 13:26:38 gpg-agent[61090] gpg-agent (GnuPG) 2.3.4 started
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK Pleased to meet you, process 61088
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- RESET
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- OPTION ttytype=xterm-256color
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- OPTION display=/private/tmp/com.apple.launchd.N7eC4KL1mw/org.xquartz:0
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- GETINFO version
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> D 2.3.4
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- OPTION allow-pinentry-notify
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- OPTION agent-awareness=2.1.0
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- SCD SERIALNO
2022-01-19 13:26:38 gpg-agent[61090] no running /opt/homebrew/Cellar/gnupg/2.3.4/libexec/scdaemon daemon - starting it
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 <- OK GNU Privacy Guard's Smartcard server ready
2022-01-19 13:26:38 gpg-agent[61090] first connection to daemon /opt/homebrew/Cellar/gnupg/2.3.4/libexec/scdaemon established
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 -> GETINFO socket_name
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 <- D /Users/shawn.ye/.gnupg/S.scdaemon
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 <- OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: additional connections at '/Users/shawn.ye/.gnupg/S.scdaemon'
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 -> OPTION event-signal=31
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 <- OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 -> SERIALNO
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 <- ERR 100696144 Operation not supported by device <SCD>
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> ERR 100696144 Operation not supported by device <SCD>
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- HAVEKEY --list=1000
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 -> KEYINFO --list
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 <- OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> [ 44 20 f2 34 bd d3 f8 cd a8 7e 28 3d 88 e8 f5 c8 ...(28 byte(s) skipped) ]
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- KEYINFO ???
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 -> KEYINFO --list
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 <- OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> S KEYINFO ??? - - - P - - -
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- RESET
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- SIGKEY ???
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- SETKEYDESC Please+enter+the+passphrase+to+unlock+the+OpenPGP+secret+key:%0A%22SunsetYe66+<???>%22%0A3072-bit+RSA+key,+ID+???,%0Acreated+2021-12-07.%0A
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- SETHASH 8 ???
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> OK
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- PKSIGN
2022-01-19 13:26:38 gpg-agent[61090] starting a new PIN Entry
2022-01-19 13:26:38 gpg-agent[61090] can't connect to the PIN entry module '/opt/homebrew/bin/pinentry-touchid': End of file
2022-01-19 13:26:38 gpg-agent[61090] DBG: error calling pinentry: No pinentry <GPG Agent>
2022-01-19 13:26:38 gpg-agent[61090] failed to unprotect the secret key: No pinentry
2022-01-19 13:26:38 gpg-agent[61090] failed to read the secret key
2022-01-19 13:26:38 gpg-agent[61090] command 'PKSIGN' failed: No pinentry
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 -> ERR 67108949 No pinentry <GPG Agent>
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_8 <- [eof]
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 -> RESTART
2022-01-19 13:26:38 gpg-agent[61090] DBG: chan_9 <- OK
Add/attach the relevant section of the log to this issue (feel free to redact your key IDs).
pinentry-touchid
:
❯ cat $TMPDIR/pinentry-touchid.log
cat: /var/folders/91/jnf_k3s16lv1fg4q386yppb00000gn/T//pinentry-touchid.log: No such file or directory
After I applied the installation instructions step by step, I got an error while signing commit. The problem is in the communication between the gpg-agent and the pinentry program as the following debug output shows: 1
$ git commit -v -s -S
gpg-agent[20618]: You may want to update to a newer pinentry
gpg-agent[20618]: failed to unprotect the secret key: Operation cancelled
gpg-agent[20618]: failed to read the secret key
gpg-agent[20618]: command 'PKSIGN' failed: Operation cancelled <Pinentry>
error: gpg failed to sign the data
fatal: failed to write commit object
I reload gpg-agent daemon:
$ gpg-agent --daemon; killall gpg-agent && gpg-agent --daemon --use-standard-socket --pinentry-program /usr/local/bin/pinentry-touchid
This one works:
$ echo GETPIN | pinentry
OK Pleased to meet you
gpg-agent:
$ gpg-agent --help
gpg-agent (GnuPG/MacGPG2) 2.2.27
libgcrypt 1.8.7
pinentry-mac:
$ pinentry --help
pinentry-mac (pinentry) 1.1.1
MacBook Pro (16-inch, Late 2019) - macOS 11 - Intel
But the pinentry-mac
is working:
$ gpg-agent --daemon; killall gpg-agent && gpg-agent --daemon --use-standard-socket --pinentry-program /usr/local/bin/pinentry-mac
My output logs:
$ cat /tmp/pinentry-touchid.log
2021/10/24 00:09:50 main.go:105: Ready!
2021/10/24 00:09:50 main.go:256: Error calling pinentry-mac: unexpected response: ERR 83918950 Inappropriate ioctl for device <Pinentry>
2021/10/24 00:09:50 main.go:260: pinentry-mac didn't return a password
Tried this solution but no luck.
Any ideas here? 🤔
pinentry-mac falls back to pinentry-curses if the env var PINENTRY_USER_DATA=USE_CURSES=1
is set, however pinentry-touchid does not respect this and will always prompt for touchid.
This is needed when pinentry is requested over a remote connection where the user has no physical access to the system, ie ssh sessions.
Hi Jorge,
Did you already manage to get pinentry-touchid to work with macOS 12.0.1? Or is it maybe already working for you?
I installed it following your guide here on github via homebrew.
For me it isn't and just throws:
sign_and_send_pubkey: signing failed for RSA "cardno:000x 0000xxxx" from agent: agent refused operation
pinentry-mac is working fine.
Here's my .zshrc:
unset SSH_AGENT_PID
if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
fi
alias pinentry='pinentry-mac'
#export GPG_TTY=$(tty)
#gpg-connect-agent updatestartuptty /bye >/dev/null
I used pinentry-mac without the last two lines and it doesn't seem to make a difference if they are there anyway, so I commented them out again.
Here is my .gnupg/gpg-agent.conf:
enable-ssh-support
use-standard-socket
default-cache-ttl 600
max-cache-ttl 7200
#pinentry-program /usr/local/bin/pinentry-mac
pinentry-program /usr/local/opt/pinentry-touchid/bin/pinentry-touchid
and finally my gpg.conf:
auto-key-retrieve
no-emit-version
default-key 907BB9A8BA3B629D6F7EFA8A04D3A0AB20551091
#keyserver
cert-digest-algo SHA256
no-comments
personal-cipher-preferences AES AES256 AES192 CAST5
personal-digest-preferences SHA256 SHA512 SHA384 SHA224
ignore-time-conflict
allow-freeform-uid
use-agent
As I said - this setup is working fine with pinentry-mac (latest version, installed via homebrew) for about two years now.
Any ideas? Or simply a "12.0.1 is just not supported right now" ? ;)
Thanks on advanced and also for your work (which, hopefully, I'll be able to use someday) ;)
Hello.
I face a problem that conflicting log file owners when using fast user switching.
Therefore, every time I switch users, required to remove /tmp/pinentry-touchid.log
as a root.
Could you possibly add some prefix or suffix to the default log file name, enable a specific log file path, or just the option of omitting logfile?
Thank you.
I just installed pinentry-touchid from homebrew, and I'm following the readme, and when I run:
$ pinentry-touchid -fix
I get the message:
flag provided but not defined: -fix
Usage of pinentry-touchid:
-check
Verify that pinentry-mac is present in the system
pinentry-touchid -check
works fine though.
macOS
GPG
gpg --version
gpg (GnuPG) 2.3.6
libgcrypt 1.10.1
Configuration
gpgconf
.gpg:OpenPGP:/usr/local/Cellar/gnupg/2.3.6/bin/gpg
gpgsm:S/MIME:/usr/local/Cellar/gnupg/2.3.6/bin/gpgsm
keyboxd:Public Keys:/usr/local/Cellar/gnupg/2.3.6/libexec/keyboxd
gpg-agent:Private Keys:/usr/local/Cellar/gnupg/2.3.6/bin/gpg-agent
scdaemon:Smartcards:/usr/local/Cellar/gnupg/2.3.6/libexec/scdaemon
dirmngr:Network:/usr/local/Cellar/gnupg/2.3.6/bin/dirmngr
pinentry:Passphrase Entry:/usr/local/opt/pinentry/bin/pinentry
I couldn't actually get gpgconf to interact at all with my ~/.gnupg/gpg-agent.conf
file, changes there just weren't respected, and gpgconf
always output the same, even after restarting:
As such the rest of the questions here aren't particularly answerable. The issue from pinentry-touchid -fix
does seem directly that it's just missing that CLI flag.
Logs
gpg-agent
:
It would be very useful for us if you could enable the basic
debug info for your gpg-agent
and attach the generated log. Add the following to your ~/.gpg-agent.conf
:
debug-level basic
log-file /Users/<USERNAME>/.gnupg/gpg-agent.log
Reload gpg-agent
with the following command:
$ gpg-connect-agent reloadagent /bye
Add/attach the relevant section of the log to this issue (feel free to redact your key IDs).
pinentry-touchid
:
pinentry-touchid
also generates its own log which you can find in $TMPDIR/pinentry-touchid.log
.
I would expect pinentry just passthrough the call to pinentry-mac, if laptop lid is closed, but instead it fails the hard way:
/opt/homebrew/opt/pinentry-touchid/bin/pinentry-touchid
2021/12/15 05:39:17 pinentry-touchid does not support devices without a Touch ID sensor!
I use the Macbook Air M1 which has touchid
Model Identifier: MacBookAir10,1
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.