-
Notifications
You must be signed in to change notification settings - Fork 5k
Add PKCS#8, SPKI and PEM support for SLH-DSA #114943
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
base: main
Are you sure you want to change the base?
Conversation
Note regarding the
|
1 similar comment
Note regarding the
|
Tagging subscribers to this area: @dotnet/area-system-security, @bartonjs, @vcsjones |
src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
|
||
if (bytesRead != data.Length) | ||
// TODO should we use ReadEncodedValue with try/catch instead so we can rethrow with a useful inner exception? | ||
if (!AsnDecoder.TryReadEncodedValue(data, encoding, out _, out _, out _, out int bytesRead) || bytesRead != data.Length) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This API does not "deeply" validate encoding rules, so I am not sure with the intention of taking in the encoding rules.
That is to say: if you want to validate that an ASN.1 object is DER, this will not thrown for an indefinite length encoded item inside a definite length encoded item. This is only reading the most "outer" thing.
The actual reading will validate the rules - this was just meant to make sure there was nothing trailing after the data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought process here was that in the previous code, ReadEncodedValue
would throw AsnContentException
(for example, when the length in the encoding was longer that the encoding itself), so either we can catch it and wrap it in a CryptoException or ArgumentException, or change it to the TryReadEncodedValue
and throw. I did the latter, but if we're already doing the work of the check (even if it is non-exhaustive), it might make sense to surface it to the user as an inner exception. We can of course just let it throw the AsnContentException
up too but I think the pattern in all the APIs is to wrap it in a CryptoException
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improving the exception is fine - but accepting the encoding rules and renaming the method is what I am specifically focusing on. I don't think it does anymore more than validate there is no trailing data, and the rules don't matter for that one specific thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does validate that the length field encoded in the input is not larger than the input itself (not enough data). And in the DER case it does validate that it isn't using variable length encoding. As you mentioned, these are both only for the top level structure, but so is the trailing data check.
How about ThrowIfInvalidLength
or ThrowIfUnexpectedLength
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renaming it to something like ThrowIfInvalidLength
is fine, but since all callers (that I see) specify BER, it shouldn't be a parameter.
For consistency, AsnContentException should not be directly thrown.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does validate that the length field encoded in the input is not larger than the input itself (not enough data)
The AsnReader
(or AsnValueReader
) is going to catch that anyway when it attempts to actually decode the structure. Why try to pre-validate it? The only reason we have the trailing data check is is because it doesn't happen automatically during reading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The AsnReader (or AsnValueReader) is going to catch that anyway
I believe that actually is the problem. AsnDecoder.ReadEncodedValue threw an AsnContentException, this method didn't catch it, and an undocumented exception type escaped the public method.
Using TryRead avoids that exception, vs making a ThrowIf have a try/catch-wrap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using TryRead avoids that exception, vs making a ThrowIf have a try/catch-wrap.
Sure. My only point is that
- The method does not actually validate the encoding in a meaningful way
- It doesn't matter if it is BER/DER in this case.
- It was already throwing crypto exceptions for truncated ASN.1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was already throwing crypto exceptions for truncated ASN.1.
If that's the case, then, full-undo. If the edge case of the AsnContentException leaking out from the top-level item having a length that exceeds the span is true, then this is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- It was already throwing crypto exceptions for truncated ASN.1.
It throws AsnContentException
: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Formats.Asn1/src/System/Formats/Asn1/AsnDecoder.cs#L539-L540
- It doesn't matter if it is BER/DER in this case.
Yes, I can relax the encoding to always be BER, but we still are going to have to wrap because of the comment above.
src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
.../Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestData.cs
Show resolved
Hide resolved
.../Common/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaTestData.cs
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs
Outdated
Show resolved
Hide resolved
...n/tests/System/Security/Cryptography/AlgorithmImplementations/SlhDsa/SlhDsaAlgorithmTests.cs
Outdated
Show resolved
Hide resolved
|
||
namespace System.Security.Cryptography.SLHDsa.Tests | ||
{ | ||
public sealed class SlhDsaApiTests : SlhDsaInstanceTestsBase |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't mix test refactorings and adding new tests. Separate changes. Don't care which is first.
(if the moves had showed as a rename, it'd be fine, but it's hard to track "did we lose coverage of this existing thing" and "do we have coverage of this new thing" at the same time)
src/libraries/Common/tests/System/Security/Cryptography/MLKemContractTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Security.Cryptography/tests/SlhDsaOpenSslConstructionTests.NotSupported.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's too much test refactoring going on with a change that's adding functionality. They need to be split into independently reviewable pieces.
Do you have a preference on how this is done? I can rebase a commit with the refactoring to the base of this PR branch, but I'm not sure if github will mess up the existing PR feedback. Or I can just create a new PR with the refactoring and merge it back into here once it's in main. |
@@ -1,4 +1,8 @@ | |||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert
The refactoring/reorganizing and the addition of new features need to be in two different PRs (two different signoffs, and end up as two different commits permanently). Based on having done this recently, I'll speculate that the easiest answer is to make a new local branch based on this branch, delete all of the new stuff, then rebase it against dotnet/main (and pre-squash so it doesn't show any work happening then being undone). After that gets merged, then you can merge it into this branch and we resume looking at it after. The other option is to just undo all of the test refactoring and show this as just new feature and new feature tests, then either never do the refactoring, or do it as a followup. |
Add support for PKCS#8, SPKI and PEM, both encrypted and unencrypted. Test have been refactored to simplify things a little and SlhDsa.cs now has full code coverage (only Debug.Assert is not covered).
TODO:
SlhDsa.cs
has some TODOs in itContributes to #113506