commit c1a05ffdefc6d7dc38e66358ef6545523589e221 Author: CentOS Sources Date: Wed Nov 3 17:54:43 2021 -0400 import dotnet3.1-3.1.118-1.el9 diff --git a/.dotnet3.1.metadata b/.dotnet3.1.metadata new file mode 100644 index 0000000..b7b9c1b --- /dev/null +++ b/.dotnet3.1.metadata @@ -0,0 +1 @@ +a7bd4df33c2e8e207f3ffb03135b917468a05dd3 SOURCES/dotnet-v3.1.118-SDK.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7db3884 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/dotnet-v3.1.118-SDK.tar.gz diff --git a/SOURCES/check-debug-symbols.py b/SOURCES/check-debug-symbols.py new file mode 100755 index 0000000..be26d87 --- /dev/null +++ b/SOURCES/check-debug-symbols.py @@ -0,0 +1,136 @@ +#!/usr/bin/python3 + +""" +Check debug symbols are present in shared object and can identify +code. + +It starts scanning from a directory and recursively scans all ELF +files found in it for various symbols to ensure all debuginfo is +present and nothing has been stripped. + +Usage: + +./check-debug-symbols /path/of/dir/to/scan/ + + +Example: + +./check-debug-symbols /usr/lib64 +""" + +# This technique was explained to me by Mark Wielaard (mjw). + +import collections +import os +import re +import subprocess +import sys + +ScanResult = collections.namedtuple('ScanResult', + 'file_name debug_info debug_abbrev file_symbols gnu_debuglink') + + +def scan_file(file): + "Scan the provided file and return a ScanResult containing results of the scan." + + # Test for .debug_* sections in the shared object. This is the main test. + # Stripped objects will not contain these. + readelf_S_result = subprocess.run(['eu-readelf', '-S', file], + stdout=subprocess.PIPE, encoding='utf-8', check=True) + has_debug_info = any(line for line in readelf_S_result.stdout.split('\n') if '] .debug_info' in line) + + has_debug_abbrev = any(line for line in readelf_S_result.stdout.split('\n') if '] .debug_abbrev' in line) + + # Test FILE symbols. These will most likely be removed by anyting that + # manipulates symbol tables because it's generally useless. So a nice test + # that nothing has messed with symbols. + def contains_file_symbols(line): + parts = line.split() + if len(parts) < 8: + return False + return \ + parts[2] == '0' and parts[3] == 'FILE' and parts[4] == 'LOCAL' and parts[5] == 'DEFAULT' and \ + parts[6] == 'ABS' and re.match(r'((.*/)?[-_a-zA-Z0-9]+\.(c|cc|cpp|cxx))?', parts[7]) + + readelf_s_result = subprocess.run(["eu-readelf", '-s', file], + stdout=subprocess.PIPE, encoding='utf-8', check=True) + has_file_symbols = any(line for line in readelf_s_result.stdout.split('\n') if contains_file_symbols(line)) + + # Test that there are no .gnu_debuglink sections pointing to another + # debuginfo file. There shouldn't be any debuginfo files, so the link makes + # no sense either. + has_gnu_debuglink = any(line for line in readelf_s_result.stdout.split('\n') if '] .gnu_debuglink' in line) + + return ScanResult(file, has_debug_info, has_debug_abbrev, has_file_symbols, has_gnu_debuglink) + +def is_elf(file): + result = subprocess.run(['file', file], stdout=subprocess.PIPE, encoding='utf-8', check=True) + return re.search('ELF 64-bit LSB (?:executable|shared object)', result.stdout) + +def scan_file_if_sensible(file): + if is_elf(file): + # print(file) + return scan_file(file) + return None + +def scan_dir(dir): + results = [] + for root, _, files in os.walk(dir): + for name in files: + result = scan_file_if_sensible(os.path.join(root, name)) + if result: + results.append(result) + return results + +def scan(file): + file = os.path.abspath(file) + if os.path.isdir(file): + return scan_dir(file) + elif os.path.isfile(file): + return [scan_file_if_sensible(file)] + +def is_bad_result(result): + return not result.debug_info or not result.debug_abbrev or not result.file_symbols or result.gnu_debuglink + +def print_scan_results(results, verbose): + # print(results) + for result in results: + file_name = result.file_name + found_issue = False + if not result.debug_info: + found_issue = True + print('error: missing .debug_info section in', file_name) + if not result.debug_abbrev: + found_issue = True + print('error: missing .debug_abbrev section in', file_name) + if not result.file_symbols: + found_issue = True + print('error: missing FILE symbols in', file_name) + if result.gnu_debuglink: + found_issue = True + print('error: unexpected .gnu_debuglink section in', file_name) + if verbose and not found_issue: + print('OK: ', file_name) + +def main(args): + verbose = False + files = [] + for arg in args: + if arg == '--verbose' or arg == '-v': + verbose = True + else: + files.append(arg) + + results = [] + for file in files: + results.extend(scan(file)) + + print_scan_results(results, verbose) + + if any(is_bad_result(result) for result in results): + return 1 + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/SOURCES/cli-telemetry-optout.patch b/SOURCES/cli-telemetry-optout.patch new file mode 100644 index 0000000..9b01f13 --- /dev/null +++ b/SOURCES/cli-telemetry-optout.patch @@ -0,0 +1,18 @@ +diff --git a/src/dotnet/Program.cs b/src/dotnet/Program.cs +index de1ebb9e6..6bbf479de 100644 +--- a/src/dotnet/Program.cs ++++ b/src/dotnet/Program.cs +@@ -28,6 +28,13 @@ public class Program + + public static int Main(string[] args) + { ++ // opt out of telemetry by default if the env var is unset ++ string telemetryValue = Environment.GetEnvironmentVariable("DOTNET_CLI_TELEMETRY_OPTOUT"); ++ if (String.IsNullOrEmpty(telemetryValue)) ++ { ++ Environment.SetEnvironmentVariable("DOTNET_CLI_TELEMETRY_OPTOUT", "1"); ++ } ++ + DebugHelper.HandleDebugSwitch(ref args); + + new MulticoreJitActivator().TryActivateMulticoreJit(); diff --git a/SOURCES/corefx-39633-cgroupv2-mountpoints.patch b/SOURCES/corefx-39633-cgroupv2-mountpoints.patch new file mode 100644 index 0000000..34fbecb --- /dev/null +++ b/SOURCES/corefx-39633-cgroupv2-mountpoints.patch @@ -0,0 +1,46 @@ +From 1864630f762160e1cb439362cc0577471624192a Mon Sep 17 00:00:00 2001 +From: Omair Majid +Date: Fri, 19 Jul 2019 19:18:51 -0400 +Subject: [PATCH] Fix up cgroup2fs in Interop.MountPoints.FormatInfo + +`stat -fc %T /sys/fs/cgroup` calls this file system `cgroup2fs` + +Add the cgroup2fs file system magic number. Available from: + + - https://www.kernel.org/doc/Documentation/cgroup-v2.txt + - man 2 statfs + +Move cgroup2fs next to cgroupfs in the drive type list, since it is also +DriveType.Ram. +--- + .../Unix/System.Native/Interop.MountPoints.FormatInfo.cs | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs b/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs +index af38a2285ba2..4240bd4853ab 100644 +--- a/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs ++++ b/src/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs +@@ -47,6 +47,7 @@ internal enum UnixFileSystemTypes : long + btrfs = 0x9123683E, + ceph = 0x00C36400, + cgroupfs = 0x0027E0EB, ++ cgroup2fs = 0x63677270, + cifs = 0xFF534D42, + coda = 0x73757245, + coherent = 0x012FF7B7, +@@ -231,7 +232,6 @@ private static DriveType GetDriveType(string fileSystemName) + case "bpf_fs": + case "btrfs": + case "btrfs_test": +- case "cgroup2fs": + case "coh": + case "daxfs": + case "drvfs": +@@ -384,6 +384,7 @@ private static DriveType GetDriveType(string fileSystemName) + case "binfmt_misc": + case "cgroup": + case "cgroupfs": ++ case "cgroup2fs": + case "configfs": + case "cramfs": + case "cramfs-wend": diff --git a/SOURCES/corefx-39686-cgroupv2-01.patch b/SOURCES/corefx-39686-cgroupv2-01.patch new file mode 100644 index 0000000..e7628e2 --- /dev/null +++ b/SOURCES/corefx-39686-cgroupv2-01.patch @@ -0,0 +1,391 @@ +From 2b2273ea4ea1c28472fa0d6ad2ffeb6374500550 Mon Sep 17 00:00:00 2001 +From: Omair Majid +Date: Wed, 23 Oct 2019 17:45:59 -0400 +Subject: [PATCH 1/2] Add cgroup v2 support to Interop.cgroups + +Fix up code to adjust cgroup v1 assumptions and check cgroup v2 paths, +locations and values. + +Continue using the older cgroup v1 terminology for APIs. +--- + .../Interop/Linux/cgroups/Interop.cgroups.cs | 116 ++++++++++++++---- + src/Common/tests/Common.Tests.csproj | 4 + + .../tests/Tests/Interop/cgroupsTests.cs | 107 ++++++++++++++++ + .../tests/DescriptionNameTests.cs | 2 +- + 4 files changed, 206 insertions(+), 23 deletions(-) + create mode 100644 src/Common/tests/Tests/Interop/cgroupsTests.cs + +diff --git a/src/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs b/src/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs +index 0ffd4d7b7c03..186fe0516c5b 100644 +--- a/src/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs ++++ b/src/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs +@@ -9,17 +9,22 @@ + + internal static partial class Interop + { ++ /// Provides access to some cgroup (v1 and v2) features + internal static partial class cgroups + { ++ // For cgroup v1, see https://www.kernel.org/doc/Documentation/cgroup-v1/ ++ // For cgroup v2, see https://www.kernel.org/doc/Documentation/cgroup-v2.txt ++ ++ /// The version of cgroup that's being used ++ internal enum CGroupVersion { None, CGroup1, CGroup2 }; ++ + /// Path to mountinfo file in procfs for the current process. + private const string ProcMountInfoFilePath = "/proc/self/mountinfo"; + /// Path to cgroup directory in procfs for the current process. + private const string ProcCGroupFilePath = "/proc/self/cgroup"; + +- /// Path to the found cgroup location, or null if it couldn't be found. +- internal static readonly string s_cgroupMemoryPath = FindCGroupPath("memory"); +- /// Path to the found cgroup memory limit_in_bytes path, or null if it couldn't be found. +- private static readonly string s_cgroupMemoryLimitPath = s_cgroupMemoryPath != null ? s_cgroupMemoryPath + "/memory.limit_in_bytes" : null; ++ /// Path to the found cgroup memory limit path, or null if it couldn't be found. ++ internal static readonly string s_cgroupMemoryLimitPath = FindCGroupMemoryLimitPath(); + + /// Tries to read the memory limit from the cgroup memory location. + /// The read limit, or 0 if it couldn't be read. +@@ -42,7 +47,7 @@ public static bool TryGetMemoryLimit(out ulong limit) + /// The path to the file to parse. + /// The parsed result, or 0 if it couldn't be parsed. + /// true if the value was read successfully; otherwise, false. +- private static bool TryReadMemoryValueFromFile(string path, out ulong result) ++ internal static bool TryReadMemoryValueFromFile(string path, out ulong result) + { + if (File.Exists(path)) + { +@@ -79,6 +84,11 @@ private static bool TryReadMemoryValueFromFile(string path, out ulong result) + result = checked(ulongValue * multiplier); + return true; + } ++ ++ // 'max' is also a possible valid value ++ // ++ // Treat this as 'no memory limit' and let the caller ++ // fallback to reading the real limit via other means + } + catch (Exception e) + { +@@ -90,12 +100,35 @@ private static bool TryReadMemoryValueFromFile(string path, out ulong result) + return false; + } + ++ /// Find the cgroup memory limit path. ++ /// The limit path if found; otherwise, null. ++ private static string FindCGroupMemoryLimitPath() ++ { ++ string cgroupMemoryPath = FindCGroupPath("memory", out CGroupVersion version); ++ if (cgroupMemoryPath != null) ++ { ++ if (version == CGroupVersion.CGroup1) ++ { ++ return cgroupMemoryPath + "/memory.limit_in_bytes"; ++ } ++ ++ if (version == CGroupVersion.CGroup2) ++ { ++ // 'memory.high' is a soft limit; the process may get throttled ++ // 'memory.max' is where OOM killer kicks in ++ return cgroupMemoryPath + "/memory.max"; ++ } ++ } ++ ++ return null; ++ } ++ + /// Find the cgroup path for the specified subsystem. + /// The subsystem, e.g. "memory". + /// The cgroup path if found; otherwise, null. +- private static string FindCGroupPath(string subsystem) ++ private static string FindCGroupPath(string subsystem, out CGroupVersion version) + { +- if (TryFindHierarchyMount(subsystem, out string hierarchyRoot, out string hierarchyMount) && ++ if (TryFindHierarchyMount(subsystem, out version, out string hierarchyRoot, out string hierarchyMount) && + TryFindCGroupPathForSubsystem(subsystem, out string cgroupPathRelativeToMount)) + { + // For a host cgroup, we need to append the relative path. +@@ -113,19 +146,24 @@ private static string FindCGroupPath(string subsystem) + /// The path of the directory in the filesystem which forms the root of this mount; null if not found. + /// The path of the mount point relative to the process's root directory; null if not found. + /// true if the mount was found; otherwise, null. +- private static bool TryFindHierarchyMount(string subsystem, out string root, out string path) ++ private static bool TryFindHierarchyMount(string subsystem, out CGroupVersion version, out string root, out string path) + { +- if (File.Exists(ProcMountInfoFilePath)) ++ return TryFindHierarchyMount(ProcMountInfoFilePath, subsystem, out version, out root, out path); ++ } ++ ++ internal static bool TryFindHierarchyMount(string mountInfoFilePath, string subsystem, out CGroupVersion version, out string root, out string path) ++ { ++ if (File.Exists(mountInfoFilePath)) + { + try + { +- using (var reader = new StreamReader(ProcMountInfoFilePath)) ++ using (var reader = new StreamReader(mountInfoFilePath)) + { + string line; + while ((line = reader.ReadLine()) != null) + { + // Look for an entry that has cgroup as the "filesystem type" +- // and that has options containing the specified subsystem. ++ // and, for cgroup1, that has options containing the specified subsystem + // See man page for /proc/[pid]/mountinfo for details, e.g.: + // (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) + // 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue +@@ -148,17 +186,35 @@ private static bool TryFindHierarchyMount(string subsystem, out string root, out + continue; + } + +- if (postSeparatorlineParts[0] != "cgroup" || +- Array.IndexOf(postSeparatorlineParts[2].Split(','), subsystem) < 0) ++ bool validCGroup1Entry = ((postSeparatorlineParts[0] == "cgroup") && ++ (Array.IndexOf(postSeparatorlineParts[2].Split(','), subsystem) >= 0)); ++ bool validCGroup2Entry = postSeparatorlineParts[0] == "cgroup2"; ++ ++ if (!validCGroup1Entry && !validCGroup2Entry) + { + // Not the relevant entry. + continue; + } + +- // Found the relevant entry. Extract the mount root and path. ++ // Found the relevant entry. Extract the cgroup version, mount root and path. ++ switch (postSeparatorlineParts[0]) ++ { ++ case "cgroup": ++ version = CGroupVersion.CGroup1; ++ break; ++ case "cgroup2": ++ version = CGroupVersion.CGroup2; ++ break; ++ default: ++ version = CGroupVersion.None; ++ Debug.Fail($"invalid value for CGroupVersion \"{postSeparatorlineParts[0]}\""); ++ break; ++ } ++ + string[] lineParts = line.Substring(0, endOfOptionalFields).Split(' '); + root = lineParts[3]; + path = lineParts[4]; ++ + return true; + } + } +@@ -169,6 +225,7 @@ private static bool TryFindHierarchyMount(string subsystem, out string root, out + } + } + ++ version = CGroupVersion.None; + root = null; + path = null; + return false; +@@ -180,27 +237,42 @@ private static bool TryFindHierarchyMount(string subsystem, out string root, out + /// + private static bool TryFindCGroupPathForSubsystem(string subsystem, out string path) + { +- if (File.Exists(ProcCGroupFilePath)) ++ return TryFindCGroupPathForSubsystem(ProcCGroupFilePath, subsystem, out path); ++ } ++ ++ internal static bool TryFindCGroupPathForSubsystem(string procCGroupFilePath, string subsystem, out string path) ++ { ++ if (File.Exists(procCGroupFilePath)) + { + try + { +- using (var reader = new StreamReader(ProcCGroupFilePath)) ++ using (var reader = new StreamReader(procCGroupFilePath)) + { + string line; + while ((line = reader.ReadLine()) != null) + { +- // Find the first entry that has the subsystem listed in its controller +- // list. See man page for cgroups for /proc/[pid]/cgroups format, e.g: +- // hierarchy-ID:controller-list:cgroup-path +- // 5:cpuacct,cpu,cpuset:/daemons +- + string[] lineParts = line.Split(':'); ++ + if (lineParts.Length != 3) + { + // Malformed line. + continue; + } + ++ // cgroup v2: Find the first entry that matches the cgroup v2 hierarchy: ++ // 0::$PATH ++ ++ if ((lineParts[0] == "0") && (string.Empty == lineParts[1])) ++ { ++ path = lineParts[2]; ++ return true; ++ } ++ ++ // cgroup v1: Find the first entry that has the subsystem listed in its controller ++ // list. See man page for cgroups for /proc/[pid]/cgroups format, e.g: ++ // hierarchy-ID:controller-list:cgroup-path ++ // 5:cpuacct,cpu,cpuset:/daemons ++ + if (Array.IndexOf(lineParts[1].Split(','), subsystem) < 0) + { + // Not the relevant entry. +@@ -214,7 +286,7 @@ private static bool TryFindCGroupPathForSubsystem(string subsystem, out string p + } + catch (Exception e) + { +- Debug.Fail($"Failed to read or parse \"{ProcMountInfoFilePath}\": {e}"); ++ Debug.Fail($"Failed to read or parse \"{procCGroupFilePath}\": {e}"); + } + } + +diff --git a/src/Common/tests/Common.Tests.csproj b/src/Common/tests/Common.Tests.csproj +index a189d856348b..979c8dd7fbe6 100644 +--- a/src/Common/tests/Common.Tests.csproj ++++ b/src/Common/tests/Common.Tests.csproj +@@ -12,6 +12,9 @@ + + Common\System\Security\Cryptography\ByteUtils.cs + ++ ++ Common\Interop\Linux\cgroups\Interop.cgroups.cs ++ + + Common\Interop\Linux\procfs\Interop.ProcFsStat.cs + +@@ -69,6 +72,7 @@ + + Common\CoreLib\System\PasteArguments.cs + ++ + + + +diff --git a/src/Common/tests/Tests/Interop/cgroupsTests.cs b/src/Common/tests/Tests/Interop/cgroupsTests.cs +new file mode 100644 +index 000000000000..f16d9242879c +--- /dev/null ++++ b/src/Common/tests/Tests/Interop/cgroupsTests.cs +@@ -0,0 +1,107 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++// See the LICENSE file in the project root for more information. ++ ++using System; ++using System.IO; ++using System.Text; ++using Xunit; ++ ++namespace Common.Tests ++{ ++ public class cgroupsTests ++ { ++ [Theory] ++ [InlineData(true, "0", 0)] ++ [InlineData(false, "max", 0)] ++ [InlineData(true, "1k", 1024)] ++ [InlineData(true, "1K", 1024)] ++ public static void ValidateTryReadMemoryValue(bool expectedResult, string valueText, ulong expectedValue) ++ { ++ string path = Path.GetTempFileName(); ++ try ++ { ++ File.WriteAllText(path, valueText); ++ ++ bool result = Interop.cgroups.TryReadMemoryValueFromFile(path, out ulong val); ++ ++ Assert.Equal(expectedResult, result); ++ if (result) ++ { ++ Assert.Equal(expectedValue, val); ++ } ++ } ++ finally ++ { ++ File.Delete(path); ++ } ++ } ++ ++ [Theory] ++ [InlineData(false, "0 0 0:0 / /foo ignore ignore - overlay overlay ignore", "ignore", 0, "/", "/")] ++ [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup2 cgroup2 ignore", "ignore", 2, "/", "/foo")] ++ [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup2 cgroup2 ignore", "memory", 2, "/", "/foo")] ++ [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup2 cgroup2 ignore", "cpu", 2, "/", "/foo")] ++ [InlineData(true, "0 0 0:0 / /foo ignore - cgroup2 cgroup2 ignore", "cpu", 2, "/", "/foo")] ++ [InlineData(true, "0 0 0:0 / /foo ignore ignore ignore - cgroup2 cgroup2 ignore", "cpu", 2, "/", "/foo")] ++ [InlineData(true, "0 0 0:0 / /foo-with-dashes ignore ignore - cgroup2 cgroup2 ignore", "ignore", 2, "/", "/foo-with-dashes")] ++ [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup cgroup memory", "memory", 1, "/", "/foo")] ++ [InlineData(true, "0 0 0:0 / /foo-with-dashes ignore ignore - cgroup cgroup memory", "memory", 1, "/", "/foo-with-dashes")] ++ [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup cgroup cpu,memory", "memory", 1, "/", "/foo")] ++ [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup cgroup memory,cpu", "memory", 1, "/", "/foo")] ++ [InlineData(false, "0 0 0:0 / /foo ignore ignore - cgroup cgroup cpu", "memory", 0, "/", "/foo")] ++ public static void ParseValidateMountInfo(bool found, string procSelfMountInfoText, string subsystem, int expectedVersion, string expectedRoot, string expectedMount) ++ { ++ string path = Path.GetTempFileName(); ++ try ++ { ++ File.WriteAllText(path, procSelfMountInfoText); ++ ++ bool result = Interop.cgroups.TryFindHierarchyMount(path, subsystem, out Interop.cgroups.CGroupVersion version, out string root, out string mount); ++ ++ Assert.Equal(found, result); ++ if (found) ++ { ++ Assert.Equal(expectedVersion, (int)version); ++ Assert.Equal(expectedRoot, root); ++ Assert.Equal(expectedMount, mount); ++ } ++ } ++ finally ++ { ++ File.Delete(path); ++ } ++ } ++ ++ [Theory] ++ [InlineData(true, "0::/foo", "ignore", "/foo")] ++ [InlineData(true, "0::/bar", "ignore", "/bar")] ++ [InlineData(true, "0::frob", "ignore", "frob")] ++ [InlineData(false, "1::frob", "ignore", "ignore")] ++ [InlineData(true, "1:foo:bar", "foo", "bar")] ++ [InlineData(true, "2:foo:bar", "foo", "bar")] ++ [InlineData(false, "2:foo:bar", "bar", "ignore")] ++ [InlineData(true, "1:foo:bar\n2:eggs:spam", "foo", "bar")] ++ [InlineData(true, "1:foo:bar\n2:eggs:spam", "eggs", "spam")] ++ public static void ParseValidateProcCGroup(bool found, string procSelfCgroupText, string subsystem, string expectedMountPath) ++ { ++ string path = Path.GetTempFileName(); ++ try ++ { ++ File.WriteAllText(path, procSelfCgroupText); ++ ++ bool result = Interop.cgroups.TryFindCGroupPathForSubsystem(path, subsystem, out string mountPath); ++ ++ Assert.Equal(found, result); ++ if (found) ++ { ++ Assert.Equal(expectedMountPath, mountPath); ++ } ++ } ++ finally ++ { ++ File.Delete(path); ++ } ++ } ++ } ++} +diff --git a/src/System.Runtime.InteropServices.RuntimeInformation/tests/DescriptionNameTests.cs b/src/System.Runtime.InteropServices.RuntimeInformation/tests/DescriptionNameTests.cs +index 910af2fd82b4..73f692898dbc 100644 +--- a/src/System.Runtime.InteropServices.RuntimeInformation/tests/DescriptionNameTests.cs ++++ b/src/System.Runtime.InteropServices.RuntimeInformation/tests/DescriptionNameTests.cs +@@ -40,7 +40,7 @@ public void DumpRuntimeInformationToConsole() + + Console.WriteLine($"### CURRENT DIRECTORY: {Environment.CurrentDirectory}"); + +- string cgroupsLocation = Interop.cgroups.s_cgroupMemoryPath; ++ string cgroupsLocation = Interop.cgroups.s_cgroupMemoryLimitPath; + if (cgroupsLocation != null) + { + Console.WriteLine($"### CGROUPS MEMORY: {cgroupsLocation}"); + diff --git a/SOURCES/corefx-39686-cgroupv2-02.patch b/SOURCES/corefx-39686-cgroupv2-02.patch new file mode 100644 index 0000000..88dcd99 --- /dev/null +++ b/SOURCES/corefx-39686-cgroupv2-02.patch @@ -0,0 +1,129 @@ +From 9a8c5e4014ffca8aff70808cc0e50a403d38c292 Mon Sep 17 00:00:00 2001 +From: Stephen Toub +Date: Wed, 23 Oct 2019 20:35:49 -0400 +Subject: [PATCH 2/2] Clean up new tests + +--- + .../tests/Tests/Interop/cgroupsTests.cs | 79 ++++++------------- + 1 file changed, 25 insertions(+), 54 deletions(-) + +diff --git a/src/Common/tests/Tests/Interop/cgroupsTests.cs b/src/Common/tests/Tests/Interop/cgroupsTests.cs +index f16d9242879c..fc6ab5c9753c 100644 +--- a/src/Common/tests/Tests/Interop/cgroupsTests.cs ++++ b/src/Common/tests/Tests/Interop/cgroupsTests.cs +@@ -2,38 +2,27 @@ + // The .NET Foundation licenses this file to you under the MIT license. + // See the LICENSE file in the project root for more information. + +-using System; + using System.IO; +-using System.Text; + using Xunit; + + namespace Common.Tests + { +- public class cgroupsTests ++ public class cgroupsTests : FileCleanupTestBase + { + [Theory] +- [InlineData(true, "0", 0)] +- [InlineData(false, "max", 0)] +- [InlineData(true, "1k", 1024)] +- [InlineData(true, "1K", 1024)] +- public static void ValidateTryReadMemoryValue(bool expectedResult, string valueText, ulong expectedValue) ++ [InlineData(true, "0", 0)] ++ [InlineData(false, "max", 0)] ++ [InlineData(true, "1k", 1024)] ++ [InlineData(true, "1K", 1024)] ++ public void ValidateTryReadMemoryValue(bool expectedResult, string valueText, ulong expectedValue) + { +- string path = Path.GetTempFileName(); +- try +- { +- File.WriteAllText(path, valueText); +- +- bool result = Interop.cgroups.TryReadMemoryValueFromFile(path, out ulong val); ++ string path = GetTestFilePath(); ++ File.WriteAllText(path, valueText); + +- Assert.Equal(expectedResult, result); +- if (result) +- { +- Assert.Equal(expectedValue, val); +- } +- } +- finally ++ Assert.Equal(expectedResult, Interop.cgroups.TryReadMemoryValueFromFile(path, out ulong val)); ++ if (expectedResult) + { +- File.Delete(path); ++ Assert.Equal(expectedValue, val); + } + } + +@@ -50,26 +39,17 @@ public static void ValidateTryReadMemoryValue(bool expectedResult, string valueT + [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup cgroup cpu,memory", "memory", 1, "/", "/foo")] + [InlineData(true, "0 0 0:0 / /foo ignore ignore - cgroup cgroup memory,cpu", "memory", 1, "/", "/foo")] + [InlineData(false, "0 0 0:0 / /foo ignore ignore - cgroup cgroup cpu", "memory", 0, "/", "/foo")] +- public static void ParseValidateMountInfo(bool found, string procSelfMountInfoText, string subsystem, int expectedVersion, string expectedRoot, string expectedMount) ++ public void ParseValidateMountInfo(bool expectedFound, string procSelfMountInfoText, string subsystem, int expectedVersion, string expectedRoot, string expectedMount) + { +- string path = Path.GetTempFileName(); +- try +- { +- File.WriteAllText(path, procSelfMountInfoText); +- +- bool result = Interop.cgroups.TryFindHierarchyMount(path, subsystem, out Interop.cgroups.CGroupVersion version, out string root, out string mount); ++ string path = GetTestFilePath(); ++ File.WriteAllText(path, procSelfMountInfoText); + +- Assert.Equal(found, result); +- if (found) +- { +- Assert.Equal(expectedVersion, (int)version); +- Assert.Equal(expectedRoot, root); +- Assert.Equal(expectedMount, mount); +- } +- } +- finally ++ Assert.Equal(expectedFound, Interop.cgroups.TryFindHierarchyMount(path, subsystem, out Interop.cgroups.CGroupVersion version, out string root, out string mount)); ++ if (expectedFound) + { +- File.Delete(path); ++ Assert.Equal(expectedVersion, (int)version); ++ Assert.Equal(expectedRoot, root); ++ Assert.Equal(expectedMount, mount); + } + } + +@@ -83,24 +63,15 @@ public static void ParseValidateMountInfo(bool found, string procSelfMountInfoTe + [InlineData(false, "2:foo:bar", "bar", "ignore")] + [InlineData(true, "1:foo:bar\n2:eggs:spam", "foo", "bar")] + [InlineData(true, "1:foo:bar\n2:eggs:spam", "eggs", "spam")] +- public static void ParseValidateProcCGroup(bool found, string procSelfCgroupText, string subsystem, string expectedMountPath) ++ public void ParseValidateProcCGroup(bool expectedFound, string procSelfCgroupText, string subsystem, string expectedMountPath) + { +- string path = Path.GetTempFileName(); +- try +- { +- File.WriteAllText(path, procSelfCgroupText); ++ string path = GetTestFilePath(); ++ File.WriteAllText(path, procSelfCgroupText); + +- bool result = Interop.cgroups.TryFindCGroupPathForSubsystem(path, subsystem, out string mountPath); +- +- Assert.Equal(found, result); +- if (found) +- { +- Assert.Equal(expectedMountPath, mountPath); +- } +- } +- finally ++ Assert.Equal(expectedFound, Interop.cgroups.TryFindCGroupPathForSubsystem(path, subsystem, out string mountPath)); ++ if (expectedFound) + { +- File.Delete(path); ++ Assert.Equal(expectedMountPath, mountPath); + } + } + } diff --git a/SOURCES/corefx-openssl-0001-Use-EVP_PKEY-for-RSA-key-generation.patch b/SOURCES/corefx-openssl-0001-Use-EVP_PKEY-for-RSA-key-generation.patch new file mode 100644 index 0000000..490e792 --- /dev/null +++ b/SOURCES/corefx-openssl-0001-Use-EVP_PKEY-for-RSA-key-generation.patch @@ -0,0 +1,349 @@ +From 2b6b45878b1be4d77eec34ab5bc80b626995a8c5 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Fri, 19 Mar 2021 15:05:41 -0700 +Subject: [PATCH 01/11] Use EVP_PKEY for RSA key generation + +--- + .../Interop.EvpPkey.Rsa.cs | 16 ++++++++ + .../Interop.Rsa.cs | 3 -- + .../Security/Cryptography/RSAOpenSsl.cs | 37 ++++--------------- + .../apibridge.c | 8 ++++ + .../apibridge.h | 1 + + .../opensslshim.h | 23 ++++++++++++ + .../pal_evp_pkey_rsa.c | 29 +++++++++++++++ + .../pal_evp_pkey_rsa.h | 5 +++ + .../pal_rsa.c | 5 --- + .../pal_rsa.h | 7 ---- + ...em.Security.Cryptography.Algorithms.csproj | 3 ++ + 11 files changed, 93 insertions(+), 44 deletions(-) + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +index 1f61a826a9..c28522784b 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +@@ -10,6 +10,22 @@ internal static partial class Interop + { + internal static partial class Crypto + { ++ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaGenerateKey")] ++ private static extern SafeEvpPKeyHandle CryptoNative_RsaGenerateKey(int keySize); ++ ++ internal static SafeEvpPKeyHandle RsaGenerateKey(int keySize) ++ { ++ SafeEvpPKeyHandle pkey = CryptoNative_RsaGenerateKey(keySize); ++ ++ if (pkey.IsInvalid) ++ { ++ pkey.Dispose(); ++ throw CreateOpenSslCryptographicException(); ++ } ++ ++ return pkey; ++ } ++ + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyGetRsa")] + internal static extern SafeRsaHandle EvpPkeyGetRsa(SafeEvpPKeyHandle pkey); + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +index a7b85ae011..a05f020ada 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +@@ -89,9 +89,6 @@ internal static partial class Crypto + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSize")] + internal static extern int RsaSize(SafeRsaHandle rsa); + +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaGenerateKeyEx")] +- internal static extern int RsaGenerateKeyEx(SafeRsaHandle rsa, int bits, SafeBignumHandle e); +- + internal static bool RsaSign(int type, ReadOnlySpan m, int m_len, Span sigret, out int siglen, SafeRsaHandle rsa) => + RsaSign(type, ref MemoryMarshal.GetReference(m), m_len, ref MemoryMarshal.GetReference(sigret), out siglen, rsa); + +diff --git a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +index 6741d28bba..4d4a8414b3 100644 +--- a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs ++++ b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +@@ -25,9 +25,6 @@ public sealed partial class RSAOpenSsl : RSA + { + private const int BitsPerByte = 8; + +- // 65537 (0x10001) in big-endian form +- private static readonly byte[] s_defaultExponent = { 0x01, 0x00, 0x01 }; +- + private Lazy _key; + + public RSAOpenSsl() +@@ -585,36 +582,18 @@ private static void CheckBoolReturn(int returnValue) + + private SafeRsaHandle GenerateKey() + { +- SafeRsaHandle key = Interop.Crypto.RsaCreate(); +- bool generated = false; +- +- Interop.Crypto.CheckValidOpenSslHandle(key); +- +- try ++ using (SafeEvpPKeyHandle pkey = Interop.Crypto.RsaGenerateKey(KeySize)) + { +- using (SafeBignumHandle exponent = Interop.Crypto.CreateBignum(s_defaultExponent)) +- { +- // The documentation for RSA_generate_key_ex does not say that it returns only +- // 0 or 1, so the call marshals it back as a full Int32 and checks for a value +- // of 1 explicitly. +- int response = Interop.Crypto.RsaGenerateKeyEx( +- key, +- KeySize, +- exponent); +- +- CheckBoolReturn(response); +- generated = true; +- } +- } +- finally +- { +- if (!generated) ++ SafeRsaHandle rsa = Interop.Crypto.EvpPkeyGetRsa(pkey); ++ ++ if (rsa.IsInvalid) + { +- key.Dispose(); ++ rsa.Dispose(); ++ throw Interop.Crypto.CreateOpenSslCryptographicException(); + } +- } + +- return key; ++ return rsa; ++ } + } + + protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) => +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c +index 167de7fd8e..def7198deb 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c +@@ -728,4 +728,12 @@ void local_SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level) + (void)ctx; + (void)level; + } ++ ++int32_t local_RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2) ++{ ++ // On OpenSSL 1.0.2 there aren't two different identifiers for RSA, ++ // so just pass the request on th EVP_PKEY_CTX_ctrl with the only identifier defined. ++ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, optype, cmd, p1, p2); ++} ++ + #endif +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h +index 5f62864b24..b58611ae73 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h +@@ -26,6 +26,7 @@ int32_t local_RSA_meth_get_flags(const RSA_METHOD* meth); + int32_t local_RSA_set0_crt_params(RSA* rsa, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp); + int32_t local_RSA_set0_factors(RSA* rsa, BIGNUM* p, BIGNUM* q); + int32_t local_RSA_set0_key(RSA* rsa, BIGNUM* n, BIGNUM* e, BIGNUM* d); ++int32_t local_RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2); + int32_t local_SSL_is_init_finished(const SSL* ssl); + unsigned long local_SSL_CTX_set_options(SSL_CTX* ctx, unsigned long options); + void local_SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index ed3994926d..dff6091e9e 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -145,6 +145,7 @@ void RSA_get0_factors(const RSA* rsa, const BIGNUM** p, const BIGNUM** q); + void RSA_get0_key(const RSA* rsa, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d); + int32_t RSA_meth_get_flags(const RSA_METHOD* meth); + const RSA_METHOD* RSA_PKCS1_OpenSSL(void); ++int32_t RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2); + int32_t RSA_set0_crt_params(RSA* rsa, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp); + int32_t RSA_set0_factors(RSA* rsa, BIGNUM* p, BIGNUM* q); + int32_t RSA_set0_key(RSA* rsa, BIGNUM* n, BIGNUM* e, BIGNUM* d); +@@ -170,6 +171,13 @@ const X509_ALGOR* X509_get0_tbs_sigalg(const X509* x509); + X509_PUBKEY* X509_get_X509_PUBKEY(const X509* x509); + int32_t X509_get_version(const X509* x509); + int32_t X509_up_ref(X509* x509); ++ ++// Redefine EVP_PKEY_CTX_set_rsa operations to use (local_)RSA_pkey_ctx_ctrl so the path is the same ++// for 1.0-built on 1.1 as on 1.1-built on 1.1. ++#undef EVP_PKEY_CTX_set_rsa_keygen_bits ++#define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ ++ RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) ++ + #endif + + #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM +@@ -341,8 +349,12 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + RENAMED_FUNCTION(EVP_MD_CTX_free, EVP_MD_CTX_destroy) \ + RENAMED_FUNCTION(EVP_MD_CTX_new, EVP_MD_CTX_create) \ + REQUIRED_FUNCTION(EVP_MD_size) \ ++ REQUIRED_FUNCTION(EVP_PKEY_CTX_ctrl) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_free) \ ++ REQUIRED_FUNCTION(EVP_PKEY_CTX_get0_pkey) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_new) \ ++ REQUIRED_FUNCTION(EVP_PKEY_CTX_new_id) \ ++ REQUIRED_FUNCTION(EVP_PKEY_base_id) \ + REQUIRED_FUNCTION(EVP_PKEY_derive_set_peer) \ + REQUIRED_FUNCTION(EVP_PKEY_derive_init) \ + REQUIRED_FUNCTION(EVP_PKEY_derive) \ +@@ -350,6 +362,8 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_PKEY_get1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_EC_KEY) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_RSA) \ ++ REQUIRED_FUNCTION(EVP_PKEY_keygen) \ ++ REQUIRED_FUNCTION(EVP_PKEY_keygen_init) \ + REQUIRED_FUNCTION(EVP_PKEY_new) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_EC_KEY) \ +@@ -432,6 +446,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + FALLBACK_FUNCTION(RSA_get0_key) \ + FALLBACK_FUNCTION(RSA_meth_get_flags) \ + REQUIRED_FUNCTION(RSA_new) \ ++ FALLBACK_FUNCTION(RSA_pkey_ctx_ctrl) \ + RENAMED_FUNCTION(RSA_PKCS1_OpenSSL, RSA_PKCS1_SSLeay) \ + REQUIRED_FUNCTION(RSA_private_decrypt) \ + REQUIRED_FUNCTION(RSA_private_encrypt) \ +@@ -727,8 +742,12 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_MD_CTX_free EVP_MD_CTX_free_ptr + #define EVP_MD_CTX_new EVP_MD_CTX_new_ptr + #define EVP_MD_size EVP_MD_size_ptr ++#define EVP_PKEY_CTX_ctrl EVP_PKEY_CTX_ctrl_ptr + #define EVP_PKEY_CTX_free EVP_PKEY_CTX_free_ptr ++#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_base_id EVP_PKEY_base_id_ptr + #define EVP_PKEY_derive_set_peer EVP_PKEY_derive_set_peer_ptr + #define EVP_PKEY_derive_init EVP_PKEY_derive_init_ptr + #define EVP_PKEY_derive EVP_PKEY_derive_ptr +@@ -736,6 +755,8 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_PKEY_get1_DSA EVP_PKEY_get1_DSA_ptr + #define EVP_PKEY_get1_EC_KEY EVP_PKEY_get1_EC_KEY_ptr + #define EVP_PKEY_get1_RSA EVP_PKEY_get1_RSA_ptr ++#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_set1_DSA EVP_PKEY_set1_DSA_ptr + #define EVP_PKEY_set1_EC_KEY EVP_PKEY_set1_EC_KEY_ptr +@@ -818,6 +839,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define RSA_get_method RSA_get_method_ptr + #define RSA_meth_get_flags RSA_meth_get_flags_ptr + #define RSA_new RSA_new_ptr ++#define RSA_pkey_ctx_ctrl RSA_pkey_ctx_ctrl_ptr + #define RSA_PKCS1_OpenSSL RSA_PKCS1_OpenSSL_ptr + #define RSA_private_decrypt RSA_private_decrypt_ptr + #define RSA_private_encrypt RSA_private_encrypt_ptr +@@ -1026,6 +1048,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define RSA_set0_crt_params local_RSA_set0_crt_params + #define RSA_set0_factors local_RSA_set0_factors + #define RSA_set0_key local_RSA_set0_key ++#define RSA_pkey_ctx_ctrl local_RSA_pkey_ctx_ctrl + #define SSL_CTX_set_security_level local_SSL_CTX_set_security_level + #define SSL_is_init_finished local_SSL_is_init_finished + #define X509_CRL_get0_nextUpdate local_X509_CRL_get0_nextUpdate +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +index e8d961dbd2..29f9238ce9 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +@@ -4,6 +4,35 @@ + + #include "pal_evp_pkey_rsa.h" + ++EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) ++{ ++ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); ++ ++ if (ctx == NULL) ++ { ++ return NULL; ++ } ++ ++ EVP_PKEY* pkey = NULL; ++ EVP_PKEY* ret = NULL; ++ ++ if (EVP_PKEY_keygen_init(ctx) == 1 && ++ EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keySize) == 1 && ++ EVP_PKEY_keygen(ctx, &pkey) == 1) ++ { ++ ret = pkey; ++ pkey = NULL; ++ } ++ ++ if (pkey != NULL) ++ { ++ EVP_PKEY_free(pkey); ++ } ++ ++ EVP_PKEY_CTX_free(ctx); ++ return ret; ++} ++ + RSA* CryptoNative_EvpPkeyGetRsa(EVP_PKEY* pkey) + { + return EVP_PKEY_get1_RSA(pkey); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +index d8ff369670..1fda149414 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +@@ -6,6 +6,11 @@ + #include "pal_compiler.h" + #include "opensslshim.h" + ++/* ++Creates an RSA key of the requested size. ++*/ ++DLLEXPORT EVP_PKEY* CryptoNative_RsaGenerateKey(int32_t keySize); ++ + /* + Shims the EVP_PKEY_get1_RSA method. + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +index f764815a04..080027de0e 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +@@ -143,11 +143,6 @@ int32_t CryptoNative_RsaSize(RSA* rsa) + return RSA_size(rsa); + } + +-int32_t CryptoNative_RsaGenerateKeyEx(RSA* rsa, int32_t bits, BIGNUM* e) +-{ +- return RSA_generate_key_ex(rsa, bits, e, NULL); +-} +- + int32_t + CryptoNative_RsaSign(int32_t type, const uint8_t* m, int32_t mlen, uint8_t* sigret, int32_t* siglen, RSA* rsa) + { +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h +index b85fed627f..1c0bc2df47 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h +@@ -86,13 +86,6 @@ Returns the RSA modulus size in bytes. + */ + DLLEXPORT int32_t CryptoNative_RsaSize(RSA* rsa); + +-/* +-Shims the RSA_generate_key_ex method. +- +-Returns 1 upon success, otherwise 0. +-*/ +-DLLEXPORT int32_t CryptoNative_RsaGenerateKeyEx(RSA* rsa, int32_t bits, BIGNUM* e); +- + /* + Shims the RSA_sign method. + +diff --git a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +index fa63b6e2fe..6ad2b78e01 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj ++++ b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +@@ -507,6 +507,9 @@ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Ecdh.cs + ++ ++ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.Rsa.cs ++ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.cs + +-- +2.31.1 + diff --git a/SOURCES/corefx-openssl-0002-Use-EVP_PKEY-for-RSA-Decrypt.patch b/SOURCES/corefx-openssl-0002-Use-EVP_PKEY-for-RSA-Decrypt.patch new file mode 100644 index 0000000..abb1fdc --- /dev/null +++ b/SOURCES/corefx-openssl-0002-Use-EVP_PKEY-for-RSA-Decrypt.patch @@ -0,0 +1,1035 @@ +From 16f162f76cdbdd150487eb9824f9d8f8e39df5ca Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Wed, 24 Mar 2021 10:27:42 -0700 +Subject: [PATCH 02/11] Use EVP_PKEY for RSA Decrypt + +--- + .../Interop.EVP.DigestAlgs.cs | 58 +++++ + .../Interop.EVP.cs | 18 +- + .../Interop.EvpPkey.Rsa.cs | 37 +++ + .../Interop.EvpPkey.cs | 3 + + .../Interop.Rsa.cs | 16 -- + .../Security/Cryptography/RSAOpenSsl.cs | 222 ++++++++++-------- + .../apibridge.c | 17 ++ + .../apibridge.h | 1 + + .../opensslshim.h | 17 +- + .../pal_evp_pkey.c | 7 + + .../pal_evp_pkey.h | 5 + + .../pal_evp_pkey_rsa.c | 137 ++++++++++- + .../pal_evp_pkey_rsa.h | 27 ++- + .../pal_rsa.c | 13 - + .../pal_rsa.h | 8 - + .../HashProviderDispenser.Unix.cs | 36 +-- + ...em.Security.Cryptography.Algorithms.csproj | 3 + + ...ystem.Security.Cryptography.OpenSsl.csproj | 3 + + 18 files changed, 444 insertions(+), 184 deletions(-) + create mode 100644 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs +new file mode 100644 +index 0000000000..53ef644d84 +--- /dev/null ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.DigestAlgs.cs +@@ -0,0 +1,58 @@ ++// 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.Runtime.InteropServices; ++using System.Security.Cryptography; ++ ++internal static partial class Interop ++{ ++ internal static partial class Crypto ++ { ++ private static volatile IntPtr s_evpMd5; ++ private static volatile IntPtr s_evpSha1; ++ private static volatile IntPtr s_evpSha256; ++ private static volatile IntPtr s_evpSha384; ++ private static volatile IntPtr s_evpSha512; ++ ++ [DllImport(Libraries.CryptoNative)] ++ private static extern IntPtr CryptoNative_EvpMd5(); ++ ++ internal static IntPtr EvpMd5() => ++ s_evpMd5 != IntPtr.Zero ? s_evpMd5 : (s_evpMd5 = CryptoNative_EvpMd5()); ++ ++ [DllImport(Libraries.CryptoNative)] ++ internal static extern IntPtr CryptoNative_EvpSha1(); ++ ++ internal static IntPtr EvpSha1() => ++ s_evpSha1 != IntPtr.Zero ? s_evpSha1 : (s_evpSha1 = CryptoNative_EvpSha1()); ++ ++ [DllImport(Libraries.CryptoNative)] ++ internal static extern IntPtr CryptoNative_EvpSha256(); ++ ++ internal static IntPtr EvpSha256() => ++ s_evpSha256 != IntPtr.Zero ? s_evpSha256 : (s_evpSha256 = CryptoNative_EvpSha256()); ++ ++ [DllImport(Libraries.CryptoNative)] ++ internal static extern IntPtr CryptoNative_EvpSha384(); ++ ++ internal static IntPtr EvpSha384() => ++ s_evpSha384 != IntPtr.Zero ? s_evpSha384 : (s_evpSha384 = CryptoNative_EvpSha384()); ++ ++ [DllImport(Libraries.CryptoNative)] ++ internal static extern IntPtr CryptoNative_EvpSha512(); ++ ++ internal static IntPtr EvpSha512() => ++ s_evpSha512 != IntPtr.Zero ? s_evpSha512 : (s_evpSha512 = CryptoNative_EvpSha512()); ++ ++ internal static IntPtr HashAlgorithmToEvp(string hashAlgorithmId) => hashAlgorithmId switch ++ { ++ nameof(HashAlgorithmName.SHA1) => EvpSha1(), ++ nameof(HashAlgorithmName.SHA256) => EvpSha256(), ++ nameof(HashAlgorithmName.SHA384) => EvpSha384(), ++ nameof(HashAlgorithmName.SHA512) => EvpSha512(), ++ nameof(HashAlgorithmName.MD5) => EvpMd5(), ++ _ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId)) ++ }; ++ } ++} +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.cs +index 67a9b54230..ea9dc5186d 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.cs +@@ -4,6 +4,7 @@ + + using System; + using System.Runtime.InteropServices; ++using System.Security.Cryptography; + using Microsoft.Win32.SafeHandles; + + internal static partial class Interop +@@ -31,23 +32,6 @@ internal static partial class Crypto + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpMdSize")] + internal extern static int EvpMdSize(IntPtr md); + +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpMd5")] +- internal extern static IntPtr EvpMd5(); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpSha1")] +- internal extern static IntPtr EvpSha1(); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpSha256")] +- internal extern static IntPtr EvpSha256(); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpSha384")] +- internal extern static IntPtr EvpSha384(); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpSha512")] +- internal extern static IntPtr EvpSha512(); +- +- + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetMaxMdSize")] + private extern static int GetMaxMdSize(); + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +index c28522784b..f023ced7f9 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +@@ -2,6 +2,8 @@ + // The .NET Foundation licenses this file to you under the MIT license. + // See the LICENSE file in the project root for more information. + ++using System; ++using System.Diagnostics; + using System.Runtime.InteropServices; + using System.Security.Cryptography; + using Microsoft.Win32.SafeHandles; +@@ -26,6 +28,41 @@ internal static SafeEvpPKeyHandle RsaGenerateKey(int keySize) + return pkey; + } + ++ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaDecrypt")] ++ private static extern int CryptoNative_RsaDecrypt( ++ SafeEvpPKeyHandle pkey, ++ ref byte source, ++ int sourceLength, ++ RSAEncryptionPaddingMode paddingMode, ++ IntPtr digestAlgorithm, ++ ref byte destination, ++ int destinationLength); ++ ++ internal static int RsaDecrypt( ++ SafeEvpPKeyHandle pkey, ++ ReadOnlySpan source, ++ RSAEncryptionPaddingMode paddingMode, ++ IntPtr digestAlgorithm, ++ Span destination) ++ { ++ int written = CryptoNative_RsaDecrypt( ++ pkey, ++ ref MemoryMarshal.GetReference(source), ++ source.Length, ++ paddingMode, ++ digestAlgorithm, ++ ref MemoryMarshal.GetReference(destination), ++ destination.Length); ++ ++ if (written < 0) ++ { ++ Debug.Assert(written == -1); ++ throw CreateOpenSslCryptographicException(); ++ } ++ ++ return written; ++ } ++ + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyGetRsa")] + internal static extern SafeRsaHandle EvpPkeyGetRsa(SafeEvpPKeyHandle pkey); + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs +index 2eff6bfcd1..3ad4bc9d08 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.cs +@@ -16,6 +16,9 @@ internal static partial class Crypto + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyDestroy")] + internal static extern void EvpPkeyDestroy(IntPtr pkey); + ++ [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); + } +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +index a05f020ada..5ad534a8f2 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +@@ -44,22 +44,6 @@ internal static partial class Crypto + SafeRsaHandle rsa, + RsaPadding padding); + +- internal static int RsaPrivateDecrypt( +- int flen, +- ReadOnlySpan from, +- Span to, +- SafeRsaHandle rsa, +- RsaPadding padding) => +- RsaPrivateDecrypt(flen, ref MemoryMarshal.GetReference(from), ref MemoryMarshal.GetReference(to), rsa, padding); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaPrivateDecrypt")] +- private extern static int RsaPrivateDecrypt( +- int flen, +- ref byte from, +- ref byte to, +- SafeRsaHandle rsa, +- RsaPadding padding); +- + internal static int RsaSignPrimitive( + ReadOnlySpan from, + Span to, +diff --git a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +index 4d4a8414b3..87e31b9dde 100644 +--- a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs ++++ b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +@@ -85,10 +85,9 @@ public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) + if (padding == null) + throw new ArgumentNullException(nameof(padding)); + +- Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor oaepProcessor); +- SafeRsaHandle key = GetKey(); +- +- int rsaSize = Interop.Crypto.RsaSize(key); ++ ValidatePadding(padding); ++ SafeEvpPKeyHandle key = GetPKey(); ++ int rsaSize = Interop.Crypto.EvpPKeySize(key); + byte[] buf = null; + Span destination = default; + +@@ -97,18 +96,15 @@ public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) + buf = CryptoPool.Rent(rsaSize); + destination = new Span(buf, 0, rsaSize); + +- if (!TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, out int bytesWritten)) +- { +- Debug.Fail($"{nameof(TryDecrypt)} should not return false for RSA_size buffer"); +- throw new CryptographicException(); +- } +- ++ int bytesWritten = Decrypt(key, data, destination, padding); + return destination.Slice(0, bytesWritten).ToArray(); + } + finally + { + CryptographicOperations.ZeroMemory(destination); + CryptoPool.Return(buf, clearSize: 0); ++ // Until EVP_PKEY is what gets stored, free the temporary key handle. ++ key.Dispose(); + } + } + +@@ -119,82 +115,73 @@ public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) + out int bytesWritten) + { + if (padding == null) +- { + throw new ArgumentNullException(nameof(padding)); +- } +- +- Interop.Crypto.RsaPadding rsaPadding = GetInteropPadding(padding, out RsaPaddingProcessor oaepProcessor); +- SafeRsaHandle key = GetKey(); + +- int keySizeBytes = Interop.Crypto.RsaSize(key); ++ ValidatePadding(padding); ++ SafeEvpPKeyHandle key = GetPKey(); ++ int keySizeBytes = Interop.Crypto.EvpPKeySize(key); + +- // OpenSSL does not take a length value for the destination, so it can write out of bounds. +- // To prevent the OOB write, decrypt into a temporary buffer. ++ // OpenSSL requires that the decryption buffer be at least as large as EVP_PKEY_size. ++ // So if the destination is too small, use a temporary buffer so we can match ++ // Windows behavior of succeeding so long as the buffer can hold the final output. + if (destination.Length < keySizeBytes) + { +- Span tmp = stackalloc byte[0]; ++ // RSA up through 4096 bits use a stackalloc ++ Span tmp = stackalloc byte[512]; + byte[] rent = null; + +- // RSA up through 4096 stackalloc +- if (keySizeBytes <= 512) ++ if (keySizeBytes > tmp.Length) + { +- tmp = stackalloc byte[keySizeBytes]; +- } +- else +- { +- rent = ArrayPool.Shared.Rent(keySizeBytes); ++ rent = CryptoPool.Rent(keySizeBytes); + tmp = rent; + } + +- bool ret = TryDecrypt(key, data, tmp, rsaPadding, oaepProcessor, out bytesWritten); ++ int written = Decrypt(key, data, tmp, padding); ++ // Until EVP_PKEY is what gets stored, free the temporary key handle. ++ key.Dispose(); ++ bool ret; + +- if (ret) ++ if (destination.Length < written) + { +- tmp = tmp.Slice(0, bytesWritten); +- +- if (bytesWritten > destination.Length) +- { +- ret = false; +- bytesWritten = 0; +- } +- else +- { +- tmp.CopyTo(destination); +- } +- +- CryptographicOperations.ZeroMemory(tmp); ++ bytesWritten = 0; ++ ret = false; ++ } ++ else ++ { ++ tmp.Slice(0, written).CopyTo(destination); ++ bytesWritten = written; ++ ret = true; + } + ++ // Whether a stackalloc or a rented array, clear our copy of ++ // the decrypted content. ++ CryptographicOperations.ZeroMemory(tmp.Slice(0, written)); ++ + if (rent != null) + { +- // Already cleared +- ArrayPool.Shared.Return(rent); ++ // Already cleared. ++ CryptoPool.Return(rent, clearSize: 0); + } + + return ret; + } + +- return TryDecrypt(key, data, destination, rsaPadding, oaepProcessor, out bytesWritten); ++ bytesWritten = Decrypt(key, data, destination, padding); ++ // Until EVP_PKEY is what gets stored, free the temporary key handle. ++ key.Dispose(); ++ return true; + } + +- private static bool TryDecrypt( +- SafeRsaHandle key, ++ private static int Decrypt( ++ SafeEvpPKeyHandle key, + ReadOnlySpan data, + Span destination, +- Interop.Crypto.RsaPadding rsaPadding, +- RsaPaddingProcessor rsaPaddingProcessor, +- out int bytesWritten) ++ RSAEncryptionPadding padding) + { +- // If rsaPadding is PKCS1 or OAEP-SHA1 then no depadding method should be present. +- // If rsaPadding is NoPadding then a depadding method should be present. +- Debug.Assert( +- (rsaPadding == Interop.Crypto.RsaPadding.NoPadding) == +- (rsaPaddingProcessor != null)); +- + // Caller should have already checked this. + Debug.Assert(!key.IsInvalid); + +- int rsaSize = Interop.Crypto.RsaSize(key); ++ int rsaSize = Interop.Crypto.EvpPKeySize(key); + + if (data.Length != rsaSize) + { +@@ -203,50 +190,24 @@ public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) + + if (destination.Length < rsaSize) + { +- bytesWritten = 0; +- return false; ++ Debug.Fail("Caller is responsible for temporary decryption buffer creation"); ++ throw new CryptographicException(); + } + +- Span decryptBuf = destination; +- byte[] paddingBuf = null; ++ IntPtr hashAlgorithm = IntPtr.Zero; + +- if (rsaPaddingProcessor != null) ++ if (padding.Mode == RSAEncryptionPaddingMode.Oaep) + { +- paddingBuf = CryptoPool.Rent(rsaSize); +- decryptBuf = paddingBuf; ++ Debug.Assert(padding.OaepHashAlgorithm.Name != null); ++ hashAlgorithm = Interop.Crypto.HashAlgorithmToEvp(padding.OaepHashAlgorithm.Name); + } + +- try +- { +- int returnValue = Interop.Crypto.RsaPrivateDecrypt(data.Length, data, decryptBuf, key, rsaPadding); +- CheckReturn(returnValue); +- +- if (rsaPaddingProcessor != null) +- { +- return rsaPaddingProcessor.DepadOaep(paddingBuf, destination, out bytesWritten); +- } +- else +- { +- // If the padding mode is RSA_NO_PADDING then the size of the decrypted block +- // will be RSA_size. If any padding was used, then some amount (determined by the padding algorithm) +- // will have been reduced, and only returnValue bytes were part of the decrypted +- // body. Either way, we can just use returnValue, but some additional bytes may have been overwritten +- // in the destination span. +- bytesWritten = returnValue; +- } +- +- return true; +- } +- finally +- { +- if (paddingBuf != null) +- { +- // DecryptBuf is paddingBuf if paddingBuf is not null, erase it before returning it. +- // If paddingBuf IS null then decryptBuf was destination, and shouldn't be cleared. +- CryptographicOperations.ZeroMemory(decryptBuf); +- CryptoPool.Return(paddingBuf, clearSize: 0); +- } +- } ++ return Interop.Crypto.RsaDecrypt( ++ key, ++ data, ++ padding.Mode, ++ hashAlgorithm, ++ destination); + } + + public override byte[] Encrypt(byte[] data, RSAEncryptionPadding padding) +@@ -550,6 +511,30 @@ private void ThrowIfDisposed() + } + } + ++ private SafeEvpPKeyHandle GetPKey() ++ { ++ SafeRsaHandle currentKey = GetKey(); ++ 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.EvpPkeySetRsa(pkeyHandle, currentKey)) ++ { ++ throw Interop.Crypto.CreateOpenSslCryptographicException(); ++ } ++ } ++ catch ++ { ++ pkeyHandle.Dispose(); ++ throw; ++ } ++ ++ return pkeyHandle; ++ } ++ + private SafeRsaHandle GetKey() + { + ThrowIfDisposed(); +@@ -843,6 +828,55 @@ private static int GetAlgorithmNid(HashAlgorithmName hashAlgorithmName) + return nid; + } + ++ private static void ValidatePadding(RSAEncryptionPadding padding) ++ { ++ if (padding == null) ++ { ++ throw new ArgumentNullException(nameof(padding)); ++ } ++ ++ // There are currently two defined padding modes: ++ // * Oaep has an option (the hash algorithm) ++ // * Pkcs1 has no options ++ // ++ // Anything other than those to modes is an error, ++ // and Pkcs1 having options set is an error, so compare it to ++ // the padding struct instead of the padding mode enum. ++ if (padding.Mode != RSAEncryptionPaddingMode.Oaep && ++ padding != RSAEncryptionPadding.Pkcs1) ++ { ++ throw PaddingModeNotSupported(); ++ } ++ } ++ ++ private static void ValidatePadding(RSASignaturePadding padding) ++ { ++ if (padding == null) ++ { ++ throw new ArgumentNullException(nameof(padding)); ++ } ++ ++ // RSASignaturePadding currently only has the mode property, so ++ // there's no need for a runtime check that PKCS#1 doesn't use ++ // nonsensical options like with RSAEncryptionPadding. ++ // ++ // This would change if we supported PSS with an MGF other than MGF-1, ++ // or with a custom salt size, or with a different MGF digest algorithm ++ // than the data digest algorithm. ++ if (padding.Mode == RSASignaturePaddingMode.Pkcs1) ++ { ++ Debug.Assert(padding == RSASignaturePadding.Pkcs1); ++ } ++ else if (padding.Mode == RSASignaturePaddingMode.Pss) ++ { ++ Debug.Assert(padding == RSASignaturePadding.Pss); ++ } ++ else ++ { ++ throw PaddingModeNotSupported(); ++ } ++ } ++ + private static Exception PaddingModeNotSupported() => + new CryptographicException(SR.Cryptography_InvalidPaddingMode); + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c +index def7198deb..ff71105837 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.c +@@ -258,6 +258,23 @@ int32_t local_DSA_set0_key(DSA* dsa, BIGNUM* bnY, BIGNUM* bnX) + return 1; + } + ++RSA* local_EVP_PKEY_get0_RSA(EVP_PKEY* pkey) ++{ ++ if (pkey == NULL) ++ { ++ return NULL; ++ } ++ ++ RSA* rsa = EVP_PKEY_get1_RSA(pkey); ++ ++ if (rsa != NULL) ++ { ++ RSA_free(rsa); ++ } ++ ++ return rsa; ++} ++ + int32_t local_EVP_PKEY_up_ref(EVP_PKEY* pkey) + { + if (!pkey) +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h +index b58611ae73..e1315499f3 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge.h +@@ -15,6 +15,7 @@ int32_t local_DSA_set0_pqg(DSA* dsa, BIGNUM* bnP, BIGNUM* bnQ, BIGNUM* bnG); + 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); ++RSA* local_EVP_PKEY_get0_RSA(EVP_PKEY* pkey); + int32_t local_EVP_PKEY_up_ref(EVP_PKEY* pkey); + void local_HMAC_CTX_free(HMAC_CTX* ctx); + HMAC_CTX* local_HMAC_CTX_new(void); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index dff6091e9e..47cb142d25 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -128,6 +128,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); ++RSA* EVP_PKEY_get0_RSA(EVP_PKEY* pkey); + int32_t EVP_PKEY_up_ref(EVP_PKEY* pkey); + void HMAC_CTX_free(HMAC_CTX* ctx); + HMAC_CTX* HMAC_CTX_new(void); +@@ -178,6 +179,12 @@ int32_t X509_up_ref(X509* x509); + #define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ + RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) + ++#undef EVP_PKEY_CTX_set_rsa_padding ++#define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \ ++ RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL) ++ ++// EVP_PKEY_CTX_set_rsa_oaep_md doesn't call RSA_pkey_ctx_ctrl in 1.1, so don't redefine it here. ++ + #endif + + #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM +@@ -355,10 +362,13 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_PKEY_CTX_new) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_new_id) \ + REQUIRED_FUNCTION(EVP_PKEY_base_id) \ ++ REQUIRED_FUNCTION(EVP_PKEY_decrypt) \ ++ REQUIRED_FUNCTION(EVP_PKEY_decrypt_init) \ + REQUIRED_FUNCTION(EVP_PKEY_derive_set_peer) \ + REQUIRED_FUNCTION(EVP_PKEY_derive_init) \ + REQUIRED_FUNCTION(EVP_PKEY_derive) \ + REQUIRED_FUNCTION(EVP_PKEY_free) \ ++ FALLBACK_FUNCTION(EVP_PKEY_get0_RSA) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_EC_KEY) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_RSA) \ +@@ -368,6 +378,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_PKEY_set1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_EC_KEY) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_RSA) \ ++ REQUIRED_FUNCTION(EVP_PKEY_size) \ + FALLBACK_FUNCTION(EVP_PKEY_up_ref) \ + REQUIRED_FUNCTION(EVP_rc2_cbc) \ + REQUIRED_FUNCTION(EVP_rc2_ecb) \ +@@ -448,7 +459,6 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(RSA_new) \ + FALLBACK_FUNCTION(RSA_pkey_ctx_ctrl) \ + RENAMED_FUNCTION(RSA_PKCS1_OpenSSL, RSA_PKCS1_SSLeay) \ +- REQUIRED_FUNCTION(RSA_private_decrypt) \ + REQUIRED_FUNCTION(RSA_private_encrypt) \ + REQUIRED_FUNCTION(RSA_public_decrypt) \ + REQUIRED_FUNCTION(RSA_public_encrypt) \ +@@ -748,10 +758,13 @@ FOR_ALL_OPENSSL_FUNCTIONS + #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_base_id EVP_PKEY_base_id_ptr ++#define EVP_PKEY_decrypt_init EVP_PKEY_decrypt_init_ptr ++#define EVP_PKEY_decrypt EVP_PKEY_decrypt_ptr + #define EVP_PKEY_derive_set_peer EVP_PKEY_derive_set_peer_ptr + #define EVP_PKEY_derive_init EVP_PKEY_derive_init_ptr + #define EVP_PKEY_derive EVP_PKEY_derive_ptr + #define EVP_PKEY_free EVP_PKEY_free_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 + #define EVP_PKEY_get1_RSA EVP_PKEY_get1_RSA_ptr +@@ -761,6 +774,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_PKEY_set1_DSA EVP_PKEY_set1_DSA_ptr + #define EVP_PKEY_set1_EC_KEY EVP_PKEY_set1_EC_KEY_ptr + #define EVP_PKEY_set1_RSA EVP_PKEY_set1_RSA_ptr ++#define EVP_PKEY_size EVP_PKEY_size_ptr + #define EVP_PKEY_up_ref EVP_PKEY_up_ref_ptr + #define EVP_rc2_cbc EVP_rc2_cbc_ptr + #define EVP_rc2_ecb EVP_rc2_ecb_ptr +@@ -841,7 +855,6 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define RSA_new RSA_new_ptr + #define RSA_pkey_ctx_ctrl RSA_pkey_ctx_ctrl_ptr + #define RSA_PKCS1_OpenSSL RSA_PKCS1_OpenSSL_ptr +-#define RSA_private_decrypt RSA_private_decrypt_ptr + #define RSA_private_encrypt RSA_private_encrypt_ptr + #define RSA_public_decrypt RSA_public_decrypt_ptr + #define RSA_public_encrypt RSA_public_encrypt_ptr +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c +index 4d479dde6c..f232b382ea 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c +@@ -2,6 +2,7 @@ + // The .NET Foundation licenses this file to you under the MIT license. + // See the LICENSE file in the project root for more information. + ++#include + #include "pal_evp_pkey.h" + + EVP_PKEY* CryptoNative_EvpPkeyCreate() +@@ -17,6 +18,12 @@ void CryptoNative_EvpPkeyDestroy(EVP_PKEY* pkey) + } + } + ++int32_t CryptoNative_EvpPKeySize(EVP_PKEY* pkey) ++{ ++ assert(pkey != NULL); ++ return EVP_PKEY_size(pkey); ++} ++ + int32_t CryptoNative_UpRefEvpPkey(EVP_PKEY* pkey) + { + if (!pkey) +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h +index 7baf997d8d..750282efdb 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.h +@@ -24,6 +24,11 @@ Always succeeds. + */ + DLLEXPORT void CryptoNative_EvpPkeyDestroy(EVP_PKEY* pkey); + ++/* ++Returns the maximum size, in bytes, of an operation with the provided key. ++*/ ++DLLEXPORT int32_t CryptoNative_EvpPKeySize(EVP_PKEY* pkey); ++ + /* + Used by System.Security.Cryptography.X509Certificates' OpenSslX509CertificateReader when + duplicating a private key context as part of duplicating the Pal object. +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +index 29f9238ce9..6235c905db 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +@@ -3,6 +3,10 @@ + // See the LICENSE file in the project root for more information. + + #include "pal_evp_pkey_rsa.h" ++#include "pal_utilities.h" ++#include ++ ++static int HasNoPrivateKey(RSA* rsa); + + EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) + { +@@ -16,8 +20,7 @@ EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) + EVP_PKEY* pkey = NULL; + EVP_PKEY* ret = NULL; + +- if (EVP_PKEY_keygen_init(ctx) == 1 && +- EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keySize) == 1 && ++ if (EVP_PKEY_keygen_init(ctx) == 1 && EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keySize) == 1 && + EVP_PKEY_keygen(ctx, &pkey) == 1) + { + ret = pkey; +@@ -33,6 +36,82 @@ EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) + return ret; + } + ++int32_t CryptoNative_RsaDecrypt(EVP_PKEY* pkey, ++ const uint8_t* source, ++ int32_t sourceLen, ++ RsaPaddingMode padding, ++ const EVP_MD* digest, ++ uint8_t* destination, ++ int32_t destinationLen) ++{ ++ assert(pkey != NULL); ++ assert(source != NULL); ++ assert(destination != NULL); ++ assert(padding >= RsaPaddingPkcs1 && padding <= RsaPaddingOaepOrPss); ++ assert(digest != NULL || padding == RsaPaddingPkcs1); ++ ++ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL); ++ ++ int ret = -1; ++ ++ if (ctx == NULL || EVP_PKEY_decrypt_init(ctx) <= 0) ++ { ++ goto done; ++ } ++ ++ if (padding == RsaPaddingPkcs1) ++ { ++ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) ++ { ++ goto done; ++ } ++ } ++ else ++ { ++ assert(padding == RsaPaddingOaepOrPss); ++ ++ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) ++ { ++ goto done; ++ } ++ ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" ++ if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, digest) <= 0) ++#pragma clang diagnostic pop ++ { ++ goto done; ++ } ++ } ++ ++ // This check may no longer be needed on OpenSSL 3.0 ++ { ++ RSA* rsa = EVP_PKEY_get0_RSA(pkey); ++ ++ if (rsa == NULL || HasNoPrivateKey(rsa)) ++ { ++ ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_NULL_PRIVATE_DECRYPT, RSA_R_VALUE_MISSING, __FILE__, __LINE__); ++ ret = -1; ++ goto done; ++ } ++ } ++ ++ size_t written = Int32ToSizeT(destinationLen); ++ ++ if (EVP_PKEY_decrypt(ctx, destination, &written, source, Int32ToSizeT(sourceLen)) > 0) ++ { ++ ret = SizeTToInt32(written); ++ } ++ ++done: ++ if (ctx != NULL) ++ { ++ EVP_PKEY_CTX_free(ctx); ++ } ++ ++ return ret; ++} ++ + RSA* CryptoNative_EvpPkeyGetRsa(EVP_PKEY* pkey) + { + return EVP_PKEY_get1_RSA(pkey); +@@ -42,3 +121,57 @@ int32_t CryptoNative_EvpPkeySetRsa(EVP_PKEY* pkey, RSA* rsa) + { + return EVP_PKEY_set1_RSA(pkey, rsa); + } ++ ++static int HasNoPrivateKey(RSA* rsa) ++{ ++ if (rsa == NULL) ++ return 1; ++ ++ // Shared pointer, don't free. ++ const RSA_METHOD* meth = RSA_get_method(rsa); ++ ++ // The method has descibed itself as having the private key external to the structure. ++ // That doesn't mean it's actually present, but we can't tell. ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" ++ if (RSA_meth_get_flags((RSA_METHOD*)meth) & RSA_FLAG_EXT_PKEY) ++#pragma clang diagnostic pop ++ { ++ return 0; ++ } ++ ++ // In the event that there's a middle-ground where we report failure when success is expected, ++ // one could do something like check if the RSA_METHOD intercepts all private key operations: ++ // ++ // * meth->rsa_priv_enc ++ // * meth->rsa_priv_dec ++ // * meth->rsa_sign (in 1.0.x this is only respected if the RSA_FLAG_SIGN_VER flag is asserted) ++ // ++ // But, for now, leave it at the EXT_PKEY flag test. ++ ++ // The module is documented as accepting either d or the full set of CRT parameters (p, q, dp, dq, qInv) ++ // So if we see d, we're good. Otherwise, if any of the rest are missing, we're public-only. ++ const BIGNUM* d; ++ RSA_get0_key(rsa, NULL, NULL, &d); ++ ++ if (d != NULL) ++ { ++ return 0; ++ } ++ ++ const BIGNUM* p; ++ const BIGNUM* q; ++ const BIGNUM* dmp1; ++ const BIGNUM* dmq1; ++ const BIGNUM* iqmp; ++ ++ RSA_get0_factors(rsa, &p, &q); ++ RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); ++ ++ if (p == NULL || q == NULL || dmp1 == NULL || dmq1 == NULL || iqmp == NULL) ++ { ++ return 1; ++ } ++ ++ return 0; ++} +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +index 1fda149414..d220065adf 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +@@ -2,15 +2,38 @@ + // The .NET Foundation licenses this file to you under the MIT license. + // See the LICENSE file in the project root for more information. + +-#include "pal_types.h" +-#include "pal_compiler.h" + #include "opensslshim.h" ++#include "pal_compiler.h" ++#include "pal_types.h" ++ ++/* ++Padding options for RSA. ++Matches RSAEncryptionPaddingMode / RSASignaturePaddingMode. ++*/ ++typedef enum ++{ ++ RsaPaddingPkcs1, ++ RsaPaddingOaepOrPss, ++} RsaPaddingMode; + + /* + Creates an RSA key of the requested size. + */ + DLLEXPORT EVP_PKEY* CryptoNative_RsaGenerateKey(int32_t keySize); + ++/* ++Decrypt source into destination using the specified RSA key (wrapped in an EVP_PKEY) and padding/digest options. ++ ++Returns the number of bytes written to destination, -1 on error. ++*/ ++DLLEXPORT int32_t CryptoNative_RsaDecrypt(EVP_PKEY* pkey, ++ const uint8_t* source, ++ int32_t sourceLen, ++ RsaPaddingMode padding, ++ const EVP_MD* digest, ++ uint8_t* destination, ++ int32_t destinationLen); ++ + /* + Shims the EVP_PKEY_get1_RSA method. + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +index 080027de0e..0c635dfca7 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +@@ -109,19 +109,6 @@ CryptoNative_RsaPublicEncrypt(int32_t flen, const uint8_t* from, uint8_t* to, RS + return RSA_public_encrypt(flen, from, to, rsa, openSslPadding); + } + +-int32_t +-CryptoNative_RsaPrivateDecrypt(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding) +-{ +- if (HasNoPrivateKey(rsa)) +- { +- ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_NULL_PRIVATE_DECRYPT, RSA_R_VALUE_MISSING, __FILE__, __LINE__); +- return -1; +- } +- +- int openSslPadding = GetOpenSslPadding(padding); +- return RSA_private_decrypt(flen, from, to, rsa, openSslPadding); +-} +- + int32_t CryptoNative_RsaSignPrimitive(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa) + { + if (HasNoPrivateKey(rsa)) +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h +index 1c0bc2df47..30d7d9fa59 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.h +@@ -55,14 +55,6 @@ Returns the size of the signature, or -1 on error. + DLLEXPORT int32_t + CryptoNative_RsaPublicEncrypt(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding); + +-/* +-Shims the RSA_private_decrypt method. +- +-Returns the size of the signature, or -1 on error. +-*/ +-DLLEXPORT int32_t +-CryptoNative_RsaPrivateDecrypt(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding); +- + /* + Shims RSA_private_encrypt with a fixed value of RSA_NO_PADDING. + +diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs +index ff8e91e7c9..589ff882bf 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs ++++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/HashProviderDispenser.Unix.cs +@@ -12,40 +12,16 @@ namespace Internal.Cryptography + { + internal static partial class HashProviderDispenser + { +- public static HashProvider CreateHashProvider(string hashAlgorithmId) ++ internal static HashProvider CreateHashProvider(string hashAlgorithmId) + { +- switch (hashAlgorithmId) +- { +- case HashAlgorithmNames.SHA1: +- return new EvpHashProvider(Interop.Crypto.EvpSha1()); +- case HashAlgorithmNames.SHA256: +- return new EvpHashProvider(Interop.Crypto.EvpSha256()); +- case HashAlgorithmNames.SHA384: +- return new EvpHashProvider(Interop.Crypto.EvpSha384()); +- case HashAlgorithmNames.SHA512: +- return new EvpHashProvider(Interop.Crypto.EvpSha512()); +- case HashAlgorithmNames.MD5: +- return new EvpHashProvider(Interop.Crypto.EvpMd5()); +- } +- throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId)); ++ IntPtr evpType = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithmId); ++ return new EvpHashProvider(evpType); + } + +- public static unsafe HashProvider CreateMacProvider(string hashAlgorithmId, byte[] key) ++ internal static unsafe HashProvider CreateMacProvider(string hashAlgorithmId, byte[] key) + { +- switch (hashAlgorithmId) +- { +- case HashAlgorithmNames.SHA1: +- return new HmacHashProvider(Interop.Crypto.EvpSha1(), key); +- case HashAlgorithmNames.SHA256: +- return new HmacHashProvider(Interop.Crypto.EvpSha256(), key); +- case HashAlgorithmNames.SHA384: +- return new HmacHashProvider(Interop.Crypto.EvpSha384(), key); +- case HashAlgorithmNames.SHA512: +- return new HmacHashProvider(Interop.Crypto.EvpSha512(), key); +- case HashAlgorithmNames.MD5: +- return new HmacHashProvider(Interop.Crypto.EvpMd5(), key); +- } +- throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmId)); ++ IntPtr evpType = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithmId); ++ return new HmacHashProvider(evpType, key); + } + + // ----------------------------- +diff --git a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +index 6ad2b78e01..c6e8b5b69a 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj ++++ b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +@@ -513,6 +513,9 @@ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.cs + ++ ++ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.DigestAlgs.cs ++ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Hmac.cs + +diff --git a/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj b/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj +index 17ab176ec2..dbbc4848e8 100644 +--- a/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj ++++ b/src/System.Security.Cryptography.OpenSsl/src/System.Security.Cryptography.OpenSsl.csproj +@@ -57,6 +57,9 @@ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.ERR.cs + ++ ++ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EVP.DigestAlgs.cs ++ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.EvpPkey.cs + +-- +2.31.1 + diff --git a/SOURCES/corefx-openssl-0003-Use-EVP_PKEY-for-RSA-signing-operations.patch b/SOURCES/corefx-openssl-0003-Use-EVP_PKEY-for-RSA-signing-operations.patch new file mode 100644 index 0000000..a7c2fc5 --- /dev/null +++ b/SOURCES/corefx-openssl-0003-Use-EVP_PKEY-for-RSA-signing-operations.patch @@ -0,0 +1,538 @@ +From 7111a92546253d6fc857f7cad8b0bff425df0798 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Fri, 2 Apr 2021 09:10:08 -0700 +Subject: [PATCH 03/11] Use EVP_PKEY for RSA signing operations + +With this change all RSA private key operations (excluding import/export) use the EVP_PKEY APIs. + +* RSAPaddingProcessor is no longer used in conjunction with the private keys, on Linux. +* The pal_rsa.c copy of HasPrivateKey has been removed. +--- + .../Interop.EvpPkey.Rsa.cs | 35 ++++++ + .../Interop.Rsa.cs | 20 ---- + .../Security/Cryptography/RSAOpenSsl.cs | 87 ++++----------- + .../opensslshim.h | 19 +++- + .../pal_evp_pkey_rsa.c | 76 ++++++++++++- + .../pal_evp_pkey_rsa.h | 14 +++ + .../pal_rsa.c | 100 ------------------ + 7 files changed, 156 insertions(+), 195 deletions(-) + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +index f023ced7f9..6aab764cff 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EvpPkey.Rsa.cs +@@ -63,6 +63,41 @@ internal static SafeEvpPKeyHandle RsaGenerateKey(int keySize) + return written; + } + ++ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSignHash")] ++ private static extern int CryptoNative_RsaSignHash( ++ SafeEvpPKeyHandle pkey, ++ RSASignaturePaddingMode paddingMode, ++ IntPtr digestAlgorithm, ++ ref byte hash, ++ int hashLength, ++ ref byte destination, ++ int destinationLength); ++ ++ internal static int RsaSignHash( ++ SafeEvpPKeyHandle pkey, ++ RSASignaturePaddingMode paddingMode, ++ IntPtr digestAlgorithm, ++ ReadOnlySpan hash, ++ Span destination) ++ { ++ int written = CryptoNative_RsaSignHash( ++ pkey, ++ paddingMode, ++ digestAlgorithm, ++ ref MemoryMarshal.GetReference(hash), ++ hash.Length, ++ ref MemoryMarshal.GetReference(destination), ++ destination.Length); ++ ++ if (written < 0) ++ { ++ Debug.Assert(written == -1); ++ throw CreateOpenSslCryptographicException(); ++ } ++ ++ return written; ++ } ++ + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpPkeyGetRsa")] + internal static extern SafeRsaHandle EvpPkeyGetRsa(SafeEvpPKeyHandle pkey); + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +index 5ad534a8f2..b2f250ffe9 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Rsa.cs +@@ -44,19 +44,6 @@ internal static partial class Crypto + SafeRsaHandle rsa, + RsaPadding padding); + +- internal static int RsaSignPrimitive( +- ReadOnlySpan from, +- Span to, +- SafeRsaHandle rsa) => +- RsaSignPrimitive(from.Length, ref MemoryMarshal.GetReference(from), ref MemoryMarshal.GetReference(to), rsa); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSignPrimitive")] +- private static extern int RsaSignPrimitive( +- int flen, +- ref byte from, +- ref byte to, +- SafeRsaHandle rsa); +- + internal static int RsaVerificationPrimitive( + ReadOnlySpan from, + Span to, +@@ -73,13 +60,6 @@ internal static partial class Crypto + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSize")] + internal static extern int RsaSize(SafeRsaHandle rsa); + +- internal static bool RsaSign(int type, ReadOnlySpan m, int m_len, Span sigret, out int siglen, SafeRsaHandle rsa) => +- RsaSign(type, ref MemoryMarshal.GetReference(m), m_len, ref MemoryMarshal.GetReference(sigret), out siglen, rsa); +- +- [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RsaSign")] +- [return: MarshalAs(UnmanagedType.Bool)] +- private static extern bool RsaSign(int type, ref byte m, int m_len, ref byte sigret, out int siglen, SafeRsaHandle rsa); +- + internal static bool RsaVerify(int type, ReadOnlySpan m, ReadOnlySpan sigbuf, SafeRsaHandle rsa) + { + bool ret = RsaVerify( +diff --git a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +index 87e31b9dde..225968fc50 100644 +--- a/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs ++++ b/src/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +@@ -655,84 +655,33 @@ public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RS + { + Debug.Assert(!string.IsNullOrEmpty(hashAlgorithm.Name)); + Debug.Assert(padding != null); ++ ValidatePadding(padding); + + signature = null; + +- // Do not factor out getting _key.Value, since the key creation should not happen on +- // invalid padding modes. ++ IntPtr digestAlgorithm = Interop.Crypto.HashAlgorithmToEvp(hashAlgorithm.Name); ++ SafeEvpPKeyHandle key = GetPKey(); ++ int bytesRequired = Interop.Crypto.EvpPKeySize(key); + +- if (padding.Mode == RSASignaturePaddingMode.Pkcs1) ++ if (allocateSignature) + { +- int algorithmNid = GetAlgorithmNid(hashAlgorithm); +- SafeRsaHandle rsa = GetKey(); +- +- int bytesRequired = Interop.Crypto.RsaSize(rsa); +- +- if (allocateSignature) +- { +- Debug.Assert(destination.Length == 0); +- signature = new byte[bytesRequired]; +- destination = signature; +- } +- +- if (destination.Length < bytesRequired) +- { +- bytesWritten = 0; +- return false; +- } +- +- if (!Interop.Crypto.RsaSign(algorithmNid, hash, hash.Length, destination, out int signatureSize, rsa)) +- { +- throw Interop.Crypto.CreateOpenSslCryptographicException(); +- } +- +- Debug.Assert( +- signatureSize == bytesRequired, +- $"RSA_sign reported signatureSize was {signatureSize}, when {bytesRequired} was expected"); +- +- bytesWritten = signatureSize; +- return true; ++ Debug.Assert(destination.Length == 0); ++ signature = new byte[bytesRequired]; ++ destination = signature; + } +- else if (padding.Mode == RSASignaturePaddingMode.Pss) ++ else if (destination.Length < bytesRequired) + { +- RsaPaddingProcessor processor = RsaPaddingProcessor.OpenProcessor(hashAlgorithm); +- SafeRsaHandle rsa = GetKey(); +- +- int bytesRequired = Interop.Crypto.RsaSize(rsa); +- +- if (allocateSignature) +- { +- Debug.Assert(destination.Length == 0); +- signature = new byte[bytesRequired]; +- destination = signature; +- } +- +- if (destination.Length < bytesRequired) +- { +- bytesWritten = 0; +- return false; +- } +- +- byte[] pssRented = CryptoPool.Rent(bytesRequired); +- Span pssBytes = new Span(pssRented, 0, bytesRequired); +- +- processor.EncodePss(hash, pssBytes, KeySize); +- +- int ret = Interop.Crypto.RsaSignPrimitive(pssBytes, destination, rsa); +- +- CryptoPool.Return(pssRented, bytesRequired); +- +- CheckReturn(ret); +- +- Debug.Assert( +- ret == bytesRequired, +- $"RSA_private_encrypt returned {ret} when {bytesRequired} was expected"); +- +- bytesWritten = ret; +- return true; ++ bytesWritten = 0; ++ return false; + } + +- throw PaddingModeNotSupported(); ++ int written = Interop.Crypto.RsaSignHash(key, padding.Mode, digestAlgorithm, hash, destination); ++ Debug.Assert(written == bytesRequired); ++ bytesWritten = written; ++ ++ // Until EVP_PKEY is what gets stored, free the temporary key handle. ++ key.Dispose(); ++ return true; + } + + public override bool VerifyHash( +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index 47cb142d25..4c15914d25 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -179,11 +179,15 @@ int32_t X509_up_ref(X509* x509); + #define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ + RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) + ++// EVP_PKEY_CTX_set_rsa_oaep_md doesn't call RSA_pkey_ctx_ctrl in 1.1, so don't redefine it here. ++ + #undef EVP_PKEY_CTX_set_rsa_padding + #define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \ + RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL) + +-// EVP_PKEY_CTX_set_rsa_oaep_md doesn't call RSA_pkey_ctx_ctrl in 1.1, so don't redefine it here. ++#undef EVP_PKEY_CTX_set_rsa_pss_saltlen ++#define EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, len) \ ++ RSA_pkey_ctx_ctrl(ctx, (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), EVP_PKEY_CTRL_RSA_PSS_SALTLEN, len, NULL) + + #endif + +@@ -209,6 +213,11 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx, + void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsigned int* len); + #endif + ++// The value -1 has the correct meaning on 1.0.x, but the constant wasn't named. ++#ifndef RSA_PSS_SALTLEN_DIGEST ++#define RSA_PSS_SALTLEN_DIGEST -1 ++#endif ++ + #define API_EXISTS(fn) (fn != NULL) + + // List of all functions from the libssl that are used in the System.Security.Cryptography.Native. +@@ -378,6 +387,8 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_PKEY_set1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_EC_KEY) \ + REQUIRED_FUNCTION(EVP_PKEY_set1_RSA) \ ++ REQUIRED_FUNCTION(EVP_PKEY_sign) \ ++ REQUIRED_FUNCTION(EVP_PKEY_sign_init) \ + REQUIRED_FUNCTION(EVP_PKEY_size) \ + FALLBACK_FUNCTION(EVP_PKEY_up_ref) \ + REQUIRED_FUNCTION(EVP_rc2_cbc) \ +@@ -459,14 +470,12 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(RSA_new) \ + FALLBACK_FUNCTION(RSA_pkey_ctx_ctrl) \ + RENAMED_FUNCTION(RSA_PKCS1_OpenSSL, RSA_PKCS1_SSLeay) \ +- REQUIRED_FUNCTION(RSA_private_encrypt) \ + REQUIRED_FUNCTION(RSA_public_decrypt) \ + REQUIRED_FUNCTION(RSA_public_encrypt) \ + FALLBACK_FUNCTION(RSA_set0_crt_params) \ + FALLBACK_FUNCTION(RSA_set0_factors) \ + FALLBACK_FUNCTION(RSA_set0_key) \ + REQUIRED_FUNCTION(RSA_set_method) \ +- REQUIRED_FUNCTION(RSA_sign) \ + REQUIRED_FUNCTION(RSA_size) \ + REQUIRED_FUNCTION(RSA_up_ref) \ + REQUIRED_FUNCTION(RSA_verify) \ +@@ -774,6 +783,8 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_PKEY_set1_DSA EVP_PKEY_set1_DSA_ptr + #define EVP_PKEY_set1_EC_KEY EVP_PKEY_set1_EC_KEY_ptr + #define EVP_PKEY_set1_RSA EVP_PKEY_set1_RSA_ptr ++#define EVP_PKEY_sign_init EVP_PKEY_sign_init_ptr ++#define EVP_PKEY_sign EVP_PKEY_sign_ptr + #define EVP_PKEY_size EVP_PKEY_size_ptr + #define EVP_PKEY_up_ref EVP_PKEY_up_ref_ptr + #define EVP_rc2_cbc EVP_rc2_cbc_ptr +@@ -855,14 +866,12 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define RSA_new RSA_new_ptr + #define RSA_pkey_ctx_ctrl RSA_pkey_ctx_ctrl_ptr + #define RSA_PKCS1_OpenSSL RSA_PKCS1_OpenSSL_ptr +-#define RSA_private_encrypt RSA_private_encrypt_ptr + #define RSA_public_decrypt RSA_public_decrypt_ptr + #define RSA_public_encrypt RSA_public_encrypt_ptr + #define RSA_set0_crt_params RSA_set0_crt_params_ptr + #define RSA_set0_factors RSA_set0_factors_ptr + #define RSA_set0_key RSA_set0_key_ptr + #define RSA_set_method RSA_set_method_ptr +-#define RSA_sign RSA_sign_ptr + #define RSA_size RSA_size_ptr + #define RSA_up_ref RSA_up_ref_ptr + #define RSA_verify RSA_verify_ptr +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +index 6235c905db..68b6a34a5d 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +@@ -91,7 +91,6 @@ int32_t CryptoNative_RsaDecrypt(EVP_PKEY* pkey, + if (rsa == NULL || HasNoPrivateKey(rsa)) + { + ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_NULL_PRIVATE_DECRYPT, RSA_R_VALUE_MISSING, __FILE__, __LINE__); +- ret = -1; + goto done; + } + } +@@ -112,6 +111,81 @@ done: + return ret; + } + ++int32_t CryptoNative_RsaSignHash(EVP_PKEY* pkey, ++ RsaPaddingMode padding, ++ const EVP_MD* digest, ++ const uint8_t* hash, ++ int32_t hashLen, ++ uint8_t* destination, ++ int32_t destinationLen) ++{ ++ assert(pkey != NULL); ++ assert(destination != NULL); ++ assert(padding >= RsaPaddingPkcs1 && padding <= RsaPaddingOaepOrPss); ++ assert(digest != NULL || padding == RsaPaddingPkcs1); ++ ++ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL); ++ ++ int ret = -1; ++ ++ if (ctx == NULL || EVP_PKEY_sign_init(ctx) <= 0) ++ { ++ goto done; ++ } ++ ++ if (padding == RsaPaddingPkcs1) ++ { ++ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) ++ { ++ goto done; ++ } ++ } ++ else ++ { ++ assert(padding == RsaPaddingOaepOrPss); ++ ++ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) <= 0 || ++ EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, RSA_PSS_SALTLEN_DIGEST) <= 0) ++ { ++ goto done; ++ } ++ } ++ ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" ++ if (EVP_PKEY_CTX_set_signature_md(ctx, digest) <= 0) ++#pragma clang diagnostic pop ++ { ++ goto done; ++ } ++ ++ // This check may no longer be needed on OpenSSL 3.0 ++ { ++ RSA* rsa = EVP_PKEY_get0_RSA(pkey); ++ ++ if (rsa == NULL || HasNoPrivateKey(rsa)) ++ { ++ ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_NULL_PRIVATE_DECRYPT, RSA_R_VALUE_MISSING, __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; ++} ++ + RSA* CryptoNative_EvpPkeyGetRsa(EVP_PKEY* pkey) + { + return EVP_PKEY_get1_RSA(pkey); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +index d220065adf..f811523f78 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.h +@@ -34,6 +34,20 @@ DLLEXPORT int32_t CryptoNative_RsaDecrypt(EVP_PKEY* pkey, + uint8_t* destination, + int32_t destinationLen); + ++/* ++Complete the RSA signature generation for the specified hash using the provided RSA key ++(wrapped in an EVP_PKEY) and padding/digest options. ++ ++Returns the number of bytes written to destination, -1 on error. ++*/ ++DLLEXPORT int32_t CryptoNative_RsaSignHash(EVP_PKEY* pkey, ++ RsaPaddingMode padding, ++ const EVP_MD* digest, ++ const uint8_t* hash, ++ int32_t hashLen, ++ uint8_t* destination, ++ int32_t destinationLen); ++ + /* + Shims the EVP_PKEY_get1_RSA method. + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +index 0c635dfca7..43268e88e1 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_rsa.c +@@ -48,60 +48,6 @@ static int GetOpenSslPadding(RsaPadding padding) + } + } + +-static int HasNoPrivateKey(RSA* rsa) +-{ +- if (rsa == NULL) +- return 1; +- +- // Shared pointer, don't free. +- const RSA_METHOD* meth = RSA_get_method(rsa); +- +- // The method has descibed itself as having the private key external to the structure. +- // That doesn't mean it's actually present, but we can't tell. +-#pragma clang diagnostic push +-#pragma clang diagnostic ignored "-Wcast-qual" +- if (RSA_meth_get_flags((RSA_METHOD*)meth) & RSA_FLAG_EXT_PKEY) +-#pragma clang diagnostic pop +- { +- return 0; +- } +- +- // In the event that there's a middle-ground where we report failure when success is expected, +- // one could do something like check if the RSA_METHOD intercepts all private key operations: +- // +- // * meth->rsa_priv_enc +- // * meth->rsa_priv_dec +- // * meth->rsa_sign (in 1.0.x this is only respected if the RSA_FLAG_SIGN_VER flag is asserted) +- // +- // But, for now, leave it at the EXT_PKEY flag test. +- +- // The module is documented as accepting either d or the full set of CRT parameters (p, q, dp, dq, qInv) +- // So if we see d, we're good. Otherwise, if any of the rest are missing, we're public-only. +- const BIGNUM* d; +- RSA_get0_key(rsa, NULL, NULL, &d); +- +- if (d != NULL) +- { +- return 0; +- } +- +- const BIGNUM* p; +- const BIGNUM* q; +- const BIGNUM* dmp1; +- const BIGNUM* dmq1; +- const BIGNUM* iqmp; +- +- RSA_get0_factors(rsa, &p, &q); +- RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); +- +- if (p == NULL || q == NULL || dmp1 == NULL || dmq1 == NULL || iqmp == NULL) +- { +- return 1; +- } +- +- return 0; +-} +- + int32_t + CryptoNative_RsaPublicEncrypt(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa, RsaPadding padding) + { +@@ -109,17 +55,6 @@ CryptoNative_RsaPublicEncrypt(int32_t flen, const uint8_t* from, uint8_t* to, RS + return RSA_public_encrypt(flen, from, to, rsa, openSslPadding); + } + +-int32_t CryptoNative_RsaSignPrimitive(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa) +-{ +- if (HasNoPrivateKey(rsa)) +- { +- ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_NULL_PRIVATE_ENCRYPT, RSA_R_VALUE_MISSING, __FILE__, __LINE__); +- return -1; +- } +- +- return RSA_private_encrypt(flen, from, to, rsa, RSA_NO_PADDING); +-} +- + int32_t CryptoNative_RsaVerificationPrimitive(int32_t flen, const uint8_t* from, uint8_t* to, RSA* rsa) + { + return RSA_public_decrypt(flen, from, to, rsa, RSA_NO_PADDING); +@@ -130,41 +65,6 @@ int32_t CryptoNative_RsaSize(RSA* rsa) + return RSA_size(rsa); + } + +-int32_t +-CryptoNative_RsaSign(int32_t type, const uint8_t* m, int32_t mlen, uint8_t* sigret, int32_t* siglen, RSA* rsa) +-{ +- if (siglen == NULL) +- { +- assert(false); +- return 0; +- } +- +- *siglen = 0; +- +- if (HasNoPrivateKey(rsa)) +- { +- ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_SIGN, RSA_R_VALUE_MISSING, __FILE__, __LINE__); +- return 0; +- } +- +- // Shared pointer to the metadata about the message digest algorithm +- const EVP_MD* digest = EVP_get_digestbynid(type); +- +- // If the digest itself isn't known then RSA_R_UNKNOWN_ALGORITHM_TYPE will get reported, but +- // we have to check that the digest size matches what we expect. +- if (digest != NULL && mlen != EVP_MD_size(digest)) +- { +- ERR_PUT_error(ERR_LIB_RSA, RSA_F_RSA_SIGN, RSA_R_INVALID_MESSAGE_LENGTH, __FILE__, __LINE__); +- return 0; +- } +- +- unsigned int unsignedSigLen = 0; +- int32_t ret = RSA_sign(type, m, Int32ToUint32(mlen), sigret, &unsignedSigLen, rsa); +- assert(unsignedSigLen <= INT32_MAX); +- *siglen = (int32_t)unsignedSigLen; +- return ret; +-} +- + int32_t + CryptoNative_RsaVerify(int32_t type, const uint8_t* m, int32_t mlen, uint8_t* sigbuf, int32_t siglen, RSA* rsa) + { +-- +2.31.1 + diff --git a/SOURCES/corefx-openssl-0004-Support-compiling-against-OpenSSL-3-headers.patch b/SOURCES/corefx-openssl-0004-Support-compiling-against-OpenSSL-3-headers.patch new file mode 100644 index 0000000..61bfe81 --- /dev/null +++ b/SOURCES/corefx-openssl-0004-Support-compiling-against-OpenSSL-3-headers.patch @@ -0,0 +1,648 @@ +From 49dc6e515d9ec0db1841e5d2d86f52916d35f667 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Mon, 5 Apr 2021 11:07:29 -0700 +Subject: [PATCH 04/11] Support compiling against OpenSSL 3 headers + +Building against OpenSSL 3's headers fails to compile, as X509_V_ERR_INVALID_CA has changed from 24 to 79, tripping a static assert. + +* Rename the managed X509VerifyStatusCode enum to X509VerifyStatusCodeUniversal, to represent the name/values that are present in all current versions of OpenSSL (1.0.2, 1.1.1, 3.0 alpha) +* Add new enums for the name/value pairs that are unique to a given version +* Add an X509VerifyStatusCode struct that just wraps the int and is a faux-union of the various enums +* Use the OpenSSL runtime version to determine which mapping table to use (after the Universal table fails) + +In addition to that, there are a few const-related changes in the 3.0 headers that are addressed. + +`corefx/src/Native$ ./build_native.sh -portablebuild=false` on systems where find_package(OpenSSL) maps to 3.0 succeeds with these changes. Portable builds still fail. + +Not all tests pass with OpenSSL 3.0 (alpha 13) with these changes, but it does reduce to three categories of error: + +* ICryptoTransform reset/reuse tests fail (OpenSSL regression is open) +* DSA small key generation fails (OpenSSL has fixed the regression for the next alpha/beta release) +* Some OuterLoop X.509 tests are failing as positively revoked when they expect ambiguous revocation states (investigation pending) +--- + .../Interop.OCSP.cs | 4 +- + .../Interop.X509.cs | 109 +++++++++++- + .../pal_evp_pkey_rsa.c | 8 +- + .../pal_x509.c | 24 ++- + .../pal_x509.h | 29 +++- + .../Pal.Unix/OpenSslX509ChainProcessor.cs | 155 ++++++++++++------ + 6 files changed, 266 insertions(+), 63 deletions(-) + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs +index bcf9e2af48..8be162e284 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs +@@ -43,7 +43,7 @@ internal static X509VerifyStatusCode X509ChainGetCachedOcspStatus(SafeX509StoreC + { + X509VerifyStatusCode response = CryptoNative_X509ChainGetCachedOcspStatus(ctx, cachePath); + +- if (response < 0) ++ if (response.Code < 0) + { + Debug.Fail($"Unexpected response from X509ChainGetCachedOcspSuccess: {response}"); + throw new CryptographicException(); +@@ -67,7 +67,7 @@ internal static X509VerifyStatusCode X509ChainGetCachedOcspStatus(SafeX509StoreC + { + X509VerifyStatusCode response = CryptoNative_X509ChainVerifyOcsp(ctx, req, resp, cachePath); + +- if (response < 0) ++ if (response.Code < 0) + { + Debug.Fail($"Unexpected response from X509ChainGetCachedOcspSuccess: {response}"); + throw new CryptographicException(); +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509.cs +index 8ffc70af6a..99747c276b 100644 +--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509.cs ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509.cs +@@ -216,13 +216,13 @@ internal static bool X509StoreCtxRebuildChain(SafeX509StoreCtxHandle ctx) + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_X509StoreCtxSetVerifyCallback")] + internal static extern void X509StoreCtxSetVerifyCallback(SafeX509StoreCtxHandle ctx, X509StoreVerifyCallback callback); + +- internal static string GetX509VerifyCertErrorString(X509VerifyStatusCode n) ++ internal static string GetX509VerifyCertErrorString(int n) + { + return Marshal.PtrToStringAnsi(X509VerifyCertErrorString(n)); + } + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_X509VerifyCertErrorString")] +- private static extern IntPtr X509VerifyCertErrorString(X509VerifyStatusCode n); ++ private static extern IntPtr X509VerifyCertErrorString(int n); + + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_X509CrlDestroy")] + internal static extern void X509CrlDestroy(IntPtr a); +@@ -239,11 +239,13 @@ internal static string GetX509VerifyCertErrorString(X509VerifyStatusCode n) + [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EncodeX509SubjectPublicKeyInfo")] + internal static extern int EncodeX509SubjectPublicKeyInfo(SafeX509Handle x509, byte[] buf); + +- internal enum X509VerifyStatusCode : int ++ internal enum X509VerifyStatusCodeUniversal + { + X509_V_OK = 0, ++ X509_V_ERR_UNSPECIFIED = 1, + X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2, + X509_V_ERR_UNABLE_TO_GET_CRL = 3, ++ X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4, + X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5, + X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6, + X509_V_ERR_CERT_SIGNATURE_FAILURE = 7, +@@ -263,18 +265,25 @@ internal enum X509VerifyStatusCode : int + X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21, + X509_V_ERR_CERT_CHAIN_TOO_LONG = 22, + X509_V_ERR_CERT_REVOKED = 23, +- X509_V_ERR_INVALID_CA = 24, ++ ++ // Code 24 varies. ++ + X509_V_ERR_PATH_LENGTH_EXCEEDED = 25, + X509_V_ERR_INVALID_PURPOSE = 26, + X509_V_ERR_CERT_UNTRUSTED = 27, + X509_V_ERR_CERT_REJECTED = 28, ++ X509_V_ERR_SUBJECT_ISSUER_MISMATCH = 29, ++ X509_V_ERR_AKID_SKID_MISMATCH = 30, ++ X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH = 31, + X509_V_ERR_KEYUSAGE_NO_CERTSIGN = 32, + X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER = 33, + X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION = 34, + X509_V_ERR_KEYUSAGE_NO_CRL_SIGN = 35, + X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION = 36, + X509_V_ERR_INVALID_NON_CA = 37, ++ X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED = 38, + X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE = 39, ++ X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED = 40, + X509_V_ERR_INVALID_EXTENSION = 41, + X509_V_ERR_INVALID_POLICY_EXTENSION = 42, + X509_V_ERR_NO_EXPLICIT_POLICY = 43, +@@ -289,7 +298,6 @@ internal enum X509VerifyStatusCode : int + X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX = 52, + X509_V_ERR_UNSUPPORTED_NAME_SYNTAX = 53, + X509_V_ERR_CRL_PATH_VALIDATION_ERROR = 54, +- X509_V_ERR_PATH_LOOP = 55, + X509_V_ERR_SUITE_B_INVALID_VERSION = 56, + X509_V_ERR_SUITE_B_INVALID_ALGORITHM = 57, + X509_V_ERR_SUITE_B_INVALID_CURVE = 58, +@@ -299,6 +307,41 @@ internal enum X509VerifyStatusCode : int + X509_V_ERR_HOSTNAME_MISMATCH = 62, + X509_V_ERR_EMAIL_MISMATCH = 63, + X509_V_ERR_IP_ADDRESS_MISMATCH = 64, ++ } ++ internal enum X509VerifyStatusCode102 ++ { ++ X509_V_ERR_INVALID_CA = 24, ++ ++ X509_V_ERR_INVALID_CALL = 65, ++ X509_V_ERR_STORE_LOOKUP = 66, ++ X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION = 67, ++ } ++ ++ internal enum X509VerifyStatusCode111 ++ { ++ X509_V_ERR_INVALID_CA = 24, ++ ++ X509_V_ERR_DANE_NO_MATCH = 65, ++ X509_V_ERR_EE_KEY_TOO_SMALL = 66, ++ X509_V_ERR_CA_KEY_TOO_SMALL = 67, ++ X509_V_ERR_CA_MD_TOO_WEAK = 68, ++ X509_V_ERR_INVALID_CALL = 69, ++ X509_V_ERR_STORE_LOOKUP = 70, ++ X509_V_ERR_NO_VALID_SCTS = 71, ++ X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION = 72, ++ X509_V_ERR_OCSP_VERIFY_NEEDED = 73, ++ X509_V_ERR_OCSP_VERIFY_FAILED = 74, ++ X509_V_ERR_OCSP_CERT_UNKNOWN = 75, ++ X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH = 76, ++ X509_V_ERR_NO_ISSUER_PUBLIC_KEY = 77, ++ X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM = 78, ++ X509_V_ERR_EC_KEY_EXPLICIT_PARAMS = 79, ++ } ++ ++ internal enum X509VerifyStatusCode30 ++ { ++ X509_V_ERR_NO_ISSUER_PUBLIC_KEY = 24, ++ + X509_V_ERR_DANE_NO_MATCH = 65, + X509_V_ERR_EE_KEY_TOO_SMALL = 66, + X509_V_ERR_CA_KEY_TOO_SMALL = 67, +@@ -310,6 +353,62 @@ internal enum X509VerifyStatusCode : int + X509_V_ERR_OCSP_VERIFY_NEEDED = 73, + X509_V_ERR_OCSP_VERIFY_FAILED = 74, + X509_V_ERR_OCSP_CERT_UNKNOWN = 75, ++ X509_V_ERR_UNSUPPORTED_SIGNATURE_ALGORITHM = 76, ++ X509_V_ERR_SIGNATURE_ALGORITHM_MISMATCH = 77, ++ X509_V_ERR_SIGNATURE_ALGORITHM_INCONSISTENCY = 78, ++ X509_V_ERR_INVALID_CA = 79, ++ X509_V_ERR_PATHLEN_INVALID_FOR_NON_CA = 80, ++ X509_V_ERR_PATHLEN_WITHOUT_KU_KEY_CERT_SIGN = 81, ++ X509_V_ERR_KU_KEY_CERT_SIGN_INVALID_FOR_NON_CA = 82, ++ X509_V_ERR_ISSUER_NAME_EMPTY = 83, ++ X509_V_ERR_SUBJECT_NAME_EMPTY = 84, ++ X509_V_ERR_MISSING_AUTHORITY_KEY_IDENTIFIER = 85, ++ X509_V_ERR_MISSING_SUBJECT_KEY_IDENTIFIER = 86, ++ X509_V_ERR_EMPTY_SUBJECT_ALT_NAME = 87, ++ X509_V_ERR_EMPTY_SUBJECT_SAN_NOT_CRITICAL = 88, ++ X509_V_ERR_CA_BCONS_NOT_CRITICAL = 89, ++ X509_V_ERR_AUTHORITY_KEY_IDENTIFIER_CRITICAL = 90, ++ X509_V_ERR_SUBJECT_KEY_IDENTIFIER_CRITICAL = 91, ++ X509_V_ERR_CA_CERT_MISSING_KEY_USAGE = 92, ++ X509_V_ERR_EXTENSIONS_REQUIRE_VERSION_3 = 93, ++ X509_V_ERR_EC_KEY_EXPLICIT_PARAMS = 94, ++ } ++ ++ internal readonly struct X509VerifyStatusCode : IEquatable ++ { ++ internal static readonly X509VerifyStatusCode X509_V_OK = X509VerifyStatusCodeUniversal.X509_V_OK; ++ ++ public int Code { get; } ++ ++ internal X509VerifyStatusCode(int code) ++ { ++ Code = code; ++ } ++ ++ public X509VerifyStatusCodeUniversal UniversalCode => (X509VerifyStatusCodeUniversal)Code; ++ public X509VerifyStatusCode102 Code102 => (X509VerifyStatusCode102)Code; ++ public X509VerifyStatusCode111 Code111 => (X509VerifyStatusCode111)Code; ++ public X509VerifyStatusCode30 Code30 => (X509VerifyStatusCode30)Code; ++ ++ public bool Equals(X509VerifyStatusCode other) => Code == other.Code; ++ ++ public override bool Equals(object obj) => obj is X509VerifyStatusCode other && Equals(other); ++ ++ public override int GetHashCode() => Code.GetHashCode(); ++ ++ public static bool operator ==(X509VerifyStatusCode left, X509VerifyStatusCode right) => left.Equals(right); ++ ++ public static bool operator !=(X509VerifyStatusCode left, X509VerifyStatusCode right) => !left.Equals(right); ++ ++ public static explicit operator X509VerifyStatusCode(int code) ++ { ++ return new X509VerifyStatusCode(code); ++ } ++ ++ public static implicit operator X509VerifyStatusCode(X509VerifyStatusCodeUniversal code) ++ { ++ return new X509VerifyStatusCode((int)code); ++ } + } + } + } +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +index 68b6a34a5d..02b31b4737 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey_rsa.c +@@ -6,7 +6,7 @@ + #include "pal_utilities.h" + #include + +-static int HasNoPrivateKey(RSA* rsa); ++static int HasNoPrivateKey(const RSA* rsa); + + EVP_PKEY* CryptoNative_RsaGenerateKey(int keySize) + { +@@ -86,7 +86,7 @@ int32_t CryptoNative_RsaDecrypt(EVP_PKEY* pkey, + + // This check may no longer be needed on OpenSSL 3.0 + { +- RSA* rsa = EVP_PKEY_get0_RSA(pkey); ++ const RSA* rsa = EVP_PKEY_get0_RSA(pkey); + + if (rsa == NULL || HasNoPrivateKey(rsa)) + { +@@ -161,7 +161,7 @@ int32_t CryptoNative_RsaSignHash(EVP_PKEY* pkey, + + // This check may no longer be needed on OpenSSL 3.0 + { +- RSA* rsa = EVP_PKEY_get0_RSA(pkey); ++ const RSA* rsa = EVP_PKEY_get0_RSA(pkey); + + if (rsa == NULL || HasNoPrivateKey(rsa)) + { +@@ -196,7 +196,7 @@ int32_t CryptoNative_EvpPkeySetRsa(EVP_PKEY* pkey, RSA* rsa) + return EVP_PKEY_set1_RSA(pkey, rsa); + } + +-static int HasNoPrivateKey(RSA* rsa) ++static int HasNoPrivateKey(const RSA* rsa) + { + if (rsa == NULL) + return 1; +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.c +index 5dd31d0e62..0554c8d3e8 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.c +@@ -33,7 +33,6 @@ c_static_assert(PAL_X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY == X509_V_ERR_U + c_static_assert(PAL_X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE); + c_static_assert(PAL_X509_V_ERR_CERT_CHAIN_TOO_LONG == X509_V_ERR_CERT_CHAIN_TOO_LONG); + c_static_assert(PAL_X509_V_ERR_CERT_REVOKED == X509_V_ERR_CERT_REVOKED); +-c_static_assert(PAL_X509_V_ERR_INVALID_CA == X509_V_ERR_INVALID_CA); + c_static_assert(PAL_X509_V_ERR_PATH_LENGTH_EXCEEDED == X509_V_ERR_PATH_LENGTH_EXCEEDED); + c_static_assert(PAL_X509_V_ERR_INVALID_PURPOSE == X509_V_ERR_INVALID_PURPOSE); + c_static_assert(PAL_X509_V_ERR_CERT_UNTRUSTED == X509_V_ERR_CERT_UNTRUSTED); +@@ -48,6 +47,26 @@ c_static_assert(PAL_X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE == X509_V_ERR_KEYUS + c_static_assert(PAL_X509_V_ERR_INVALID_EXTENSION == X509_V_ERR_INVALID_EXTENSION); + c_static_assert(PAL_X509_V_ERR_INVALID_POLICY_EXTENSION == X509_V_ERR_INVALID_POLICY_EXTENSION); + c_static_assert(PAL_X509_V_ERR_NO_EXPLICIT_POLICY == X509_V_ERR_NO_EXPLICIT_POLICY); ++c_static_assert(PAL_X509_V_ERR_DIFFERENT_CRL_SCOPE == X509_V_ERR_DIFFERENT_CRL_SCOPE); ++c_static_assert(PAL_X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE == X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE); ++c_static_assert(PAL_X509_V_ERR_UNNESTED_RESOURCE == X509_V_ERR_UNNESTED_RESOURCE); ++c_static_assert(PAL_X509_V_ERR_PERMITTED_VIOLATION == X509_V_ERR_PERMITTED_VIOLATION); ++c_static_assert(PAL_X509_V_ERR_EXCLUDED_VIOLATION == X509_V_ERR_EXCLUDED_VIOLATION); ++c_static_assert(PAL_X509_V_ERR_SUBTREE_MINMAX == X509_V_ERR_SUBTREE_MINMAX); ++c_static_assert(PAL_X509_V_ERR_APPLICATION_VERIFICATION == X509_V_ERR_APPLICATION_VERIFICATION); ++c_static_assert(PAL_X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE == X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE); ++c_static_assert(PAL_X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX == X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX); ++c_static_assert(PAL_X509_V_ERR_UNSUPPORTED_NAME_SYNTAX == X509_V_ERR_UNSUPPORTED_NAME_SYNTAX); ++c_static_assert(PAL_X509_V_ERR_CRL_PATH_VALIDATION_ERROR == X509_V_ERR_CRL_PATH_VALIDATION_ERROR); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_INVALID_VERSION == X509_V_ERR_SUITE_B_INVALID_VERSION); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_INVALID_ALGORITHM == X509_V_ERR_SUITE_B_INVALID_ALGORITHM); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_INVALID_CURVE == X509_V_ERR_SUITE_B_INVALID_CURVE); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM == X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED); ++c_static_assert(PAL_X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 == X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256); ++c_static_assert(PAL_X509_V_ERR_HOSTNAME_MISMATCH == X509_V_ERR_HOSTNAME_MISMATCH); ++c_static_assert(PAL_X509_V_ERR_EMAIL_MISMATCH == X509_V_ERR_EMAIL_MISMATCH); ++c_static_assert(PAL_X509_V_ERR_IP_ADDRESS_MISMATCH == X509_V_ERR_IP_ADDRESS_MISMATCH); + + EVP_PKEY* CryptoNative_GetX509EvpPublicKey(X509* x509) + { +@@ -1109,7 +1128,10 @@ CryptoNative_X509ChainVerifyOcsp(X509_STORE_CTX* storeCtx, OCSP_REQUEST* req, OC + + if (bio != NULL) + { ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" + if (i2d_OCSP_RESPONSE_bio(bio, resp)) ++#pragma clang diagnostic pop + { + clearErr = 0; + } +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.h b/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.h +index 7f242b4c2e..f7114e9642 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_x509.h +@@ -18,7 +18,10 @@ typedef enum { + /* + The error codes used when verifying X509 certificate chains. + +-These values should be kept in sync with Interop.Crypto.X509VerifyStatusCode. ++These values should be kept in sync with Interop.Crypto.X509VerifyStatusCodeUniversal. ++ ++Codes specific to specific versions of OpenSSL can also be returned, ++but are not represented in this enum due to their non-constant nature. + */ + typedef enum { + PAL_X509_V_OK = 0, +@@ -43,7 +46,9 @@ typedef enum { + PAL_X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21, + PAL_X509_V_ERR_CERT_CHAIN_TOO_LONG = 22, + PAL_X509_V_ERR_CERT_REVOKED = 23, +- PAL_X509_V_ERR_INVALID_CA = 24, ++ ++ // Code 24 varies ++ + PAL_X509_V_ERR_PATH_LENGTH_EXCEEDED = 25, + PAL_X509_V_ERR_INVALID_PURPOSE = 26, + PAL_X509_V_ERR_CERT_UNTRUSTED = 27, +@@ -58,6 +63,26 @@ typedef enum { + PAL_X509_V_ERR_INVALID_EXTENSION = 41, + PAL_X509_V_ERR_INVALID_POLICY_EXTENSION = 42, + PAL_X509_V_ERR_NO_EXPLICIT_POLICY = 43, ++ PAL_X509_V_ERR_DIFFERENT_CRL_SCOPE = 44, ++ PAL_X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE = 45, ++ PAL_X509_V_ERR_UNNESTED_RESOURCE = 46, ++ PAL_X509_V_ERR_PERMITTED_VIOLATION = 47, ++ PAL_X509_V_ERR_EXCLUDED_VIOLATION = 48, ++ PAL_X509_V_ERR_SUBTREE_MINMAX = 49, ++ PAL_X509_V_ERR_APPLICATION_VERIFICATION = 50, ++ PAL_X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE = 51, ++ PAL_X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX = 52, ++ PAL_X509_V_ERR_UNSUPPORTED_NAME_SYNTAX = 53, ++ PAL_X509_V_ERR_CRL_PATH_VALIDATION_ERROR = 54, ++ PAL_X509_V_ERR_SUITE_B_INVALID_VERSION = 56, ++ PAL_X509_V_ERR_SUITE_B_INVALID_ALGORITHM = 57, ++ PAL_X509_V_ERR_SUITE_B_INVALID_CURVE = 58, ++ PAL_X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM = 59, ++ PAL_X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED = 60, ++ PAL_X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 = 61, ++ PAL_X509_V_ERR_HOSTNAME_MISMATCH = 62, ++ PAL_X509_V_ERR_EMAIL_MISMATCH = 63, ++ PAL_X509_V_ERR_IP_ADDRESS_MISMATCH = 64, + } X509VerifyStatusCode; + + typedef int32_t (*X509StoreVerifyCallback)(int32_t, X509_STORE_CTX*); +diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs +index d28286f016..a7f777261e 100644 +--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs ++++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs +@@ -13,10 +13,14 @@ + using System.Security.Cryptography.X509Certificates.Asn1; + using Microsoft.Win32.SafeHandles; + ++using X509VerifyStatusCodeUniversal = Interop.Crypto.X509VerifyStatusCodeUniversal; ++ + namespace Internal.Cryptography.Pal + { + internal sealed class OpenSslX509ChainProcessor : IChainPal + { ++ private delegate X509ChainStatusFlags MapVersionSpecificCode(Interop.Crypto.X509VerifyStatusCode code); ++ + // The average chain is 3 (End-Entity, Intermediate, Root) + // 10 is plenty big. + private const int DefaultChainCapacity = 10; +@@ -30,6 +34,8 @@ internal sealed class OpenSslX509ChainProcessor : IChainPal + private static readonly CachedDirectoryStoreProvider s_userPersonalStore = + new CachedDirectoryStoreProvider(X509Store.MyStoreName); + ++ private static readonly MapVersionSpecificCode s_mapVersionSpecificCode = GetVersionLookup(); ++ + private SafeX509Handle _leafHandle; + private SafeX509StoreHandle _store; + private readonly SafeX509StackHandle _untrustedLookup; +@@ -156,10 +162,10 @@ internal Interop.Crypto.X509VerifyStatusCode FindFirstChain(X509Certificate2Coll + + internal static bool IsCompleteChain(Interop.Crypto.X509VerifyStatusCode statusCode) + { +- switch (statusCode) ++ switch (statusCode.UniversalCode) + { +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + return false; + default: + return true; +@@ -173,7 +179,7 @@ internal static bool IsCompleteChain(Interop.Crypto.X509VerifyStatusCode statusC + SafeX509StoreCtxHandle storeCtx = _storeCtx; + + Interop.Crypto.X509VerifyStatusCode statusCode = +- Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; ++ X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; + + while (!IsCompleteChain(statusCode)) + { +@@ -426,7 +432,7 @@ private Interop.Crypto.X509VerifyStatusCode CheckOcsp() + Interop.Crypto.X509VerifyStatusCode status = + Interop.Crypto.X509ChainGetCachedOcspStatus(_storeCtx, ocspCache); + +- if (status != Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_CRL) ++ if (status != X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_CRL) + { + return status; + } +@@ -468,7 +474,7 @@ private Interop.Crypto.X509VerifyStatusCode CheckOcsp() + { + if (resp == null || resp.IsInvalid) + { +- return Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_CRL; ++ return X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_CRL; + } + + try +@@ -744,77 +750,111 @@ private static void AddUniqueStatus(IList list, ref X509ChainSt + + private static X509ChainStatusFlags MapVerifyErrorToChainStatus(Interop.Crypto.X509VerifyStatusCode code) + { +- switch (code) ++ switch (code.UniversalCode) + { +- case Interop.Crypto.X509VerifyStatusCode.X509_V_OK: ++ case X509VerifyStatusCodeUniversal.X509_V_OK: + return X509ChainStatusFlags.NoError; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_NOT_YET_VALID: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_HAS_EXPIRED: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_NOT_YET_VALID: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_HAS_EXPIRED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + return X509ChainStatusFlags.NotTimeValid; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_REVOKED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_REVOKED: + return X509ChainStatusFlags.Revoked; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_SIGNATURE_FAILURE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_SIGNATURE_FAILURE: + return X509ChainStatusFlags.NotSignatureValid; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_UNTRUSTED: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_UNTRUSTED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + return X509ChainStatusFlags.UntrustedRoot; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CRL_HAS_EXPIRED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CRL_HAS_EXPIRED: + return X509ChainStatusFlags.OfflineRevocation; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CRL_NOT_YET_VALID: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CRL_SIGNATURE_FAILURE: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_CRL: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CRL_NOT_YET_VALID: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CRL_SIGNATURE_FAILURE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_CRL: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: + return X509ChainStatusFlags.RevocationStatusUnknown; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_INVALID_EXTENSION: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_INVALID_EXTENSION: + return X509ChainStatusFlags.InvalidExtension; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + return X509ChainStatusFlags.PartialChain; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_INVALID_PURPOSE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_INVALID_PURPOSE: + return X509ChainStatusFlags.NotValidForUsage; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_INVALID_CA: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_INVALID_NON_CA: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_PATH_LENGTH_EXCEEDED: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_KEYUSAGE_NO_CERTSIGN: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_INVALID_NON_CA: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_PATH_LENGTH_EXCEEDED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_KEYUSAGE_NO_CERTSIGN: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: + return X509ChainStatusFlags.InvalidBasicConstraints; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_INVALID_POLICY_EXTENSION: +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_NO_EXPLICIT_POLICY: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_INVALID_POLICY_EXTENSION: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_NO_EXPLICIT_POLICY: + return X509ChainStatusFlags.InvalidPolicyConstraints; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_REJECTED: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_REJECTED: + return X509ChainStatusFlags.ExplicitDistrust; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: + return X509ChainStatusFlags.HasNotSupportedCriticalExtension; + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_CHAIN_TOO_LONG: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_CHAIN_TOO_LONG: + throw new CryptographicException(); + +- case Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_OUT_OF_MEM: ++ case X509VerifyStatusCodeUniversal.X509_V_ERR_OUT_OF_MEM: + throw new OutOfMemoryException(); + ++ default: ++ return s_mapVersionSpecificCode(code); ++ } ++ } ++ ++ private static X509ChainStatusFlags MapOpenSsl30Code(Interop.Crypto.X509VerifyStatusCode code) ++ { ++ switch (code.Code30) ++ { ++ case Interop.Crypto.X509VerifyStatusCode30.X509_V_ERR_INVALID_CA: ++ return X509ChainStatusFlags.InvalidBasicConstraints; ++ default: ++ Debug.Fail("Unrecognized X509VerifyStatusCode:" + code); ++ throw new CryptographicException(); ++ } ++ } ++ ++ private static X509ChainStatusFlags MapOpenSsl102Code(Interop.Crypto.X509VerifyStatusCode code) ++ { ++ switch (code.Code102) ++ { ++ case Interop.Crypto.X509VerifyStatusCode102.X509_V_ERR_INVALID_CA: ++ return X509ChainStatusFlags.InvalidBasicConstraints; ++ default: ++ Debug.Fail("Unrecognized X509VerifyStatusCode:" + code); ++ throw new CryptographicException(); ++ } ++ } ++ ++ private static X509ChainStatusFlags MapOpenSsl111Code(Interop.Crypto.X509VerifyStatusCode code) ++ { ++ switch (code.Code111) ++ { ++ case Interop.Crypto.X509VerifyStatusCode111.X509_V_ERR_INVALID_CA: ++ return X509ChainStatusFlags.InvalidBasicConstraints; + default: + Debug.Fail("Unrecognized X509VerifyStatusCode:" + code); + throw new CryptographicException(); +@@ -969,7 +1009,7 @@ internal int VerifyCallback(int ok, IntPtr ctx) + int errorDepth = Interop.Crypto.X509StoreCtxGetErrorDepth(storeCtx); + + if (AbortOnSignatureError && +- errorCode == Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_SIGNATURE_FAILURE) ++ errorCode == X509VerifyStatusCodeUniversal.X509_V_ERR_CERT_SIGNATURE_FAILURE) + { + AbortedForSignatureError = true; + return 0; +@@ -979,9 +1019,9 @@ internal int VerifyCallback(int ok, IntPtr ctx) + // * For compatibility with Windows / .NET Framework, do not report X509_V_CRL_NOT_YET_VALID. + // * X509_V_ERR_DIFFERENT_CRL_SCOPE will result in X509_V_ERR_UNABLE_TO_GET_CRL + // which will trigger OCSP, so is ignorable. +- if (errorCode != Interop.Crypto.X509VerifyStatusCode.X509_V_OK && +- errorCode != Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CRL_NOT_YET_VALID && +- errorCode != Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_DIFFERENT_CRL_SCOPE) ++ if (errorCode != X509VerifyStatusCodeUniversal.X509_V_OK && ++ errorCode != X509VerifyStatusCodeUniversal.X509_V_ERR_CRL_NOT_YET_VALID && ++ errorCode != X509VerifyStatusCodeUniversal.X509_V_ERR_DIFFERENT_CRL_SCOPE) + { + if (_errors == null) + { +@@ -1016,6 +1056,23 @@ internal int VerifyCallback(int ok, IntPtr ctx) + } + } + ++ private static MapVersionSpecificCode GetVersionLookup() ++ { ++ // 3.0+ are M_NN_00_PP_p (Major, Minor, 0, Patch, Preview) ++ // 1.x.y are 1_XX_YY_PP_p ++ if (SafeEvpPKeyHandle.OpenSslVersion >= 0x3_00_00_00_0) ++ { ++ return MapOpenSsl30Code; ++ } ++ ++ if (SafeEvpPKeyHandle.OpenSslVersion >= 0x1_01_01_00_0) ++ { ++ return MapOpenSsl111Code; ++ } ++ ++ return MapOpenSsl102Code; ++ } ++ + private unsafe struct ErrorCollection + { + // As of OpenSSL 1.1.1 there are 75 defined X509_V_ERR values, +@@ -1059,7 +1116,7 @@ public Enumerator GetEnumerator() + + private static int FindBucket(Interop.Crypto.X509VerifyStatusCode statusCode, out int bitValue) + { +- int val = (int)statusCode; ++ int val = statusCode.Code; + + int bucket; + +-- +2.31.1 + diff --git a/SOURCES/corefx-openssl-0005-Make-portable-builds-work-across-OpenSSL-1.0.2-1.1.1.patch b/SOURCES/corefx-openssl-0005-Make-portable-builds-work-across-OpenSSL-1.0.2-1.1.1.patch new file mode 100644 index 0000000..079a6c6 --- /dev/null +++ b/SOURCES/corefx-openssl-0005-Make-portable-builds-work-across-OpenSSL-1.0.2-1.1.1.patch @@ -0,0 +1,829 @@ +From 07c2b5773e994e8922a24757605a5eff05073167 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Wed, 14 Apr 2021 16:38:19 -0700 +Subject: [PATCH 05/11] Make portable builds work across OpenSSL + 1.0.2/1.1.1/3.0 + +Overall structure of changes + +* Pull compatibility headers out into separate include files, because opensslshim.h is too big. +* Use forward definition of EVP_PKEY_CTX_set_rsa_keygen_bits and friends. + * These are in a new apibridge file because they're for bridging up to 3.0, and the existing one was for 1.1(.1) + * Some constants needed for this file changed between 1.1 and 3.0, so there are a lot of asserts and redefines. +* On OpenSSL 3.0, build a legacy version of ERR_put_error since it has the easier signature to work with. +* FALLBACK_FUNCTION doesn't care which version it bound to, if it doesn't find it use a local_ function. +* Renamed NEW_REQUIRED_FUNCTION to REQUIRED_FUNCTION_110 because "new" is now "sort of old". +* There's a manual sanity test that either ERR_put_error or the three new functions that together replace it are found, so we don't end up in a state where we can't report shim-injected errors. + +Portable build checker: +* Built with OpenSSL 1.0.2 headers (Ubuntu 16.04 default libssl-dev) + * Ran with 1.0.2 (Ubuntu 16.04 default libssl) + * Ran with 1.1.1 (Ubuntu 18.04 default libssl) + * Ran with 3.0 (Ubuntu 16.04 with local build of OpenSSL 3.0 alpha 13) +* Built with OpenSSL 1.1.1 headers (Ubuntu 18.04 default libssl-dev) + * Ran with 1.0.2 (Ubuntu 16.04 default libssl) + * Ran with 1.1.1 (Ubuntu 18.04 default libssl) + * Ran with 3.0 (Ubuntu 16.04 with local build of OpenSSL 3.0 alpha 13) +* Built with OpenSSL 3.0 headers (Ubuntu 16.04 with local build of OpenSSL 3.0 alpha 13 and some surgery to the extra_libs.cmake) + * Ran with 1.0.2 (Ubuntu 16.04 default libssl) + * Ran with 1.1.1 (Ubuntu 18.04 default libssl) + * Ran with 3.0 (Ubuntu 16.04 with local build of OpenSSL 3.0 alpha 13) + +3.0 doesn't run error-free, but it runs with the same error rate from portable and direct builds. All verification was limited to the System.Security.Cryptography.Algorithms.Tests run, but that's generally representative of the bindings. +--- + .../CMakeLists.txt | 1 + + .../apibridge_30.c | 104 +++++++++ + .../apibridge_30.h | 13 ++ + .../apibridge_30_rev.h | 10 + + .../openssl.c | 2 +- + .../opensslshim.c | 29 ++- + .../opensslshim.h | 204 +++++++----------- + .../osslcompat_102.h | 34 +++ + .../osslcompat_111.h | 80 +++++++ + .../osslcompat_30.h | 23 ++ + .../pal_ssl.c | 2 +- + 11 files changed, 367 insertions(+), 135 deletions(-) + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/apibridge_30_rev.h + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/osslcompat_102.h + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h + create mode 100644 src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt b/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt +index b2f4e33f0b..19dab3035d 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt ++++ b/src/Native/Unix/System.Security.Cryptography.Native/CMakeLists.txt +@@ -23,6 +23,7 @@ include_directories(${OPENSSL_INCLUDE_DIR}) + + set(NATIVECRYPTO_SOURCES + apibridge.c ++ apibridge_30.c + openssl.c + pal_asn1.c + pal_bignum.c +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c +new file mode 100644 +index 0000000000..63b5531863 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.c +@@ -0,0 +1,104 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++#include "opensslshim.h" ++#include "pal_crypto_types.h" ++#include "pal_types.h" ++ ++#include "../Common/pal_safecrt.h" ++#include ++ ++#if defined NEED_OPENSSL_1_0 || defined NEED_OPENSSL_1_1 ++ ++#include "apibridge_30.h" ++ ++// 1.0 and 1.1 agree on the values of the EVP_PKEY_ values, but some of them changed in 3.0. ++// If we're running on 3.0 we already call the real methods, not these fallbacks, so we need to always use ++// the 1.0/1.1 values here. ++ ++// These values are in common. ++c_static_assert(EVP_PKEY_CTRL_MD == 1); ++c_static_assert(EVP_PKEY_CTRL_RSA_KEYGEN_BITS == 0x1003); ++c_static_assert(EVP_PKEY_CTRL_RSA_OAEP_MD == 0x1009); ++c_static_assert(EVP_PKEY_CTRL_RSA_PADDING == 0x1001); ++c_static_assert(EVP_PKEY_CTRL_RSA_PSS_SALTLEN == 0x1002); ++c_static_assert(EVP_PKEY_OP_KEYGEN == (1 << 2)); ++c_static_assert(EVP_PKEY_RSA == 6); ++ ++#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM ++ ++c_static_assert(EVP_PKEY_OP_SIGN == (1 << 3)); ++c_static_assert(EVP_PKEY_OP_VERIFY == (1 << 4)); ++c_static_assert(EVP_PKEY_OP_TYPE_CRYPT == ((1 << 8) | (1 << 9))); ++c_static_assert(EVP_PKEY_OP_TYPE_SIG == 0xF8); ++ ++#else ++ ++#undef EVP_PKEY_OP_SIGN ++#define EVP_PKEY_OP_SIGN (1 << 3) ++#undef EVP_PKEY_OP_VERIFY ++#define EVP_PKEY_OP_VERIFY (1 << 4) ++#undef EVP_PKEY_OP_TYPE_CRYPT ++#define EVP_PKEY_OP_TYPE_CRYPT ((1 << 8) | (1 << 9)) ++#undef EVP_PKEY_OP_TYPE_SIG ++#define EVP_PKEY_OP_TYPE_SIG 0xF8 // OP_SIGN | OP_VERIFY | OP_VERIFYRECOVER | OP_SIGNCTX | OP_VERIFYCTX ++ ++#endif ++ ++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); ++} ++ ++int local_EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX* ctx, const EVP_MD* md) ++{ ++ // set_rsa_oaep_md doesn't route through RSA_pkey_ctx_ctrl n 1.1, unlike the other set_rsa operations. ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" ++ return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void*)md); ++#pragma clang diagnostic pop ++} ++ ++int local_EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX* ctx, int pad_mode) ++{ ++ return RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad_mode, NULL); ++} ++ ++int local_EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX* ctx, int saltlen) ++{ ++ return RSA_pkey_ctx_ctrl( ++ ctx, (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY), EVP_PKEY_CTRL_RSA_PSS_SALTLEN, saltlen, NULL); ++} ++ ++int local_EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX* ctx, const EVP_MD* md) ++{ ++#pragma clang diagnostic push ++#pragma clang diagnostic ignored "-Wcast-qual" ++ return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0, (void*)md); ++#pragma clang diagnostic pop ++} ++ ++#endif // defined NEED_OPENSSL_1_0 || defined NEED_OPENSSL_1_1 ++ ++#ifdef NEED_OPENSSL_3_0 ++ ++#include "apibridge_30_rev.h" ++ ++void local_ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file, int32_t line) ++{ ++ // In portable builds, ensure that we found the 3.0 error reporting functions. ++ // In non-portable builds, this is just assert(true), but then we call the functions, ++ // so the compiler ensures they're there anyways. ++ assert(API_EXISTS(ERR_new) && API_EXISTS(ERR_set_debug) && API_EXISTS(ERR_set_error)); ++ ERR_new(); ++ ++ // ERR_set_debug saves only the pointer, not the value, as it expects constants. ++ // So just ignore the legacy numeric code, and use the 3.0 "Uh, I don't know" ++ // function name. ++ (void)func; ++ ERR_set_debug(file, line, "(unknown function)"); ++ ++ ERR_set_error(lib, reason, NULL); ++} ++ ++#endif // defined NEED_OPENSSL_3_0 +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h +new file mode 100644 +index 0000000000..0f28900cb7 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30.h +@@ -0,0 +1,13 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++// Functions based on OpenSSL 3.0 API, used when building against/running with older versions. ++ ++#pragma once ++#include "pal_types.h" ++ ++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); ++int local_EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX* ctx, int saltlen); ++int local_EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX* ctx, const EVP_MD* md); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30_rev.h b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30_rev.h +new file mode 100644 +index 0000000000..657cc969d2 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/apibridge_30_rev.h +@@ -0,0 +1,10 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++// Functions based on OpenSSL 3.0 API, used when building against/running with older versions. ++ ++#pragma once ++#include "pal_types.h" ++ ++// For 3.0 to behave like previous versions. ++void local_ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file, int32_t line); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/openssl.c b/src/Native/Unix/System.Security.Cryptography.Native/openssl.c +index 1a9ea04839..456741360d 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/openssl.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/openssl.c +@@ -1256,7 +1256,7 @@ done: + } + #endif // NEED_OPENSSL_1_0 */ + +-#ifdef NEED_OPENSSL_1_1 ++#if defined NEED_OPENSSL_1_1 || defined NEED_OPENSSL_3_0 + + // Only defined in OpenSSL 1.1.1+, has no effect on 1.1.0. + #ifndef OPENSSL_INIT_NO_ATEXIT +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.c b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.c +index b085114a6b..edd7a6dd2d 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.c +@@ -13,7 +13,7 @@ + + // Define pointers to all the used OpenSSL functions + #define REQUIRED_FUNCTION(fn) __typeof(fn) fn##_ptr; +-#define NEW_REQUIRED_FUNCTION(fn) __typeof(fn) fn##_ptr; ++#define REQUIRED_FUNCTION_110(fn) __typeof(fn) fn##_ptr; + #define LIGHTUP_FUNCTION(fn) __typeof(fn) fn##_ptr; + #define FALLBACK_FUNCTION(fn) __typeof(fn) fn##_ptr; + #define RENAMED_FUNCTION(fn,oldfn) __typeof(fn) fn##_ptr; +@@ -23,7 +23,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #undef RENAMED_FUNCTION + #undef FALLBACK_FUNCTION + #undef LIGHTUP_FUNCTION +-#undef NEW_REQUIRED_FUNCTION ++#undef REQUIRED_FUNCTION_110 + #undef REQUIRED_FUNCTION + + // x.x.x, considering the max number of decimal digits for each component +@@ -73,7 +73,12 @@ static bool OpenLibrary() + + if (libssl == NULL) + { +- // Prefer OpenSSL 1.1.x ++ // Prefer OpenSSL 3.x ++ DlOpen(MAKELIB("3")); ++ } ++ ++ if (libssl == NULL) ++ { + DlOpen(MAKELIB("1.1")); + } + +@@ -117,7 +122,7 @@ static void InitializeOpenSSLShim() + #define REQUIRED_FUNCTION(fn) \ + if (!(fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); } + +-#define NEW_REQUIRED_FUNCTION(fn) \ ++#define REQUIRED_FUNCTION_110(fn) \ + if (!v1_0_sentinel && !(fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); } + + #define LIGHTUP_FUNCTION(fn) \ +@@ -127,8 +132,8 @@ static void InitializeOpenSSLShim() + if (!(fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn)))) { fn##_ptr = (__typeof(fn))local_##fn; } + + #define RENAMED_FUNCTION(fn,oldfn) \ +- if (!v1_0_sentinel && !(fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); } \ +- if (v1_0_sentinel && !(fn##_ptr = (__typeof(fn))(dlsym(libssl, #oldfn)))) { fprintf(stderr, "Cannot get required symbol " #oldfn " from libssl\n"); abort(); } ++ fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn));\ ++ if (!fn##_ptr && !(fn##_ptr = (__typeof(fn))(dlsym(libssl, #oldfn)))) { fprintf(stderr, "Cannot get required symbol " #oldfn " from libssl\n"); abort(); } + + #define LEGACY_FUNCTION(fn) \ + if (v1_0_sentinel && !(fn##_ptr = (__typeof(fn))(dlsym(libssl, #fn)))) { fprintf(stderr, "Cannot get required symbol " #fn " from libssl\n"); abort(); } +@@ -138,8 +143,18 @@ static void InitializeOpenSSLShim() + #undef RENAMED_FUNCTION + #undef FALLBACK_FUNCTION + #undef LIGHTUP_FUNCTION +-#undef NEW_REQUIRED_FUNCTION ++#undef REQUIRED_FUNCTION_110 + #undef REQUIRED_FUNCTION ++ ++ // Sanity check that we have at least one functioning way of reporting errors. ++ if (ERR_put_error_ptr == &local_ERR_put_error) ++ { ++ if (ERR_new_ptr == NULL || ERR_set_debug_ptr == NULL || ERR_set_error_ptr == NULL) ++ { ++ fprintf(stderr, "Cannot determine the error reporting routine from libssl\n"); ++ abort(); ++ } ++ } + } + + __attribute__((destructor)) +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index 4c15914d25..1dc9a8c35c 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -36,6 +36,7 @@ + #include + + #include "pal_crypto_config.h" ++#define OPENSSL_VERSION_3_0_RTM 0x30000000L + #define OPENSSL_VERSION_1_1_1_RTM 0x10101000L + #define OPENSSL_VERSION_1_1_0_RTM 0x10100000L + #define OPENSSL_VERSION_1_0_2_RTM 0x10002000L +@@ -64,6 +65,22 @@ + #undef SSLv23_method + #endif + ++#ifdef ERR_put_error ++#undef ERR_put_error ++void ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file, int32_t line); ++#endif ++ ++// The value -1 has the correct meaning on 1.0.x, but the constant wasn't named. ++#ifndef RSA_PSS_SALTLEN_DIGEST ++#define RSA_PSS_SALTLEN_DIGEST -1 ++#endif ++ ++#if defined FEATURE_DISTRO_AGNOSTIC_SSL || OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM ++#include "apibridge_30_rev.h" ++#endif ++#if defined FEATURE_DISTRO_AGNOSTIC_SSL || OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM ++#include "apibridge_30.h" ++#endif + #if defined FEATURE_DISTRO_AGNOSTIC_SSL || OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM + #include "apibridge.h" + #endif +@@ -72,6 +89,7 @@ + + #define NEED_OPENSSL_1_0 true + #define NEED_OPENSSL_1_1 true ++#define NEED_OPENSSL_3_0 true + + #if !HAVE_OPENSSL_EC2M + // In portable build, we need to support the following functions even if they were not present +@@ -93,110 +111,16 @@ int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str); + const SSL_CIPHER* SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr); + #endif + +-#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM +-typedef struct stack_st _STACK; +-int CRYPTO_add_lock(int* pointer, int amount, int type, const char* file, int line); +-int CRYPTO_num_locks(void); +-void CRYPTO_set_locking_callback(void (*func)(int mode, int type, const char* file, int line)); +-void ERR_load_crypto_strings(void); +-int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX* a); +-int EVP_CIPHER_CTX_init(EVP_CIPHER_CTX* a); +-void HMAC_CTX_cleanup(HMAC_CTX* ctx); +-void HMAC_CTX_init(HMAC_CTX* ctx); +-void OPENSSL_add_all_algorithms_conf(void); +-int SSL_library_init(void); +-void SSL_load_error_strings(void); +-int SSL_state(const SSL* ssl); +-unsigned long SSLeay(void); ++#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM ++#include "osslcompat_102.h" ++#elif OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM ++#include "osslcompat_30.h" ++#include "osslcompat_102.h" + #else +-typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS; +-typedef struct stack_st OPENSSL_STACK; +- +-#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L +-#define OPENSSL_INIT_ADD_ALL_CIPHERS 0x00000004L +-#define OPENSSL_INIT_ADD_ALL_DIGESTS 0x00000008L +-#define OPENSSL_INIT_LOAD_CONFIG 0x00000040L +-#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L +- +-const BIGNUM* DSA_get0_key(const DSA* dsa, const BIGNUM** pubKey, const BIGNUM** privKey); +-void DSA_get0_pqg(const DSA* dsa, const BIGNUM** p, const BIGNUM** q, const BIGNUM** g); +-const DSA_METHOD* DSA_get_method(const DSA* dsa); +-int32_t DSA_set0_key(DSA* dsa, BIGNUM* bnY, BIGNUM* bnX); +-int32_t DSA_set0_pqg(DSA* dsa, BIGNUM* bnP, BIGNUM* bnQ, BIGNUM* bnG); +-void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX* ctx); +-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); +-RSA* EVP_PKEY_get0_RSA(EVP_PKEY* pkey); +-int32_t EVP_PKEY_up_ref(EVP_PKEY* pkey); +-void HMAC_CTX_free(HMAC_CTX* ctx); +-HMAC_CTX* HMAC_CTX_new(void); +-int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS* settings); +-void OPENSSL_sk_free(OPENSSL_STACK*); +-OPENSSL_STACK* OPENSSL_sk_new_null(void); +-int OPENSSL_sk_num(const OPENSSL_STACK*); +-void* OPENSSL_sk_pop(OPENSSL_STACK* st); +-void OPENSSL_sk_pop_free(OPENSSL_STACK* st, void (*func)(void*)); +-int OPENSSL_sk_push(OPENSSL_STACK* st, const void* data); +-void* OPENSSL_sk_value(const OPENSSL_STACK*, int); +-long OpenSSL_version_num(void); +-void RSA_get0_crt_params(const RSA* rsa, const BIGNUM** dmp1, const BIGNUM** dmq1, const BIGNUM** iqmp); +-void RSA_get0_factors(const RSA* rsa, const BIGNUM** p, const BIGNUM** q); +-void RSA_get0_key(const RSA* rsa, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d); +-int32_t RSA_meth_get_flags(const RSA_METHOD* meth); +-const RSA_METHOD* RSA_PKCS1_OpenSSL(void); +-int32_t RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2); +-int32_t RSA_set0_crt_params(RSA* rsa, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp); +-int32_t RSA_set0_factors(RSA* rsa, BIGNUM* p, BIGNUM* q); +-int32_t RSA_set0_key(RSA* rsa, BIGNUM* n, BIGNUM* e, BIGNUM* d); +-int32_t SSL_is_init_finished(SSL* ssl); +-#undef SSL_CTX_set_options +-unsigned long SSL_CTX_set_options(SSL_CTX* ctx, unsigned long options); +-void SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level); +-#undef SSL_session_reused +-int SSL_session_reused(SSL* ssl); +-const SSL_METHOD* TLS_method(void); +-const ASN1_TIME* X509_CRL_get0_nextUpdate(const X509_CRL* crl); +-int32_t X509_NAME_get0_der(X509_NAME* x509Name, const uint8_t** pder, size_t* pderlen); +-int32_t X509_PUBKEY_get0_param( +- ASN1_OBJECT** palgOid, const uint8_t** pkeyBytes, int* pkeyBytesLen, X509_ALGOR** palg, X509_PUBKEY* pubkey); +-X509* X509_STORE_CTX_get0_cert(X509_STORE_CTX* ctx); +-STACK_OF(X509)* X509_STORE_CTX_get0_chain(X509_STORE_CTX* ctx); +-STACK_OF(X509)* X509_STORE_CTX_get0_untrusted(X509_STORE_CTX* ctx); +-X509_VERIFY_PARAM* X509_STORE_get0_param(X509_STORE* ctx); +-const ASN1_TIME* X509_get0_notAfter(const X509* x509); +-const ASN1_TIME* X509_get0_notBefore(const X509* x509); +-ASN1_BIT_STRING* X509_get0_pubkey_bitstr(const X509* x509); +-const X509_ALGOR* X509_get0_tbs_sigalg(const X509* x509); +-X509_PUBKEY* X509_get_X509_PUBKEY(const X509* x509); +-int32_t X509_get_version(const X509* x509); +-int32_t X509_up_ref(X509* x509); +- +-// Redefine EVP_PKEY_CTX_set_rsa operations to use (local_)RSA_pkey_ctx_ctrl so the path is the same +-// for 1.0-built on 1.1 as on 1.1-built on 1.1. +-#undef EVP_PKEY_CTX_set_rsa_keygen_bits +-#define EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) \ +- RSA_pkey_ctx_ctrl(ctx, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL) +- +-// EVP_PKEY_CTX_set_rsa_oaep_md doesn't call RSA_pkey_ctx_ctrl in 1.1, so don't redefine it here. +- +-#undef EVP_PKEY_CTX_set_rsa_padding +-#define EVP_PKEY_CTX_set_rsa_padding(ctx, pad) \ +- RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL) +- +-#undef EVP_PKEY_CTX_set_rsa_pss_saltlen +-#define EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, len) \ +- RSA_pkey_ctx_ctrl(ctx, (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), EVP_PKEY_CTRL_RSA_PSS_SALTLEN, len, NULL) +- ++#include "osslcompat_30.h" ++#include "osslcompat_111.h" + #endif + +-#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM +-X509_STORE* X509_STORE_CTX_get0_store(X509_STORE_CTX* ctx); +-int32_t X509_check_host(X509* x509, const char* name, size_t namelen, unsigned int flags, char** peername); +-#define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 4 +- +-#endif + + #if !HAVE_OPENSSL_ALPN + #undef HAVE_OPENSSL_ALPN +@@ -213,11 +137,6 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx, + void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsigned int* len); + #endif + +-// The value -1 has the correct meaning on 1.0.x, but the constant wasn't named. +-#ifndef RSA_PSS_SALTLEN_DIGEST +-#define RSA_PSS_SALTLEN_DIGEST -1 +-#endif +- + #define API_EXISTS(fn) (fn != NULL) + + // List of all functions from the libssl that are used in the System.Security.Cryptography.Native. +@@ -326,10 +245,13 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(ERR_error_string_n) \ + REQUIRED_FUNCTION(ERR_get_error) \ + LEGACY_FUNCTION(ERR_load_crypto_strings) \ +- REQUIRED_FUNCTION(ERR_put_error) \ ++ LIGHTUP_FUNCTION(ERR_new) \ + REQUIRED_FUNCTION(ERR_peek_error) \ + REQUIRED_FUNCTION(ERR_peek_last_error) \ ++ FALLBACK_FUNCTION(ERR_put_error) \ + REQUIRED_FUNCTION(ERR_reason_error_string) \ ++ LIGHTUP_FUNCTION(ERR_set_debug) \ ++ LIGHTUP_FUNCTION(ERR_set_error) \ + REQUIRED_FUNCTION(EVP_aes_128_cbc) \ + REQUIRED_FUNCTION(EVP_aes_128_ccm) \ + REQUIRED_FUNCTION(EVP_aes_128_ecb) \ +@@ -370,6 +292,11 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + 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_rsa_keygen_bits) \ ++ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_oaep_md) \ ++ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_padding) \ ++ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_pss_saltlen) \ ++ FALLBACK_FUNCTION(EVP_PKEY_CTX_set_signature_md) \ + REQUIRED_FUNCTION(EVP_PKEY_base_id) \ + REQUIRED_FUNCTION(EVP_PKEY_decrypt) \ + REQUIRED_FUNCTION(EVP_PKEY_decrypt_init) \ +@@ -438,7 +365,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(OCSP_RESPONSE_new) \ + LEGACY_FUNCTION(OPENSSL_add_all_algorithms_conf) \ + REQUIRED_FUNCTION(OPENSSL_cleanse) \ +- NEW_REQUIRED_FUNCTION(OPENSSL_init_ssl) \ ++ REQUIRED_FUNCTION_110(OPENSSL_init_ssl) \ + RENAMED_FUNCTION(OPENSSL_sk_free, sk_free) \ + RENAMED_FUNCTION(OPENSSL_sk_new_null, sk_new_null) \ + RENAMED_FUNCTION(OPENSSL_sk_num, sk_num) \ +@@ -510,11 +437,11 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(SSL_get_error) \ + REQUIRED_FUNCTION(SSL_get_finished) \ + REQUIRED_FUNCTION(SSL_get_peer_cert_chain) \ +- REQUIRED_FUNCTION(SSL_get_peer_certificate) \ + REQUIRED_FUNCTION(SSL_get_peer_finished) \ + REQUIRED_FUNCTION(SSL_get_SSL_CTX) \ + REQUIRED_FUNCTION(SSL_get_version) \ + LIGHTUP_FUNCTION(SSL_get0_alpn_selected) \ ++ RENAMED_FUNCTION(SSL_get1_peer_certificate, SSL_get_peer_certificate) \ + LEGACY_FUNCTION(SSL_library_init) \ + LEGACY_FUNCTION(SSL_load_error_strings) \ + REQUIRED_FUNCTION(SSL_new) \ +@@ -606,7 +533,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + + // Declare pointers to all the used OpenSSL functions + #define REQUIRED_FUNCTION(fn) extern __typeof(fn)* fn##_ptr; +-#define NEW_REQUIRED_FUNCTION(fn) extern __typeof(fn)* fn##_ptr; ++#define REQUIRED_FUNCTION_110(fn) extern __typeof(fn)* fn##_ptr; + #define LIGHTUP_FUNCTION(fn) extern __typeof(fn)* fn##_ptr; + #define FALLBACK_FUNCTION(fn) extern __typeof(fn)* fn##_ptr; + #define RENAMED_FUNCTION(fn,oldfn) extern __typeof(fn)* fn##_ptr; +@@ -616,7 +543,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #undef RENAMED_FUNCTION + #undef FALLBACK_FUNCTION + #undef LIGHTUP_FUNCTION +-#undef NEW_REQUIRED_FUNCTION ++#undef REQUIRED_FUNCTION_110 + #undef REQUIRED_FUNCTION + + // Redefine all calls to OpenSSL functions as calls through pointers that are set +@@ -722,10 +649,13 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define ERR_error_string_n ERR_error_string_n_ptr + #define ERR_get_error ERR_get_error_ptr + #define ERR_load_crypto_strings ERR_load_crypto_strings_ptr ++#define ERR_new ERR_new_ptr + #define ERR_peek_error ERR_peek_error_ptr + #define ERR_peek_last_error ERR_peek_last_error_ptr + #define ERR_put_error ERR_put_error_ptr + #define ERR_reason_error_string ERR_reason_error_string_ptr ++#define ERR_set_debug ERR_set_debug_ptr ++#define ERR_set_error ERR_set_error_ptr + #define EVP_aes_128_cbc EVP_aes_128_cbc_ptr + #define EVP_aes_128_ecb EVP_aes_128_ecb_ptr + #define EVP_aes_128_gcm EVP_aes_128_gcm_ptr +@@ -766,6 +696,11 @@ 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_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 ++#define EVP_PKEY_CTX_set_rsa_pss_saltlen EVP_PKEY_CTX_set_rsa_pss_saltlen_ptr ++#define EVP_PKEY_CTX_set_signature_md EVP_PKEY_CTX_set_signature_md_ptr + #define EVP_PKEY_base_id EVP_PKEY_base_id_ptr + #define EVP_PKEY_decrypt_init EVP_PKEY_decrypt_init_ptr + #define EVP_PKEY_decrypt EVP_PKEY_decrypt_ptr +@@ -875,13 +810,6 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define RSA_size RSA_size_ptr + #define RSA_up_ref RSA_up_ref_ptr + #define RSA_verify RSA_verify_ptr +-#define sk_free OPENSSL_sk_free_ptr +-#define sk_new_null OPENSSL_sk_new_null_ptr +-#define sk_num OPENSSL_sk_num_ptr +-#define sk_pop OPENSSL_sk_pop_ptr +-#define sk_pop_free OPENSSL_sk_pop_free_ptr +-#define sk_push OPENSSL_sk_push_ptr +-#define sk_value OPENSSL_sk_value_ptr + #define SSL_CIPHER_get_bits SSL_CIPHER_get_bits_ptr + #define SSL_CIPHER_find SSL_CIPHER_find_ptr + #define SSL_CIPHER_get_id SSL_CIPHER_get_id_ptr +@@ -912,11 +840,11 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define SSL_get_error SSL_get_error_ptr + #define SSL_get_finished SSL_get_finished_ptr + #define SSL_get_peer_cert_chain SSL_get_peer_cert_chain_ptr +-#define SSL_get_peer_certificate SSL_get_peer_certificate_ptr + #define SSL_get_peer_finished SSL_get_peer_finished_ptr + #define SSL_get_SSL_CTX SSL_get_SSL_CTX_ptr + #define SSL_get_version SSL_get_version_ptr + #define SSL_get0_alpn_selected SSL_get0_alpn_selected_ptr ++#define SSL_get1_peer_certificate SSL_get1_peer_certificate_ptr + #define SSL_is_init_finished SSL_is_init_finished_ptr + #define SSL_library_init SSL_library_init_ptr + #define SSL_load_error_strings SSL_load_error_strings_ptr +@@ -1011,7 +939,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + // STACK_OF types will have been declared with inline functions to handle the pointer casting. + // Since these inline functions are strongly bound to the OPENSSL_sk_* functions in 1.1 we need to + // rebind things here. +-#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM ++#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM + // type-safe OPENSSL_sk_free + #define sk_GENERAL_NAME_free(stack) OPENSSL_sk_free((OPENSSL_STACK*)(1 ? stack : (STACK_OF(GENERAL_NAME)*)0)) + #define sk_X509_free(stack) OPENSSL_sk_free((OPENSSL_STACK*)(1 ? stack : (STACK_OF(X509)*)0)) +@@ -1039,6 +967,17 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define sk_GENERAL_NAME_value(stack, idx) (GENERAL_NAME*)OPENSSL_sk_value((const OPENSSL_STACK*)(1 ? stack : (const STACK_OF(GENERAL_NAME)*)0), idx) + #define sk_X509_NAME_value(stack, idx) (X509_NAME*)OPENSSL_sk_value((const OPENSSL_STACK*)(1 ? stack : (const STACK_OF(X509_NAME)*)0), idx) + #define sk_X509_value(stack, idx) (X509*)OPENSSL_sk_value((const OPENSSL_STACK*)(1 ? stack : (const STACK_OF(X509)*)0), idx) ++ ++#elif OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM ++ ++#define sk_free OPENSSL_sk_free_ptr ++#define sk_new_null OPENSSL_sk_new_null_ptr ++#define sk_num OPENSSL_sk_num_ptr ++#define sk_pop OPENSSL_sk_pop_ptr ++#define sk_pop_free OPENSSL_sk_pop_free_ptr ++#define sk_push OPENSSL_sk_push_ptr ++#define sk_value OPENSSL_sk_value_ptr ++ + #endif + + +@@ -1046,9 +985,26 @@ FOR_ALL_OPENSSL_FUNCTIONS + + #define API_EXISTS(fn) true + +-#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM +- ++#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM ++#define NEED_OPENSSL_3_0 true ++#elif OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM ++#define NEED_OPENSSL_1_1 true ++#else + #define NEED_OPENSSL_1_0 true ++#endif ++ ++#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM ++ ++// Undo renames for renamed-in-3.0 ++#define SSL_get1_peer_certificate SSL_get_peer_certificate ++ ++#endif ++ ++#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM ++ ++#define ERR_put_error local_ERR_put_error ++ ++#elif OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM + + // Alias "future" API to the local_ version. + #define DSA_get0_key local_DSA_get0_key +@@ -1110,10 +1066,6 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define OPENSSL_sk_value sk_value + #define TLS_method SSLv23_method + +-#else // if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0_RTM +- +-#define NEED_OPENSSL_1_1 true +- + #endif + + #endif // FEATURE_DISTRO_AGNOSTIC_SSL +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_102.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_102.h +new file mode 100644 +index 0000000000..2ee440c320 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_102.h +@@ -0,0 +1,34 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++// ++ ++#pragma once ++ ++// Function prototypes unique to OpenSSL 1.0.2 ++ ++typedef struct stack_st _STACK; ++ ++#undef CRYPTO_num_locks ++#undef CRYPTO_set_locking_callback ++#undef ERR_load_crypto_strings ++#undef EVP_CIPHER_CTX_cleanup ++#undef EVP_CIPHER_CTX_init ++#undef OPENSSL_add_all_algorithms_conf ++#undef SSL_library_init ++#undef SSL_load_error_strings ++#undef SSL_state ++#undef SSLeay ++ ++int CRYPTO_add_lock(int* pointer, int amount, int type, const char* file, int line); ++int CRYPTO_num_locks(void); ++void CRYPTO_set_locking_callback(void (*func)(int mode, int type, const char* file, int line)); ++void ERR_load_crypto_strings(void); ++int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX* a); ++int EVP_CIPHER_CTX_init(EVP_CIPHER_CTX* a); ++void HMAC_CTX_cleanup(HMAC_CTX* ctx); ++void HMAC_CTX_init(HMAC_CTX* ctx); ++void OPENSSL_add_all_algorithms_conf(void); ++int SSL_library_init(void); ++void SSL_load_error_strings(void); ++int SSL_state(const SSL* ssl); ++unsigned long SSLeay(void); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h +new file mode 100644 +index 0000000000..0a730cef89 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_111.h +@@ -0,0 +1,80 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++// Function prototypes unique to OpenSSL 1.1.x ++ ++#pragma once ++#include "pal_types.h" ++ ++#undef SSL_CTX_set_options ++#undef SSL_session_reused ++ ++typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS; ++typedef struct stack_st OPENSSL_STACK; ++ ++#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L ++#define OPENSSL_INIT_ADD_ALL_CIPHERS 0x00000004L ++#define OPENSSL_INIT_ADD_ALL_DIGESTS 0x00000008L ++#define OPENSSL_INIT_LOAD_CONFIG 0x00000040L ++#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L ++ ++const BIGNUM* DSA_get0_key(const DSA* dsa, const BIGNUM** pubKey, const BIGNUM** privKey); ++void DSA_get0_pqg(const DSA* dsa, const BIGNUM** p, const BIGNUM** q, const BIGNUM** g); ++const DSA_METHOD* DSA_get_method(const DSA* dsa); ++int32_t DSA_set0_key(DSA* dsa, BIGNUM* bnY, BIGNUM* bnX); ++int32_t DSA_set0_pqg(DSA* dsa, BIGNUM* bnP, BIGNUM* bnQ, BIGNUM* bnG); ++void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX* ctx); ++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); ++RSA* EVP_PKEY_get0_RSA(EVP_PKEY* pkey); ++int32_t EVP_PKEY_up_ref(EVP_PKEY* pkey); ++void HMAC_CTX_free(HMAC_CTX* ctx); ++HMAC_CTX* HMAC_CTX_new(void); ++int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS* settings); ++void OPENSSL_sk_free(OPENSSL_STACK*); ++OPENSSL_STACK* OPENSSL_sk_new_null(void); ++int OPENSSL_sk_num(const OPENSSL_STACK*); ++void* OPENSSL_sk_pop(OPENSSL_STACK* st); ++void OPENSSL_sk_pop_free(OPENSSL_STACK* st, void (*func)(void*)); ++int OPENSSL_sk_push(OPENSSL_STACK* st, const void* data); ++void* OPENSSL_sk_value(const OPENSSL_STACK*, int); ++long OpenSSL_version_num(void); ++const RSA_METHOD* RSA_PKCS1_OpenSSL(void); ++void RSA_get0_crt_params(const RSA* rsa, const BIGNUM** dmp1, const BIGNUM** dmq1, const BIGNUM** iqmp); ++void RSA_get0_factors(const RSA* rsa, const BIGNUM** p, const BIGNUM** q); ++void RSA_get0_key(const RSA* rsa, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d); ++int32_t RSA_meth_get_flags(const RSA_METHOD* meth); ++int32_t RSA_pkey_ctx_ctrl(EVP_PKEY_CTX* ctx, int32_t optype, int32_t cmd, int32_t p1, void* p2); ++int32_t RSA_set0_crt_params(RSA* rsa, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp); ++int32_t RSA_set0_factors(RSA* rsa, BIGNUM* p, BIGNUM* q); ++int32_t RSA_set0_key(RSA* rsa, BIGNUM* n, BIGNUM* e, BIGNUM* d); ++int SSL_CTX_config(SSL_CTX* ctx, const char* name); ++unsigned long SSL_CTX_set_options(SSL_CTX* ctx, unsigned long options); ++void SSL_CTX_set_security_level(SSL_CTX* ctx, int32_t level); ++int32_t SSL_is_init_finished(SSL* ssl); ++int SSL_session_reused(SSL* ssl); ++const SSL_METHOD* TLS_method(void); ++const ASN1_TIME* X509_CRL_get0_nextUpdate(const X509_CRL* crl); ++int32_t X509_NAME_get0_der(X509_NAME* x509Name, const uint8_t** pder, size_t* pderlen); ++int32_t X509_PUBKEY_get0_param( ++ ASN1_OBJECT** palgOid, const uint8_t** pkeyBytes, int* pkeyBytesLen, X509_ALGOR** palg, X509_PUBKEY* pubkey); ++X509* X509_STORE_CTX_get0_cert(X509_STORE_CTX* ctx); ++STACK_OF(X509) * X509_STORE_CTX_get0_chain(X509_STORE_CTX* ctx); ++STACK_OF(X509) * X509_STORE_CTX_get0_untrusted(X509_STORE_CTX* ctx); ++X509_VERIFY_PARAM* X509_STORE_get0_param(X509_STORE* ctx); ++const ASN1_TIME* X509_get0_notAfter(const X509* x509); ++const ASN1_TIME* X509_get0_notBefore(const X509* x509); ++ASN1_BIT_STRING* X509_get0_pubkey_bitstr(const X509* x509); ++const X509_ALGOR* X509_get0_tbs_sigalg(const X509* x509); ++X509_PUBKEY* X509_get_X509_PUBKEY(const X509* x509); ++int32_t X509_get_version(const X509* x509); ++int32_t X509_up_ref(X509* x509); ++ ++#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_0_2_RTM ++int32_t X509_check_host(X509* x509, const char* name, size_t namelen, unsigned int flags, char** peername); ++X509_STORE* X509_STORE_CTX_get0_store(X509_STORE_CTX* ctx); ++#define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 4 ++ ++#endif +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +new file mode 100644 +index 0000000000..0fe57c9132 +--- /dev/null ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +@@ -0,0 +1,23 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++// Function prototypes unique to OpenSSL 3.0 ++ ++#pragma once ++#include "pal_types.h" ++ ++#undef EVP_PKEY_CTX_set_rsa_keygen_bits ++#undef EVP_PKEY_CTX_set_rsa_oaep_md ++#undef EVP_PKEY_CTX_set_rsa_padding ++#undef EVP_PKEY_CTX_set_rsa_pss_saltlen ++#undef EVP_PKEY_CTX_set_signature_md ++ ++void ERR_new(void); ++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_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); ++X509* SSL_get1_peer_certificate(const SSL* ssl); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c +index 7764464bc8..c2e3fb2028 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_ssl.c +@@ -285,7 +285,7 @@ int32_t CryptoNative_IsSslStateOK(SSL* ssl) + + X509* CryptoNative_SslGetPeerCertificate(SSL* ssl) + { +- return SSL_get_peer_certificate(ssl); ++ return SSL_get1_peer_certificate(ssl); + } + + X509Stack* CryptoNative_SslGetPeerCertChain(SSL* ssl) +-- +2.31.1 + diff --git a/SOURCES/corefx-openssl-0006-Fix-merge-issues-and-make-the-build-work.patch b/SOURCES/corefx-openssl-0006-Fix-merge-issues-and-make-the-build-work.patch new file mode 100644 index 0000000..ff0de38 --- /dev/null +++ b/SOURCES/corefx-openssl-0006-Fix-merge-issues-and-make-the-build-work.patch @@ -0,0 +1,36 @@ +From 5848349f1e0df84949a01b41d41904036cc070f7 Mon Sep 17 00:00:00 2001 +From: Omair Majid +Date: Fri, 4 Jun 2021 17:21:28 -0400 +Subject: [PATCH 06/11] Fix merge issues and make the build work + +--- + .../Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs +index a7f777261e..d5ec28b1ae 100644 +--- a/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs ++++ b/src/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs +@@ -370,8 +370,8 @@ internal void Finish(OidCollection applicationPolicy, OidCollection certificateP + // chain is just fine (unless it returned a negative code for an exception) + Debug.Assert(verify, "verify should have returned true"); + +- const Interop.Crypto.X509VerifyStatusCode NoCrl = +- Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_UNABLE_TO_GET_CRL; ++ Interop.Crypto.X509VerifyStatusCode NoCrl = ++ X509VerifyStatusCodeUniversal.X509_V_ERR_UNABLE_TO_GET_CRL; + + ErrorCollection? errors = + workingChain.LastError > 0 ? (ErrorCollection?)workingChain[0] : null; +@@ -726,7 +726,7 @@ private static ArraySegment Base64UrlEncode(ReadOnlySpan input) + X509ChainStatus chainStatus = new X509ChainStatus + { + Status = statusFlag, +- StatusInformation = Interop.Crypto.GetX509VerifyCertErrorString(errorCode), ++ StatusInformation = Interop.Crypto.GetX509VerifyCertErrorString(errorCode.Code), + }; + + elementStatus.Add(chainStatus); +-- +2.31.1 + diff --git a/SOURCES/corefx-openssl-0007-OpenSSL3-Register-legacy-algorithms-when-needed.patch b/SOURCES/corefx-openssl-0007-OpenSSL3-Register-legacy-algorithms-when-needed.patch new file mode 100644 index 0000000..9de0b17 --- /dev/null +++ b/SOURCES/corefx-openssl-0007-OpenSSL3-Register-legacy-algorithms-when-needed.patch @@ -0,0 +1,179 @@ +From 7f171bb20e0816cd2d5af57437553f1a31a886af Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Thu, 15 Apr 2021 08:06:27 -0700 +Subject: [PATCH 07/11] OpenSSL3: Register legacy algorithms when needed + +--- + .../Interop.LegacyAlgorithms.cs | 31 +++++++++++++++++++ + .../openssl.c | 10 ++++++ + .../openssl.h | 2 ++ + .../opensslshim.h | 6 ++++ + .../osslcompat_30.h | 4 +++ + .../Cryptography/DesImplementation.Unix.cs | 2 ++ + .../Cryptography/RC2Implementation.Unix.cs | 2 ++ + ...em.Security.Cryptography.Algorithms.csproj | 3 ++ + 8 files changed, 60 insertions(+) + create mode 100644 src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.LegacyAlgorithms.cs + +diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.LegacyAlgorithms.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.LegacyAlgorithms.cs +new file mode 100644 +index 0000000000..800b14b788 +--- /dev/null ++++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.LegacyAlgorithms.cs +@@ -0,0 +1,31 @@ ++// Licensed to the .NET Foundation under one or more agreements. ++// The .NET Foundation licenses this file to you under the MIT license. ++ ++using System.Runtime.InteropServices; ++ ++internal static partial class Interop ++{ ++ internal static partial class Crypto ++ { ++ private static volatile bool s_loadedLegacy; ++ private static readonly object s_legacyLoadLock = new object(); ++ ++ [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_RegisterLegacyAlgorithms")] ++ private static extern void CryptoNative_RegisterLegacyAlgorithms(); ++ ++ internal static void EnsureLegacyAlgorithmsRegistered() ++ { ++ if (!s_loadedLegacy) ++ { ++ lock (s_legacyLoadLock) ++ { ++ if (!s_loadedLegacy) ++ { ++ CryptoNative_RegisterLegacyAlgorithms(); ++ s_loadedLegacy = true; ++ } ++ } ++ } ++ } ++ } ++} +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/openssl.c b/src/Native/Unix/System.Security.Cryptography.Native/openssl.c +index 456741360d..6792bdb1a1 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/openssl.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/openssl.c +@@ -1117,6 +1117,16 @@ int64_t CryptoNative_OpenSslVersionNumber() + return (int64_t)OpenSSL_version_num(); + } + ++void CryptoNative_RegisterLegacyAlgorithms() ++{ ++#if NEED_OPENSSL_3_0 ++ if (API_EXISTS(OSSL_PROVIDER_try_load)) ++ { ++ OSSL_PROVIDER_try_load(NULL, "legacy", 1); ++ } ++#endif ++} ++ + #ifdef NEED_OPENSSL_1_0 + // Lock used to make sure EnsureopenSslInitialized itself is thread safe + static pthread_mutex_t g_initLock = PTHREAD_MUTEX_INITIALIZER; +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/openssl.h b/src/Native/Unix/System.Security.Cryptography.Native/openssl.h +index 1b4604024e..7bf0da2426 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/openssl.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/openssl.h +@@ -73,3 +73,5 @@ DLLEXPORT int32_t CryptoNative_LookupFriendlyNameByOid(const char* oidValue, con + DLLEXPORT int32_t CryptoNative_EnsureOpenSslInitialized(void); + + DLLEXPORT int64_t CryptoNative_OpenSslVersionNumber(void); ++ ++DLLEXPORT void CryptoNative_RegisterLegacyAlgorithms(void); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index 1dc9a8c35c..957860cae4 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -41,6 +41,10 @@ + #define OPENSSL_VERSION_1_1_0_RTM 0x10100000L + #define OPENSSL_VERSION_1_0_2_RTM 0x10002000L + ++#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM ++#include ++#endif ++ + #if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_1_RTM + #define HAVE_OPENSSL_SET_CIPHERSUITES 1 + #else +@@ -374,6 +378,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + RENAMED_FUNCTION(OPENSSL_sk_push, sk_push) \ + RENAMED_FUNCTION(OPENSSL_sk_value, sk_value) \ + FALLBACK_FUNCTION(OpenSSL_version_num) \ ++ LIGHTUP_FUNCTION(OSSL_PROVIDER_try_load) \ + REQUIRED_FUNCTION(PEM_read_bio_PKCS7) \ + REQUIRED_FUNCTION(PEM_read_bio_X509) \ + REQUIRED_FUNCTION(PEM_read_bio_X509_AUX) \ +@@ -778,6 +783,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define OPENSSL_sk_push OPENSSL_sk_push_ptr + #define OPENSSL_sk_value OPENSSL_sk_value_ptr + #define OpenSSL_version_num OpenSSL_version_num_ptr ++#define OSSL_PROVIDER_try_load OSSL_PROVIDER_try_load_ptr + #define PEM_read_bio_PKCS7 PEM_read_bio_PKCS7_ptr + #define PEM_read_bio_X509 PEM_read_bio_X509_ptr + #define PEM_read_bio_X509_AUX PEM_read_bio_X509_AUX_ptr +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +index 0fe57c9132..b87b4e7250 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +@@ -12,6 +12,9 @@ + #undef EVP_PKEY_CTX_set_rsa_pss_saltlen + #undef EVP_PKEY_CTX_set_signature_md + ++typedef struct ossl_provider_st OSSL_PROVIDER; ++typedef struct ossl_lib_ctx_st OSSL_LIB_CTX; ++ + void ERR_new(void); + void ERR_set_debug(const char *file, int line, const char *func); + void ERR_set_error(int lib, int reason, const char *fmt, ...); +@@ -20,4 +23,5 @@ 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); ++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/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/DesImplementation.Unix.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/DesImplementation.Unix.cs +index 721efeec6c..0416a86577 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/DesImplementation.Unix.cs ++++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/DesImplementation.Unix.cs +@@ -31,6 +31,8 @@ partial class DesImplementation + throw new NotSupportedException(); + } + ++ Interop.Crypto.EnsureLegacyAlgorithmsRegistered(); ++ + BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, key, 0, iv, encrypting); + return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting); + } +diff --git a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RC2Implementation.Unix.cs b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RC2Implementation.Unix.cs +index 0c06cdbcf7..93e5e9a713 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RC2Implementation.Unix.cs ++++ b/src/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/RC2Implementation.Unix.cs +@@ -33,6 +33,8 @@ partial class RC2Implementation + throw new NotSupportedException(); + } + ++ Interop.Crypto.EnsureLegacyAlgorithmsRegistered(); ++ + BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, key, effectiveKeyLength, iv, encrypting); + return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting); + } +diff --git a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +index c6e8b5b69a..cf5c6731c2 100644 +--- a/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj ++++ b/src/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +@@ -519,6 +519,9 @@ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.Hmac.cs + ++ ++ Common\Interop\Unix\System.Security.Cryptography.Native\Interop.LegacyAlgorithms.cs ++ + + Common\Interop\Unix\System.Security.Cryptography.Native\Interop.RAND.cs + +-- +2.31.1 + diff --git a/SOURCES/corefx-openssl-0008-Work-around-OpenSSL-3.0-ciphers-not-restoring-origin.patch b/SOURCES/corefx-openssl-0008-Work-around-OpenSSL-3.0-ciphers-not-restoring-origin.patch new file mode 100644 index 0000000..b6d1267 --- /dev/null +++ b/SOURCES/corefx-openssl-0008-Work-around-OpenSSL-3.0-ciphers-not-restoring-origin.patch @@ -0,0 +1,79 @@ +From 30e2e4cbb11a4fbdb7102133b19bfc990a2ba939 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Fri, 16 Apr 2021 09:38:47 -0700 +Subject: [PATCH 08/11] Work around OpenSSL 3.0 ciphers not restoring original + IV on reset. + +--- + .../opensslshim.h | 2 ++ + .../osslcompat_30.h | 1 + + .../pal_evp_cipher.c | 20 ++++++++++++++++++- + 3 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index 957860cae4..c5052c1ba5 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -271,6 +271,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + LEGACY_FUNCTION(EVP_CIPHER_CTX_cleanup) \ + REQUIRED_FUNCTION(EVP_CIPHER_CTX_ctrl) \ + FALLBACK_FUNCTION(EVP_CIPHER_CTX_free) \ ++ LIGHTUP_FUNCTION(EVP_CIPHER_CTX_get_original_iv) \ + LEGACY_FUNCTION(EVP_CIPHER_CTX_init) \ + FALLBACK_FUNCTION(EVP_CIPHER_CTX_new) \ + FALLBACK_FUNCTION(EVP_CIPHER_CTX_reset) \ +@@ -676,6 +677,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_CIPHER_CTX_cleanup EVP_CIPHER_CTX_cleanup_ptr + #define EVP_CIPHER_CTX_ctrl EVP_CIPHER_CTX_ctrl_ptr + #define EVP_CIPHER_CTX_free EVP_CIPHER_CTX_free_ptr ++#define EVP_CIPHER_CTX_get_original_iv EVP_CIPHER_CTX_get_original_iv_ptr + #define EVP_CIPHER_CTX_init EVP_CIPHER_CTX_init_ptr + #define EVP_CIPHER_CTX_new EVP_CIPHER_CTX_new_ptr + #define EVP_CIPHER_CTX_reset EVP_CIPHER_CTX_reset_ptr +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +index b87b4e7250..bb529df51e 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +@@ -18,6 +18,7 @@ typedef struct ossl_lib_ctx_st OSSL_LIB_CTX; + void ERR_new(void); + 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_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); +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c +index af2483fa0c..4d21294fa1 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_cipher.c +@@ -127,8 +127,26 @@ int32_t CryptoNative_EvpCipherReset(EVP_CIPHER_CTX* ctx) + // + // But since we have a different object returned for CreateEncryptor + // and CreateDecryptor we don't need to worry about that. ++ uint8_t* iv = NULL; + +- return EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, KEEP_CURRENT_DIRECTION); ++#ifdef NEED_OPENSSL_3_0 ++ // OpenSSL 3.0 alpha 13 does not properly reset the IV. Work around that by ++ // asking for the original IV, and giving it back. ++ uint8_t tmpIV[EVP_MAX_IV_LENGTH]; ++ ++ // If we're direct against 3.0, or we're portable and found 3.0 ++ if (API_EXISTS(EVP_CIPHER_CTX_get_original_iv)) ++ { ++ if (EVP_CIPHER_CTX_get_original_iv(ctx, tmpIV, sizeof(tmpIV)) != 1) ++ { ++ return 0; ++ } ++ ++ iv = tmpIV; ++ } ++#endif ++ ++ return EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, KEEP_CURRENT_DIRECTION); + } + + int32_t CryptoNative_EvpCipherCtxSetPadding(EVP_CIPHER_CTX* x, int32_t padding) +-- +2.31.1 + diff --git a/SOURCES/corefx-openssl-0009-Use-1-instead-of-true-for-more-portable-code.patch b/SOURCES/corefx-openssl-0009-Use-1-instead-of-true-for-more-portable-code.patch new file mode 100644 index 0000000..8bf261b --- /dev/null +++ b/SOURCES/corefx-openssl-0009-Use-1-instead-of-true-for-more-portable-code.patch @@ -0,0 +1,48 @@ +From b7700862a9a85e5bab302c158d5aa6ac1af7c5c1 Mon Sep 17 00:00:00 2001 +From: Omair Majid +Date: Mon, 7 Jun 2021 11:37:48 -0400 +Subject: [PATCH 09/11] Use `1` instead of `true` for more portable code + +--- + .../opensslshim.h | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index c5052c1ba5..b0d1a71671 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -91,9 +91,9 @@ void ERR_put_error(int32_t lib, int32_t func, int32_t reason, const char* file, + + #ifdef FEATURE_DISTRO_AGNOSTIC_SSL + +-#define NEED_OPENSSL_1_0 true +-#define NEED_OPENSSL_1_1 true +-#define NEED_OPENSSL_3_0 true ++#define NEED_OPENSSL_1_0 1 ++#define NEED_OPENSSL_1_1 1 ++#define NEED_OPENSSL_3_0 1 + + #if !HAVE_OPENSSL_EC2M + // In portable build, we need to support the following functions even if they were not present +@@ -991,14 +991,14 @@ FOR_ALL_OPENSSL_FUNCTIONS + + #else // FEATURE_DISTRO_AGNOSTIC_SSL + +-#define API_EXISTS(fn) true ++#define API_EXISTS(fn) 1 + + #if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_3_0_RTM +-#define NEED_OPENSSL_3_0 true ++#define NEED_OPENSSL_3_0 1 + #elif OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_1_0_RTM +-#define NEED_OPENSSL_1_1 true ++#define NEED_OPENSSL_1_1 1 + #else +-#define NEED_OPENSSL_1_0 true ++#define NEED_OPENSSL_1_0 1 + #endif + + #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM +-- +2.31.1 + diff --git a/SOURCES/corefx-openssl-0010-Stop-using-ERR_GET_FUNC-since-it-has-been-removed-in.patch b/SOURCES/corefx-openssl-0010-Stop-using-ERR_GET_FUNC-since-it-has-been-removed-in.patch new file mode 100644 index 0000000..6faad01 --- /dev/null +++ b/SOURCES/corefx-openssl-0010-Stop-using-ERR_GET_FUNC-since-it-has-been-removed-in.patch @@ -0,0 +1,80 @@ +From c746b2a3bd8ae3b76740e2b4f2cf12646eedbb51 Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Sat, 21 Aug 2021 05:05:19 -0700 +Subject: [PATCH 10/11] Stop using ERR_GET_FUNC, since it has been removed in + OSSL3 Beta2. (#57869) + +--- + .../openssl.c | 25 +++++++++++-------- + .../opensslshim.h | 2 ++ + 2 files changed, 16 insertions(+), 11 deletions(-) + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/openssl.c b/src/Native/Unix/System.Security.Cryptography.Native/openssl.c +index 6792bdb1a1..e55486dc80 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/openssl.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/openssl.c +@@ -1064,27 +1064,30 @@ int32_t CryptoNative_LookupFriendlyNameByOid(const char* oidValue, const char** + return -2; + } + ++ // First, check if oidValue parses as a dotted decimal OID. If not, we'll ++ // return not-found and let the system cache that. ++ int asnRet = a2d_ASN1_OBJECT(NULL, 0, oidValue, -1); ++ ++ if (asnRet <= 0) ++ { ++ return 0; ++ } ++ + // Do a lookup with no_name set. The purpose of this function is to map only the + // dotted decimal to the friendly name. "sha1" in should not result in "sha1" out. + oid = OBJ_txt2obj(oidValue, 1); + +- if (!oid) ++ if (oid == NULL) + { +- unsigned long err = ERR_peek_last_error(); +- +- // If the most recent error pushed onto the error queue is NOT from OID parsing +- // then signal for an exception to be thrown. +- if (err != 0 && ERR_GET_FUNC(err) != ASN1_F_A2D_ASN1_OBJECT) +- { +- return -1; +- } +- +- return 0; ++ // We know that the OID parsed (unless it underwent concurrent modification, ++ // which is unsupported), so any error in this stage should be an exception. ++ return -1; + } + + // Look in the predefined, and late-registered, OIDs list to get the lookup table + // identifier for this OID. The OBJ_txt2obj object will not have ln set. + nid = OBJ_obj2nid(oid); ++ ASN1_OBJECT_free(oid); + + if (nid == NID_undef) + { +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index b0d1a71671..c11285e7dd 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -148,6 +148,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + // that needs to be added. + + #define FOR_ALL_OPENSSL_FUNCTIONS \ ++ REQUIRED_FUNCTION(a2d_ASN1_OBJECT) \ + REQUIRED_FUNCTION(ASN1_BIT_STRING_free) \ + REQUIRED_FUNCTION(ASN1_d2i_bio) \ + REQUIRED_FUNCTION(ASN1_i2d_bio) \ +@@ -554,6 +555,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + + // Redefine all calls to OpenSSL functions as calls through pointers that are set + // to the functions from the libssl.so selected by the shim. ++#define a2d_ASN1_OBJECT a2d_ASN1_OBJECT_ptr + #define ASN1_BIT_STRING_free ASN1_BIT_STRING_free_ptr + #define ASN1_GENERALIZEDTIME_free ASN1_GENERALIZEDTIME_free_ptr + #define ASN1_d2i_bio ASN1_d2i_bio_ptr +-- +2.31.1 + diff --git a/SOURCES/corefx-openssl-0011-Adjust-crypto-shim-for-functions-renamed-for-OSSL3-b.patch b/SOURCES/corefx-openssl-0011-Adjust-crypto-shim-for-functions-renamed-for-OSSL3-b.patch new file mode 100644 index 0000000..39c30e8 --- /dev/null +++ b/SOURCES/corefx-openssl-0011-Adjust-crypto-shim-for-functions-renamed-for-OSSL3-b.patch @@ -0,0 +1,140 @@ +From 05fb8ceb229d76ae32bd18e707b3682c8302490c Mon Sep 17 00:00:00 2001 +From: Jeremy Barton +Date: Tue, 13 Jul 2021 01:38:33 -0700 +Subject: [PATCH 11/11] Adjust crypto shim for functions renamed for OSSL3 + beta1 + +--- + .../opensslshim.h | 15 +++++++++------ + .../osslcompat_30.h | 3 +++ + .../System.Security.Cryptography.Native/pal_evp.c | 2 +- + .../pal_evp_pkey.c | 2 +- + 4 files changed, 14 insertions(+), 8 deletions(-) + +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +index c11285e7dd..b3386d381f 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/opensslshim.h +@@ -292,7 +292,7 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_md5) \ + RENAMED_FUNCTION(EVP_MD_CTX_free, EVP_MD_CTX_destroy) \ + RENAMED_FUNCTION(EVP_MD_CTX_new, EVP_MD_CTX_create) \ +- REQUIRED_FUNCTION(EVP_MD_size) \ ++ RENAMED_FUNCTION(EVP_MD_get_size, EVP_MD_size) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_ctrl) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_free) \ + REQUIRED_FUNCTION(EVP_PKEY_CTX_get0_pkey) \ +@@ -303,13 +303,14 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_padding) \ + FALLBACK_FUNCTION(EVP_PKEY_CTX_set_rsa_pss_saltlen) \ + FALLBACK_FUNCTION(EVP_PKEY_CTX_set_signature_md) \ +- REQUIRED_FUNCTION(EVP_PKEY_base_id) \ + REQUIRED_FUNCTION(EVP_PKEY_decrypt) \ + REQUIRED_FUNCTION(EVP_PKEY_decrypt_init) \ + REQUIRED_FUNCTION(EVP_PKEY_derive_set_peer) \ + REQUIRED_FUNCTION(EVP_PKEY_derive_init) \ + REQUIRED_FUNCTION(EVP_PKEY_derive) \ + REQUIRED_FUNCTION(EVP_PKEY_free) \ ++ RENAMED_FUNCTION(EVP_PKEY_get_base_id, EVP_PKEY_base_id) \ ++ RENAMED_FUNCTION(EVP_PKEY_get_size, EVP_PKEY_size) \ + FALLBACK_FUNCTION(EVP_PKEY_get0_RSA) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_DSA) \ + REQUIRED_FUNCTION(EVP_PKEY_get1_EC_KEY) \ +@@ -322,7 +323,6 @@ void SSL_get0_alpn_selected(const SSL* ssl, const unsigned char** protocol, unsi + REQUIRED_FUNCTION(EVP_PKEY_set1_RSA) \ + REQUIRED_FUNCTION(EVP_PKEY_sign) \ + REQUIRED_FUNCTION(EVP_PKEY_sign_init) \ +- REQUIRED_FUNCTION(EVP_PKEY_size) \ + FALLBACK_FUNCTION(EVP_PKEY_up_ref) \ + REQUIRED_FUNCTION(EVP_rc2_cbc) \ + REQUIRED_FUNCTION(EVP_rc2_ecb) \ +@@ -699,7 +699,7 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_md5 EVP_md5_ptr + #define EVP_MD_CTX_free EVP_MD_CTX_free_ptr + #define EVP_MD_CTX_new EVP_MD_CTX_new_ptr +-#define EVP_MD_size EVP_MD_size_ptr ++#define EVP_MD_get_size EVP_MD_get_size_ptr + #define EVP_PKEY_CTX_ctrl EVP_PKEY_CTX_ctrl_ptr + #define EVP_PKEY_CTX_free EVP_PKEY_CTX_free_ptr + #define EVP_PKEY_CTX_get0_pkey EVP_PKEY_CTX_get0_pkey_ptr +@@ -710,13 +710,14 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_PKEY_CTX_set_rsa_padding EVP_PKEY_CTX_set_rsa_padding_ptr + #define EVP_PKEY_CTX_set_rsa_pss_saltlen EVP_PKEY_CTX_set_rsa_pss_saltlen_ptr + #define EVP_PKEY_CTX_set_signature_md EVP_PKEY_CTX_set_signature_md_ptr +-#define EVP_PKEY_base_id EVP_PKEY_base_id_ptr + #define EVP_PKEY_decrypt_init EVP_PKEY_decrypt_init_ptr + #define EVP_PKEY_decrypt EVP_PKEY_decrypt_ptr + #define EVP_PKEY_derive_set_peer EVP_PKEY_derive_set_peer_ptr + #define EVP_PKEY_derive_init EVP_PKEY_derive_init_ptr + #define EVP_PKEY_derive EVP_PKEY_derive_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_size EVP_PKEY_get_size_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 +@@ -729,7 +730,6 @@ FOR_ALL_OPENSSL_FUNCTIONS + #define EVP_PKEY_set1_RSA EVP_PKEY_set1_RSA_ptr + #define EVP_PKEY_sign_init EVP_PKEY_sign_init_ptr + #define EVP_PKEY_sign EVP_PKEY_sign_ptr +-#define EVP_PKEY_size EVP_PKEY_size_ptr + #define EVP_PKEY_up_ref EVP_PKEY_up_ref_ptr + #define EVP_rc2_cbc EVP_rc2_cbc_ptr + #define EVP_rc2_ecb EVP_rc2_ecb_ptr +@@ -1006,6 +1006,9 @@ FOR_ALL_OPENSSL_FUNCTIONS + #if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_3_0_RTM + + // 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_size EVP_PKEY_size + #define SSL_get1_peer_certificate SSL_get_peer_certificate + + #endif +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +index bb529df51e..dba69f1382 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h ++++ b/src/Native/Unix/System.Security.Cryptography.Native/osslcompat_30.h +@@ -19,10 +19,13 @@ void ERR_new(void); + 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_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_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/Native/Unix/System.Security.Cryptography.Native/pal_evp.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp.c +index 9665ffe3fa..5ec3c63122 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp.c +@@ -59,7 +59,7 @@ int32_t CryptoNative_EvpDigestFinalEx(EVP_MD_CTX* ctx, uint8_t* md, uint32_t* s) + + int32_t CryptoNative_EvpMdSize(const EVP_MD* md) + { +- return EVP_MD_size(md); ++ return EVP_MD_get_size(md); + } + + const EVP_MD* CryptoNative_EvpMd5() +diff --git a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c +index f232b382ea..67410bc4e8 100644 +--- a/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c ++++ b/src/Native/Unix/System.Security.Cryptography.Native/pal_evp_pkey.c +@@ -21,7 +21,7 @@ void CryptoNative_EvpPkeyDestroy(EVP_PKEY* pkey) + int32_t CryptoNative_EvpPKeySize(EVP_PKEY* pkey) + { + assert(pkey != NULL); +- return EVP_PKEY_size(pkey); ++ return EVP_PKEY_get_size(pkey); + } + + int32_t CryptoNative_UpRefEvpPkey(EVP_PKEY* pkey) +-- +2.31.1 + diff --git a/SOURCES/corefx-optflags-support.patch b/SOURCES/corefx-optflags-support.patch new file mode 100644 index 0000000..9b08f1f --- /dev/null +++ b/SOURCES/corefx-optflags-support.patch @@ -0,0 +1,40 @@ +diff --git a/src/Native/Unix/CMakeLists.txt b/src/Native/Unix/CMakeLists.txt +index 7d804a1e54..717c2718d7 100644 +--- a/src/Native/Unix/CMakeLists.txt ++++ b/src/Native/Unix/CMakeLists.txt +@@ -25,7 +25,7 @@ add_compile_options(-fPIC) + add_compile_options(-Wthread-safety) + add_compile_options(-Wno-thread-safety-analysis) ++ add_compile_options(-Wno-alloca) + endif() +-add_compile_options(-Werror) + + if(CMAKE_SYSTEM_NAME STREQUAL Emscripten) + set(CLR_CMAKE_PLATFORM_WASM 1) +diff --git a/src/Native/Unix/configure.cmake b/src/Native/Unix/configure.cmake +index f4a30ad6cb..f2db68402a 100644 +--- a/src/Native/Unix/configure.cmake ++++ b/src/Native/Unix/configure.cmake +@@ -27,6 +27,12 @@ else () + message(FATAL_ERROR "Unknown platform. Cannot define PAL_UNIX_NAME, used by RuntimeInformation.") + endif () + ++ ++set (PREVIOUS_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) ++set (CMAKE_CXX_FLAGS "-D_GNU_SOURCE") ++set (PREVIOUS_CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) ++set (CMAKE_C_FLAGS "-D_GNU_SOURCE") ++ + # We compile with -Werror, so we need to make sure these code fragments compile without warnings. + # Older CMake versions (3.8) do not assign the result of their tests, causing unused-value errors + # which are not distinguished from the test failing. So no error for that one. +@@ -698,6 +704,9 @@ endif() + + set (CMAKE_REQUIRED_LIBRARIES) + ++set (CMAKE_CXX_FLAGS "${PREVIOUS_CMAKE_CXX_FLAGS}") ++set (CMAKE_C_FLAGS "${PREVIOUS_CMAKE_C_FLAGS}") ++ + check_c_source_compiles( + " + #include diff --git a/SOURCES/dotnet.sh.in b/SOURCES/dotnet.sh.in new file mode 100644 index 0000000..65b92a0 --- /dev/null +++ b/SOURCES/dotnet.sh.in @@ -0,0 +1,14 @@ + +# Set location for AppHost lookup +[ -z "$DOTNET_ROOT" ] && export DOTNET_ROOT=@LIBDIR@/dotnet + +# Add dotnet tools directory to PATH +DOTNET_TOOLS_PATH="$HOME/.dotnet/tools" +case "$PATH" in + *"$DOTNET_TOOLS_PATH"* ) true ;; + * ) PATH="$PATH:$DOTNET_TOOLS_PATH" ;; +esac + +# Extract self-contained executables under HOME +# to avoid multi-user issues from using the default '/var/tmp'. +[ -z "$DOTNET_BUNDLE_EXTRACT_BASE_DIR" ] && export DOTNET_BUNDLE_EXTRACT_BASE_DIR="${XDG_CACHE_HOME:-"$HOME"/.cache}/dotnet_bundle_extract" diff --git a/SOURCES/source-build-ilasm-ildasm-path-fix.patch b/SOURCES/source-build-ilasm-ildasm-path-fix.patch new file mode 100644 index 0000000..298b50f --- /dev/null +++ b/SOURCES/source-build-ilasm-ildasm-path-fix.patch @@ -0,0 +1,15 @@ +diff --git a/Directory.Build.props b/Directory.Build.props +index f6a6f54a..8247c3ee 100644 +--- a/Directory.Build.props ++++ b/Directory.Build.props +@@ -133,8 +133,8 @@ + $(BaseOutputPath)aspnet-debug + $(AspNetRazorBuildServerLogDir)razor-build-server.log + invalid: ILAsm is not expected to be needed in the online build +- $(PrebuiltSourceBuiltPackagesPath)coreclr-tools/$(BuildArchitecture)/ilasm +- $(ToolPackageExtractDir)coreclr-tools/$(BuildArchitecture)/ildasm ++ $(PrebuiltSourceBuiltPackagesPath)coreclr-tools/ilasm ++ $(ToolPackageExtractDir)coreclr-tools/ildasm + invalid: ILDasm is not expected to be needed in the offline build + + $(BaseOutputPath)git-info/ diff --git a/SOURCES/source-build-warnings-are-not-errors.patch b/SOURCES/source-build-warnings-are-not-errors.patch new file mode 100644 index 0000000..4f75cfd --- /dev/null +++ b/SOURCES/source-build-warnings-are-not-errors.patch @@ -0,0 +1,21 @@ +From c82976fd5eb4cbcf67faaba62f0bc59634d30338 Mon Sep 17 00:00:00 2001 +From: Chris Rummel +Date: Fri, 14 Aug 2020 15:34:07 -0500 +Subject: [PATCH] Disable XLiff warning as error + +--- + repos/xliff-tasks.proj | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/repos/xliff-tasks.proj b/repos/xliff-tasks.proj +index da2ae79c5b..9b86754018 100644 +--- a/repos/xliff-tasks.proj ++++ b/repos/xliff-tasks.proj +@@ -7,6 +7,7 @@ + $(BuildCommandArgs) /v:$(LogVerbosity) + $(BuildCommandArgs) /flp:Verbosity=Diag + $(BuildCommandArgs) /bl ++ $(BuildCommandArgs) /p:TreatWarningsAsErrors=false + $(BuildCommandArgs) $(RedirectRepoOutputToLog) + + $(DotnetToolCommand) $(BuildCommandArgs) diff --git a/SPECS/dotnet3.1.spec b/SPECS/dotnet3.1.spec new file mode 100644 index 0000000..27221cb --- /dev/null +++ b/SPECS/dotnet3.1.spec @@ -0,0 +1,900 @@ +%bcond_with bootstrap + +# Avoid provides/requires from private libraries +%global privlibs libhostfxr +%global privlibs %{privlibs}|libclrjit +%global privlibs %{privlibs}|libcoreclr +%global privlibs %{privlibs}|libcoreclrtraceptprovider +%global privlibs %{privlibs}|libdbgshim +%global privlibs %{privlibs}|libhostpolicy +%global privlibs %{privlibs}|libmscordaccore +%global privlibs %{privlibs}|libmscordbi +%global privlibs %{privlibs}|libsos +%global privlibs %{privlibs}|libsosplugin +%global __provides_exclude ^(%{privlibs})\\.so +%global __requires_exclude ^(%{privlibs})\\.so + +# LTO triggers a compilation error for a source level issue. Given that LTO should not +# change the validity of any given source and the nature of the error (undefined enum), I +# suspect a generator program is mis-behaving in some way. This needs further debugging, +# until that's done, disable LTO. This has to happen before setting the flags below. +%define _lto_cflags %{nil} + + +%global host_version 3.1.18 +%global runtime_version 3.1.18 +%global aspnetcore_runtime_version %{runtime_version} +%global sdk_version 3.1.118 +# upstream can update releases without revving the SDK version so these don't always match +%global src_version %{sdk_version} +%global templates_version %(echo %{runtime_version} | awk 'BEGIN { FS="."; OFS="." } {print $1, $2, $3+1 }') + +%global host_rpm_version %{host_version} +%global aspnetcore_runtime_rpm_version %{aspnetcore_runtime_version} +%global runtime_rpm_version %{runtime_version} +%global sdk_rpm_version %{sdk_version} + +%if 0%{?fedora} || 0%{?rhel} < 8 +%global use_bundled_libunwind 0 +%else +%global use_bundled_libunwind 1 +%endif + +%ifarch aarch64 +%global use_bundled_libunwind 1 +%endif + +%ifarch x86_64 +%global runtime_arch x64 +%endif +%ifarch aarch64 +%global runtime_arch arm64 +%endif + +%{!?runtime_id:%global runtime_id %(. /etc/os-release ; echo "${ID}.${VERSION_ID%%.*}")-%{runtime_arch}} + +Name: dotnet3.1 +Version: %{sdk_rpm_version} +Release: 1%{?dist} +Summary: .NET Core Runtime and SDK +License: MIT and ASL 2.0 and BSD and LGPLv2+ and CC-BY and CC0 and MS-PL and EPL-1.0 and GPL+ and GPLv2 and ISC and OFL and zlib +URL: https://github.com/dotnet/ + +# The source is generated on a Fedora box via: +# ./build-dotnet-tarball v%%{src_version}-SDK +Source0: dotnet-v%{src_version}-SDK.tar.gz +Source1: check-debug-symbols.py +Source2: dotnet.sh.in + +Patch1: source-build-warnings-are-not-errors.patch +Patch2: source-build-ilasm-ildasm-path-fix.patch + +# Fix building with our additional CFLAGS/CXXFLAGS/LDFLAGS +Patch100: corefx-optflags-support.patch + +# Add some support for cgroupv2 in corefx +# All these patches are upstreamed for 5.0 +Patch101: corefx-39686-cgroupv2-01.patch +Patch102: corefx-39686-cgroupv2-02.patch +Patch103: corefx-39633-cgroupv2-mountpoints.patch + +# https://github.com/dotnet/corefx/pull/43078 +Patch106: corefx-openssl-0001-Use-EVP_PKEY-for-RSA-key-generation.patch +Patch107: corefx-openssl-0002-Use-EVP_PKEY-for-RSA-Decrypt.patch +Patch108: corefx-openssl-0003-Use-EVP_PKEY-for-RSA-signing-operations.patch +Patch109: corefx-openssl-0004-Support-compiling-against-OpenSSL-3-headers.patch +Patch110: corefx-openssl-0005-Make-portable-builds-work-across-OpenSSL-1.0.2-1.1.1.patch +Patch111: corefx-openssl-0006-Fix-merge-issues-and-make-the-build-work.patch +Patch112: corefx-openssl-0007-OpenSSL3-Register-legacy-algorithms-when-needed.patch +Patch113: corefx-openssl-0008-Work-around-OpenSSL-3.0-ciphers-not-restoring-origin.patch +Patch114: corefx-openssl-0009-Use-1-instead-of-true-for-more-portable-code.patch +Patch115: corefx-openssl-0010-Stop-using-ERR_GET_FUNC-since-it-has-been-removed-in.patch +Patch116: corefx-openssl-0011-Adjust-crypto-shim-for-functions-renamed-for-OSSL3-b.patch + +# Fix build with clang 10; Already applied at tarball-build time +# Patch200: coreclr-clang10.patch +# Fix build on recent versions of gcc/clang +# https://github.com/libunwind/libunwind/pull/166 +# Already applied +#Patch201: coreclr-libunwind-fno-common.patch + +# Disable telemetry by default; make it opt-in +Patch500: cli-telemetry-optout.patch + + +%if 0%{?fedora} > 32 || 0%{?rhel} > 8 +ExclusiveArch: aarch64 x86_64 +%else +ExclusiveArch: x86_64 +%endif + +BuildRequires: clang +BuildRequires: cmake +BuildRequires: coreutils +%if %{without bootstrap} +BuildRequires: dotnet-build-reference-packages +BuildRequires: dotnet-sdk-3.1 +BuildRequires: dotnet-sdk-3.1-source-built-artifacts +%endif +BuildRequires: findutils +BuildRequires: git +%if 0%{?fedora} || 0%{?rhel} > 7 +BuildRequires: glibc-langpack-en +%endif +BuildRequires: hostname +BuildRequires: krb5-devel +BuildRequires: libcurl-devel +BuildRequires: libicu-devel +%if ! %{use_bundled_libunwind} +BuildRequires: libunwind-devel +%endif +BuildRequires: lldb-devel +BuildRequires: llvm +BuildRequires: lttng-ust-devel +BuildRequires: make +BuildRequires: openssl-devel +%if 0%{?rhel} > 8 +BuildRequires: compat-openssl11 +%endif +BuildRequires: python3 +BuildRequires: systemtap-sdt-devel +BuildRequires: tar +BuildRequires: zlib-devel + +%description +.NET Core is a fast, lightweight and modular platform for creating +cross platform applications that work on Linux, macOS and Windows. + +It particularly focuses on creating console applications, web +applications and micro-services. + +.NET Core contains a runtime conforming to .NET Standards a set of +framework libraries, an SDK containing compilers and a 'dotnet' +application to drive everything. + + +%package -n dotnet + +Version: %{sdk_rpm_version} +Summary: .NET Core CLI tools and runtime + +Requires: dotnet-sdk-3.1%{?_isa} >= %{sdk_rpm_version}-%{release} + +%description -n dotnet +.NET Core is a fast, lightweight and modular platform for creating +cross platform applications that work on Linux, macOS and Windows. + +It particularly focuses on creating console applications, web +applications and micro-services. + +.NET Core contains a runtime conforming to .NET Standards a set of +framework libraries, an SDK containing compilers and a 'dotnet' +application to drive everything. + + +%package -n dotnet-host + +Version: %{host_rpm_version} +Summary: .NET command line launcher + +%description -n dotnet-host +The .NET Core host is a command line program that runs a standalone +.NET core application or launches the SDK. + +.NET Core is a fast, lightweight and modular platform for creating +cross platform applications that work on Linux, Mac and Windows. + +It particularly focuses on creating console applications, web +applications and micro-services. + + +%package -n dotnet-hostfxr-3.1 + +Version: %{host_rpm_version} +Summary: .NET Core command line host resolver + +# Theoretically any version of the host should work. But lets aim for the one +# provided by this package, or from a newer version of .NET Core +Requires: dotnet-host%{?_isa} >= %{host_rpm_version}-%{release} + +%description -n dotnet-hostfxr-3.1 +The .NET Core host resolver contains the logic to resolve and select +the right version of the .NET Core SDK or runtime to use. + +.NET Core is a fast, lightweight and modular platform for creating +cross platform applications that work on Linux, Mac and Windows. + +It particularly focuses on creating console applications, web +applications and micro-services. + + +%package -n dotnet-runtime-3.1 + +Version: %{runtime_rpm_version} +Summary: NET Core 3.1 runtime + +Requires: dotnet-hostfxr-3.1%{?_isa} >= %{host_rpm_version}-%{release} + +# libicu is dlopen()ed +Requires: libicu%{?_isa} + +%if %{use_bundled_libunwind} +Provides: bundled(libunwind) = 1.3 +%endif + +%description -n dotnet-runtime-3.1 +The .NET Core runtime contains everything needed to run .NET Core applications. +It includes a high performance Virtual Machine as well as the framework +libraries used by .NET Core applications. + +.NET Core is a fast, lightweight and modular platform for creating +cross platform applications that work on Linux, Mac and Windows. + +It particularly focuses on creating console applications, web +applications and micro-services. + + +%package -n aspnetcore-runtime-3.1 + +Version: %{aspnetcore_runtime_rpm_version} +Summary: ASP.NET Core 3.1 runtime + +Requires: dotnet-runtime-3.1%{?_isa} >= %{runtime_rpm_version}-%{release} + +%description -n aspnetcore-runtime-3.1 +The ASP.NET Core runtime contains everything needed to run .NET Core +web applications. It includes a high performance Virtual Machine as +well as the framework libraries used by .NET Core applications. + +ASP.NET Core is a fast, lightweight and modular platform for creating +cross platform web applications that work on Linux, Mac and Windows. + +It particularly focuses on creating console applications, web +applications and micro-services. + + +%package -n dotnet-templates-3.1 + +Version: %{sdk_rpm_version} +Summary: .NET Core 3.1 templates + +# Theoretically any version of the host should work. But lets aim for the one +# provided by this package, or from a newer version of .NET Core +Requires: dotnet-host%{?_isa} >= %{host_rpm_version}-%{release} + +%description -n dotnet-templates-3.1 +This package contains templates used by the .NET Core SDK. + +ASP.NET Core is a fast, lightweight and modular platform for creating +cross platform web applications that work on Linux, Mac and Windows. + +It particularly focuses on creating console applications, web +applications and micro-services. + + +%package -n dotnet-sdk-3.1 + +Version: %{sdk_rpm_version} +Summary: .NET Core 3.1 Software Development Kit + +Provides: bundled(js-jquery) +Provides: bundled(npm) + +Requires: dotnet-runtime-3.1%{?_isa} >= %{runtime_rpm_version}-%{release} +Requires: aspnetcore-runtime-3.1%{?_isa} >= %{aspnetcore_runtime_rpm_version}-%{release} + +Requires: dotnet-apphost-pack-3.1%{?_isa} >= %{runtime_rpm_version}-%{release} +Requires: dotnet-targeting-pack-3.1%{?_isa} >= %{runtime_rpm_version}-%{release} +Requires: aspnetcore-targeting-pack-3.1%{?_isa} >= %{aspnetcore_runtime_rpm_version}-%{release} +Requires: netstandard-targeting-pack-2.1%{?_isa} >= %{sdk_rpm_version}-%{release} + +Requires: dotnet-templates-3.1%{?_isa} >= %{sdk_rpm_version}-%{release} + +%description -n dotnet-sdk-3.1 +The .NET Core SDK is a collection of command line applications to +create, build, publish and run .NET Core applications. + +.NET Core is a fast, lightweight and modular platform for creating +cross platform applications that work on Linux, Mac and Windows. + +It particularly focuses on creating console applications, web +applications and micro-services. + + +%global dotnet_targeting_pack() %{expand: +%package -n %{1} + +Version: %{2} +Summary: Targeting Pack for %{3} %{4} + +Requires: dotnet-host%{?_isa} + +%description -n %{1} +This package provides a targeting pack for %{3} %{4} +that allows developers to compile against and target %{3} %{4} +applications using the .NET Core SDK. + +%files -n %{1} +%dir %{_libdir}/dotnet/packs +%{_libdir}/dotnet/packs/%{5} +} + +%dotnet_targeting_pack dotnet-apphost-pack-3.1 %{runtime_rpm_version} Microsoft.NETCore.App 3.1 Microsoft.NETCore.App.Host.%{runtime_id} +%dotnet_targeting_pack dotnet-targeting-pack-3.1 %{runtime_rpm_version} Microsoft.NETCore.App 3.1 Microsoft.NETCore.App.Ref +%dotnet_targeting_pack aspnetcore-targeting-pack-3.1 %{aspnetcore_runtime_rpm_version} Microsoft.AspNetCore.App 3.1 Microsoft.AspNetCore.App.Ref +%dotnet_targeting_pack netstandard-targeting-pack-2.1 %{sdk_rpm_version} NETStandard.Library 2.1 NETStandard.Library.Ref + + +%package -n dotnet-sdk-3.1-source-built-artifacts + +Version: %{sdk_rpm_version} +Summary: Internal package for building .NET Core 3.1 Software Development Kit + +%description -n dotnet-sdk-3.1-source-built-artifacts +The .NET Core source-built archive is a collection of packages needed +to build the .NET Core SDK itself. + +These are not meant for general use. + + +%prep +%setup -q -n dotnet-v%{src_version}-SDK + +%if %{without bootstrap} +# Remove all prebuilts +find -iname '*.dll' -type f -delete +find -iname '*.so' -type f -delete +find -iname '*.tar.gz' -type f -delete +find -iname '*.nupkg' -type f -delete +find -iname '*.zip' -type f -delete +rm -rf .dotnet/ +rm -rf packages/source-built +%endif + +%if %{without bootstrap} +mkdir -p packages/archive +ln -s %{_libdir}/dotnet/source-built-artifacts/*.tar.gz packages/archive/ +ln -s %{_libdir}/dotnet/reference-packages/Private.SourceBuild.ReferencePackages*.tar.gz packages/archive +%endif + +# Fix bad hardcoded path in build +sed -i 's|/usr/share/dotnet|%{_libdir}/dotnet|' src/core-setup.*/src/corehost/common/pal.unix.cpp + +# Disable warnings +sed -i 's|skiptests|skiptests ignorewarnings|' repos/coreclr.proj + +%patch1 -p1 +%patch2 -p1 + +pushd src/corefx.* +%patch100 -p1 +%patch101 -p1 +%patch102 -p1 +%patch103 -p1 +%patch106 -p1 +%patch107 -p1 +%patch108 -p1 +%patch109 -p1 +%patch110 -p1 +%patch111 -p1 +%patch112 -p1 +%patch113 -p1 +%patch114 -p1 +%patch115 -p1 +%patch116 -p1 +popd + +pushd src/coreclr.* +#%%patch200 -p1 +#%%patch201 -p1 +popd + +pushd src/core-setup.* +popd + +pushd src/cli.* +%patch500 -p1 +popd + + +# If CLR_CMAKE_USE_SYSTEM_LIBUNWIND=TRUE is misisng, add it back +grep CLR_CMAKE_USE_SYSTEM_LIBUNWIND repos/coreclr.common.props || \ + sed -i 's|\$(BuildArguments) |$(BuildArguments) cmakeargs -DCLR_CMAKE_USE_SYSTEM_LIBUNWIND=TRUE|' repos/coreclr.common.props + +%if %{use_bundled_libunwind} +sed -i 's|-DCLR_CMAKE_USE_SYSTEM_LIBUNWIND=TRUE|-DCLR_CMAKE_USE_SYSTEM_LIBUNWIND=FALSE|' repos/coreclr.common.props +%endif + +%ifnarch x86_64 +mkdir -p artifacts/obj/%{runtime_arch}/Release +cp artifacts/obj/x64/Release/PackageVersions.props artifacts/obj/%{runtime_arch}/Release/PackageVersions.props +%endif + +cat source-build-info.txt + +find -iname 'nuget.config' -exec echo {}: \; -exec cat {} \; -exec echo \; + + +%build +cat /etc/os-release + +%if %{without bootstrap} +# We need to create a copy because we will mutate this +cp -a %{_libdir}/dotnet previously-built-dotnet +%endif + +%if 0%{?fedora} > 32 || 0%{?rhel} > 8 +# Setting this macro ensures that only clang supported options will be +# added to ldflags and cflags. +%global toolchain clang +%set_build_flags +%else +# Filter flags not supported by clang +# -specs= +%global dotnet_cflags %(echo %optflags | sed -re 's/-specs=[^ ]*//g') +%global dotnet_ldflags %(echo %{__global_ldflags} | sed -re 's/-specs=[^ ]*//g') +export CFLAGS="%{dotnet_cflags}" +export CXXFLAGS="%{dotnet_cflags}" +export LDFLAGS="%{dotnet_ldflags}" +%endif + +%ifarch aarch64 +# mbranch-protection=standard breaks unwinding in CoreCLR through libunwind +CFLAGS=$(echo $CFLAGS | sed -e 's/-mbranch-protection=standard //') +CXXFLAGS=$(echo $CXXFLAGS | sed -e 's/-mbranch-protection=standard //') +%endif + +# fstack-clash-protection breaks CoreCLR +CFLAGS=$(echo $CFLAGS | sed -e 's/-fstack-clash-protection//' ) +CXXFLAGS=$(echo $CXXFLAGS | sed -e 's/-fstack-clash-protection//' ) + +echo $CFLAGS +echo $CXXFLAGS +echo $LDFLAGS + +#%%if %%{without bootstrap} +# --with-ref-packages %%{_libdir}/dotnet/reference-packages/ \ +# --with-packages %%{_libdir}/dotnet/source-built-artifacts/*.tar.gz \ +# --with-sdk %%{_libdir}/dotnet \ +#%%endif + +VERBOSE=1 ./build.sh \ +%if %{without bootstrap} + --with-sdk previously-built-dotnet \ +%endif + -- \ + /v:n \ + /p:SkipPortableRuntimeBuild=true \ + /p:LogVerbosity=n \ + /p:MinimalConsoleLogOutput=false \ + /p:ContinueOnPrebuiltBaselineError=true \ + + +sed -e 's|[@]LIBDIR[@]|%{_libdir}|g' %{SOURCE2} > dotnet.sh + + +%install +install -dm 0755 %{buildroot}%{_libdir}/dotnet +ls artifacts/%{runtime_arch}/Release +tar xf artifacts/%{runtime_arch}/Release/dotnet-sdk-%{sdk_version}-%{runtime_id}.tar.gz -C %{buildroot}%{_libdir}/dotnet/ + +# Install managed symbols +tar xf artifacts/%{runtime_arch}/Release/runtime/dotnet-runtime-symbols-%{runtime_version}-%{runtime_id}.tar.gz \ + -C %{buildroot}/%{_libdir}/dotnet/shared/Microsoft.NETCore.App/%{runtime_version}/ + +# Fix executable permissions on files +find %{buildroot}%{_libdir}/dotnet/ -type f -name '*.dll' -exec chmod -x {} \; +find %{buildroot}%{_libdir}/dotnet/ -type f -name '*.pdb' -exec chmod -x {} \; +find %{buildroot}%{_libdir}/dotnet/ -type f -name '*.props' -exec chmod -x {} \; +find %{buildroot}%{_libdir}/dotnet/ -type f -name '*.pubxml' -exec chmod -x {} \; +find %{buildroot}%{_libdir}/dotnet/ -type f -name '*.targets' -exec chmod -x {} \; +chmod 0755 %{buildroot}/%{_libdir}/dotnet/sdk/%{sdk_version}/AppHostTemplate/apphost +chmod 0755 %{buildroot}/%{_libdir}/dotnet/packs/Microsoft.NETCore.App.Host.%{runtime_id}/%{runtime_version}/runtimes/%{runtime_id}/native/libnethost.so +chmod 0755 %{buildroot}/%{_libdir}/dotnet/packs/Microsoft.NETCore.App.Host.%{runtime_id}/%{runtime_version}/runtimes/%{runtime_id}/native/apphost +chmod 0644 %{buildroot}/%{_libdir}/dotnet/packs/Microsoft.NETCore.App.Host.%{runtime_id}/%{runtime_version}/runtimes/%{runtime_id}/native/nethost.h + +install -dm 0755 %{buildroot}%{_sysconfdir}/profile.d/ +install dotnet.sh %{buildroot}%{_sysconfdir}/profile.d/ + +install -dm 0755 %{buildroot}/%{_datadir}/bash-completion/completions +# dynamic completion needs the file to be named the same as the base command +install src/cli.*/scripts/register-completions.bash %{buildroot}/%{_datadir}/bash-completion/completions/dotnet + +# TODO: the zsh completion script needs to be ported to use #compdef +#install -dm 755 %%{buildroot}/%%{_datadir}/zsh/site-functions +#install src/cli/scripts/register-completions.zsh %%{buildroot}/%%{_datadir}/zsh/site-functions/_dotnet + +install -dm 0755 %{buildroot}%{_bindir} +ln -s ../../%{_libdir}/dotnet/dotnet %{buildroot}%{_bindir}/ + +install -dm 0755 %{buildroot}%{_mandir}/man1/ +find -iname 'dotnet*.1' -type f -exec cp {} %{buildroot}%{_mandir}/man1/ \; + +echo "%{_libdir}/dotnet" >> install_location +install -dm 0755 %{buildroot}%{_sysconfdir}/dotnet +install install_location %{buildroot}%{_sysconfdir}/dotnet/ + +install -dm 0755 %{buildroot}%{_libdir}/dotnet/source-built-artifacts +install artifacts/%{runtime_arch}/Release/Private.SourceBuilt.Artifacts.*.tar.gz %{buildroot}/%{_libdir}/dotnet/source-built-artifacts/ + +# Check debug symbols in all elf objects. This is not in %%check +# because native binaries are stripped by rpm-build after %%install. +# So we need to do this check earlier. +echo "Testing build results for debug symbols..." +%{SOURCE1} -v %{buildroot}%{_libdir}/dotnet/ + + +%check +%{buildroot}%{_libdir}/dotnet/dotnet --info + + +%files -n dotnet +# empty package useful for dependencies + +%files -n dotnet-host +%dir %{_libdir}/dotnet +%{_libdir}/dotnet/dotnet +%dir %{_libdir}/dotnet/host +%dir %{_libdir}/dotnet/host/fxr +%{_bindir}/dotnet +%license %{_libdir}/dotnet/LICENSE.txt +%license %{_libdir}/dotnet/ThirdPartyNotices.txt +%doc %{_mandir}/man1/dotnet*.1.gz +%{_sysconfdir}/profile.d/dotnet.sh +%{_sysconfdir}/dotnet +%dir %{_datadir}/bash-completion +%dir %{_datadir}/bash-completion/completions +%{_datadir}/bash-completion/completions/dotnet + +%files -n dotnet-hostfxr-3.1 +%dir %{_libdir}/dotnet/host/fxr +%{_libdir}/dotnet/host/fxr/%{host_version} + +%files -n dotnet-runtime-3.1 +%dir %{_libdir}/dotnet/shared +%dir %{_libdir}/dotnet/shared/Microsoft.NETCore.App +%{_libdir}/dotnet/shared/Microsoft.NETCore.App/%{runtime_version} + +%files -n aspnetcore-runtime-3.1 +%dir %{_libdir}/dotnet/shared +%dir %{_libdir}/dotnet/shared/Microsoft.AspNetCore.App +%{_libdir}/dotnet/shared/Microsoft.AspNetCore.App/%{aspnetcore_runtime_version} + +%files -n dotnet-templates-3.1 +%dir %{_libdir}/dotnet/templates +%{_libdir}/dotnet/templates/%{templates_version} + +%files -n dotnet-sdk-3.1 +%dir %{_libdir}/dotnet/sdk +%{_libdir}/dotnet/sdk/%{sdk_version} +%dir %{_libdir}/dotnet/packs + +%files -n dotnet-sdk-3.1-source-built-artifacts +%dir %{_libdir}/dotnet +%{_libdir}/dotnet/source-built-artifacts + + +%changelog +* Fri Aug 27 2021 Omair Majid - 3.1.118-1 +- Update to .NET SDK 3.1.118 and Runtime 3.1.18 +- Resolves: RHBZ#1961848 + +* Tue Aug 24 2021 Omair Majid - 3.1.117-2 +- Fix building and running against OpenSSL 3.0 +- Resolves: RHBZ#1991050 + +* Thu Aug 12 2021 Omair Majid - 3.1.117-1 +- Update to .NET SDK 3.1.117 and Runtime 3.1.17 +- Resolves: RHBZ#1961848 + +* Mon Aug 09 2021 Mohan Boddu - 3.1.116-3 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags + Related: rhbz#1991688 + +* Wed Jun 16 2021 Mohan Boddu - 3.1.116-2 +- Rebuilt for RHEL 9 BETA for openssl 3.0 + Related: rhbz#1971065 + +* Fri Jun 11 2021 Omair Majid - 3.1.116-1 +- Update to .NET SDK 3.1.116 and Runtime 3.1.16 +- Resolves: RHBZ#1961848 + +* Mon Jun 07 2021 Omair Majid - 3.1.115-2 +- Support building against OpenSSL 3.0 +- Resolves: RHBZ#1965045 + +* Tue May 18 2021 Omair Majid - 3.1.115-1 +- Update to .NET SDK 3.1.115 and Runtime 3.1.15 +- Resolves: RHBZ#1961848 + +* Wed Apr 21 2021 Omair Majid - 3.1.113-3 +- Fix build by adding CentOS 9 RIDs +- Resolves: RHBZ#1951312 + +* Thu Apr 15 2021 Mohan Boddu - 3.1.113-3 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 + +* Tue Mar 30 2021 Jonathan Wakely - 3.1.113-2 +- Rebuilt for removed libstdc++ symbol (#1937698) + +* Wed Mar 17 2021 Omair Majid - 3.1.113-1 +- Update to .NET Core SDK 3.1.113 and Runtime 3.1.13 + +* Wed Feb 17 2021 Omair Majid - 3.1.112-3 +- Hack an RID for RHEL 9 into the build SDK + +* Wed Feb 17 2021 Omair Majid - 3.1.112-2 +- Add Fedora 35 Runtime ID + +* Fri Feb 12 2021 Omair Majid - 3.1.112-1 +- Update to .NET Core SDK 3.1.112 and Runtime 3.1.12 + +* Tue Jan 26 2021 Fedora Release Engineering - 3.1.111-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Fri Jan 15 2021 Omair Majid - 3.1.111-1 +- Update to .NET Core SDK 3.1.111 and Runtime 3.1.11 + +* Sun Dec 06 2020 Jeff Law - 3.1.110-2 +- Fix missing #include for gcc-11 + +* Tue Nov 10 2020 Omair Majid - 3.1.110-1 +- Update to .NET Core SDK 3.1.110 and Runtime 3.1.10 + +* Wed Oct 14 2020 Omair Majid - 3.1.109-1 +- Update to .NET Core SDK 3.1.109 and Runtime 3.1.9 + +* Mon Sep 21 2020 Tom Stellard - 3.1.108-2 +- Use toolchain macro for setting clang-specific c/ld flags + +* Wed Sep 16 2020 Troy Dawson - 3.1.108-1 +- Generate runtime_id the same way that it does in the various build scripts + +* Fri Sep 11 2020 Omair Majid - 3.1.108-1 +- Update to .NET Core SDK 3.1.108 and Runtime 3.1.8 + +* Wed Sep 09 2020 Omair Majid - 3.1.107-1 +- Add Fedora 34 RID +- Fix build of bundled libunwind + +* Wed Aug 19 2020 Omair Majid - 3.1.107-1 +- Update to .NET Core Runtime 3.1.7 and SDK 3.1.107 + +* Thu Aug 13 2020 Omair Majid - 3.1.106-3 +- Filter out -mbranch-protection=standard from cflags + +* Sat Aug 01 2020 Fedora Release Engineering - 3.1.106-3 +- Second attempt - Rebuilt for + https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Mon Jul 27 2020 Fedora Release Engineering - 3.1.106-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Tue Jul 21 2020 Jo Shields - 3.1.106-1 +- Update to .NET Core Runtime 3.1.6 and SDK 3.1.106 + +* Tue Jul 21 2020 Omair Majid - 3.1.105-5 +- Fix up commented-out define for disabling LTO + +* Mon Jul 20 2020 Jeff Law - 3.1.105-5 +- Disable LTO + +* Sat Jun 27 2020 Omair Majid - 3.1.105-4 +- Disable bootstrap + +* Fri Jun 26 2020 Omair Majid - 3.1.105-3 +- Re-bootstrap aarch64 + +* Fri Jun 19 2020 Omair Majid - 3.1.105-3 +- Disable bootstrap + +* Thu Jun 18 2020 Omair Majid - 3.1.105-1 +- Bootstrap aarch64 + +* Tue Jun 16 2020 Chris Rummel - 3.1.105-1 +- Update to .NET Core Runtime 3.1.5 and SDK 3.1.105 + +* Fri Jun 05 2020 Chris Rummel - 3.1.104-1 +- Update to .NET Core Runtime 3.1.4 and SDK 3.1.104 + +* Thu Apr 09 2020 Chris Rummel - 3.1.103-1 +- Update to .NET Core Runtime 3.1.3 and SDK 3.1.103 + +* Mon Mar 16 2020 Omair Majid - 3.1.102-1 +- Update to .NET Core Runtime 3.1.2 and SDK 3.1.102 + +* Fri Feb 28 2020 Omair Majid - 3.1.101-4 +- Disable bootstrap + +* Fri Feb 28 2020 Omair Majid - 3.1.101-3 +- Enable bootstrap +- Add Fedora 33 runtime ids + +* Thu Feb 27 2020 Omair Majid - 3.1.101-2 +- Disable bootstrap + +* Tue Jan 21 2020 Omair Majid - 3.1.101-1 +- Update to .NET Core Runtime 3.1.1 and SDK 3.1.101 + +* Thu Dec 05 2019 Omair Majid - 3.1.100-1 +- Update to .NET Core Runtime 3.1.0 and SDK 3.1.100 + +* Mon Nov 18 2019 Omair Majid - 3.1.100-0.4.preview3 +- Fix apphost permissions + +* Fri Nov 15 2019 Omair Majid - 3.1.100-0.3.preview3 +- Update to .NET Core Runtime 3.1.0-preview3.19553.2 and SDK + 3.1.100-preview3-014645 + +* Wed Nov 06 2019 Omair Majid - 3.1.100-0.2 +- Update to .NET Core 3.1 Preview 2 + +* Wed Oct 30 2019 Omair Majid - 3.1.100-0.1 +- Update to .NET Core 3.1 Preview 1 + +* Thu Oct 24 2019 Omair Majid - 3.0.100-5 +- Add cgroupv2 support to .NET Core + +* Wed Oct 16 2019 Omair Majid - 3.0.100-4 +- Include fix from coreclr for building on Fedora 32 + +* Wed Oct 16 2019 Omair Majid - 3.0.100-3 +- Harden built binaries to pass annocheck + +* Fri Oct 11 2019 Omair Majid - 3.0.100-2 +- Export DOTNET_ROOT in profile to make apphost lookup work + +* Fri Sep 27 2019 Omair Majid - 3.0.100-1 +- Update to .NET Core Runtime 3.0.0 and SDK 3.0.100 + +* Wed Sep 25 2019 Omair Majid - 3.0.100-0.18.rc1 +- Update to .NET Core Runtime 3.0.0-rc1-19456-20 and SDK 3.0.100-rc1-014190 + +* Tue Sep 17 2019 Omair Majid - 3.0.100-0.16.preview9 +- Fix files duplicated between dotnet-apphost-pack-3.0 and dotnet-targeting-pack-3.0 +- Fix dependencies between .NET SDK and the targeting packs + +* Mon Sep 16 2019 Omair Majid - 3.0.100-0.15.preview9 +- Update to .NET Core Runtime 3.0.0-preview 9 and SDK 3.0.100-preview9 + +* Mon Aug 19 2019 Omair Majid - 3.0.100-0.11.preview8 +- Update to .NET Core Runtime 3.0.0-preview8-28405-07 and SDK + 3.0.100-preview8-013656 + +* Tue Jul 30 2019 Omair Majid - 3.0.100-0.9.preview7 +- Update to .NET Core Runtime 3.0.0-preview7-27912-14 and SDK + 3.0.100-preview7-012821 + +* Fri Jul 26 2019 Omair Majid - 3.0.100-0.8.preview7 +- Update to .NET Core Runtime 3.0.0-preview7-27902-19 and SDK + 3.0.100-preview7-012802 + +* Wed Jun 26 2019 Omair Majid - 3.0.0-0.7.preview6 +- Obsolete dotnet-sdk-3.0.1xx +- Add supackages for targeting packs +- Add -fcf-protection to CFLAGS + +* Wed Jun 26 2019 Omair Majid - 3.0.0-0.6.preview6 +- Update to .NET Core Runtime 3.0.0-preview6-27804-01 and SDK 3.0.100-preview6-012264 +- Set dotnet installation location in /etc/dotnet/install_location +- Update targeting packs +- Install managed symbols +- Completely conditionalize libunwind bundling + +* Tue May 07 2019 Omair Majid - 3.0.0-0.3.preview4 +- Update to .NET Core 3.0 preview 4 + +* Tue Dec 18 2018 Omair Majid - 3.0.0-0.1.preview1 +- Update to .NET Core 3.0 preview 1 + +* Fri Dec 07 2018 Omair Majid - 2.2.100 +- Update to .NET Core 2.2.0 + +* Wed Nov 07 2018 Omair Majid - 2.2.100-0.2.preview3 +- Update to .NET Core 2.2.0-preview3 + +* Fri Nov 02 2018 Omair Majid - 2.1.403-3 +- Add host-fxr-2.1 subpackage + +* Mon Oct 15 2018 Omair Majid - 2.1.403-2 +- Disable telemetry by default +- Users have to manually export DOTNET_CLI_TELEMETRY_OPTOUT=0 to enable + +* Tue Oct 02 2018 Omair Majid - 2.1.403-1 +- Update to .NET Core Runtime 2.1.5 and SDK 2.1.403 + +* Wed Sep 26 2018 Omair Majid - 2.1.402-2 +- Add ~/.dotnet/tools to $PATH to make it easier to use dotnet tools + +* Thu Sep 13 2018 Omair Majid - 2.1.402-1 +- Update to .NET Core Runtime 2.1.4 and SDK 2.1.402 + +* Wed Sep 05 2018 Omair Majid - 2.1.401-2 +- Use distro-standard flags when building .NET Core + +* Tue Aug 21 2018 Omair Majid - 2.1.401-1 +- Update to .NET Core Runtime 2.1.3 and SDK 2.1.401 + +* Mon Aug 20 2018 Omair Majid - 2.1.302-1 +- Update to .NET Core Runtime 2.1.2 and SDK 2.1.302 + +* Fri Jul 20 2018 Omair Majid - 2.1.301-1 +- Update to .NET Core 2.1 + +* Thu May 03 2018 Omair Majid - 2.0.7-1 +- Update to .NET Core 2.0.7 + +* Wed Mar 28 2018 Omair Majid - 2.0.6-2 +- Enable bash completion for dotnet +- Remove redundant buildrequires and requires + +* Wed Mar 14 2018 Omair Majid - 2.0.6-1 +- Update to .NET Core 2.0.6 + +* Fri Feb 23 2018 Omair Majid - 2.0.5-1 +- Update to .NET Core 2.0.5 + +* Wed Jan 24 2018 Omair Majid - 2.0.3-5 +- Don't apply corefx clang warnings fix on clang < 5 + +* Fri Jan 19 2018 Omair Majid - 2.0.3-4 +- Add a test script to sanity check debug and symbol info. +- Build with clang 5.0 +- Make main package real instead of using a virtual provides (see RHBZ 1519325) + +* Wed Nov 29 2017 Omair Majid - 2.0.3-3 +- Add a Provides for 'dotnet' +- Fix conditional macro + +* Tue Nov 28 2017 Omair Majid - 2.0.3-2 +- Fix build on Fedora 27 + +* Fri Nov 17 2017 Omair Majid - 2.0.3-1 +- Update to .NET Core 2.0.3 + +* Thu Oct 19 2017 Omair Majid - 2.0.0-4 +- Add a hack to let omnisharp work + +* Wed Aug 30 2017 Omair Majid - 2.0.0-3 +- Add a patch for building coreclr and core-setup correctly on Fedora >= 27 + +* Fri Aug 25 2017 Omair Majid - 2.0.0-2 +- Move libicu/libcurl/libunwind requires to runtime package +- Make sdk depend on the exact version of the runtime package + +* Thu Aug 24 2017 Omair Majid - 2.0.0-1 +- Update to 2.0.0 final release + +* Wed Jul 26 2017 Omair Majid - 2.0.0-0.3.preview2 +- Add man pages + +* Tue Jul 25 2017 Omair Majid - 2.0.0-0.2.preview2 +- Add Requires on libicu +- Split into multiple packages +- Do not repeat first-run message + +* Fri Jul 21 2017 Omair Majid - 2.0.0-0.1.preview2 +- Update to .NET Core 2.0 Preview 2 + +* Thu Mar 16 2017 Nemanja Milošević - 1.1.0-7 +- rebuilt with latest libldb +* Wed Feb 22 2017 Nemanja Milosevic - 1.1.0-6 +- compat-openssl 1.0 for F26 for now +* Sun Feb 19 2017 Nemanja Milosevic - 1.1.0-5 +- Fix wrong commit id's +* Sat Feb 18 2017 Nemanja Milosevic - 1.1.0-4 +- Use commit id's instead of branch names +* Sat Feb 18 2017 Nemanja Milosevic - 1.1.0-3 +- Improper patch5 fix +* Sat Feb 18 2017 Nemanja Milosevic - 1.1.0-2 +- SPEC cleanup +- git removal (using all tarballs for reproducible builds) +- more reasonable versioning +* Thu Feb 09 2017 Nemanja Milosevic - 1.1.0-1 +- Fixed debuginfo going to separate package (Patch1) +- Added F25/F26 RIL and fixed the version info (Patch2) +- Added F25/F26 RIL in Microsoft.NETCore.App suported runtime graph (Patch3) +- SPEC file cleanup +* Wed Jan 11 2017 Nemanja Milosevic - 1.1.0-0 +- Initial RPM for Fedora 25/26. +