-
Notifications
You must be signed in to change notification settings - Fork 581
Description
Describe the Bug
When looping through the PgpPublicKeyRing.GetPublicKeys in a supplied Public Key File, the Primary Key is reported to possess a capability of the Subkey (Encryption)
GPG generates key pairs where the Primary is used for Authentication and Certification, and the subkey is used for Encryption.
According to https://github.com/gpg/gnupg/blob/master/doc/DETAILS which describes the output of a key listing --with-colums
Field 12 - Key capabilities
The defined capabilities are:e
Encrypt
s
Sign
c
Certify
a
Authentication
r
Restricted encryption (subkey only use)
t
Timestamping
g
Group key
?
Unknown capability
A key may have any combination of them in any order. In addition to these letters, the primary key has uppercase versions of the letters to denote the usable capabilities of the entire key, and a potential letter ‘D’ to indicate a disabled key.
For a recipient of my encrypted file the output from :> gpg --list-keys --with-colons
is
pub:f:4096:1:AAAAAAAAAAAAAAAA:1706608025:1864460825::-:::**scESC**::::::23::0:
fpr:::::::::<redacted>:
uid:f::::1706608027::<redacted>::<redacted>::::::::::0:
sub:f:4096:1:BBBBBBBBBBBBBBBB:1706608025:1864460825:::::**e**::::::23:
fpr:::::::::<redacted>:
The Primary key AAAAAAAAAAAAAAAA has Capabilities (s)ign and (c)ertify in the Capability Field highlighted with the ** characters (Bold doesn't work in Code). It also includes the overall key capabilities (ESC) which indicates that in addition to it's own (s) and (c), one of it's subkeys will have the (e)ncryption capability.
Subkey BBBBBBBBBBBBBBBB has Capability (e)
When looping through the PgpPublicKeyRing.GetPublicKeys using the following function I was originally checking for the first key that had the Capability IsEncryptionKey reported - BUT this was returning the Primary key. I had to work around the issue by adding additional code to check for a subkey with the encryption capability, and to return that.
`
Private Function ReadPublicKeyFromFile(fileName As String) As PgpPublicKey
Using keyIn = File.OpenRead(fileName)
Console.WriteLine("")
Console.WriteLine("Seeking Encryption Key ")
Console.WriteLine("")
Dim masterPublicKey As PgpPublicKey = Nothing
Dim subPublicKey As PgpPublicKey = Nothing
Dim pubRings = New PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(keyIn))
For Each kRing As PgpPublicKeyRing In pubRings.GetKeyRings()
For Each key As PgpPublicKey In kRing.GetPublicKeys()
Console.WriteLine("Check Public KeyId: " & key.KeyId.ToString("X16"))
Console.WriteLine(" IsMasterKey: " & key.IsMasterKey.ToString)
Console.WriteLine(" IsEncrpytKey: " & key.IsEncryptionKey.ToString)
Console.WriteLine(" PubKeyAlgo: " & key.Algorithm.ToString)
Console.WriteLine(" PubKeyStrength: " & key.BitStrength.ToString)
Console.WriteLine(" PubKeyVersion: " & key.Version.ToString)
Console.WriteLine("")
'GPG default behaviour is to use a subkey for encryption/decryption - so make sure to check for a subkey with encryption capability
If key.IsEncryptionKey Then
If key.IsMasterKey Then
masterPublicKey = key
Else
subPublicKey = key
Console.WriteLine("Using SubKey KeyId: " & subPublicKey.KeyId.ToString("X16"))
Return key
End If
End If
Next
Next
'GPG default behaviour is to use a subkey for encryption/decryption
'If no subkey was found with the encryptionKey attribute set ten return the master key if that is capable of encrypting
If masterPublicKey IsNot Nothing Then
Console.WriteLine("Using Master KeyId: " & masterPublicKey.KeyId.ToString("X16"))
Return masterPublicKey
End If
End Using
Throw New ArgumentException("Can't find encryption key in key ring.")
End Function
`
This is the console output from the code
Seeking Encryption Key
Check Public KeyId: AAAAAAAAAAAAAAAA
IsMasterKey: True
**IsEncrpytKey: True**
PubKeyAlgo: RsaGeneral
PubKeyStrength: 4096
PubKeyVersion: 4
Check Public KeyId: BBBBBBBBBBBBBBBB
IsMasterKey: False
IsEncrpytKey: True
PubKeyAlgo: RsaGeneral
PubKeyStrength: 4096
PubKeyVersion: 4
Using SubKey KeyId: BBBBBBBBBBBBBBBB
As you can see from the output the Primary key (IsMasterKey: True) reports it has the encryption capability (IsEncryptKey: True) even though that capability belongs to the subkey. For the Primary key - IsEncryptKey should be False
The Subkey correctly reports that it is not the master key and it has the encryption capability
The result of this issue was that files got encrypted with the Primary key, and the recipient had to manually decrypt them as the referenced key does not have the (e)ncryption capability
To Reproduce
Steps to reproduce the behavior:
Run the code above - or the equivalent in C#
Expected Behavior
The original function return
If key.IsEncryptionKey Then Return key End If
should not be seeing the Primary key as having the (e)ncryption capability and should not have returned until it was on the subkey.
Screenshots and Logs
If applicable, add screenshots and logs to help explain your problem.
Product Deployment
Please complete the following information:
- Deployment format: [Nuget package for Visual Studio 2022]
- Version [Latest stable 2.6.1]
Desktop
Please complete the following information:
- OS: [Windows 11 64-bit]
- Browser [N/A]
- Version [N/A]
Additional Context
Add any other context about the problem here.