Skip to content

Commit

Permalink
Serialise keyserver preferences and preferred keyserver; add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewgdotcom committed Sep 20, 2024
1 parent b88eb6d commit cda34e7
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 12 deletions.
39 changes: 27 additions & 12 deletions openpgp/packet/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ type Signature struct {
PreferredCipherSuites [][2]uint8
IssuerKeyId *uint64
IssuerFingerprint []byte
SignerUserId, PreferredKeyserver *string
SignerUserId *string
IsPrimaryId *bool
Notations []*Notation
IntendedRecipients []*Recipient
Expand All @@ -110,6 +110,16 @@ type Signature struct {
// See RFC 9580, section 5.2.3.22 for details.
TrustRegularExpression *string

// KeyserverPrefsValid is set if any keyserver preferences were given. See RFC 9580, section
// 5.2.3.25 for details.
KeyserverPrefsValid bool
KeyserverPrefNoModify bool

// PreferredKeyserver can be set to a URI where the latest version of the
// key that this signature is made over can be found. See RFC 9580, section
// 5.2.3.26 for details.
PreferredKeyserver string

// PolicyURI can be set to the URI of a document that describes the
// policy under which the signature was issued. See RFC 9580, section
// 5.2.3.28 for details.
Expand All @@ -120,11 +130,6 @@ type Signature struct {
FlagsValid bool
FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage, FlagSplitKey, FlagAuthenticate, FlagGroupKey bool

// KeyserverPrefsValid is set if any keyserver preferences were given. See RFC 9580, section
// 5.2.3.25 for details.
KeyserverPrefsValid bool
KeyserverPrefNoModify bool

// RevocationReason is set if this signature has been revoked.
// See RFC 9580, section 5.2.3.31 for details.
RevocationReason *ReasonForRevocation
Expand Down Expand Up @@ -542,8 +547,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
}
case prefKeyserverSubpacket:
// Preferred keyserver, section 5.2.3.26
preferredKeyserver := string(subpacket)
sig.PreferredKeyserver = &preferredKeyserver
sig.PreferredKeyserver = string(subpacket)
case primaryUserIdSubpacket:
// Primary User ID, section 5.2.3.27
if len(subpacket) != 1 {
Expand Down Expand Up @@ -642,8 +646,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket[13:21])
}
case intendedRecipientSubpacket:
// Intended Recipient Fingerprint
// https://datatracker.ietf.org/doc/html/draft-ietf-openpgp-crypto-refresh#name-intended-recipient-fingerpr
// Intended Recipient Fingerprint, section 5.2.3.36
if len(subpacket) < 1 {
return nil, errors.StructuralError("invalid intended recipient fingerpring length")
}
Expand All @@ -655,8 +658,7 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
copy(fingerprint, subpacket[1:])
sig.IntendedRecipients = append(sig.IntendedRecipients, &Recipient{int(version), fingerprint})
case prefCipherSuitesSubpacket:
// Preferred AEAD cipher suites
// See https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-07.html#name-preferred-aead-ciphersuites
// Preferred AEAD cipher suites, section 5.2.3.15
if len(subpacket)%2 != 0 {
err = errors.StructuralError("invalid aead cipher suite length")
return
Expand Down Expand Up @@ -1307,6 +1309,19 @@ func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubp
if len(sig.PreferredCompression) > 0 {
subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression})
}
// Keyserver Preferences
// Keyserver preferences may only appear in self-signatures or certification signatures.
if sig.KeyserverPrefsValid {
var prefs byte
if sig.KeyserverPrefNoModify {
prefs |= KeyserverPrefNoModify
}
subpackets = append(subpackets, outputSubpacket{true, keyserverPrefsSubpacket, false, []byte{prefs}})
}
// Preferred Keyserver
if len(sig.PreferredKeyserver) > 0 {
subpackets = append(subpackets, outputSubpacket{true, prefKeyserverSubpacket, false, []uint8(sig.PreferredKeyserver)})
}
// Primary User ID
if sig.IsPrimaryId != nil && *sig.IsPrimaryId {
subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}})
Expand Down
65 changes: 65 additions & 0 deletions openpgp/packet/signature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,71 @@ func TestSignatureWithLifetime(t *testing.T) {
}
}

func TestSignatureWithPrefKeyserver(t *testing.T) {
testKeyserver := "hkps://example.com"
sig := &Signature{
SigType: SigTypeGenericCert,
PubKeyAlgo: PubKeyAlgoRSA,
Hash: crypto.SHA256,
PreferredKeyserver: testKeyserver,
KeyserverPrefsValid: true,
KeyserverPrefNoModify: true,
}

packet, err := Read(readerFromHex(rsaPkDataHex))
if err != nil {
t.Fatalf("failed to deserialize public key: %v", err)
}
pubKey := packet.(*PublicKey)

packet, err = Read(readerFromHex(privKeyRSAHex))
if err != nil {
t.Fatalf("failed to deserialize private key: %v", err)
}
privKey := packet.(*PrivateKey)

err = privKey.Decrypt([]byte("testing"))
if err != nil {
t.Fatalf("failed to decrypt private key: %v", err)
}

err = sig.SignUserId("", pubKey, privKey, nil)
if err != nil {
t.Errorf("failed to sign user id: %v", err)
}

buf := bytes.NewBuffer([]byte{})
err = sig.Serialize(buf)
if err != nil {
t.Errorf("failed to serialize signature: %v", err)
}

packet, _ = Read(bytes.NewReader(buf.Bytes()))
sig = packet.(*Signature)
if sig.PreferredKeyserver != testKeyserver {
t.Errorf("preferred keyserver is wrong: %s instead of %s", sig.PreferredKeyserver, testKeyserver)
}
if sig.KeyserverPrefsValid != true {
t.Errorf("keyserver preferences is not true")
}
if sig.KeyserverPrefNoModify != true {
t.Errorf("keyserverNoModify is not true")
}

for _, subPacket := range sig.rawSubpackets {
if subPacket.subpacketType == prefKeyserverSubpacket {
if subPacket.isCritical {
t.Errorf("preferred keyserver subpacket is marked as critical")
}
}
if subPacket.subpacketType == keyserverPrefsSubpacket {
if subPacket.isCritical {
t.Errorf("keyserver preferences subpacket is marked as critical")
}
}
}
}

func TestSignatureWithPolicyURI(t *testing.T) {
testPolicy := "This is a test policy"
sig := &Signature{
Expand Down

0 comments on commit cda34e7

Please sign in to comment.