diff --git a/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Der.cs b/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Der.cs index b750a2de5e9d8f..32137c08566fcc 100644 --- a/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Der.cs +++ b/src/libraries/Common/src/Internal/Cryptography/AsymmetricAlgorithmHelpers.Der.cs @@ -13,6 +13,34 @@ namespace Internal.Cryptography // internal static partial class AsymmetricAlgorithmHelpers { + internal static bool ValidateRfc3279DerSequence(ReadOnlySpan signature) + { + try + { + AsnValueReader reader = new AsnValueReader(signature, AsnEncodingRules.DER); + AsnValueReader payload = reader.ReadSequence(); + + if (reader.HasData) + { + return false; + } + + payload.ReadIntegerBytes(); + payload.ReadIntegerBytes(); + + if (payload.HasData) + { + return false; + } + + return true; + } + catch (AsnContentException) + { + return false; + } + } + /// /// Convert Ieee1363 format of (r, s) to Der format /// diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Dsa.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Dsa.cs deleted file mode 100644 index ff9140632d3fb3..00000000000000 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Dsa.cs +++ /dev/null @@ -1,207 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Security.Cryptography; -using Microsoft.Win32.SafeHandles; - -internal static partial class Interop -{ - internal static partial class Crypto - { - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaUpRef")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DsaUpRef(IntPtr dsa); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaDestroy")] - internal static extern void DsaDestroy(IntPtr dsa); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaGenerateKey")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DsaGenerateKey(out SafeDsaHandle dsa, int bits); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaSizeSignature")] - private static extern int DsaSizeSignature(SafeDsaHandle dsa); - - /// - /// Return the maximum size of the DER-encoded key in bytes. - /// - internal static int DsaEncodedSignatureSize(SafeDsaHandle dsa) - { - int size = DsaSizeSignature(dsa); - return size; - } - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaSizeQ")] - private static extern int DsaSizeQ(SafeDsaHandle dsa); - - /// - /// Return the size of the 'r' or 's' signature fields in bytes. - /// - internal static int DsaSignatureFieldSize(SafeDsaHandle dsa) - { - int size = DsaSizeQ(dsa); - Debug.Assert(size * 2 < DsaEncodedSignatureSize(dsa)); - return size; - } - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaSizeP")] - private static extern int DsaSizeP(SafeDsaHandle dsa); - - /// - /// Return the size of the key in bytes. - /// - internal static int DsaKeySize(SafeDsaHandle dsa) - { - int keySize = DsaSizeP(dsa); - - // Assume an even multiple of 8 bytes \ 64 bits (OpenSsl also makes the same assumption) - keySize = (keySize + 7) / 8 * 8; - return keySize; - } - - internal static bool DsaSign(SafeDsaHandle dsa, ReadOnlySpan hash, Span refSignature, out int outSignatureLength) => - DsaSign(dsa, ref MemoryMarshal.GetReference(hash), hash.Length, ref MemoryMarshal.GetReference(refSignature), out outSignatureLength); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaSign")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DsaSign(SafeDsaHandle dsa, ref byte hash, int hashLength, ref byte refSignature, out int outSignatureLength); - - internal static bool DsaVerify(SafeDsaHandle dsa, ReadOnlySpan hash, ReadOnlySpan signature) - { - bool ret = DsaVerify( - dsa, - ref MemoryMarshal.GetReference(hash), - hash.Length, - ref MemoryMarshal.GetReference(signature), - signature.Length); - - // Error queue already cleaned on the native function. - - return ret; - } - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaVerify")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool DsaVerify(SafeDsaHandle dsa, ref byte hash, int hashLength, ref byte signature, int signatureLength); - - internal static DSAParameters ExportDsaParameters(SafeDsaHandle key, bool includePrivateParameters) - { - Debug.Assert( - key != null && !key.IsInvalid, - "Callers should check the key is invalid and throw an exception with a message"); - - if (key == null || key.IsInvalid) - { - throw new CryptographicException(); - } - - IntPtr p_bn, q_bn, g_bn, y_bn, x_bn; // these are not owned - int p_cb, q_cb, g_cb, y_cb, x_cb; - - bool refAdded = false; - try - { - key.DangerousAddRef(ref refAdded); // Protect access to the *_bn variables - - if (!GetDsaParameters(key, - out p_bn, out p_cb, - out q_bn, out q_cb, - out g_bn, out g_cb, - out y_bn, out y_cb, - out x_bn, out x_cb)) - { - throw new CryptographicException(); - } - - // Match Windows semantics where p, g and y have same length - int pgy_cb = GetMax(p_cb, g_cb, y_cb); - - // Match Windows semantics where q and x have same length - int qx_cb = GetMax(q_cb, x_cb); - - DSAParameters dsaParameters = new DSAParameters - { - P = Crypto.ExtractBignum(p_bn, pgy_cb)!, - Q = Crypto.ExtractBignum(q_bn, qx_cb)!, - G = Crypto.ExtractBignum(g_bn, pgy_cb)!, - Y = Crypto.ExtractBignum(y_bn, pgy_cb)!, - }; - - if (includePrivateParameters) - { - dsaParameters.X = Crypto.ExtractBignum(x_bn, qx_cb); - } - - return dsaParameters; - } - finally - { - if (refAdded) - key.DangerousRelease(); - } - } - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetDsaParameters")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetDsaParameters( - SafeDsaHandle key, - out IntPtr p, out int p_cb, - out IntPtr q, out int q_cb, - out IntPtr g, out int g_cb, - out IntPtr y, out int y_cb, - out IntPtr x, out int x_cb); - - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaKeyCreateByExplicitParameters")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DsaKeyCreateByExplicitParameters( - out SafeDsaHandle dsa, - byte[] p, - int pLength, - byte[] q, - int qLength, - byte[] g, - int gLength, - byte[] y, - int yLength, - byte[]? x, - int xLength); - - /// - /// Return the maximum value in the array; assumes non-negative values. - /// - private static int GetMax(int[] values) - { - int max = 0; - - foreach (var i in values) - { - Debug.Assert(i >= 0); - if (i > max) - max = i; - } - - return max; - } - - /// - /// Return the maximum value in the array; assumes non-negative values. - /// - private static int GetMax(int value1, int value2) - { - Debug.Assert(value1 >= 0); - Debug.Assert(value2 >= 0); - return (value1 > value2 ? value1 : value2); - } - - /// - /// Return the maximum value in the array; assumes non-negative values. - /// - private static int GetMax(int value1, int value2, int value3) - { - return GetMax(GetMax(value1, value2), value3); - } - } -} diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcDsa.ImportExport.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcDsa.ImportExport.cs index 9687abdafdc01e..287a9ac5555eaa 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcDsa.ImportExport.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EcDsa.ImportExport.cs @@ -295,5 +295,40 @@ internal static ECParameters GetECCurveParameters( key.DangerousRelease(); } } + + /// + /// Return the maximum value in the array; assumes non-negative values. + /// + private static int GetMax(int[] values) + { + int max = 0; + + foreach (var i in values) + { + Debug.Assert(i >= 0); + if (i > max) + max = i; + } + + return max; + } + + /// + /// Return the maximum value in the array; assumes non-negative values. + /// + private static int GetMax(int value1, int value2) + { + Debug.Assert(value1 >= 0); + Debug.Assert(value2 >= 0); + return (value1 > value2 ? value1 : value2); + } + + /// + /// Return the maximum value in the array; assumes non-negative values. + /// + private static int GetMax(int value1, int value2, int value3) + { + return GetMax(GetMax(value1, value2), value3); + } } } diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Dsa.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Dsa.cs index 820f300b0641eb..282e144d96b03b 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Dsa.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Dsa.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Cryptography; using Microsoft.Win32.SafeHandles; @@ -9,11 +11,89 @@ internal static partial class Interop { internal static partial class Crypto { - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyGetDsa")] - internal static extern SafeDsaHandle EvpPkeyGetDsa(SafeEvpPKeyHandle pkey); + [DllImport(Libraries.CryptoNative)] + private static extern SafeEvpPKeyHandle CryptoNative_EvpPKeyCreateDsa(IntPtr dsa); - [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeySetDsa")] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool EvpPkeySetDsa(SafeEvpPKeyHandle pkey, SafeDsaHandle key); + internal static SafeEvpPKeyHandle EvpPKeyCreateDsa(IntPtr dsa) + { + Debug.Assert(dsa != IntPtr.Zero); + + SafeEvpPKeyHandle pkey = CryptoNative_EvpPKeyCreateDsa(dsa); + + if (pkey.IsInvalid) + { + pkey.Dispose(); + throw CreateOpenSslCryptographicException(); + } + + return pkey; + } + + [DllImport(Libraries.CryptoNative)] + private static extern SafeEvpPKeyHandle CryptoNative_DsaGenerateKey(int keySize); + + internal static SafeEvpPKeyHandle DsaGenerateKey(int keySize) + { + SafeEvpPKeyHandle handle = CryptoNative_DsaGenerateKey(keySize); + + if (handle.IsInvalid) + { + handle.Dispose(); + throw CreateOpenSslCryptographicException(); + } + + return handle; + } + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DsaSizeQ")] + private static extern int DsaSizeQ(SafeEvpPKeyHandle dsa); + + /// + /// Return the size of the 'r' or 's' signature fields in bytes. + /// + internal static int DsaSignatureFieldSize(SafeEvpPKeyHandle dsa) + { + int size = DsaSizeQ(dsa); + Debug.Assert(size * 2 < EvpPKeySize(dsa)); + return size; + } + + [DllImport(Libraries.CryptoNative)] + private static extern unsafe int CryptoNative_DsaSignHash( + SafeEvpPKeyHandle key, + byte* hash, + int hashLen, + byte* destination, + int destinationLen); + + internal static int DsaSignHash( + SafeEvpPKeyHandle key, + ReadOnlySpan hash, + Span destination) + { + int written; + + unsafe + { + fixed (byte* hashPtr = hash) + fixed (byte* destPtr = destination) + { + written = CryptoNative_DsaSignHash( + key, + hashPtr, + hash.Length, + destPtr, + destination.Length); + } + } + + if (written < 0) + { + Debug.Assert(written == -1); + throw CreateOpenSslCryptographicException(); + } + + return written; + } } } diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs index 924c2da14d4b59..b8f3e919e2e8c4 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs @@ -40,12 +40,72 @@ internal static SafeEvpPKeyHandle EvpPKeyDuplicate( [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyDestroy")] internal static extern void EvpPkeyDestroy(IntPtr pkey); + /// + /// Gets the size of the key, in bits, in an algorithm-specific manner. + /// + /// + /// * RSA: The bit length of the modulus value. + /// * DSA: The bit length of the P value. + /// + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPKeyBits")] + internal static extern int EvpPKeyBits(SafeEvpPKeyHandle pkey); + + /// + /// Gets the maximum size, in bytes, of a buffer used in conjunction with this key. + /// + /// + /// * RSA: The length of the modulus value. + /// * DSA: The length of a DER-encoded SEQUENCE(INTEGER(r),INTEGER(s)) signature. + /// [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPKeySize")] internal static extern int EvpPKeySize(SafeEvpPKeyHandle pkey); [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_UpRefEvpPkey")] internal static extern int UpRefEvpPkey(SafeEvpPKeyHandle handle); + [DllImport(Libraries.CryptoNative)] + private static extern unsafe int CryptoNative_SimpleVerifyHash( + SafeEvpPKeyHandle pkey, + byte* hash, + int hashLen, + byte* signature, + int signatureLen); + + internal static bool SimpleVerifyHash( + SafeEvpPKeyHandle pkey, + ReadOnlySpan hash, + ReadOnlySpan signature) + { + int ret; + + unsafe + { + fixed (byte* hashPtr = hash) + fixed (byte* signaturePtr = signature) + { + ret = CryptoNative_SimpleVerifyHash( + pkey, + hashPtr, + hash.Length, + signaturePtr, + signature.Length); + } + } + + if (ret == 1) + { + return true; + } + + if (ret == 0) + { + return false; + } + + Debug.Assert(ret == -1); + throw CreateOpenSslCryptographicException(); + } + [DllImport(Libraries.CryptoNative)] private static extern unsafe SafeEvpPKeyHandle CryptoNative_DecodeSubjectPublicKeyInfo( byte* buf, diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeDsaHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeDsaHandle.Unix.cs deleted file mode 100644 index 0899f2f1938b9e..00000000000000 --- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeDsaHandle.Unix.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Diagnostics; -using System.Security; -using System.Runtime.InteropServices; - -namespace Microsoft.Win32.SafeHandles -{ - internal sealed class SafeDsaHandle : SafeHandle - { - public SafeDsaHandle() : - base(IntPtr.Zero, ownsHandle: true) - { - } - - protected override bool ReleaseHandle() - { - Interop.Crypto.DsaDestroy(handle); - SetHandle(IntPtr.Zero); - return true; - } - - public override bool IsInvalid - { - get { return handle == IntPtr.Zero; } - } - - internal static SafeDsaHandle DuplicateHandle(IntPtr handle) - { - Debug.Assert(handle != IntPtr.Zero); - - // Reliability: Allocate the SafeHandle before calling Dsa_up_ref so - // that we don't lose a tracked reference in low-memory situations. - SafeDsaHandle safeHandle = new SafeDsaHandle(); - - if (!Interop.Crypto.DsaUpRef(handle)) - { - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } - - safeHandle.SetHandle(handle); - return safeHandle; - } - } -} diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.Encrypted.cs b/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.Encrypted.cs new file mode 100644 index 00000000000000..3858a518d5f46b --- /dev/null +++ b/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.Encrypted.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers; +using System.Diagnostics; +using System.Formats.Asn1; +using System.Numerics; +using System.Security.Cryptography.Asn1; + +namespace System.Security.Cryptography +{ + internal static partial class DSAKeyFormatHelper + { + internal static void ReadEncryptedPkcs8( + ReadOnlySpan source, + ReadOnlySpan password, + out int bytesRead, + out DSAParameters key) + { + KeyFormatHelper.ReadEncryptedPkcs8( + s_validOids, + source, + password, + ReadDsaPrivateKey, + out bytesRead, + out key); + } + + internal static void ReadEncryptedPkcs8( + ReadOnlySpan source, + ReadOnlySpan passwordBytes, + out int bytesRead, + out DSAParameters key) + { + KeyFormatHelper.ReadEncryptedPkcs8( + s_validOids, + source, + passwordBytes, + ReadDsaPrivateKey, + out bytesRead, + out key); + } + } +} diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs index 63c7b451e142b4..94b452643d4965 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Diagnostics; using System.Formats.Asn1; using System.Numerics; @@ -8,7 +9,7 @@ namespace System.Security.Cryptography { - internal static class DSAKeyFormatHelper + internal static partial class DSAKeyFormatHelper { private static readonly string[] s_validOids = { @@ -128,47 +129,54 @@ internal static ReadOnlyMemory ReadSubjectPublicKeyInfo( out bytesRead); } - internal static void ReadPkcs8( - ReadOnlySpan source, - out int bytesRead, - out DSAParameters key) + /// + /// Checks that a SubjectPublicKeyInfo represents a DSA key. + /// + /// The number of bytes read from . + internal static unsafe int CheckSubjectPublicKeyInfo(ReadOnlySpan source) { - KeyFormatHelper.ReadPkcs8( - s_validOids, - source, - ReadDsaPrivateKey, - out bytesRead, - out key); + int bytesRead; + + fixed (byte* ptr = source) + { + using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) + { + _ = ReadSubjectPublicKeyInfo(manager.Memory, out bytesRead); + } + } + + return bytesRead; } - internal static void ReadEncryptedPkcs8( + internal static void ReadPkcs8( ReadOnlySpan source, - ReadOnlySpan password, out int bytesRead, out DSAParameters key) { - KeyFormatHelper.ReadEncryptedPkcs8( + KeyFormatHelper.ReadPkcs8( s_validOids, source, - password, ReadDsaPrivateKey, out bytesRead, out key); } - internal static void ReadEncryptedPkcs8( - ReadOnlySpan source, - ReadOnlySpan passwordBytes, - out int bytesRead, - out DSAParameters key) + internal static unsafe int CheckPkcs8(ReadOnlySpan source) { - KeyFormatHelper.ReadEncryptedPkcs8( - s_validOids, - source, - passwordBytes, - ReadDsaPrivateKey, - out bytesRead, - out key); + int bytesRead; + + fixed (byte* ptr = source) + { + using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) + { + _ = KeyFormatHelper.ReadPkcs8( + s_validOids, + manager.Memory, + out bytesRead); + } + } + + return bytesRead; } internal static AsnWriter WriteSubjectPublicKeyInfo(in DSAParameters dsaParameters) diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs index 7c75208f8a2ea0..354ea39b177d9a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/DSAOpenSsl.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Formats.Asn1; using System.IO; using Internal.Cryptography; using Microsoft.Win32.SafeHandles; @@ -32,7 +33,7 @@ public sealed partial class DSAOpenSsl : DSA private const int SignatureStackBufSize = 72; private const int BitsPerByte = 8; - private Lazy _key = null!; + private Lazy _key = null!; public DSAOpenSsl() : this(2048) @@ -43,7 +44,7 @@ public DSAOpenSsl(int keySize) { LegalKeySizesValue = s_legalKeySizes; base.KeySize = keySize; - _key = new Lazy(GenerateKey); + _key = new Lazy(GenerateKey); } public override int KeySize @@ -60,7 +61,7 @@ public override int KeySize ThrowIfDisposed(); FreeKey(); - _key = new Lazy(GenerateKey); + _key = new Lazy(GenerateKey); } } @@ -84,15 +85,43 @@ public override KeySizes[] LegalKeySizes public override DSAParameters ExportParameters(bool includePrivateParameters) { // It's entirely possible that this line will cause the key to be generated in the first place. - SafeDsaHandle key = GetKey(); + SafeEvpPKeyHandle key = GetKey(); + DSAParameters ret; - DSAParameters dsaParameters = Interop.Crypto.ExportDsaParameters(key, includePrivateParameters); - bool hasPrivateKey = dsaParameters.X != null; + if (includePrivateParameters) + { + ArraySegment pkcs8 = Interop.Crypto.RentEncodePkcs8PrivateKey(key); + + try + { + DSAKeyFormatHelper.ReadPkcs8(pkcs8, out int read, out ret); + Debug.Assert(read == pkcs8.Count); + } + catch (CryptographicException) + { + throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); + } + finally + { + CryptoPool.Return(pkcs8); + } + } + else + { + ArraySegment spki = Interop.Crypto.RentEncodeSubjectPublicKeyInfo(key); - if (hasPrivateKey != includePrivateParameters) - throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey); + try + { + DSAKeyFormatHelper.ReadSubjectPublicKeyInfo(spki, out int read, out ret); + Debug.Assert(read == spki.Count); + } + finally + { + CryptoPool.Return(spki); + } + } - return dsaParameters; + return ret; } public override void ImportParameters(DSAParameters parameters) @@ -116,19 +145,66 @@ public override void ImportParameters(DSAParameters parameters) ThrowIfDisposed(); - SafeDsaHandle key; - if (!Interop.Crypto.DsaKeyCreateByExplicitParameters( - out key, - parameters.P, parameters.P.Length, - parameters.Q, parameters.Q.Length, - parameters.G, parameters.G.Length, - parameters.Y, parameters.Y.Length, - parameters.X, parameters.X != null ? parameters.X.Length : 0)) + if (hasPrivateKey) { - throw Interop.Crypto.CreateOpenSslCryptographicException(); + AsnWriter writer = DSAKeyFormatHelper.WritePkcs8(parameters); + ArraySegment pkcs8 = writer.RentAndEncode(); + + try + { + ImportPkcs8PrivateKey(pkcs8, checkAlgorithm: false, out _); + } + finally + { + CryptoPool.Return(pkcs8); + } } + else + { + AsnWriter writer = DSAKeyFormatHelper.WriteSubjectPublicKeyInfo(parameters); + ArraySegment spki = writer.RentAndEncode(); + + try + { + ImportSubjectPublicKeyInfo(spki, checkAlgorithm: false, out _); + } + finally + { + CryptoPool.Return(spki); + } + } + } + + public override void ImportSubjectPublicKeyInfo(ReadOnlySpan source, out int bytesRead) + { + ThrowIfDisposed(); - SetKey(key); + ImportSubjectPublicKeyInfo(source, checkAlgorithm: true, out bytesRead); + } + + private void ImportSubjectPublicKeyInfo( + ReadOnlySpan source, + bool checkAlgorithm, + out int bytesRead) + { + int read; + + if (checkAlgorithm) + { + read = DSAKeyFormatHelper.CheckSubjectPublicKeyInfo(source); + } + else + { + read = source.Length; + } + + SafeEvpPKeyHandle newKey = Interop.Crypto.DecodeSubjectPublicKeyInfo( + source.Slice(0, read), + Interop.Crypto.EvpAlgorithmId.DSA); + + Debug.Assert(!newKey.IsInvalid); + SetKey(newKey); + bytesRead = read; } public override void ImportEncryptedPkcs8PrivateKey( @@ -149,6 +225,35 @@ public override void ImportEncryptedPkcs8PrivateKey( base.ImportEncryptedPkcs8PrivateKey(password, source, out bytesRead); } + public override void ImportPkcs8PrivateKey(ReadOnlySpan source, out int bytesRead) + { + ThrowIfDisposed(); + + ImportPkcs8PrivateKey(source, checkAlgorithm: true, out bytesRead); + } + + private void ImportPkcs8PrivateKey(ReadOnlySpan source, bool checkAlgorithm, out int bytesRead) + { + int read; + + if (checkAlgorithm) + { + read = DSAKeyFormatHelper.CheckPkcs8(source); + } + else + { + read = source.Length; + } + + SafeEvpPKeyHandle newKey = Interop.Crypto.DecodePkcs8PrivateKey( + source.Slice(0, read), + Interop.Crypto.EvpAlgorithmId.DSA); + + Debug.Assert(!newKey.IsInvalid); + SetKey(newKey); + bytesRead = read; + } + protected override void Dispose(bool disposing) { if (disposing) @@ -164,7 +269,7 @@ private void FreeKey() { if (_key != null && _key.IsValueCreated) { - SafeDsaHandle handle = _key.Value; + SafeEvpPKeyHandle handle = _key.Value; if (handle != null) { @@ -173,7 +278,7 @@ private void FreeKey() } } - private static void CheckInvalidKey(SafeDsaHandle key) + private static void CheckInvalidKey(SafeEvpPKeyHandle key) { if (key == null || key.IsInvalid) { @@ -181,16 +286,9 @@ private static void CheckInvalidKey(SafeDsaHandle key) } } - private SafeDsaHandle GenerateKey() + private SafeEvpPKeyHandle GenerateKey() { - SafeDsaHandle key; - - if (!Interop.Crypto.DsaGenerateKey(out key, KeySize)) - { - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } - - return key; + return Interop.Crypto.DsaGenerateKey(KeySize); } protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) @@ -215,12 +313,14 @@ public override byte[] CreateSignature(byte[] rgbHash) if (rgbHash == null) throw new ArgumentNullException(nameof(rgbHash)); - SafeDsaHandle key = GetKey(); - int signatureSize = Interop.Crypto.DsaEncodedSignatureSize(key); + SafeEvpPKeyHandle key = GetKey(); + + int signatureSize = Interop.Crypto.EvpPKeySize(key); int signatureFieldSize = Interop.Crypto.DsaSignatureFieldSize(key) * BitsPerByte; + Debug.Assert(signatureSize <= SignatureStackBufSize); Span signDestination = stackalloc byte[SignatureStackBufSize]; - ReadOnlySpan derSignature = SignHash(rgbHash, signDestination, signatureSize, key); + ReadOnlySpan derSignature = SignHash(key, rgbHash, signDestination); return AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(derSignature, signatureFieldSize); } @@ -246,8 +346,10 @@ protected override bool TryCreateSignatureCore( public override bool TryCreateSignature(ReadOnlySpan hash, Span destination, out int bytesWritten) #endif { - SafeDsaHandle key = GetKey(); - int maxSignatureSize = Interop.Crypto.DsaEncodedSignatureSize(key); + SafeEvpPKeyHandle key = GetKey(); + + int maxSignatureSize = Interop.Crypto.EvpPKeySize(key); + Debug.Assert(maxSignatureSize <= SignatureStackBufSize); Span signDestination = stackalloc byte[SignatureStackBufSize]; #if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS @@ -265,7 +367,7 @@ public override bool TryCreateSignature(ReadOnlySpan hash, Span dest int fieldSizeBits = fieldSizeBytes * 8; - ReadOnlySpan derSignature = SignHash(hash, signDestination, maxSignatureSize, key); + ReadOnlySpan derSignature = SignHash(key, hash, signDestination); bytesWritten = AsymmetricAlgorithmHelpers.ConvertDerToIeee1363(derSignature, fieldSizeBits, destination); Debug.Assert(bytesWritten == p1363SignatureSize); return true; @@ -284,7 +386,7 @@ public override bool TryCreateSignature(ReadOnlySpan hash, Span dest return false; } - ReadOnlySpan derSignature = SignHash(hash, signDestination, maxSignatureSize, key); + ReadOnlySpan derSignature = SignHash(key, hash, signDestination); if (destination == signDestination) { @@ -305,29 +407,11 @@ public override bool TryCreateSignature(ReadOnlySpan hash, Span dest } private static ReadOnlySpan SignHash( + SafeEvpPKeyHandle key, ReadOnlySpan hash, - Span destination, - int signatureLength, - SafeDsaHandle key) + Span destination) { - if (signatureLength > destination.Length) - { - Debug.Fail($"Stack-based signDestination is insufficient ({signatureLength} needed)"); - destination = new byte[signatureLength]; - } - - if (!Interop.Crypto.DsaSign(key, hash, destination, out int actualLength)) - { - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } - - Debug.Assert( - actualLength <= signatureLength, - "DSA_sign reported an unexpected signature size", - "DSA_sign reported signatureSize was {0}, when <= {1} was expected", - actualLength, - signatureLength); - + int actualLength = Interop.Crypto.DsaSignHash(key, hash, destination); return destination.Slice(0, actualLength); } @@ -354,7 +438,7 @@ protected override bool VerifySignatureCore( public override bool VerifySignature(ReadOnlySpan hash, ReadOnlySpan signature) #endif { - SafeDsaHandle key = GetKey(); + SafeEvpPKeyHandle key = GetKey(); #if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS if (signatureFormat == DSASignatureFormat.IeeeP1363FixedFieldConcatenation) @@ -370,7 +454,14 @@ public override bool VerifySignature(ReadOnlySpan hash, ReadOnlySpan signature = AsymmetricAlgorithmHelpers.ConvertIeee1363ToDer(signature); #if INTERNAL_ASYMMETRIC_IMPLEMENTATIONS } - else if (signatureFormat != DSASignatureFormat.Rfc3279DerSequence) + else if (signatureFormat == DSASignatureFormat.Rfc3279DerSequence) + { + if (!AsymmetricAlgorithmHelpers.ValidateRfc3279DerSequence(signature)) + { + return false; + } + } + else { Debug.Fail($"Missing internal implementation handler for signature format {signatureFormat}"); throw new CryptographicException( @@ -378,7 +469,7 @@ public override bool VerifySignature(ReadOnlySpan hash, ReadOnlySpan signatureFormat.ToString()); } #endif - return Interop.Crypto.DsaVerify(key, hash, signature); + return Interop.Crypto.SimpleVerifyHash(key, hash, signature); } private void ThrowIfDisposed() @@ -395,25 +486,27 @@ private void ThrowIfDisposed() } } - private SafeDsaHandle GetKey() + private SafeEvpPKeyHandle GetKey() { ThrowIfDisposed(); - SafeDsaHandle key = _key.Value; + SafeEvpPKeyHandle key = _key.Value; CheckInvalidKey(key); return key; } - private void SetKey(SafeDsaHandle newKey) + [System.Diagnostics.CodeAnalysis.MemberNotNull(nameof(_key))] + private void SetKey(SafeEvpPKeyHandle newKey) { + Debug.Assert(!newKey.IsInvalid); // Do not call ThrowIfDisposed here, as it breaks the SafeEvpPKey ctor + FreeKey(); + _key = new Lazy(newKey); // Use ForceSet instead of the property setter to ensure that LegalKeySizes doesn't interfere // with the already loaded key. - ForceSetKeySize(BitsPerByte * Interop.Crypto.DsaKeySize(newKey)); - - _key = new Lazy(newKey); + ForceSetKeySize(Interop.Crypto.EvpPKeyBits(newKey)); } private static readonly KeySizes[] s_legalKeySizes = new KeySizes[] { new KeySizes(minSize: 512, maxSize: 3072, skipSize: 64) }; diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index d6d66c78ae1d48..27afc6bba29a52 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -22,8 +22,6 @@ internal static partial class RSAImplementation #endif public sealed partial class RSAOpenSsl : RSA { - private const int BitsPerByte = 8; - private Lazy _key; public RSAOpenSsl() @@ -666,7 +664,7 @@ private void SetKey(SafeEvpPKeyHandle newKey) // Use ForceSet instead of the property setter to ensure that LegalKeySizes doesn't interfere // with the already loaded key. - ForceSetKeySize(BitsPerByte * Interop.Crypto.EvpPKeySize(newKey)); + ForceSetKeySize(Interop.Crypto.EvpPKeyBits(newKey)); } private static void ValidateParameters(ref RSAParameters parameters) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt b/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt index a9987063b54167..cf91e53f8a6843 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt @@ -22,7 +22,6 @@ set(NATIVECRYPTO_SOURCES pal_asn1.c pal_bignum.c pal_bio.c - pal_dsa.c pal_ecdsa.c pal_ecc_import_export.c pal_eckey.c diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c index 15df621f7a7dfa..88e927b777e615 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.c @@ -298,6 +298,23 @@ int32_t local_DSA_set0_key(DSA* dsa, BIGNUM* bnY, BIGNUM* bnX) return 1; } +DSA* local_EVP_PKEY_get0_DSA(EVP_PKEY* pkey) +{ + if (pkey == NULL) + { + return NULL; + } + + DSA* dsa = EVP_PKEY_get1_DSA(pkey); + + if (dsa != NULL) + { + DSA_free(dsa); + } + + return dsa; +} + RSA* local_EVP_PKEY_get0_RSA(EVP_PKEY* pkey) { if (pkey == NULL) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h index 3998f1abbf3a4a..4ff09b7f98ec7e 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge.h @@ -16,6 +16,7 @@ void local_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX* ctx); EVP_CIPHER_CTX* local_EVP_CIPHER_CTX_new(void); int32_t local_EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX* ctx); int local_EVP_PKEY_check(EVP_PKEY_CTX* ctx); +DSA* local_EVP_PKEY_get0_DSA(EVP_PKEY* pkey); RSA* local_EVP_PKEY_get0_RSA(EVP_PKEY* pkey); int local_EVP_PKEY_public_check(EVP_PKEY_CTX* ctx); int32_t local_EVP_PKEY_up_ref(EVP_PKEY* pkey); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c index 63b553186327c4..cc37544ca94980 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c @@ -45,6 +45,11 @@ c_static_assert(EVP_PKEY_OP_TYPE_SIG == 0xF8); #endif +int local_EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX* ctx, int qbits) +{ + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, qbits, NULL); +} + int local_EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX* ctx, int bits) { return RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h index 0f28900cb7b5c9..32aa99d9aa1e77 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h @@ -6,6 +6,7 @@ #pragma once #include "pal_types.h" +int local_EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX* ctx, int qbits); int local_EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX* ctx, int bits); int local_EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); int local_EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int pad_mode); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c index bf68f23be3633a..dcf1a826f6ffc5 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/entrypoints.c @@ -8,7 +8,6 @@ #include "pal_asn1.h" #include "pal_bignum.h" #include "pal_bio.h" -#include "pal_dsa.h" #include "pal_ecc_import_export.h" #include "pal_ecdsa.h" #include "pal_eckey.h" @@ -61,15 +60,9 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_DecodeX509) DllImportEntry(CryptoNative_DecodeX509BasicConstraints2Extension) DllImportEntry(CryptoNative_DecodeX509Crl) - DllImportEntry(CryptoNative_DsaDestroy) DllImportEntry(CryptoNative_DsaGenerateKey) - DllImportEntry(CryptoNative_DsaKeyCreateByExplicitParameters) - DllImportEntry(CryptoNative_DsaSign) - DllImportEntry(CryptoNative_DsaSizeP) + DllImportEntry(CryptoNative_DsaSignHash) DllImportEntry(CryptoNative_DsaSizeQ) - DllImportEntry(CryptoNative_DsaSizeSignature) - DllImportEntry(CryptoNative_DsaUpRef) - DllImportEntry(CryptoNative_DsaVerify) DllImportEntry(CryptoNative_EcDsaSign) DllImportEntry(CryptoNative_EcDsaSize) DllImportEntry(CryptoNative_EcDsaVerify) @@ -145,16 +138,16 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_EvpMdCtxCreate) DllImportEntry(CryptoNative_EvpMdCtxDestroy) DllImportEntry(CryptoNative_EvpMdSize) + DllImportEntry(CryptoNative_EvpPKeyBits) DllImportEntry(CryptoNative_EvpPkeyCreate) + DllImportEntry(CryptoNative_EvpPKeyCreateDsa) DllImportEntry(CryptoNative_EvpPKeyCreateRsa) DllImportEntry(CryptoNative_EvpPKeyCtxCreate) DllImportEntry(CryptoNative_EvpPKeyCtxDestroy) DllImportEntry(CryptoNative_EvpPKeyDeriveSecretAgreement) DllImportEntry(CryptoNative_EvpPkeyDestroy) DllImportEntry(CryptoNative_EvpPKeyDuplicate) - DllImportEntry(CryptoNative_EvpPkeyGetDsa) DllImportEntry(CryptoNative_EvpPkeyGetEcKey) - DllImportEntry(CryptoNative_EvpPkeySetDsa) DllImportEntry(CryptoNative_EvpPkeySetEcKey) DllImportEntry(CryptoNative_EvpPKeySize) DllImportEntry(CryptoNative_EvpRC2Cbc) @@ -167,7 +160,6 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_GetAsn1IntegerDerSize) DllImportEntry(CryptoNative_GetAsn1StringBytes) DllImportEntry(CryptoNative_GetBigNumBytes) - DllImportEntry(CryptoNative_GetDsaParameters) DllImportEntry(CryptoNative_GetECCurveParameters) DllImportEntry(CryptoNative_GetECKeyParameters) DllImportEntry(CryptoNative_GetMaxMdSize) @@ -235,6 +227,7 @@ static const Entry s_cryptoNative[] = DllImportEntry(CryptoNative_RsaGenerateKey) DllImportEntry(CryptoNative_RsaSignHash) DllImportEntry(CryptoNative_RsaVerifyHash) + DllImportEntry(CryptoNative_SimpleVerifyHash) DllImportEntry(CryptoNative_UpRefEvpPkey) DllImportEntry(CryptoNative_X509ChainBuildOcspRequest) DllImportEntry(CryptoNative_X509ChainGetCachedOcspStatus) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h index 69c95b532ade08..e9a6cbee787c14 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/opensslshim.h @@ -328,6 +328,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); REQUIRED_FUNCTION(EVP_PKEY_CTX_get0_pkey) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_new) \ REQUIRED_FUNCTION(EVP_PKEY_CTX_new_id) \ + FALLBACK_FUNCTION(EVP_PKEY_CTX_set_dsa_paramgen_q_bits) \ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_keygen_bits) \ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_oaep_md) \ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_padding) \ @@ -343,7 +344,9 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); REQUIRED_FUNCTION(EVP_PKEY_encrypt_init) \ REQUIRED_FUNCTION(EVP_PKEY_free) \ RENAMED_FUNCTION(EVP_PKEY_get_base_id, EVP_PKEY_base_id) \ + RENAMED_FUNCTION(EVP_PKEY_get_bits, EVP_PKEY_bits) \ RENAMED_FUNCTION(EVP_PKEY_get_size, EVP_PKEY_size) \ + FALLBACK_FUNCTION(EVP_PKEY_get0_DSA) \ FALLBACK_FUNCTION(EVP_PKEY_get0_RSA) \ REQUIRED_FUNCTION(EVP_PKEY_get1_DSA) \ REQUIRED_FUNCTION(EVP_PKEY_get1_EC_KEY) \ @@ -351,6 +354,8 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void); REQUIRED_FUNCTION(EVP_PKEY_keygen) \ REQUIRED_FUNCTION(EVP_PKEY_keygen_init) \ REQUIRED_FUNCTION(EVP_PKEY_new) \ + REQUIRED_FUNCTION(EVP_PKEY_paramgen) \ + REQUIRED_FUNCTION(EVP_PKEY_paramgen_init) \ FALLBACK_FUNCTION(EVP_PKEY_public_check) \ REQUIRED_FUNCTION(EVP_PKEY_set1_DSA) \ REQUIRED_FUNCTION(EVP_PKEY_set1_EC_KEY) \ @@ -776,6 +781,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_PKEY_CTX_get0_pkey EVP_PKEY_CTX_get0_pkey_ptr #define EVP_PKEY_CTX_new EVP_PKEY_CTX_new_ptr #define EVP_PKEY_CTX_new_id EVP_PKEY_CTX_new_id_ptr +#define EVP_PKEY_CTX_set_dsa_paramgen_q_bits EVP_PKEY_CTX_set_dsa_paramgen_q_bits_ptr #define EVP_PKEY_CTX_set_rsa_keygen_bits EVP_PKEY_CTX_set_rsa_keygen_bits_ptr #define EVP_PKEY_CTX_set_rsa_oaep_md EVP_PKEY_CTX_set_rsa_oaep_md_ptr #define EVP_PKEY_CTX_set_rsa_padding EVP_PKEY_CTX_set_rsa_padding_ptr @@ -791,7 +797,9 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_PKEY_encrypt EVP_PKEY_encrypt_ptr #define EVP_PKEY_free EVP_PKEY_free_ptr #define EVP_PKEY_get_base_id EVP_PKEY_get_base_id_ptr +#define EVP_PKEY_get_bits EVP_PKEY_get_bits_ptr #define EVP_PKEY_get_size EVP_PKEY_get_size_ptr +#define EVP_PKEY_get0_DSA EVP_PKEY_get0_DSA_ptr #define EVP_PKEY_get0_RSA EVP_PKEY_get0_RSA_ptr #define EVP_PKEY_get1_DSA EVP_PKEY_get1_DSA_ptr #define EVP_PKEY_get1_EC_KEY EVP_PKEY_get1_EC_KEY_ptr @@ -799,6 +807,8 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_PKEY_keygen EVP_PKEY_keygen_ptr #define EVP_PKEY_keygen_init EVP_PKEY_keygen_init_ptr #define EVP_PKEY_new EVP_PKEY_new_ptr +#define EVP_PKEY_paramgen EVP_PKEY_paramgen_ptr +#define EVP_PKEY_paramgen_init EVP_PKEY_paramgen_init_ptr #define EVP_PKEY_public_check EVP_PKEY_public_check_ptr #define EVP_PKEY_set1_DSA EVP_PKEY_set1_DSA_ptr #define EVP_PKEY_set1_EC_KEY EVP_PKEY_set1_EC_KEY_ptr @@ -1106,6 +1116,7 @@ FOR_ALL_OPENSSL_FUNCTIONS // Undo renames for renamed-in-3.0 #define EVP_MD_get_size EVP_MD_size #define EVP_PKEY_get_base_id EVP_PKEY_base_id +#define EVP_PKEY_get_bits EVP_PKEY_bits #define EVP_PKEY_get_size EVP_PKEY_size #define SSL_get1_peer_certificate SSL_get_peer_certificate @@ -1128,6 +1139,7 @@ FOR_ALL_OPENSSL_FUNCTIONS #define EVP_CIPHER_CTX_new local_EVP_CIPHER_CTX_new #define EVP_CIPHER_CTX_reset local_EVP_CIPHER_CTX_reset #define EVP_PKEY_check local_EVP_PKEY_check +#define EVP_PKEY_get0_DSA local_EVP_PKEY_get0_DSA #define EVP_PKEY_get0_RSA local_EVP_PKEY_get0_RSA #define EVP_PKEY_public_check local_EVP_PKEY_public_check #define EVP_PKEY_up_ref local_EVP_PKEY_up_ref diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h index 59f0fc5f59d5df..ca14fa98d56911 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h @@ -30,6 +30,7 @@ EVP_CIPHER_CTX* EVP_CIPHER_CTX_new(void); int32_t EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX* ctx); void EVP_MD_CTX_free(EVP_MD_CTX* ctx); EVP_MD_CTX* EVP_MD_CTX_new(void); +DSA* EVP_PKEY_get0_DSA(EVP_PKEY* pkey); RSA* EVP_PKEY_get0_RSA(EVP_PKEY* pkey); int EVP_PKEY_check(EVP_PKEY_CTX* ctx); int EVP_PKEY_public_check(EVP_PKEY_CTX* ctx); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h index dba69f1382d2fc..ec24f7367f3ecb 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h @@ -20,12 +20,14 @@ void ERR_set_debug(const char *file, int line, const char *func); void ERR_set_error(int lib, int reason, const char *fmt, ...); int EVP_CIPHER_CTX_get_original_iv(EVP_CIPHER_CTX *ctx, void *buf, size_t len); int EVP_MD_get_size(const EVP_MD* md); +int EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX* ctx, int qbits); int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX* ctx, int bits); int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int pad_mode); int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX* ctx, int saltlen); int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); int EVP_PKEY_get_base_id(const EVP_PKEY* pkey); +int EVP_PKEY_get_bits(const EVP_PKEY* pkey); int EVP_PKEY_get_size(const EVP_PKEY* pkey); OSSL_PROVIDER* OSSL_PROVIDER_try_load(OSSL_LIB_CTX* , const char* name, int retain_fallbacks); X509* SSL_get1_peer_certificate(const SSL* ssl); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_dsa.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_dsa.c deleted file mode 100644 index c8b6892654ea2a..00000000000000 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_dsa.c +++ /dev/null @@ -1,243 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "pal_dsa.h" -#include "pal_utilities.h" - -int32_t CryptoNative_DsaUpRef(DSA* dsa) -{ - return DSA_up_ref(dsa); -} - -void CryptoNative_DsaDestroy(DSA* dsa) -{ - if (dsa != NULL) - { - DSA_free(dsa); - } -} - -int32_t CryptoNative_DsaGenerateKey(DSA** dsa, int32_t bits) -{ - if (!dsa) - { - assert(false); - return 0; - } - - *dsa = DSA_new(); - if (!(*dsa)) - { - return 0; - } - - if (!DSA_generate_parameters_ex(*dsa, bits, NULL, 0, NULL, NULL, NULL) || - !DSA_generate_key(*dsa)) - { - DSA_free(*dsa); - *dsa = NULL; - return 0; - } - - return 1; -} - -int32_t CryptoNative_DsaSizeSignature(DSA* dsa) -{ - return DSA_size(dsa); -} - -int32_t CryptoNative_DsaSizeP(DSA* dsa) -{ - if (dsa) - { - const BIGNUM* p; - DSA_get0_pqg(dsa, &p, NULL, NULL); - - if (p) - { - return BN_num_bytes(p); - } - } - - return -1; -} - -int32_t CryptoNative_DsaSizeQ(DSA* dsa) -{ - if (dsa) - { - const BIGNUM* q; - DSA_get0_pqg(dsa, NULL, &q, NULL); - - if (q) - { - return BN_num_bytes(q); - } - } - - return -1; -} - -int32_t CryptoNative_DsaSign( - DSA* dsa, - const uint8_t* hash, - int32_t hashLength, - uint8_t* refsignature, - int32_t* outSignatureLength) -{ - if (outSignatureLength == NULL || dsa == NULL) - { - assert(false); - return 0; - } - - // DSA_OpenSSL() returns a shared pointer, no need to free/cache. - if (DSA_get_method(dsa) == DSA_OpenSSL()) - { - const BIGNUM* privKey; - - DSA_get0_key(dsa, NULL, &privKey); - - if (!privKey) - { - *outSignatureLength = 0; - ERR_PUT_error(ERR_LIB_DSA, DSA_F_DSA_DO_SIGN, DSA_R_MISSING_PARAMETERS, __FILE__, __LINE__); - return 0; - } - } - - unsigned int unsignedSigLen = 0; - int32_t success = DSA_sign(0, hash, hashLength, refsignature, &unsignedSigLen, dsa); - if (!success) // Only 0 and 1 returned - { - *outSignatureLength = 0; - return 0; - } - - assert(unsignedSigLen <= INT32_MAX); - *outSignatureLength = (int32_t)unsignedSigLen; - return 1; -} - -int32_t CryptoNative_DsaVerify( - DSA* dsa, - const uint8_t* hash, - int32_t hashLength, - uint8_t* signature, - int32_t signatureLength) -{ - int32_t success = DSA_verify(0, hash, hashLength, signature, signatureLength, dsa); - if (success != 1) - { - if (success == -1) - { - // Clear the queue, as we don't check the error information. - // Managed caller expects the error queue to be cleared in case of error. - ERR_clear_error(); - } - return 0; - } - - return 1; -} - -int32_t CryptoNative_GetDsaParameters( - const DSA* dsa, - const BIGNUM** p, int32_t* pLength, - const BIGNUM** q, int32_t* qLength, - const BIGNUM** g, int32_t* gLength, - const BIGNUM** y, int32_t* yLength, - const BIGNUM** x, int32_t* xLength) -{ - assert(p != NULL); - assert(q != NULL); - assert(g != NULL); - assert(y != NULL); - assert(x != NULL); - assert(pLength != NULL); - assert(qLength != NULL); - assert(gLength != NULL); - assert(yLength != NULL); - assert(xLength != NULL); - - DSA_get0_pqg(dsa, p, q, g); - *pLength = BN_num_bytes(*p); - *qLength = BN_num_bytes(*q); - *gLength = BN_num_bytes(*g); - - DSA_get0_key(dsa, y, x); - *yLength = BN_num_bytes(*y); - // x (the private key) is optional - *xLength = (*x == NULL) ? 0 : BN_num_bytes(*x); - - return 1; -} - -static BIGNUM* MakeBignum(uint8_t* buffer, int32_t bufferLength) -{ - if (buffer && bufferLength) - { - return BN_bin2bn(buffer, bufferLength, NULL); - } - - return NULL; -} - -int32_t CryptoNative_DsaKeyCreateByExplicitParameters( - DSA** outDsa, - uint8_t* p, - int32_t pLength, - uint8_t* q, - int32_t qLength, - uint8_t* g, - int32_t gLength, - uint8_t* y, - int32_t yLength, - uint8_t* x, - int32_t xLength) -{ - if (!outDsa) - { - assert(false); - return 0; - } - - *outDsa = DSA_new(); - if (!*outDsa) - { - return 0; - } - - DSA* dsa = *outDsa; - - BIGNUM* bnP = MakeBignum(p, pLength); - BIGNUM* bnQ = MakeBignum(q, qLength); - BIGNUM* bnG = MakeBignum(g, gLength); - - if (!DSA_set0_pqg(dsa, bnP, bnQ, bnG)) - { - // BN_free handles NULL input - BN_free(bnP); - BN_free(bnQ); - BN_free(bnG); - return 0; - } - - // Control was transferred, do not free. - bnP = NULL; - bnQ = NULL; - bnG = NULL; - - BIGNUM* bnY = MakeBignum(y, yLength); - BIGNUM* bnX = MakeBignum(x, xLength); - - if (!DSA_set0_key(dsa, bnY, bnX)) - { - BN_free(bnY); - BN_free(bnX); - return 0; - } - - return 1; -} diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_dsa.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_dsa.h deleted file mode 100644 index e935d1927fdea2..00000000000000 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_dsa.h +++ /dev/null @@ -1,103 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "pal_types.h" -#include "pal_compiler.h" -#include "opensslshim.h" - -/* -Shims the DSA_up_ref method. - -Returns 1 upon success, otherwise 0. -*/ -PALEXPORT int32_t CryptoNative_DsaUpRef(DSA* dsa); - -/* -Cleans up and deletes a DSA instance. - -Implemented by calling DSA_free - -No-op if dsa is null. -The given DSA pointer is invalid after this call. -Always succeeds. -*/ -PALEXPORT void CryptoNative_DsaDestroy(DSA* dsa); - -/* -Shims the DSA_generate_key_ex method. - -Returns 1 upon success, otherwise 0. -*/ -PALEXPORT int32_t CryptoNative_DsaGenerateKey(DSA** dsa, int32_t bits); - -/* -Shims the DSA_size method. - -Returns the size of the ASN.1 encoded signature. -*/ -PALEXPORT int32_t CryptoNative_DsaSizeSignature(DSA* dsa); - -/* -Returns the size of the p parameter in bytes. -*/ -PALEXPORT int32_t CryptoNative_DsaSizeP(DSA* dsa); - -/* -Returns the size of the q parameter in bytes. -*/ -PALEXPORT int32_t CryptoNative_DsaSizeQ(DSA* dsa); - -/* -Shims the DSA_sign method. - -Returns 1 upon success, otherwise 0. -*/ -PALEXPORT int32_t -CryptoNative_DsaSign( - DSA* dsa, - const uint8_t* hash, - int32_t hashLength, - uint8_t* signature, - int32_t* outSignatureLength); - -/* -Shims the DSA_verify method. - -Returns 1 upon success, otherwise 0. -*/ -PALEXPORT int32_t -CryptoNative_DsaVerify( - DSA* dsa, - const uint8_t* hash, - int32_t hashLength, - uint8_t* signature, - int32_t signatureLength); - -/* -Gets all the parameters from the DSA instance. - -Returns 1 upon success, otherwise 0. -*/ -PALEXPORT int32_t CryptoNative_GetDsaParameters( - const DSA* dsa, - const BIGNUM** p, int32_t* pLength, - const BIGNUM** q, int32_t* qLength, - const BIGNUM** g, int32_t* gLength, - const BIGNUM** y, int32_t* yLength, - const BIGNUM** x, int32_t* xLength); - -/* -Sets all the parameters on the DSA instance. -*/ -PALEXPORT int32_t CryptoNative_DsaKeyCreateByExplicitParameters( - DSA** dsa, - uint8_t* p, - int32_t pLength, - uint8_t* q, - int32_t qLength, - uint8_t* g, - int32_t gLength, - uint8_t* y, - int32_t yLength, - uint8_t* x, - int32_t xLength); diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c index 6839d4c2fe04ef..b841f0f8ae0cfa 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c @@ -3,6 +3,7 @@ #include #include "pal_evp_pkey.h" +#include "pal_utilities.h" EVP_PKEY* CryptoNative_EvpPkeyCreate() { @@ -42,6 +43,15 @@ EVP_PKEY* CryptoNative_EvpPKeyDuplicate(EVP_PKEY* currentKey, int32_t algId) success = false; } } + else if (currentAlgId == EVP_PKEY_DSA) + { + DSA* dsa = EVP_PKEY_get0_DSA(currentKey); + + if (dsa == NULL || !EVP_PKEY_set1_DSA(newKey, dsa)) + { + success = false; + } + } else { ERR_put_error(ERR_LIB_EVP, 0, EVP_R_UNSUPPORTED_ALGORITHM, __FILE__, __LINE__); @@ -65,6 +75,12 @@ void CryptoNative_EvpPkeyDestroy(EVP_PKEY* pkey) } } +int32_t CryptoNative_EvpPKeyBits(EVP_PKEY* pkey) +{ + assert(pkey != NULL); + return EVP_PKEY_get_bits(pkey); +} + int32_t CryptoNative_EvpPKeySize(EVP_PKEY* pkey) { assert(pkey != NULL); @@ -81,6 +97,30 @@ int32_t CryptoNative_UpRefEvpPkey(EVP_PKEY* pkey) return EVP_PKEY_up_ref(pkey); } +int32_t CryptoNative_SimpleVerifyHash(EVP_PKEY* pkey, const uint8_t* hash, int32_t hashLen, const uint8_t* signature, int32_t signatureLen) +{ + assert(pkey != NULL); + assert(signature != NULL); + + int ret = -1; + EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL); + + if (ctx == NULL || EVP_PKEY_verify_init(ctx) <= 0) + { + goto done; + } + + ret = EVP_PKEY_verify(ctx, signature, Int32ToSizeT(signatureLen), hash, Int32ToSizeT(hashLen)); + +done: + if (ctx != NULL) + { + EVP_PKEY_CTX_free(ctx); + } + + return ret; +} + static bool CheckKey(EVP_PKEY* key, int32_t algId, int32_t (*check_func)(EVP_PKEY_CTX*)) { if (algId != NID_undef && EVP_PKEY_get_base_id(key) != algId) diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h index 012ac98e03db20..ec724734659b9e 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h @@ -29,6 +29,11 @@ Always succeeds. */ PALEXPORT void CryptoNative_EvpPkeyDestroy(EVP_PKEY* pkey); +/* +Returns the algorithm-specific key size, in bits. +*/ +PALEXPORT int32_t CryptoNative_EvpPKeyBits(EVP_PKEY* pkey); + /* Returns the maximum size, in bytes, of an operation with the provided key. */ @@ -43,6 +48,16 @@ Returns the number (as of this call) of references to the EVP_PKEY. Anything les */ PALEXPORT int32_t CryptoNative_UpRefEvpPkey(EVP_PKEY* pkey); +/* +Verify a signature for the specified hash using the provided key (wrapped in an EVP_PKEY) for algorithms +with no signature options. + +Not suitable for use with RSA. Use RsaVerifyHash instead. + +Returns 1 on a verified signature, 0 on a mismatched signature, -1 on error. +*/ +PALEXPORT int32_t CryptoNative_SimpleVerifyHash(EVP_PKEY* pkey, const uint8_t* hash, int32_t hashLen, const uint8_t* signature, int32_t signatureLen); + /* Decodes an X.509 SubjectPublicKeyInfo into an EVP_PKEY*, verifying the interpreted algorithm type. diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_dsa.c b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_dsa.c index 1b95369e842646..81b837df74989a 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_dsa.c +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_dsa.c @@ -2,13 +2,145 @@ // The .NET Foundation licenses this file to you under the MIT license. #include "pal_evp_pkey_dsa.h" +#include "pal_utilities.h" +#include -DSA* CryptoNative_EvpPkeyGetDsa(EVP_PKEY* pkey) +EVP_PKEY* CryptoNative_EvpPKeyCreateDsa(DSA* currentKey) { - return EVP_PKEY_get1_DSA(pkey); + assert(currentKey != NULL); + + EVP_PKEY* pkey = EVP_PKEY_new(); + + if (pkey == NULL) + { + return NULL; + } + + if (!EVP_PKEY_set1_DSA(pkey, currentKey)) + { + EVP_PKEY_free(pkey); + return NULL; + } + + return pkey; } -int32_t CryptoNative_EvpPkeySetDsa(EVP_PKEY* pkey, DSA* dsa) +EVP_PKEY* CryptoNative_DsaGenerateKey(int32_t keySize) { - return EVP_PKEY_set1_DSA(pkey, dsa); + EVP_PKEY_CTX* paramCtx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL); + + if (paramCtx == NULL) + { + return NULL; + } + + EVP_PKEY* paramKey = NULL; + EVP_PKEY* pkey = NULL; + EVP_PKEY* ret = NULL; + EVP_PKEY_CTX* keyCtx = NULL; + + // FIPS 186-4 4.2 + int qbits = keySize > 1024 ? 256 : 160; + + if (EVP_PKEY_paramgen_init(paramCtx) == 1 && EVP_PKEY_CTX_set_dsa_paramgen_bits(paramCtx, keySize) == 1 && + EVP_PKEY_CTX_set_dsa_paramgen_q_bits(paramCtx, qbits) == 1 && + EVP_PKEY_paramgen(paramCtx, ¶mKey) == 1 && (keyCtx = EVP_PKEY_CTX_new(paramKey, NULL)) != NULL && + EVP_PKEY_keygen_init(keyCtx) == 1 && EVP_PKEY_keygen(keyCtx, &pkey) == 1) + { + ret = pkey; + pkey = NULL; + } + + if (paramKey != NULL) + { + EVP_PKEY_free(paramKey); + } + + if (pkey != NULL) + { + EVP_PKEY_free(pkey); + } + + if (paramCtx != NULL) + { + EVP_PKEY_CTX_free(paramCtx); + } + + EVP_PKEY_CTX_free(keyCtx); + return ret; +} + +int32_t CryptoNative_DsaSizeQ(EVP_PKEY* pkey) +{ + assert(pkey != NULL); + + // TODO: OpenSSL 3: Use EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_FFC_Q, &q_out) to get Q. + + int ret = -1; + DSA* dsa = EVP_PKEY_get0_DSA(pkey); + + if (dsa != NULL) + { + const BIGNUM* q = NULL; + DSA_get0_pqg(dsa, NULL, &q, NULL); + + if (q != NULL) + { + ret = BN_num_bytes(q); + } + } + + return ret; +} + +int32_t CryptoNative_DsaSignHash( + EVP_PKEY* pkey, const uint8_t* hash, int32_t hashLen, uint8_t* destination, int32_t destinationLen) +{ + assert(pkey != NULL); + assert(destination != NULL); + + int ret = -1; + EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL); + + if (ctx == NULL || EVP_PKEY_sign_init(ctx) <= 0) + { + goto done; + } + + // This check may no longer be needed on OpenSSL 3.0 + { + DSA* dsa = EVP_PKEY_get0_DSA(pkey); + + // DSA_OpenSSL() returns a shared pointer, no need to free/cache. + if (dsa != NULL) + { + if (DSA_get_method(dsa) == DSA_OpenSSL()) + { + const BIGNUM* privKey; + + DSA_get0_key(dsa, NULL, &privKey); + + if (privKey == NULL) + { + ERR_PUT_error(ERR_LIB_DSA, 0, DSA_R_MISSING_PARAMETERS, __FILE__, __LINE__); + goto done; + } + } + } + } + + size_t written = Int32ToSizeT(destinationLen); + + if (EVP_PKEY_sign(ctx, destination, &written, hash, Int32ToSizeT(hashLen)) > 0) + { + ret = SizeTToInt32(written); + } + +done: + if (ctx != NULL) + { + EVP_PKEY_CTX_free(ctx); + } + + return ret; } diff --git a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_dsa.h b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_dsa.h index a8fee01814b14f..ba0eb984eb755a 100644 --- a/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_dsa.h +++ b/src/libraries/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_dsa.h @@ -1,21 +1,31 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#include "pal_types.h" -#include "pal_compiler.h" #include "opensslshim.h" +#include "pal_compiler.h" +#include "pal_types.h" /* -Shims the EVP_PKEY_get1_DSA method. +Creates an EVP_PKEY* from an existing DSA* +*/ +PALEXPORT EVP_PKEY* CryptoNative_EvpPKeyCreateDsa(DSA* currentKey); -Returns the DSA instance for the EVP_PKEY. +/* +Generate a new DSA key whose P/G/Y values are of size keySize, and the Q/X values +are appropriate for the key size. +*/ +PALEXPORT EVP_PKEY* CryptoNative_DsaGenerateKey(int32_t keySize); + +/* +Returns the size of the q parameter in bytes. */ -PALEXPORT DSA* CryptoNative_EvpPkeyGetDsa(EVP_PKEY* pkey); +PALEXPORT int32_t CryptoNative_DsaSizeQ(EVP_PKEY* pkey); /* -Shims the EVP_PKEY_set1_DSA method to set the DSA -instance on the EVP_KEY. +Complete the DSA signature generation for the specified hash using the provided DSA key +(wrapped in an EVP_PKEY). -Returns 1 upon success, otherwise 0. +Returns the number of bytes written to destination, -1 on error. */ -PALEXPORT int32_t CryptoNative_EvpPkeySetDsa(EVP_PKEY* pkey, DSA* dsa); +PALEXPORT int32_t CryptoNative_DsaSignHash( + EVP_PKEY* pkey, const uint8_t* hash, int32_t hashLen, uint8_t* destination, int32_t destinationLen); diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj index 754b2e38861435..c36600ca2e1385 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj @@ -122,6 +122,8 @@ Link="Common\System\Security\Cryptography\CryptoPool.cs" /> + + - - - - + Common\System\Security\Cryptography\Asn1\AttributeAsn.xml.cs Common\System\Security\Cryptography\Asn1\AttributeAsn.xml + + Common\System\Security\Cryptography\Asn1\DssParms.xml + + + Common\System\Security\Cryptography\Asn1\DssParms.xml.cs + Common\System\Security\Cryptography\Asn1\DssParms.xml + Common\System\Security\Cryptography\Asn1\PrivateKeyInfoAsn.xml diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/DSAOpenSsl.cs b/src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/DSAOpenSsl.cs index f0bef49360ea8f..e6483f0080e509 100644 --- a/src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/DSAOpenSsl.cs +++ b/src/libraries/System.Security.Cryptography.OpenSsl/src/System/Security/Cryptography/DSAOpenSsl.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Microsoft.Win32.SafeHandles; +using System.Diagnostics; namespace System.Security.Cryptography { @@ -10,7 +10,7 @@ public sealed partial class DSAOpenSsl : DSA public DSAOpenSsl(DSAParameters parameters) { // Make _key be non-null before calling ImportParameters - _key = new Lazy(); + _key = new Lazy(); ImportParameters(parameters); } @@ -31,15 +31,11 @@ public DSAOpenSsl(SafeEvpPKeyHandle pkeyHandle) if (pkeyHandle.IsInvalid) throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(pkeyHandle)); - // If dsa is valid it has already been up-ref'd, so we can just use this handle as-is. - SafeDsaHandle key = Interop.Crypto.EvpPkeyGetDsa(pkeyHandle); - if (key.IsInvalid) - { - key.Dispose(); - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } + SafeEvpPKeyHandle newKey = Interop.Crypto.EvpPKeyDuplicate( + pkeyHandle, + Interop.Crypto.EvpAlgorithmId.DSA); - SetKey(key); + SetKey(newKey); } /// @@ -57,8 +53,10 @@ public DSAOpenSsl(IntPtr handle) if (handle == IntPtr.Zero) throw new ArgumentException(SR.Cryptography_OpenInvalidHandle, nameof(handle)); - SafeDsaHandle ecKeyHandle = SafeDsaHandle.DuplicateHandle(handle); - SetKey(ecKeyHandle); + SafeEvpPKeyHandle key = Interop.Crypto.EvpPKeyCreateDsa(handle); + Debug.Assert(!key.IsInvalid); + + SetKey(key); } /// @@ -68,26 +66,7 @@ public DSAOpenSsl(IntPtr handle) /// A SafeHandle for the DSA key in OpenSSL public SafeEvpPKeyHandle DuplicateKeyHandle() { - SafeDsaHandle currentKey = _key.Value; - SafeEvpPKeyHandle pkeyHandle = Interop.Crypto.EvpPkeyCreate(); - - try - { - // Wrapping our key in an EVP_PKEY will up_ref our key. - // When the EVP_PKEY is Disposed it will down_ref the key. - // So everything should be copacetic. - if (!Interop.Crypto.EvpPkeySetDsa(pkeyHandle, currentKey)) - { - throw Interop.Crypto.CreateOpenSslCryptographicException(); - } - - return pkeyHandle; - } - catch - { - pkeyHandle.Dispose(); - throw; - } + return Interop.Crypto.EvpPKeyDuplicate(GetKey(), Interop.Crypto.EvpAlgorithmId.DSA); } } } diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj b/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj index 3b1071dd9124bb..51af521c8444a7 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj @@ -600,6 +600,8 @@ Link="Common\Interop\OSX\System.Security.Cryptography.Native.Apple\Interop.X509.macOS.cs" /> +