Skip to content

Commit 1a52cd6

Browse files
authored
Improve exceptions thrown by MLKem and MLDsaOpenSsl when key types aren't available
1 parent 68e5dd7 commit 1a52cd6

File tree

10 files changed

+69
-18
lines changed

10 files changed

+69
-18
lines changed

src/libraries/Common/src/System/Security/Cryptography/MLDsaImplementation.Windows.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ protected override void ExportMLDsaPrivateSeedCore(Span<byte> destination)
132132
{
133133
if (!_hasSeed)
134134
{
135-
throw new CryptographicException(SR.Cryptography_MLDsaNoSeed);
135+
throw new CryptographicException(SR.Cryptography_PqcNoSeed);
136136
}
137137

138138
ExportKey(

src/libraries/Common/src/System/Security/Cryptography/MLKem.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,6 +1843,22 @@ private static string EncodeAsnWriterToPem(string label, AsnWriter writer, bool
18431843
#endif
18441844
}
18451845

1846+
private protected static void ThrowIfNoSeed(bool hasSeed)
1847+
{
1848+
if (!hasSeed)
1849+
{
1850+
throw new CryptographicException(SR.Cryptography_PqcNoSeed);
1851+
}
1852+
}
1853+
1854+
private protected static void ThrowIfNoDecapsulationKey(bool hasDecapsulationKey)
1855+
{
1856+
if (!hasDecapsulationKey)
1857+
{
1858+
throw new CryptographicException(SR.Cryptography_KemNoDecapsulationKey);
1859+
}
1860+
}
1861+
18461862
private delegate TResult ExportPkcs8PrivateKeyFunc<TResult>(ReadOnlySpan<byte> pkcs8);
18471863

18481864
private delegate AsnWriter WriteEncryptedPkcs8Func<TChar>(

src/libraries/Common/src/System/Security/Cryptography/MLKemImplementation.Windows.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ protected override void DecapsulateCore(ReadOnlySpan<byte> ciphertext, Span<byte
8282
Debug.Assert(IsSupported);
8383
Debug.Assert(ciphertext.Length == Algorithm.CiphertextSizeInBytes);
8484
Debug.Assert(sharedSecret.Length == Algorithm.SharedSecretSizeInBytes);
85+
86+
ThrowIfNoDecapsulationKey(_hasDecapsulationKey);
87+
8588
uint written = Interop.BCrypt.BCryptDecapsulate(_key, ciphertext, sharedSecret, 0);
8689
Debug.Assert(written == (uint)sharedSecret.Length);
8790
}
@@ -105,12 +108,16 @@ protected override void EncapsulateCore(Span<byte> ciphertext, Span<byte> shared
105108
protected override void ExportPrivateSeedCore(Span<byte> destination)
106109
{
107110
Debug.Assert(destination.Length == Algorithm.PrivateSeedSizeInBytes);
111+
112+
ThrowIfNoSeed(_hasSeed);
108113
ExportKey(KeyBlobMagicNumber.BCRYPT_MLKEM_PRIVATE_SEED_MAGIC, destination);
109114
}
110115

111116
protected override void ExportDecapsulationKeyCore(Span<byte> destination)
112117
{
113118
Debug.Assert(destination.Length == Algorithm.DecapsulationKeySizeInBytes);
119+
120+
ThrowIfNoDecapsulationKey(_hasDecapsulationKey);
114121
ExportKey(KeyBlobMagicNumber.BCRYPT_MLKEM_PRIVATE_MAGIC, destination);
115122
}
116123

src/libraries/Common/tests/System/Security/Cryptography/MLKemBaseTests.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ public void ExportPrivateSeed_OnlyHasDecapsulationKey()
4848
{
4949
using MLKem kem = ImportDecapsulationKey(MLKemAlgorithm.MLKem512, MLKemTestData.MLKem512DecapsulationKey);
5050

51-
Assert.ThrowsAny<CryptographicException>(() => kem.ExportPrivateSeed());
52-
Assert.ThrowsAny<CryptographicException>(() => kem.ExportPrivateSeed(
51+
Assert.Throws<CryptographicException>(() => kem.ExportPrivateSeed());
52+
Assert.Throws<CryptographicException>(() => kem.ExportPrivateSeed(
5353
new byte[MLKemAlgorithm.MLKem512.PrivateSeedSizeInBytes]));
5454
}
5555

@@ -58,8 +58,8 @@ public void ExportPrivateSeed_OnlyHasEncapsulationKey()
5858
{
5959
using MLKem kem = ImportEncapsulationKey(MLKemAlgorithm.MLKem512, MLKemTestData.MLKem512EncapsulationKey);
6060

61-
Assert.ThrowsAny<CryptographicException>(() => kem.ExportPrivateSeed());
62-
Assert.ThrowsAny<CryptographicException>(() => kem.ExportPrivateSeed(
61+
Assert.Throws<CryptographicException>(() => kem.ExportPrivateSeed());
62+
Assert.Throws<CryptographicException>(() => kem.ExportPrivateSeed(
6363
new byte[MLKemAlgorithm.MLKem512.PrivateSeedSizeInBytes]));
6464
}
6565

@@ -68,8 +68,8 @@ public void ExportDecapsulationKey_OnlyHasEncapsulationKey()
6868
{
6969
using MLKem kem = ImportEncapsulationKey(MLKemAlgorithm.MLKem512, MLKemTestData.MLKem512EncapsulationKey);
7070

71-
Assert.ThrowsAny<CryptographicException>(() => kem.ExportDecapsulationKey());
72-
Assert.ThrowsAny<CryptographicException>(() => kem.ExportDecapsulationKey(
71+
Assert.Throws<CryptographicException>(() => kem.ExportDecapsulationKey());
72+
Assert.Throws<CryptographicException>(() => kem.ExportDecapsulationKey(
7373
new byte[MLKemAlgorithm.MLKem512.DecapsulationKeySizeInBytes]));
7474
}
7575

@@ -344,7 +344,7 @@ public void ExportPkcs8PrivateKey_DecapsulationKey_Roundtrip()
344344
using MLKem imported = MLKem.ImportPkcs8PrivateKey(pkcs8);
345345
Assert.Equal(MLKemAlgorithm.MLKem512, imported.Algorithm);
346346

347-
Assert.ThrowsAny<CryptographicException>(() => kem.ExportPrivateSeed());
347+
Assert.Throws<CryptographicException>(() => kem.ExportPrivateSeed());
348348
AssertExtensions.SequenceEqual(MLKemTestData.MLKem512DecapsulationKey, kem.ExportDecapsulationKey());
349349
});
350350
}
@@ -370,7 +370,7 @@ public void ExportEncryptedPkcs8PrivateKey_DecapsulationKey_Roundtrip()
370370
AssertExtensions.SequenceEqual(
371371
MLKemTestData.MLKem512DecapsulationKey,
372372
imported.ExportDecapsulationKey());
373-
Assert.ThrowsAny<CryptographicException>(() => imported.ExportPrivateSeed());
373+
Assert.Throws<CryptographicException>(() => imported.ExportPrivateSeed());
374374
});
375375
}
376376

src/libraries/Microsoft.Bcl.Cryptography/src/Resources/Strings.resx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,15 @@
168168
<data name="Cryptography_KemPkcs8KeyMismatch" xml:space="preserve">
169169
<value>The specified PKCS#8 key contains a seed that does not match the expanded key.</value>
170170
</data>
171+
<data name="Cryptography_KemNoDecapsulationKey" xml:space="preserve">
172+
<value>The current instance does not contain a decapsulation key.</value>
173+
</data>
171174
<data name="Cryptography_KeyWrongSizeForAlgorithm" xml:space="preserve">
172175
<value>The specified key is not the correct size for the indicated algorithm.</value>
173176
</data>
174177
<data name="Cryptography_MLDsaNoSecretKey" xml:space="preserve">
175178
<value>The current instance does not contain a secret key.</value>
176179
</data>
177-
<data name="Cryptography_MLDsaNoSeed" xml:space="preserve">
178-
<value>The current instance does not contain a seed.</value>
179-
</data>
180180
<data name="Cryptography_MLDsaPkcs8KeyMismatch" xml:space="preserve">
181181
<value>The specified PKCS#8 key contains a seed that does not match the expanded key.</value>
182182
</data>
@@ -201,6 +201,9 @@
201201
<data name="Cryptography_PlaintextCiphertextLengthMismatch" xml:space="preserve">
202202
<value>Plaintext and ciphertext must have the same length.</value>
203203
</data>
204+
<data name="Cryptography_PqcNoSeed" xml:space="preserve">
205+
<value>The current instance does not contain a seed.</value>
206+
</data>
204207
<data name="Cryptography_UnknownAlgorithmIdentifier" xml:space="preserve">
205208
<value>The algorithm identified by '{0}' is unknown, not valid for the requested usage, or was not handled.</value>
206209
</data>

src/libraries/System.Security.Cryptography/src/Resources/Strings.resx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,9 @@
525525
<data name="Cryptography_KemInvalidAlgorithmHandle" xml:space="preserve">
526526
<value>The specified EVP_PKEY handle is not a known ML-KEM algorithm.</value>
527527
</data>
528+
<data name="Cryptography_KemNoDecapsulationKey" xml:space="preserve">
529+
<value>The current instance does not contain a decapsulation key.</value>
530+
</data>
528531
<data name="Cryptography_KemPkcs8KeyMismatch" xml:space="preserve">
529532
<value>The specified PKCS#8 key contains a seed that does not match the expanded key.</value>
530533
</data>
@@ -552,9 +555,6 @@
552555
<data name="Cryptography_MLDsaNoSecretKey" xml:space="preserve">
553556
<value>The current instance does not contain a secret key.</value>
554557
</data>
555-
<data name="Cryptography_MLDsaNoSeed" xml:space="preserve">
556-
<value>The current instance does not contain a seed.</value>
557-
</data>
558558
<data name="Cryptography_MLDsaPkcs8KeyMismatch" xml:space="preserve">
559559
<value>The specified PKCS#8 key contains a seed that does not match the expanded key.</value>
560560
</data>
@@ -690,6 +690,9 @@
690690
<data name="Cryptography_PlaintextTooLarge" xml:space="preserve">
691691
<value>The specified plaintext size is too large.</value>
692692
</data>
693+
<data name="Cryptography_PqcNoSeed" xml:space="preserve">
694+
<value>The current instance does not contain a seed.</value>
695+
</data>
693696
<data name="Cryptography_PrivateKey_DoesNotMatch" xml:space="preserve">
694697
<value>The provided key does not match the public key for this certificate.</value>
695698
</data>

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MLDsaImplementation.OpenSsl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ protected override void ExportMLDsaPrivateSeedCore(Span<byte> destination)
7373
{
7474
if (!_hasSeed)
7575
{
76-
throw new CryptographicException(SR.Cryptography_MLDsaNoSeed);
76+
throw new CryptographicException(SR.Cryptography_PqcNoSeed);
7777
}
7878

7979
Interop.Crypto.MLDsaExportSeed(_key, destination);

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MLDsaOpenSsl.OpenSsl.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,26 @@ protected override void ExportMLDsaPublicKeyCore(Span<byte> destination) =>
8181
Interop.Crypto.MLDsaExportPublicKey(_key, destination);
8282

8383
/// <inheritdoc />
84-
protected override void ExportMLDsaSecretKeyCore(Span<byte> destination) =>
84+
protected override void ExportMLDsaSecretKeyCore(Span<byte> destination)
85+
{
86+
if (!_hasSecretKey)
87+
{
88+
throw new CryptographicException(SR.Cryptography_MLDsaNoSecretKey);
89+
}
90+
8591
Interop.Crypto.MLDsaExportSecretKey(_key, destination);
92+
}
8693

8794
/// <inheritdoc />
88-
protected override void ExportMLDsaPrivateSeedCore(Span<byte> destination) =>
95+
protected override void ExportMLDsaPrivateSeedCore(Span<byte> destination)
96+
{
97+
if (!_hasSeed)
98+
{
99+
throw new CryptographicException(SR.Cryptography_PqcNoSeed);
100+
}
101+
89102
Interop.Crypto.MLDsaExportSeed(_key, destination);
103+
}
90104

91105
/// <inheritdoc />
92106
protected override bool TryExportPkcs8PrivateKeyCore(Span<byte> destination, out int bytesWritten)

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MLKemImplementation.OpenSsl.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ protected override void Dispose(bool disposing)
7676

7777
protected override void DecapsulateCore(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret)
7878
{
79+
ThrowIfNoDecapsulationKey(_hasDecapsulationKey);
7980
Interop.Crypto.EvpKemDecapsulate(_key, ciphertext, sharedSecret);
8081
}
8182

@@ -86,11 +87,13 @@ protected override void EncapsulateCore(Span<byte> ciphertext, Span<byte> shared
8687

8788
protected override void ExportPrivateSeedCore(Span<byte> destination)
8889
{
90+
ThrowIfNoSeed(_hasSeed);
8991
Interop.Crypto.EvpKemExportPrivateSeed(_key, destination);
9092
}
9193

9294
protected override void ExportDecapsulationKeyCore(Span<byte> destination)
9395
{
96+
ThrowIfNoDecapsulationKey(_hasDecapsulationKey);
9497
Interop.Crypto.EvpKemExportDecapsulationKey(_key, destination);
9598
}
9699

src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/MLKemOpenSsl.OpenSsl.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ protected override void Dispose(bool disposing)
7070
/// <inheritdoc />
7171
protected override void DecapsulateCore(ReadOnlySpan<byte> ciphertext, Span<byte> sharedSecret)
7272
{
73+
// This cannot use _hasDecapsulationKey here because this field only indicates if it is exportable, not if
74+
// it is usable. This instance could represent an ML-KEM instance with a decapsulation key in hardware,
75+
// for example.
7376
Interop.Crypto.EvpKemDecapsulate(_key, ciphertext, sharedSecret);
7477
}
7578

@@ -82,12 +85,14 @@ protected override void EncapsulateCore(Span<byte> ciphertext, Span<byte> shared
8285
/// <inheritdoc />
8386
protected override void ExportPrivateSeedCore(Span<byte> destination)
8487
{
88+
ThrowIfNoSeed(_hasSeed);
8589
Interop.Crypto.EvpKemExportPrivateSeed(_key, destination);
8690
}
8791

8892
/// <inheritdoc />
8993
protected override void ExportDecapsulationKeyCore(Span<byte> destination)
9094
{
95+
ThrowIfNoDecapsulationKey(_hasDecapsulationKey);
9196
Interop.Crypto.EvpKemExportDecapsulationKey(_key, destination);
9297
}
9398

0 commit comments

Comments
 (0)