Skip to content

Update Mozilla SPKI and SignatureAlgorithm encoding lints#950

Merged
christopher-henderson merged 8 commits intozmap:masterfrom
digirenpeter:master
May 25, 2025
Merged

Update Mozilla SPKI and SignatureAlgorithm encoding lints#950
christopher-henderson merged 8 commits intozmap:masterfrom
digirenpeter:master

Conversation

@digirenpeter
Copy link
Copy Markdown
Contributor

It looks like Mozilla updated their Root Store policy to allow for P-521 so I'm updating the 2 related Mozilla lints.
https://www.mozilla.org/en-US/about/governance/policies/security-group/certs/policy/#5-certificates

Updated SPKI section:

When ECDSA keys are encoded in a SubjectPublicKeyInfo structure, the algorithm field MUST be one of the following, as specified by [RFC 5480, Section 2.1.1](https://datatracker.ietf.org/doc/html/rfc5480#section-2.1.1):

the encoded AlgorithmIdentifier for a P-256 key MUST match the following hex-encoded 
bytes: 301306072a8648ce3d020106082a8648ce3d030107;

the encoded AlgorithmIdentifier for a P-384 key MUST match the following hex-encoded 
bytes: 301006072a8648ce3d020106052b81040022; or

the encoded AlgorithmIdentifier for a P-521 key MUST match the following hex-encoded 
bytes: 301006072a8648ce3d020106052b81040023.

The above encodings consist of an ecPublicKey OID (1.2.840.10045.2.1) with a named curve parameter of the corresponding curve OID. Certificates MUST NOT use the implicit or specified curve forms.

Updated SignatureAlgorithm section:

When a root or intermediate certificate's ECDSA key is used to produce a signature, only the following algorithms MAY be used, and with the following encoding requirements:

if the signing key is P-256, the signature MUST use ECDSA with SHA-256. The encoded AlgorithmIdentifier MUST match 
the following hex-encoded bytes: 300a06082a8648ce3d040302.

if the signing key is P-384, the signature MUST use ECDSA with SHA-384. The encoded AlgorithmIdentifier MUST match 
the following hex-encoded bytes: 300a06082a8648ce3d040303.

if the signing key is P-521, the signature MUST use ECDSA with SHA-512. When encoded, the AlgorithmIdentifier MUST 
be byte-for-byte identical with the following hex-encoded bytes: 300a06082a8648ce3d040304.

The above encodings consist of the corresponding OID with the parameters field omitted, as specified by [RFC 5758, Section 3.2](https://datatracker.ietf.org/doc/html/rfc5758#section-3.2). 
Certificates MUST NOT include a NULL parameter. Note this differs from RSASSA-PKCS1-v1_5, which includes an explicit NULL

Copy link
Copy Markdown
Member

@christopher-henderson christopher-henderson left a comment

Choose a reason for hiding this comment

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

Thank you @digirenpeter! The implementation of this lint is one of the more esoteric ones, so I appreciate you doing the legwork to find all of the correct encodings.

The linter is complaining that it doesn't like the new else block due to cyclomatic complexity.

I believe that the following annotation on the Execute method should convince the linter to calm down.

//nolint:nestif
func (l *ecdsaSignatureAidEncoding) Execute(c *x509.Certificate) *lint.LintResult {

const maxP256SigByteLen = 72
// len <= 2+2+2+49+49 (= 104)
const maxP384SigByteLen = 104
// len <= 2+2+2+67+67 (= 140)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It took me a bit to confirm this, which means it took you longer than that to write it 😆 thank you!

@mtgag
Copy link
Copy Markdown
Contributor

mtgag commented May 12, 2025

Could I propose a change? I suggest adding an IneffectiveDate (i.e., the point in time when P-521 becomes allowed) to the old lints, and duplicating the PR implementation into new lints with an EffectiveDate (i.e., when P-521 becomes allowed). This way, we can avoid false negatives for P-521 certificates issued before that date. While this approach duplicates some code, I believe it is the simplest way to address the issue.

We could also keep the new implementation and set the date when P-521 becomes allowed as the EffectiveDate. If linting older certificates is not required, this approach would work as well. I suppose this touches on a more general issue with linting: if only forward linting is needed, then this solution should suffice. However, if retrospective linting is also necessary, then the first proposal would address that. Any thoughts?

@digirenpeter
Copy link
Copy Markdown
Contributor Author

@mtgag In the old version the policy had this line (It still does, but just for Curve25519 and 448):

The following curves are not prohibited, but are not currently supported: P-521, Curve25519, and Curve448.

So I would argue that the lint was being overly strict before by returning an error for P-521. In this case I think it's fine for this specific lint to be forward linting, since before it should've probably been returning a warning for P-521.

@mtgag
Copy link
Copy Markdown
Contributor

mtgag commented May 13, 2025

@mtgag In the old version the policy had this line (It still does, but just for Curve25519 and 448):

The following curves are not prohibited, but are not currently supported: P-521, Curve25519, and Curve448.

So I would argue that the lint was being overly strict before by returning an error for P-521. In this case I think it's fine for this specific lint to be forward linting, since before it should've probably been returning a warning for P-521.

The original lint refers to version 2.7 of the Mozilla policy (see: https://github.com/mozilla/pkipolicy/blob/2.7/rootstore/policy.md#512-ecdsa).

In my opinion, either option 1, adding MozillaPolicy30Date as the ineffective date to the original lint and moving the PR implementation to a new lint with MozillaPolicy30Date as its effective date, or option 2, simply updating the effective date of the new lint to MozillaPolicy30Date, reflects the situation more accurately than option 3, which updates the implementation while keeping the original MozillaPolicy27Date.

@digirenpeter
Copy link
Copy Markdown
Contributor Author

I see what you mean, I'll update the effective date.

@christopher-henderson
Copy link
Copy Markdown
Member

Howdy @digirenpeter, it looks like you went with option 2, simply updating the effective date of the new lint to MozillaPolicy30Date. Is this correct?

@mtgag thank you for chiming in! Does the change now reflect your vision?

@digirenpeter
Copy link
Copy Markdown
Contributor Author

That's right, I feel like option 2 is the cleanest, but I'm open to option 3 if people feel strongly enough about it.

@mtgag
Copy link
Copy Markdown
Contributor

mtgag commented May 19, 2025

Howdy @digirenpeter, it looks like you went with option 2, simply updating the effective date of the new lint to MozillaPolicy30Date. Is this correct?

@mtgag thank you for chiming in! Does the change now reflect your vision?

Yes, option 2 is perfectly fine.

@christopher-henderson christopher-henderson merged commit 82294d2 into zmap:master May 25, 2025
4 checks passed
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.

3 participants