Skip to content

Add Signature.IssuerKeyVersion field#310

Merged
twiss merged 8 commits into
ProtonMail:mainfrom
pgpkeys-eu:feature/issuerfpfixes
May 19, 2026
Merged

Add Signature.IssuerKeyVersion field#310
twiss merged 8 commits into
ProtonMail:mainfrom
pgpkeys-eu:feature/issuerfpfixes

Conversation

@andrewgdotcom
Copy link
Copy Markdown
Contributor

@andrewgdotcom andrewgdotcom commented May 16, 2026

  • exposes version field from IssuerFingerprint subpacket
  • remove redundant nil checks

(closes #296)

@andrewgdotcom andrewgdotcom changed the title Minor fixes to IssuerFingerprint implementation Minor fixes to IssuerFingerprint implementation (closes #296) May 16, 2026
@twiss
Copy link
Copy Markdown
Collaborator

twiss commented May 18, 2026

Thanks for the PR! However I wouldn't put exposing a new field in the category of "minor fixes" 😅

Also, if we set a new field when reading signature packets, we should also set it when creating them, such as here:

IssuerFingerprint: signer.Fingerprint,
(among other places).

And, we should also take it into account when writing the signature here, so that it roundtrips correctly:

contents := append([]uint8{uint8(issuer.Version)}, sig.IssuerFingerprint...)

And finally we could then remove the issuer parameter from buildSubpackets which was probably a mistake to begin with:

func (sig *Signature) buildSubpackets(issuer PublicKey, config *Config) (subpackets []outputSubpacket, err error) {

@andrewgdotcom andrewgdotcom changed the title Minor fixes to IssuerFingerprint implementation (closes #296) Updates to IssuerFingerprint implementation (closes #296) May 18, 2026
@andrewgdotcom
Copy link
Copy Markdown
Contributor Author

It would be nice if there was a "versioned fingerprint" type that we could use instead of having separate fields, but that would either require a breaking api change, or even more redundancy...

@twiss
Copy link
Copy Markdown
Collaborator

twiss commented May 18, 2026

Thanks!

After looking at the code again I think IssuerKeyVersion is less clunky and makes more sense than IssuerFingerprintVersion. I changed it locally with some other tiny cleanup, but can't push to the branch. Would you mind allowing maintainers to push to the branch? Otherwise if you prefer I can also make a new PR.

@andrewgdotcom
Copy link
Copy Markdown
Contributor Author

Would you mind allowing maintainers to push to the branch?

I don't have that option, it's only available in personal branches, not org branches. If you want to PR into my branch, or just take my branch and mangle it, feel free :-)

@andrewgdotcom
Copy link
Copy Markdown
Contributor Author

Scratch the above, I've given you write access to my fork.

@twiss twiss changed the title Updates to IssuerFingerprint implementation (closes #296) Add Signature.IssuerKeyVersion field May 19, 2026
@twiss
Copy link
Copy Markdown
Collaborator

twiss commented May 19, 2026

That also works, thanks!

I've pushed the change, lmk if it still looks reasonable to you and then I'll merge.

Comment thread openpgp/v2/read.go Outdated
PubKeyAlgo: ops.PubKeyAlgo,
IssuerKeyId: ops.KeyId,
Salt: ops.Salt,
IssuerKeyVersion: uint8(ops.Version),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, re-reading this, this part is not correct because it assumes the signing key version matches the one-pass signature version, which is unfortunately not necessarily the case: https://www.rfc-editor.org/rfc/rfc9580.html#signed-message-versions

I'm somewhat wondering whether we need this field in SignatureCandidate or should drop it for now, since we don't have this information here. Do you have an opinion?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oof, good catch. I'm inclined to say that if we don't have the info, we should just drop it. Will need to remove the corresponding check further down... leave it with me.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implicit logic elsewhere is that if IssuerFingerprint is nil, IssuerKeyVersion is 0 - so maybe the most self-consistent (and future-proof) thing to do is set this to ops.Version IFF ops.Version is >= 6, and 0 otherwise?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made the IFF change now, as it mirrors the equivalent logic in newSignatureCandidateFromSignature. I've also made a couple of driveby fixes to SignatureCandidate.validate().

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it's guaranteed to be future proof because if we define key version 7 without defining one-pass signature version 7; we would have an issuer fingerprint without a known issuer key version (which arguably is not ideal and so we should have included an issuer key version field). Arguably we should then not do that but.. that's to be decided in the future 🙃

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the definition of ops v6 assumes the fingerprint length is fixed, so we're already taking that risk... 😁 I think lockstep version bumps of key, sig and ops should be standard practice in future, even if there are no wire format changes in some of the packets (we did the same thing in v2->v3)

Copy link
Copy Markdown
Collaborator

@twiss twiss May 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's true. However, in the absence of a field on the wire, what are we actually checking with this field here?

We're setting the issuer key version to 6 if the OPS version is 6, and then later we're checking the OPS version against the signature version and the (assumed) OPS issuer key version against the signature's issuer key version. So, in a very roundabout way, we're checking that if the OPS version is 6, the signature version and issuer key version field must also be 6. However, we're still not actually checking the issuer key version field against the verification key version.

I think it would be more straightforward to just check the signature's issuer key version field against the verification key version, and also check that the signature version and signing key version correspond properly as per Table 27 (i.e. #309). Then we don't have to carry this extra field around based on various assumptions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, I've reverted this (and also simplified some of the test logic further)

Copy link
Copy Markdown
Collaborator

@twiss twiss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@twiss twiss merged commit d642649 into ProtonMail:main May 19, 2026
9 checks passed
@andrewgdotcom andrewgdotcom deleted the feature/issuerfpfixes branch May 19, 2026 15:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose the version octet from IssuerFingerprint subpacket.

2 participants