Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for parsing TrustSignature packets #138

Merged
merged 4 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions openpgp/packet/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,3 +537,9 @@ const (
CurveBrainpoolP384 Curve = "BrainpoolP384"
CurveBrainpoolP512 Curve = "BrainpoolP512"
)

// TrustLevel represents a trust level per RFC4880 5.2.3.13
type TrustLevel uint8

// TrustAmount represents a trust amount per RFC4880 5.2.3.13
type TrustAmount uint8
16 changes: 16 additions & 0 deletions openpgp/packet/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ type Signature struct {
SignerUserId *string
IsPrimaryId *bool

// TrustLevel and TrustAmount can be set by the signer to assert that
// the key is not only valid but also trustworthy at the specified
// level.
// See RFC 4880, section 5.2.3.13 for details.
TrustLevel TrustLevel
TrustAmount TrustAmount

// PolicyURI can be set to the URI of a document that describes the
// policy under which the signature was issued. See RFC 4880, section
// 5.2.3.20 for details.
Expand Down Expand Up @@ -221,6 +228,7 @@ type signatureSubpacketType uint8
const (
creationTimeSubpacket signatureSubpacketType = 2
signatureExpirationSubpacket signatureSubpacketType = 3
trustSubpacket signatureSubpacketType = 5
keyExpirationSubpacket signatureSubpacketType = 9
prefSymmetricAlgosSubpacket signatureSubpacketType = 11
issuerSubpacket signatureSubpacketType = 16
Expand Down Expand Up @@ -301,6 +309,10 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r
}
sig.SigLifetimeSecs = new(uint32)
*sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket)
case trustSubpacket:
// Trust level and amount, section 5.2.3.13
sig.TrustLevel = TrustLevel(subpacket[0])
sig.TrustAmount = TrustAmount(subpacket[1])
case keyExpirationSubpacket:
// Key expiration time, section 5.2.3.6
if !isHashed {
Expand Down Expand Up @@ -902,6 +914,10 @@ func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubp
subpackets = append(subpackets, outputSubpacket{true, featuresSubpacket, false, []byte{features}})
}

if sig.TrustLevel != 0 {
subpackets = append(subpackets, outputSubpacket{true, trustSubpacket, true, []byte{byte(sig.TrustLevel), byte(sig.TrustAmount)}})
}

if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 {
keyLifetime := make([]byte, 4)
binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs)
Expand Down
26 changes: 26 additions & 0 deletions openpgp/packet/signature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,32 @@ func TestSignatureWithPolicyURI(t *testing.T) {
}
}

func TestSignatureWithTrust(t *testing.T) {
packet, err := Read(readerFromHex(signatureWithTrustDataHex))
if err != nil {
t.Error(err)
return
}
sig, ok := packet.(*Signature)
if !ok || sig.SigType != SigTypeGenericCert || sig.PubKeyAlgo != PubKeyAlgoRSA || sig.Hash != crypto.SHA256 || sig.TrustLevel != 0x01 || sig.TrustAmount != 0x03C {
t.Errorf("failed to parse, got: %#v", packet)
}

out := new(bytes.Buffer)
err = sig.Serialize(out)
if err != nil {
t.Errorf("error reserializing: %s", err)
return
}

expected, _ := hex.DecodeString(signatureWithTrustDataHex)
if !bytes.Equal(expected, out.Bytes()) {
t.Errorf("output doesn't match input (got vs expected):\n%s\n%s", hex.Dump(out.Bytes()), hex.Dump(expected))
}
}

const signatureDataHex = "c2c05c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"

const signatureWithTrustDataHex = "c2ad0410010800210502886e09001621040f0bfb42b3b08bece556fffcc181c053de849bf20385013c000035d803ff405c3c10211d680d3f5192e44d5acf7a25068a9938b5e5b1337735658ef8916e6878735ddfe15679c4868fcf46f02890104a5fb7caffa8e628a202deeda8376d58e586d60c1759e667fa49d87c7564c83b88f59db2631dc7e68535fd4a13b6096f91b05f7bb9989ddb36fc7e6e35dcc2f493468320cbe66e27895744eab2ae4b"

const positiveCertSignatureDataHex = "c2c0b304130108005d050b0908070206150a09080b020416020301021e010217802418686b70733a2f2f686b70732e706f6f6c2e736b732d6b6579736572766572732e6e65741621045ef9b8a44d89b32f94f3e9333679666422d0f62605025b2cc122021b2f000a09103679666422d0f62668e1080098b71f59ce893769ccb603344290e89df8f12d6ea906cc1c2b166c61a02679070744565f8280712b4e6bdfd482b758ef935655f1674c8f3633ab173d27cbe31e46368a8255134ecc5249ad66324cc4f6a79f160459b326711cfdc35032aac0903657a934f80f79768786ddd6554aa8d385c03adbee17c4e3e2831752d4910077da3b1f5562d267a57540a1c2b0dd2d96ed055c06098599b2390d61cfa37c6d19d9d63749fb3c3cfe0036fd959ba616eb23486216563fed8fdd19f96f5da9943db1698705fb688c1354c379ef01de307c4a0ac016e6385324cb0a7b49cfeee8961a289c8fa4c81d0e24e00969039db223a9835e8b86a8d85df645175f8aa0f8f2"