8000 Dispose all resources used in CmsSignature by PranavSenthilnathan · Pull Request #115666 · dotnet/runtime · GitHub
[go: up one dir, main page]

Skip to content

Dispose all resources used in CmsSignature #115666

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

PranavSenthilnathan
Copy link
Member

Dispose keys in CmsSignature more consistently.

Contributes to #115578

@PranavSenthilnathan PranavSenthilnathan self-assigned this May 16, 2025
@Copilot Copilot AI review requested due to automatic review settings May 16, 2025 20:30
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-security, @bartonjs, @vcsjones
See info in area-owners.md if you want to be subscribed.

Copy link
Contributor
@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors the handling of signing keys in CmsSignature to ensure all disposable resources are consistently disposed. The changes include:

  • Introducing a new helper method GetSigningKey to centralize key retrieval and disposal.
  • Updating the implementations for RSA, DSA, ECDsa, and SlhDsa to use the new helper method.
  • Minor renaming adjustments for clarity in key-related parameters.

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
CmsSignature.cs Added GetSigningKey helper to encapsulate key retrieval and disposal logic.
CmsSignature.SlhDsa.cs Updated signing logic to use GetSigningKey for consistent disposal.
CmsSignature.RSA.cs Refactored signing and verification for RSA to leverage GetSigningKey and ensure proper resource disposal.
CmsSignature.ECDsa.cs Replaced direct disposal of keys with GetSigningKey and adjusted parameter naming.
CmsSignature.DSA.cs Updated DSA signing to use GetSigningKey for improved resource management.


if (key != null)
{
using (DSA certKey = certificate.GetDSAPublicKey()!)
Copy link
Preview
Copilot AI May 16, 2025

Choose a reason for hiding this comment

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

Multiple calls to certificate.GetDSAPublicKey() for signature verification could be optimized by storing the key in a temporary variable.

Suggested change
using (DSA certKey = certificate.GetDSAPublicKey()!)
using (DSA certKey = dsaPublicKey!)

Copilot uses AI. Check for mistakes.

Copy link
Member Author

Choose a reason for hiding this comment

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

If a private key isn't passed in as an argument but the cert has an associated private key, then GetDSAPublicKey will never be called, so we should only call it when it is needed.

Also GetDSAPublicKey is never called multiple times. If GetSigningKey calls it, it's to fail the Sign call with an appropriate "no private key" error and there won't be subsequent calls to GetSigningKey.


if (key != null)
{
using (ECDsa certKey = certificate.GetECDsaPublicKey()!)
Copy link
Member Author

Choose a reason for hiding this comment

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

using declaration would be nice here since scope is obvious. Just curious, what is the reason we generally prefer using blocks?

Copy link
Member

Choose a reason for hiding this comment

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

In my personal opinion: Braced using statements make it very clear where the end of the scope is.

if (needSomething)
{
    using (Something something = GetSomething())
    {
       ...
+      Console.WriteLine("Done.");
    }
}

You can see that that increased the lifetime of something. Maybe that's important, but in the "Done" only case here, it isn't. That should be outside the braces. When it looks like

if (needSomething)
{
    using Something something = GetSomething();
    ...
+   Console.WriteLine("Done");
}

Well, the brace that it went in front of is the "if". That matches the context it belonged to. But it extended the lifetime of something. Which may be irrelevant, or may be bad.

In security code, it is always important to know what the lifetime of things is. So braced usings.

Copy link
Member

Choose a reason for hiding this comment

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

I wonder if all of these "verify it against the cert public key" should be moved to other methods, so this becomes

if (key != null && !VerifyWithPublicKey(certificate, dataHash, signedHash))
{
   ...
}

which will keep the same indentation and logic levels.

It's also fine as inline code; since I don't know that it's going to extract a lot of code or help codify a pattern.

certPublicKey;

if (privateKey is null)
using (GetSigningKey(key, certificate, silent, certificate.GetRSAPublicKey, out RSA? privateKey))
Copy link
Member Author

Choose a reason for hiding this comment

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

Same here, using declaration would avoid all the indent diffs. This initialized at the top of the function and its lifetime should extend until the method returns.

@@ -100,26 +100,17 @@ protected override bool Sign(
// not enforce them here. It is up to the caller to choose an appropriate hash.

signatureParameters = null;
signatureAlgorithm = _signatureAlgorithm;
Copy link
Member

Choose a reason for hiding this comment

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

You've moved an assignment of this out to earlier than it used to be. Do any of the callers ever use this out in a shared memory location (i.e. a static field)?

It's generally best to only ever have one write to an out, just in case they become "side effect visible"; and this change makes signature failure go from non-null back to null.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oops, I'll remove the other null assignment below that I missed. The other algos also follow this pattern of assignment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0