Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 1cb15df

Browse files
author
Paulo Janotti
authored
Port "Keep SSL error queue clean" to 2.1 (#29438)
* Reducing chances of polluting SSL error queue (#29351)
1 parent 6906dbf commit 1cb15df

File tree

28 files changed

+283
-79
lines changed

28 files changed

+283
-79
lines changed

src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ASN1.Print.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ internal static string DerStringToManagedString(byte[] derString)
2626

2727
if (asn1String.IsInvalid)
2828
{
29+
Interop.Crypto.ErrClearError();
2930
return null;
3031
}
3132

@@ -54,6 +55,8 @@ private static string Asn1StringToManagedString<THandle>(
5455

5556
using (SafeBioHandle bio = CreateMemoryBio())
5657
{
58+
CheckValidOpenSslHandle(bio);
59+
5760
int len = asn1StringPrintEx(bio, asn1String, Asn1StringPrintFlags.ASN1_STRFLGS_UTF8_CONVERT);
5861

5962
if (len < 0)

src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ASN1.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,17 @@ internal static partial class Crypto
2020
private static extern unsafe int ObjObj2Txt(byte* buf, int buf_len, IntPtr a);
2121

2222
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetObjectDefinitionByName", CharSet = CharSet.Ansi)]
23-
internal static extern IntPtr GetObjectDefinitionByName(string friendlyName);
23+
private static extern IntPtr CryptoNative_GetObjectDefinitionByName(string friendlyName);
24+
internal static IntPtr GetObjectDefinitionByName(string friendlyName)
25+
{
26+
IntPtr ret = CryptoNative_GetObjectDefinitionByName(friendlyName);
27+
if (ret == IntPtr.Zero)
28+
{
29+
ErrClearError();
30+
}
31+
32+
return ret;
33+
}
2434

2535
// Returns shared pointers, should not be tracked as a SafeHandle.
2636
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_ObjNid2Obj")]

src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Bignum.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,14 @@ private static IntPtr CreateBignumPtr(byte[] bigEndianValue)
2929
return IntPtr.Zero;
3030
}
3131

32-
return BigNumFromBinary(bigEndianValue, bigEndianValue.Length);
32+
IntPtr ret = BigNumFromBinary(bigEndianValue, bigEndianValue.Length);
33+
34+
if (ret == IntPtr.Zero)
35+
{
36+
throw CreateOpenSslCryptographicException();
37+
}
38+
39+
return ret;
3340
}
3441

3542
internal static SafeBignumHandle CreateBignum(byte[] bigEndianValue)

src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Crypto.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,18 @@ internal static partial class Crypto
1616
private delegate int NegativeSizeReadMethod<in THandle>(THandle handle, byte[] buf, int cBuf);
1717

1818
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioTell")]
19-
internal static extern int BioTell(SafeBioHandle bio);
19+
internal static extern int CryptoNative_BioTell(SafeBioHandle bio);
20+
21+
internal static int BioTell(SafeBioHandle bio)
22+
{
23+
int ret = CryptoNative_BioTell(bio);
24+
if (ret < 0)
25+
{
26+
throw CreateOpenSslCryptographicException();
27+
}
28+
29+
return ret;
30+
}
2031

2132
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_BioSeek")]
2233
internal static extern int BioSeek(SafeBioHandle bio, int pos);

src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Dsa.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,19 @@ internal static bool DsaSign(SafeDsaHandle dsa, ReadOnlySpan<byte> hash, int has
7373
[return: MarshalAs(UnmanagedType.Bool)]
7474
private static extern bool DsaSign(SafeDsaHandle dsa, ref byte hash, int hashLength, ref byte refSignature, out int outSignatureLength);
7575

76-
internal static bool DsaVerify(SafeDsaHandle dsa, ReadOnlySpan<byte> hash, int hashLength, ReadOnlySpan<byte> signature, int signatureLength) =>
77-
DsaVerify(dsa, ref MemoryMarshal.GetReference(hash), hashLength, ref MemoryMarshal.GetReference(signature), signatureLength);
76+
internal static bool DsaVerify(SafeDsaHandle dsa, ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature)
77+
{
78+
bool ret = DsaVerify(
79+
dsa,
80+
ref MemoryMarshal.GetReference(hash),
81+
hash.Length,
82+
ref MemoryMarshal.GetReference(signature),
83+
signature.Length);
84+
85+
// Error queue already cleaned on the native function.
86+
87+
return ret;
88+
}
7889

7990
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaVerify")]
8091
[return: MarshalAs(UnmanagedType.Bool)]

src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcDsa.ImportExport.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ internal static SafeEcKeyHandle EcKeyCreateByKeyParameters(
3333
int rc = EcKeyCreateByKeyParameters(out key, oid, qx, qxLength, qy, qyLength, d, dLength);
3434
if (rc == -1)
3535
{
36-
if (key != null)
37-
key.Dispose();
36+
key?.Dispose();
37+
Interop.Crypto.ErrClearError();
38+
3839
throw new PlatformNotSupportedException(string.Format(SR.Cryptography_CurveNotSupported, oid));
3940
}
4041
return key;
@@ -92,6 +93,10 @@ internal static SafeEcKeyHandle EcKeyCreateByExplicitCurve(ECCurve curve)
9293
throw Interop.Crypto.CreateOpenSslCryptographicException();
9394
}
9495

96+
// EcKeyCreateByExplicitParameters may have polluted the error queue, but key was good in the end.
97+
// Clean up the error queue.
98+
Interop.Crypto.ErrClearError();
99+
95100
return key;
96101
}
97102

src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcDsa.cs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,22 @@ internal static bool EcDsaSign(ReadOnlySpan<byte> dgst, int dlen, Span<byte> sig
1717
[return: MarshalAs(UnmanagedType.Bool)]
1818
private static extern bool EcDsaSign(ref byte dgst, int dlen, ref byte sig, [In, Out] ref int siglen, SafeEcKeyHandle ecKey);
1919

20-
internal static unsafe int EcDsaVerify(ReadOnlySpan<byte> dgst, int dgst_len, ReadOnlySpan<byte> sigbuf, int sig_len, SafeEcKeyHandle ecKey) =>
21-
EcDsaVerify(ref MemoryMarshal.GetReference(dgst), dgst_len, ref MemoryMarshal.GetReference(sigbuf), sig_len, ecKey);
20+
internal static int EcDsaVerify(ReadOnlySpan<byte> dgst, ReadOnlySpan<byte> sigbuf, SafeEcKeyHandle ecKey)
21+
{
22+
int ret = EcDsaVerify(
23+
ref MemoryMarshal.GetReference(dgst),
24+
dgst.Length,
25+
ref MemoryMarshal.GetReference(sigbuf),
26+
sigbuf.Length,
27+
ecKey);
28+
29+
if (ret < 0)
30+
{
31+
ErrClearError();
32+
}
33+
34+
return ret;
35+
}
2236

2337
/*-
2438
* returns
@@ -31,6 +45,18 @@ internal static unsafe int EcDsaVerify(ReadOnlySpan<byte> dgst, int dgst_len, Re
3145

3246
// returns the maximum length of a DER encoded ECDSA signature created with this key.
3347
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EcDsaSize")]
34-
internal static extern int EcDsaSize(SafeEcKeyHandle ecKey);
48+
private static extern int CryptoNative_EcDsaSize(SafeEcKeyHandle ecKey);
49+
50+
internal static int EcDsaSize(SafeEcKeyHandle ecKey)
51+
{
52+
int ret = CryptoNative_EcDsaSize(ecKey);
53+
54+
if (ret == 0)
55+
{
56+
throw CreateOpenSslCryptographicException();
57+
}
58+
59+
return ret;
60+
}
3561
}
3662
}

src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcKey.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,17 @@ internal static partial class Interop
1212
internal static partial class Crypto
1313
{
1414
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EcKeyCreateByOid")]
15-
internal static extern SafeEcKeyHandle EcKeyCreateByOid(string oid);
15+
private static extern SafeEcKeyHandle CryptoNative_EcKeyCreateByOid(string oid);
16+
internal static SafeEcKeyHandle EcKeyCreateByOid(string oid)
17+
{
18+
SafeEcKeyHandle handle = CryptoNative_EcKeyCreateByOid(oid);
19+
if (handle == null || handle.IsInvalid)
20+
{
21+
ErrClearError();
22+
}
23+
24+
return handle;
25+
}
1626

1727
[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EcKeyDestroy")]
1828
internal static extern void EcKeyDestroy(IntPtr a);

src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Encode.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,18 @@ internal static byte[] OpenSslEncode<THandle>(GetEncodedSizeFunc<THandle> getSiz
2828
byte[] data = new byte[size];
2929

3030
int size2 = encode(handle, data);
31-
Debug.Assert(size == size2);
31+
if (size2 < 1)
32+
{
33+
Debug.Fail(
34+
$"{nameof(OpenSslEncode)}: {nameof(getSize)} succeeded ({size}) and {nameof(encode)} failed ({size2})");
3235

36+
// If it ever happens, ensure the error queue gets cleared.
37+
// And since it didn't write the data, reporting an exception is good too.
38+
throw CreateOpenSslCryptographicException();
39+
}
40+
41+
Debug.Assert(size == size2);
42+
3343
return data;
3444
}
3545
}

src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX50
7979

8080
if (!Ssl.SetEncryptionPolicy(innerContext, policy))
8181
{
82+
Crypto.ErrClearError();
8283
throw new PlatformNotSupportedException(SR.Format(SR.net_ssl_encryptionpolicy_notsupported, policy));
8384
}
8485

@@ -129,7 +130,10 @@ internal static SafeSslHandle AllocateSslContext(SslProtocols protocols, SafeX50
129130
string punyCode = s_idnMapping.GetAscii(sslAuthenticationOptions.TargetHost);
130131

131132
// Similar to windows behavior, set SNI on openssl by default for client context, ignore errors.
132-
Ssl.SslSetTlsExtHostName(context, punyCode);
133+
if (!Ssl.SslSetTlsExtHostName(context, punyCode))
134+
{
135+
Crypto.ErrClearError();
136+
}
133137
}
134138

135139
if (hasCertificateAndKey)
@@ -210,7 +214,7 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r
210214
if (sendCount <= 0)
211215
{
212216
// Make sure we clear out the error that is stored in the queue
213-
Crypto.ErrGetError();
217+
Crypto.ErrClearError();
214218
sendBuf = null;
215219
sendCount = 0;
216220
}
@@ -227,6 +231,10 @@ internal static bool DoSslHandshake(SafeSslHandle context, byte[] recvBuf, int r
227231

228232
internal static int Encrypt(SafeSslHandle context, ReadOnlyMemory<byte> input, ref byte[] output, out Ssl.SslErrorCode errorCode)
229233
{
234+
#if DEBUG
235+
ulong assertNoError = Crypto.ErrPeekError();
236+
Debug.Assert(assertNoError == 0, "OpenSsl error queue is not empty, run: 'openssl errstr " + assertNoError.ToString("X") + "' for original error.");
237+
#endif
230238
errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE;
231239

232240
int retVal;
@@ -267,7 +275,7 @@ internal static int Encrypt(SafeSslHandle context, ReadOnlyMemory<byte> input, r
267275
if (retVal <= 0)
268276
{
269277
// Make sure we clear out the error that is stored in the queue
270-
Crypto.ErrGetError();
278+
Crypto.ErrClearError();
271279
}
272280
}
273281

@@ -276,6 +284,10 @@ internal static int Encrypt(SafeSslHandle context, ReadOnlyMemory<byte> input, r
276284

277285
internal static int Decrypt(SafeSslHandle context, byte[] outBuffer, int offset, int count, out Ssl.SslErrorCode errorCode)
278286
{
287+
#if DEBUG
288+
ulong assertNoError = Crypto.ErrPeekError();
289+
Debug.Assert(assertNoError == 0, "OpenSsl error queue is not empty, run: 'openssl errstr " + assertNoError.ToString("X") + "' for original error.");
290+
#endif
279291
errorCode = Ssl.SslErrorCode.SSL_ERROR_NONE;
280292

281293
int retVal = BioWrite(context.InputBio, outBuffer, offset, count);
@@ -505,7 +517,9 @@ private static void SetSslCertificate(SafeSslContextHandle contextPtr, SafeX509H
505517

506518
internal static SslException CreateSslException(string message)
507519
{
508-
ulong errorVal = Crypto.ErrGetError();
520+
// Capture last error to be consistent with CreateOpenSslCryptographicException
521+
ulong errorVal = Crypto.ErrPeekLastError();
522+
Crypto.ErrClearError();
509523
string msg = SR.Format(message, Marshal.PtrToStringAnsi(Crypto.ErrReasonErrorString(errorVal)));
510524
return new SslException(msg, (int)errorVal);
511525
}

0 commit comments

Comments
 (0)