Merge branch 'upstream'
Former-commit-id: 70340005d173498c8871669ddb9867e171cbb3e1
This commit is contained in:
commit
1ffecf6eb5
@ -84,8 +84,8 @@ DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
|
||||
$(top_srcdir)/configure $(am__configure_deps) \
|
||||
$(srcdir)/config.h.in mkinstalldirs \
|
||||
$(srcdir)/mono-uninstalled.pc.in COPYING.LIB ChangeLog NEWS \
|
||||
compile config.guess config.rpath config.sub depcomp \
|
||||
install-sh missing ltmain.sh
|
||||
compile config.guess config.rpath config.sub install-sh \
|
||||
missing ltmain.sh
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/iconv.m4 \
|
||||
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
|
||||
|
@ -75,6 +75,7 @@ namespace System.Web.Services.Configuration
|
||||
try {
|
||||
var hack = this.EvaluationContext;
|
||||
} catch (ConfigurationErrorsException) {
|
||||
this.actualPath = GetConfigurationDirectory();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -127,6 +128,7 @@ namespace System.Web.Services.Configuration
|
||||
var hack = this.EvaluationContext;
|
||||
} catch (ConfigurationErrorsException) {
|
||||
base.Reset(parentElement);
|
||||
this.actualPath = GetConfigurationDirectory();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@ -43,7 +43,7 @@ namespace System.Runtime.InteropServices {
|
||||
// Should not have been instantiable - here for binary compatibility in V4.
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !MONO
|
||||
[System.Security.SecurityCritical] // auto-generated
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
@ -58,8 +58,8 @@ namespace System.Runtime.InteropServices {
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
internal static extern String GetHostBindingFile();
|
||||
|
||||
#if !FEATURE_CORECLR
|
||||
#endif
|
||||
#if !FEATURE_CORECLR && !MONO
|
||||
[System.Security.SecurityCritical] // auto-generated
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
|
||||
@ -78,7 +78,7 @@ namespace System.Runtime.InteropServices {
|
||||
[MethodImpl (MethodImplOptions.NoInlining)]
|
||||
public static String GetSystemVersion()
|
||||
{
|
||||
#if FEATURE_CORECLR
|
||||
#if FEATURE_CORECLR || MONO
|
||||
|
||||
return Assembly.GetExecutingAssembly().ImageRuntimeVersion;
|
||||
|
||||
@ -97,15 +97,36 @@ namespace System.Runtime.InteropServices {
|
||||
[ResourceConsumption(ResourceScope.Machine)]
|
||||
public static String GetRuntimeDirectory()
|
||||
{
|
||||
#if !MOBILE
|
||||
//
|
||||
// Workaround for csc hardcoded behaviour where executing mscorlib
|
||||
// location is always the first path to search for references unless
|
||||
// they have full path. Mono build is using simple assembly names for
|
||||
// references and -lib for path which is by default csc dehaviour never
|
||||
// used
|
||||
//
|
||||
var sdk = Environment.GetEnvironmentVariable ("CSC_SDK_PATH_DISABLED");
|
||||
if (sdk != null)
|
||||
return null;
|
||||
#endif
|
||||
String dir = GetRuntimeDirectoryImpl();
|
||||
#if !DISABLE_CAS_USE
|
||||
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, dir).Demand();
|
||||
#endif
|
||||
return dir;
|
||||
}
|
||||
|
||||
#if MONO
|
||||
static String GetRuntimeDirectoryImpl()
|
||||
{
|
||||
return Path.GetDirectoryName (typeof (object).Assembly.Location);
|
||||
}
|
||||
#else
|
||||
[System.Security.SecurityCritical] // auto-generated
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
internal static extern String GetRuntimeDirectoryImpl();
|
||||
#endif
|
||||
|
||||
// Returns the system ConfigurationFile
|
||||
public static String SystemConfigurationFile {
|
||||
@ -113,19 +134,24 @@ namespace System.Runtime.InteropServices {
|
||||
[ResourceExposure(ResourceScope.Machine)]
|
||||
[ResourceConsumption(ResourceScope.Machine)]
|
||||
get {
|
||||
#if MONO
|
||||
String path = Environment.GetMachineConfigPath ();
|
||||
#else
|
||||
StringBuilder sb = new StringBuilder(Path.MAX_PATH);
|
||||
sb.Append(GetRuntimeDirectory());
|
||||
sb.Append(AppDomainSetup.RuntimeConfigurationFile);
|
||||
String path = sb.ToString();
|
||||
#endif
|
||||
|
||||
#if !DISABLE_CAS_USE
|
||||
// Do security check
|
||||
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand();
|
||||
|
||||
#endif
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
#if FEATURE_COMINTEROP
|
||||
#if FEATURE_COMINTEROP && !MONO
|
||||
[System.Security.SecurityCritical]
|
||||
[ResourceExposure(ResourceScope.Process)]
|
||||
[ResourceConsumption(ResourceScope.Process)]
|
||||
|
@ -1 +1 @@
|
||||
f0d95f2e3a9502289ad1dba49a96fc174998e83f
|
||||
7f83cf34517d801b0428a702ae9dd6fa9d28a79b
|
@ -233,10 +233,8 @@ AM_CONDITIONAL(POWERPC_DARWIN,test x$powerpc_darwin = xtrue)
|
||||
AC_MSG_CHECKING(for __sync_bool_compare_and_swap)
|
||||
AC_TRY_COMPILE([],[
|
||||
volatile unsigned int foo = 0;
|
||||
int main(int argc, char** argv) {
|
||||
unsigned int r1 = __sync_bool_compare_and_swap(&foo, 0, 1);
|
||||
return 0;
|
||||
}
|
||||
unsigned int r1 = __sync_bool_compare_and_swap(&foo, 0, 1);
|
||||
return 0;
|
||||
], [
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAS___SYNC_BOOL_COMPARE_AND_SWAP)
|
||||
|
@ -41,6 +41,8 @@ namespace Microsoft.Build.Tasks {
|
||||
ITaskItem[] assignedProjects;
|
||||
string solutionConfigurationContents;
|
||||
ITaskItem[] unassignedProjects;
|
||||
Dictionary<Guid, string> guidToConfigPlatform;
|
||||
Dictionary<string, string> absolutePathToConfigPlatform;
|
||||
|
||||
public AssignProjectConfiguration ()
|
||||
{
|
||||
@ -53,10 +55,10 @@ namespace Microsoft.Build.Tasks {
|
||||
return true;
|
||||
|
||||
XmlReader xr = null;
|
||||
Dictionary<Guid, string> guidToConfigPlatform = null;
|
||||
guidToConfigPlatform = new Dictionary<Guid, string> ();
|
||||
absolutePathToConfigPlatform = new Dictionary<string, string> ();
|
||||
try {
|
||||
xr = XmlReader.Create (new StringReader (solutionConfigurationContents));
|
||||
guidToConfigPlatform = new Dictionary<Guid, string> ();
|
||||
|
||||
xr.Read ();
|
||||
while (!xr.EOF) {
|
||||
@ -65,12 +67,20 @@ namespace Microsoft.Build.Tasks {
|
||||
continue;
|
||||
|
||||
string guid_str = xr.GetAttribute ("Project");
|
||||
string abs_path = xr.GetAttribute ("AbsolutePath");
|
||||
string config_str = xr.ReadString ();
|
||||
|
||||
if (String.IsNullOrEmpty (config_str))
|
||||
continue;
|
||||
|
||||
Guid guid;
|
||||
if (!String.IsNullOrEmpty (guid_str) && !String.IsNullOrEmpty (config_str) &&
|
||||
TryParseGuid (guid_str, out guid))
|
||||
if (TryParseGuid (guid_str, out guid))
|
||||
guidToConfigPlatform [guid] = config_str;
|
||||
|
||||
if (!String.IsNullOrEmpty (abs_path)) {
|
||||
abs_path = Path.GetFullPath (abs_path);
|
||||
absolutePathToConfigPlatform [abs_path] = config_str;
|
||||
}
|
||||
}
|
||||
} catch (XmlException xe) {
|
||||
Log.LogError ("XmlException while parsing SolutionConfigurationContents: {0}",
|
||||
@ -84,32 +94,22 @@ namespace Microsoft.Build.Tasks {
|
||||
List<ITaskItem> tempAssignedProjects = new List<ITaskItem> ();
|
||||
List<ITaskItem> tempUnassignedProjects = new List<ITaskItem> ();
|
||||
foreach (ITaskItem item in ProjectReferences) {
|
||||
string config;
|
||||
string config = GetConfigPlatformFromProjectReference (item);
|
||||
|
||||
string guid_str = item.GetMetadata ("Project");
|
||||
|
||||
Guid guid = Guid.Empty;
|
||||
if (!string.IsNullOrEmpty(guid_str) && !TryParseGuid (guid_str, out guid)) {
|
||||
Log.LogError ("Project reference '{0}' has invalid or missing guid for metadata 'Project'.",
|
||||
item.ItemSpec);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (guid != Guid.Empty && guidToConfigPlatform.TryGetValue (guid, out config)) {
|
||||
string [] parts = config.Split (new char [] {'|'}, 2);
|
||||
|
||||
ITaskItem new_item = new TaskItem (item);
|
||||
|
||||
new_item.SetMetadata ("SetConfiguration", "Configuration=" + parts [0]);
|
||||
new_item.SetMetadata ("SetPlatform", "Platform=" +
|
||||
((parts.Length > 1) ? parts [1] : String.Empty));
|
||||
|
||||
tempAssignedProjects.Add (new_item);
|
||||
} else {
|
||||
Log.LogWarning ("Project reference '{0}' could not be resolved.",
|
||||
item.ItemSpec);
|
||||
if (String.IsNullOrEmpty (config)) {
|
||||
tempUnassignedProjects.Add (item);
|
||||
continue;
|
||||
}
|
||||
|
||||
string [] parts = config.Split (new char [] {'|'}, 2);
|
||||
|
||||
ITaskItem new_item = new TaskItem (item);
|
||||
|
||||
new_item.SetMetadata ("SetConfiguration", "Configuration=" + parts [0]);
|
||||
new_item.SetMetadata ("SetPlatform", "Platform=" +
|
||||
((parts.Length > 1) ? parts [1] : String.Empty));
|
||||
|
||||
tempAssignedProjects.Add (new_item);
|
||||
}
|
||||
|
||||
assignedProjects = tempAssignedProjects.ToArray ();
|
||||
@ -118,9 +118,29 @@ namespace Microsoft.Build.Tasks {
|
||||
return true;
|
||||
}
|
||||
|
||||
string GetConfigPlatformFromProjectReference (ITaskItem item)
|
||||
{
|
||||
string guid_str = item.GetMetadata ("Project");
|
||||
string proj_full_path = item.GetMetadata ("FullPath");
|
||||
|
||||
string config;
|
||||
Guid guid = Guid.Empty;
|
||||
if (TryParseGuid (guid_str, out guid) && guidToConfigPlatform.TryGetValue (guid, out config))
|
||||
return config;
|
||||
|
||||
string abs_path = item.GetMetadata ("FullPath");
|
||||
if (absolutePathToConfigPlatform.TryGetValue (abs_path, out config))
|
||||
return config;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool TryParseGuid (string guid_str, out Guid guid)
|
||||
{
|
||||
guid = Guid.Empty;
|
||||
if (String.IsNullOrEmpty (guid_str))
|
||||
return false;
|
||||
|
||||
try {
|
||||
guid = new Guid (guid_str);
|
||||
} catch (ArgumentNullException) {
|
||||
|
@ -32,6 +32,7 @@ using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Tasks;
|
||||
using Microsoft.Build.Utilities;
|
||||
using NUnit.Framework;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace MonoTests.Microsoft.Build.Tasks
|
||||
@ -58,22 +59,73 @@ namespace MonoTests.Microsoft.Build.Tasks
|
||||
"{DAE34193-B5C7-4488-A911-29EE15C84CBE}"
|
||||
};
|
||||
|
||||
CreateAndCheckProject (guids, project_ref_guids, new string[] {
|
||||
"AssignedProjects : foo0.csproj;foo1.csproj;foo2.csproj;foo3.csproj: SetConfig: Configuration=Release",
|
||||
CreateAndCheckProject (guids, new bool[] {true, true, true, true, true, true},
|
||||
project_ref_guids, new string[] {
|
||||
"AssignedProjects : foo0.csproj;foo1.csproj;foo2.csproj;foo3.csproj;foo4.csproj: SetConfig: Configuration=Release",
|
||||
"AssignedProjects : foo0.csproj: SetPlatform: Platform=AnyCPU0",
|
||||
"AssignedProjects : foo1.csproj: SetPlatform: Platform=AnyCPU1",
|
||||
"AssignedProjects : foo2.csproj: SetPlatform: Platform=AnyCPU2",
|
||||
"AssignedProjects : foo3.csproj: SetPlatform: Platform=AnyCPU3",
|
||||
"UnassignedProjects : foo4.csproj"},
|
||||
"AssignedProjects : foo4.csproj: SetPlatform: Platform=AnyCPU4",
|
||||
"UnassignedProjects : "},
|
||||
true,
|
||||
"A1#");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidProjectGuid ()
|
||||
public void TestNoGuidAndNoAbsolutePathFound()
|
||||
{
|
||||
string[] guids = new string[] {
|
||||
"asd"
|
||||
};
|
||||
|
||||
string[] project_ref_guids = new string[] {
|
||||
"{DAE34193-B5C7-4488-A911-29EE15C84CB8}",
|
||||
"invalid guid",
|
||||
""
|
||||
};
|
||||
|
||||
CreateAndCheckProject (guids, new bool[]{false},
|
||||
project_ref_guids,
|
||||
new string[] {
|
||||
"AssignedProjects : : SetConfig: ",
|
||||
"AssignedProjects : : SetPlatform: ",
|
||||
"UnassignedProjects : foo0.csproj;foo1.csproj;foo2.csproj"
|
||||
},
|
||||
true, "A1#");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidProjectGuidWithAbsolutePath ()
|
||||
{
|
||||
string[] guids = new string[] {
|
||||
null, // no AbsPath
|
||||
"another invalid guid", // has AbsPath
|
||||
};
|
||||
|
||||
string[] project_ref_guids = new string[] {
|
||||
"1234zxc", // this won't match because no AbsPath
|
||||
"xzxoiu", // match with the second project, foo1.csproj
|
||||
"{23F291D9-78DF-4133-8CF2-78CE104DDE63}",
|
||||
"badref" // no corresponding project at all
|
||||
};
|
||||
|
||||
CreateAndCheckProject (guids, new bool[]{false, true},
|
||||
project_ref_guids,
|
||||
new string[] {
|
||||
"AssignedProjects : foo1.csproj: SetConfig: Configuration=Release",
|
||||
"AssignedProjects : foo1.csproj: SetPlatform: Platform=AnyCPU1",
|
||||
"UnassignedProjects : foo0.csproj;foo2.csproj;foo3.csproj"
|
||||
},
|
||||
true, "A1#");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoGuidWithAbsolutePath ()
|
||||
{
|
||||
string[] guids = new string[] {
|
||||
"",
|
||||
null
|
||||
};
|
||||
|
||||
string[] project_ref_guids = new string[] {
|
||||
@ -82,7 +134,14 @@ namespace MonoTests.Microsoft.Build.Tasks
|
||||
"invalid guid"
|
||||
};
|
||||
|
||||
CreateAndCheckProject (guids, project_ref_guids, null, false, "A1#");
|
||||
CreateAndCheckProject (guids, new bool[]{true, false},
|
||||
project_ref_guids,
|
||||
new string[] {
|
||||
"AssignedProjects : foo0.csproj: SetConfig: Configuration=Release",
|
||||
"AssignedProjects : foo0.csproj: SetPlatform: Platform=AnyCPU0",
|
||||
"UnassignedProjects : foo1.csproj;foo2.csproj"
|
||||
},
|
||||
true, "A1#");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -97,7 +156,8 @@ namespace MonoTests.Microsoft.Build.Tasks
|
||||
"{23F291D9-78DF-4133-8CF2-78CE104DDE63}"
|
||||
};
|
||||
|
||||
CreateAndCheckProject (guids, project_ref_guids,
|
||||
CreateAndCheckProject (guids, new bool[]{false, true},
|
||||
project_ref_guids,
|
||||
new string [] {
|
||||
"AssignedProjects : foo1.csproj: SetConfig: Configuration=Release",
|
||||
"AssignedProjects : foo1.csproj: SetPlatform: Platform=AnyCPU0",
|
||||
@ -106,14 +166,14 @@ namespace MonoTests.Microsoft.Build.Tasks
|
||||
}
|
||||
|
||||
|
||||
void CreateAndCheckProject (string[] guids, string[] project_ref_guids, string[] messages, bool build_result, string prefix)
|
||||
void CreateAndCheckProject (string[] guids, bool[] set_project_paths, string[] project_ref_guids, string[] messages, bool build_result, string prefix)
|
||||
{
|
||||
Engine engine = new Engine (Consts.BinPath);
|
||||
Project project = engine.CreateNewProject ();
|
||||
TestMessageLogger testLogger = new TestMessageLogger ();
|
||||
engine.RegisterLogger (testLogger);
|
||||
|
||||
string projectString = CreateProject (guids, project_ref_guids);
|
||||
string projectString = CreateProject (guids, set_project_paths, project_ref_guids);
|
||||
project.LoadXml (projectString);
|
||||
|
||||
try {
|
||||
@ -131,12 +191,12 @@ namespace MonoTests.Microsoft.Build.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
string CreateProject (string[] guids, string[] project_ref_guids)
|
||||
string CreateProject (string[] guids, bool[] set_project_paths, string[] project_ref_guids)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
sb.Append (@"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">");
|
||||
sb.Append ("\n" + GetUsingTask ("AssignProjectConfiguration"));
|
||||
sb.AppendFormat (@"<PropertyGroup>{0}</PropertyGroup>", CreateSolutionConfigurationProperty (guids, "Release|AnyCPU"));
|
||||
sb.AppendFormat (@"<PropertyGroup>{0}</PropertyGroup>", CreateSolutionConfigurationProperty (guids, set_project_paths, "Release|AnyCPU"));
|
||||
sb.Append (CreateProjectReferencesItemGroup (project_ref_guids));
|
||||
|
||||
sb.Append ("\n\t<Target Name=\"1\">\n");
|
||||
@ -154,13 +214,19 @@ namespace MonoTests.Microsoft.Build.Tasks
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
string CreateSolutionConfigurationProperty (string[] guids, string config_str)
|
||||
string CreateSolutionConfigurationProperty (string[] guids, bool[] set_project_paths, string config_str)
|
||||
{
|
||||
string abs_proj_path_prefix = Path.GetFullPath ("foo");
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
sb.Append ("\n<CurrentSolutionConfigurationContents>\n");
|
||||
sb.Append ("\t<foo xmlns=\"\">\n");
|
||||
for (int i = 0; i < guids.Length; i++) {
|
||||
sb.AppendFormat ("\t\t<bar Project=\"{0}\">{1}{2}</bar>\n",
|
||||
sb.Append ("\t\t<bar");
|
||||
if (guids[i] != null)
|
||||
sb.AppendFormat (" Project=\"{0}\"", guids[i]);
|
||||
if (set_project_paths[i])
|
||||
sb.AppendFormat (" AbsolutePath=\"{0}{1}.csproj\" ", abs_proj_path_prefix, i);
|
||||
sb.AppendFormat (">{1}{2}</bar>\n",
|
||||
guids[i], config_str, i);
|
||||
}
|
||||
sb.Append ("\t</foo>\n");
|
||||
@ -173,8 +239,12 @@ namespace MonoTests.Microsoft.Build.Tasks
|
||||
{
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
sb.Append ("\n<ItemGroup>\n");
|
||||
for (int i = 0; i < guids.Length; i ++)
|
||||
sb.AppendFormat ("\t<ProjectReference Include=\"foo{1}.csproj\"><Project>{0}</Project></ProjectReference>\n", guids [i], i);
|
||||
for (int i = 0; i < guids.Length; i ++) {
|
||||
sb.AppendFormat ("\t<ProjectReference Include=\"foo{0}.csproj\">", i);
|
||||
if (guids[i] != null)
|
||||
sb.AppendFormat ("<Project>{0}</Project>", guids[i]);
|
||||
sb.Append ("</ProjectReference>\n");
|
||||
}
|
||||
sb.Append ("</ItemGroup>\n");
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
@ -145,13 +145,6 @@ namespace MonoTests.Microsoft.Build.Tasks {
|
||||
|
||||
Assert.AreEqual (0, testLogger.CheckHead ("Text", "HelpKeyword", "Code"), "A1");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExecute1 ()
|
||||
{
|
||||
Error error = new Error ();
|
||||
Assert.AreEqual (false, error.Execute (), "A1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,6 +197,19 @@ namespace MonoTests.Microsoft.Build.Tasks
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int CheckFullLog (string text)
|
||||
{
|
||||
for (int i = 0; i < all_messages.Count; i ++) {
|
||||
BuildEventArgs arg = all_messages [i];
|
||||
if (text == arg.Message) {
|
||||
all_messages.RemoveAt (i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public void DumpMessages ()
|
||||
{
|
||||
foreach (BuildEventArgs arg in all_messages)
|
||||
|
@ -16,7 +16,18 @@ LIB_MCS_FLAGS = \
|
||||
/r:System.Xml.dll \
|
||||
/r:$(XBUILD_FRAMEWORK)
|
||||
|
||||
TEST_MCS_FLAGS = /r:$(XBUILD_ENGINE) /r:$(XBUILD_FRAMEWORK) -r:System.dll -r:System.Core.dll
|
||||
TEST_RESX_RESOURCES = Test/Microsoft.Build.Utilities/Strings.resources
|
||||
|
||||
TEST_MCS_FLAGS = /r:$(XBUILD_ENGINE) /r:$(XBUILD_FRAMEWORK) -r:System.dll -r:System.Core.dll $(TEST_RESX_RESOURCES:%=-resource:%)
|
||||
|
||||
include $(XBUILD_DIR)/xbuild_test.make
|
||||
include ../../build/library.make
|
||||
|
||||
EXTRA_DISTFILES = $(TEST_RESX_RESOURCES:.resources=.resx)
|
||||
|
||||
CLEAN_FILES += $(TEST_RESX_RESOURCES)
|
||||
|
||||
$(TEST_RESX_RESOURCES): %.resources: %.resx
|
||||
$(RESGEN) $< || cp $@.prebuilt $@
|
||||
|
||||
$(test_lib): $(TEST_RESX_RESOURCES)
|
||||
|
@ -38,7 +38,6 @@ namespace Microsoft.Build.Utilities
|
||||
string helpKeywordPrefix;
|
||||
ITaskHost hostObject;
|
||||
TaskLoggingHelper log;
|
||||
ResourceManager taskResources;
|
||||
|
||||
protected Task()
|
||||
: this (null, null)
|
||||
@ -53,7 +52,8 @@ namespace Microsoft.Build.Utilities
|
||||
protected Task(ResourceManager taskResources,
|
||||
string helpKeywordPrefix)
|
||||
{
|
||||
this.taskResources = taskResources;
|
||||
log = new TaskLoggingHelper (this);
|
||||
log.TaskResources = taskResources;
|
||||
this.helpKeywordPrefix = helpKeywordPrefix;
|
||||
}
|
||||
|
||||
@ -65,7 +65,6 @@ namespace Microsoft.Build.Utilities
|
||||
}
|
||||
set {
|
||||
buildEngine = value;
|
||||
log = new TaskLoggingHelper (this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,10 +98,10 @@ namespace Microsoft.Build.Utilities
|
||||
|
||||
protected ResourceManager TaskResources {
|
||||
get {
|
||||
return taskResources;
|
||||
return log.TaskResources;
|
||||
}
|
||||
set {
|
||||
taskResources = value;
|
||||
log.TaskResources = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,11 +41,14 @@ namespace Microsoft.Build.Utilities
|
||||
string helpKeywordPrefix;
|
||||
string taskName;
|
||||
ResourceManager taskResources;
|
||||
ITask taskInstance;
|
||||
|
||||
public TaskLoggingHelper (ITask taskInstance)
|
||||
{
|
||||
if (taskInstance != null)
|
||||
this.buildEngine = taskInstance.BuildEngine;
|
||||
if (taskInstance == null)
|
||||
throw new ArgumentNullException ("taskInstance");
|
||||
|
||||
this.taskInstance = taskInstance;
|
||||
taskName = null;
|
||||
}
|
||||
|
||||
@ -67,7 +70,14 @@ namespace Microsoft.Build.Utilities
|
||||
if (resourceName == null)
|
||||
throw new ArgumentNullException ("resourceName");
|
||||
|
||||
return null;
|
||||
if (taskResources == null)
|
||||
throw new InvalidOperationException ("Task did not register any task resources");
|
||||
|
||||
string resourceString = taskResources.GetString (resourceName);
|
||||
if (resourceString == null)
|
||||
throw new ArgumentException ($"No resource string found for resource named {resourceName}");
|
||||
|
||||
return FormatString (resourceString, args);
|
||||
}
|
||||
|
||||
[MonoTODO]
|
||||
@ -100,10 +110,12 @@ namespace Microsoft.Build.Utilities
|
||||
if (message == null)
|
||||
throw new ArgumentNullException ("message");
|
||||
|
||||
ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
|
||||
|
||||
BuildErrorEventArgs beea = new BuildErrorEventArgs (
|
||||
null, null, buildEngine.ProjectFileOfTaskNode, 0, 0, 0, 0, FormatString (message, messageArgs),
|
||||
null, null, BuildEngine.ProjectFileOfTaskNode, 0, 0, 0, 0, FormatString (message, messageArgs),
|
||||
helpKeywordPrefix, null);
|
||||
buildEngine.LogErrorEvent (beea);
|
||||
BuildEngine.LogErrorEvent (beea);
|
||||
hasLoggedErrors = true;
|
||||
}
|
||||
|
||||
@ -117,12 +129,14 @@ namespace Microsoft.Build.Utilities
|
||||
if (message == null)
|
||||
throw new ArgumentNullException ("message");
|
||||
|
||||
ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
|
||||
|
||||
BuildErrorEventArgs beea = new BuildErrorEventArgs (
|
||||
subcategory, errorCode, file, lineNumber,
|
||||
columnNumber, endLineNumber, endColumnNumber,
|
||||
FormatString (message, messageArgs), helpKeyword /*it's helpKeyword*/,
|
||||
null /*it's senderName*/);
|
||||
buildEngine.LogErrorEvent (beea);
|
||||
BuildEngine.LogErrorEvent (beea);
|
||||
hasLoggedErrors = true;
|
||||
}
|
||||
|
||||
@ -144,14 +158,16 @@ namespace Microsoft.Build.Utilities
|
||||
if (exception == null)
|
||||
throw new ArgumentNullException ("exception");
|
||||
|
||||
ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
|
||||
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
sb.Append (exception.Message);
|
||||
if (showStackTrace == true)
|
||||
sb.Append (exception.StackTrace);
|
||||
BuildErrorEventArgs beea = new BuildErrorEventArgs (
|
||||
null, null, buildEngine.ProjectFileOfTaskNode, 0, 0, 0, 0, sb.ToString (),
|
||||
null, null, BuildEngine.ProjectFileOfTaskNode, 0, 0, 0, 0, sb.ToString (),
|
||||
exception.HelpLink, exception.Source);
|
||||
buildEngine.LogErrorEvent (beea);
|
||||
BuildEngine.LogErrorEvent (beea);
|
||||
hasLoggedErrors = true;
|
||||
}
|
||||
|
||||
@ -159,7 +175,7 @@ namespace Microsoft.Build.Utilities
|
||||
params object[] messageArgs)
|
||||
{
|
||||
LogErrorFromResources (null, null, null, null, 0, 0, 0,
|
||||
0, messageResourceName, null);
|
||||
0, messageResourceName, messageArgs);
|
||||
}
|
||||
|
||||
public void LogErrorFromResources (string subcategoryResourceName,
|
||||
@ -172,13 +188,22 @@ namespace Microsoft.Build.Utilities
|
||||
string messageResourceName,
|
||||
params object[] messageArgs)
|
||||
{
|
||||
if (messageResourceName == null)
|
||||
throw new ArgumentNullException ("messageResourceName");
|
||||
|
||||
ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
|
||||
|
||||
string subcategory = null;
|
||||
if (!String.IsNullOrEmpty (subcategoryResourceName))
|
||||
subcategory = taskResources.GetString (subcategoryResourceName);
|
||||
|
||||
BuildErrorEventArgs beea = new BuildErrorEventArgs (
|
||||
taskResources.GetString (subcategoryResourceName),
|
||||
subcategory,
|
||||
errorCode, file, lineNumber, columnNumber,
|
||||
endLineNumber, endColumnNumber,
|
||||
taskResources.GetString (messageResourceName),
|
||||
FormatResourceString (messageResourceName, messageArgs),
|
||||
helpKeyword, null );
|
||||
buildEngine.LogErrorEvent (beea);
|
||||
BuildEngine.LogErrorEvent (beea);
|
||||
hasLoggedErrors = true;
|
||||
}
|
||||
|
||||
@ -226,16 +251,17 @@ namespace Microsoft.Build.Utilities
|
||||
public void LogMessageFromResources (string messageResourceName,
|
||||
params object[] messageArgs)
|
||||
{
|
||||
LogMessage (taskResources.GetString (messageResourceName),
|
||||
messageArgs);
|
||||
LogMessageFromResources (MessageImportance.Normal, messageResourceName, messageArgs);
|
||||
}
|
||||
|
||||
public void LogMessageFromResources (MessageImportance importance,
|
||||
string messageResourceName,
|
||||
params object[] messageArgs)
|
||||
{
|
||||
LogMessage (importance, taskResources.GetString (
|
||||
messageResourceName), messageArgs);
|
||||
if (messageResourceName == null)
|
||||
throw new ArgumentNullException ("messageResourceName");
|
||||
|
||||
LogMessage (importance, FormatResourceString (messageResourceName, messageArgs));
|
||||
}
|
||||
|
||||
public bool LogMessagesFromFile (string fileName)
|
||||
@ -280,10 +306,12 @@ namespace Microsoft.Build.Utilities
|
||||
if (lineOfText == null)
|
||||
throw new ArgumentNullException ("lineOfText");
|
||||
|
||||
ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
|
||||
|
||||
BuildMessageEventArgs bmea = new BuildMessageEventArgs (
|
||||
lineOfText, helpKeywordPrefix,
|
||||
null, messageImportance);
|
||||
buildEngine.LogMessageEvent (bmea);
|
||||
BuildEngine.LogMessageEvent (bmea);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -291,11 +319,13 @@ namespace Microsoft.Build.Utilities
|
||||
public void LogWarning (string message,
|
||||
params object[] messageArgs)
|
||||
{
|
||||
ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
|
||||
|
||||
// FIXME: what about all the parameters?
|
||||
BuildWarningEventArgs bwea = new BuildWarningEventArgs (
|
||||
null, null, buildEngine.ProjectFileOfTaskNode, 0, 0, 0, 0, FormatString (message, messageArgs),
|
||||
null, null, BuildEngine.ProjectFileOfTaskNode, 0, 0, 0, 0, FormatString (message, messageArgs),
|
||||
helpKeywordPrefix, null);
|
||||
buildEngine.LogWarningEvent (bwea);
|
||||
BuildEngine.LogWarningEvent (bwea);
|
||||
}
|
||||
|
||||
public void LogWarning (string subcategory, string warningCode,
|
||||
@ -305,11 +335,13 @@ namespace Microsoft.Build.Utilities
|
||||
string message,
|
||||
params object[] messageArgs)
|
||||
{
|
||||
ThrowInvalidOperationIf (BuildEngine == null, "Task is attempting to log before it was initialized");
|
||||
|
||||
BuildWarningEventArgs bwea = new BuildWarningEventArgs (
|
||||
subcategory, warningCode, file, lineNumber,
|
||||
columnNumber, endLineNumber, endColumnNumber,
|
||||
FormatString (message, messageArgs), helpKeyword, null);
|
||||
buildEngine.LogWarningEvent (bwea);
|
||||
BuildEngine.LogWarningEvent (bwea);
|
||||
}
|
||||
|
||||
public void LogWarningFromException (Exception exception)
|
||||
@ -331,8 +363,10 @@ namespace Microsoft.Build.Utilities
|
||||
public void LogWarningFromResources (string messageResourceName,
|
||||
params object[] messageArgs)
|
||||
{
|
||||
LogWarning (taskResources.GetString (messageResourceName),
|
||||
messageArgs);
|
||||
if (messageResourceName == null)
|
||||
throw new ArgumentNullException ("messageResourceName");
|
||||
|
||||
LogWarningFromResources (null, null, null, null, 0, 0, 0, 0, messageResourceName, messageArgs);
|
||||
}
|
||||
|
||||
public void LogWarningFromResources (string subcategoryResourceName,
|
||||
@ -346,11 +380,17 @@ namespace Microsoft.Build.Utilities
|
||||
string messageResourceName,
|
||||
params object[] messageArgs)
|
||||
{
|
||||
LogWarning (taskResources.GetString (subcategoryResourceName),
|
||||
if (messageResourceName == null)
|
||||
throw new ArgumentNullException ("messageResourceName");
|
||||
|
||||
string subcategory = null;
|
||||
if (!String.IsNullOrEmpty (subcategoryResourceName))
|
||||
subcategory = taskResources.GetString (subcategoryResourceName);
|
||||
|
||||
LogWarning (subcategory,
|
||||
warningCode, helpKeyword, file, lineNumber,
|
||||
columnNumber, endLineNumber, endColumnNumber,
|
||||
taskResources.GetString (messageResourceName),
|
||||
messageArgs);
|
||||
FormatResourceString (messageResourceName, messageArgs));
|
||||
}
|
||||
|
||||
public void LogWarningWithCodeFromResources (string messageResourceName,
|
||||
@ -391,9 +431,15 @@ namespace Microsoft.Build.Utilities
|
||||
{
|
||||
}
|
||||
|
||||
void ThrowInvalidOperationIf (bool condition, string message)
|
||||
{
|
||||
if (condition)
|
||||
throw new InvalidOperationException (message);
|
||||
}
|
||||
|
||||
protected IBuildEngine BuildEngine {
|
||||
get {
|
||||
return buildEngine;
|
||||
return taskInstance?.BuildEngine;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,3 +4,5 @@ Microsoft.Build.Utilities/TaskItemTest.cs
|
||||
Microsoft.Build.Utilities/TaskLoggingHelperTest.cs
|
||||
Microsoft.Build.Utilities/ToolLocationHelperTest.cs
|
||||
Microsoft.Build.Utilities/ToolTaskTest.cs
|
||||
../../Microsoft.Build.Tasks/Test/Microsoft.Build.Tasks/TestMessageLogger.cs
|
||||
../../Microsoft.Build.Engine/Test/Microsoft.Build.BuildEngine/Consts.cs
|
||||
|
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 1.3
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">1.3</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1">this is my long string</data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
[base64 mime encoded serialized .NET Framework object]
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
[base64 mime encoded string representing a byte array form of the .NET Framework object]
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used forserialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>1.3</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="MessageResource1">
|
||||
<value>Message from resources with arg '{0}'</value>
|
||||
</data>
|
||||
</root>
|
@ -3,8 +3,10 @@
|
||||
//
|
||||
// Author:
|
||||
// Marek Sieradzki (marek.sieradzki@gmail.com)
|
||||
// Ankit Jain (ankit.jain@xamarin.com)
|
||||
//
|
||||
// (C) 2005 Marek Sieradzki
|
||||
// (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
@ -27,15 +29,27 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
using Microsoft.Build.BuildEngine;
|
||||
using NUnit.Framework;
|
||||
using MonoTests.Microsoft.Build.Tasks;
|
||||
|
||||
namespace MonoTests.Microsoft.Build.Utilities {
|
||||
|
||||
class TestTask : Task {
|
||||
public static Action<TaskLoggingHelper> action = null;
|
||||
|
||||
public TestTask ()
|
||||
: base (new ResourceManager("Strings", typeof(TestTask).GetTypeInfo().Assembly))
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
action (Log);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -46,6 +60,11 @@ namespace MonoTests.Microsoft.Build.Utilities {
|
||||
TaskLoggingHelper tlh;
|
||||
TestTask task;
|
||||
|
||||
public TaskLoggingHelperTest ()
|
||||
{
|
||||
task = new TestTask ();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAssignment ()
|
||||
{
|
||||
@ -77,6 +96,218 @@ namespace MonoTests.Microsoft.Build.Utilities {
|
||||
string output;
|
||||
tlh.ExtractMessageCode (null, out output);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException (typeof (ArgumentNullException))]
|
||||
public void TestLogErrorFromResourcesNullMessage ()
|
||||
{
|
||||
tlh = new TaskLoggingHelper (task);
|
||||
tlh.LogErrorFromResources (null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException (typeof (ArgumentNullException))]
|
||||
public void TestLogErrorFromResourcesNullMessage2 ()
|
||||
{
|
||||
tlh = new TaskLoggingHelper (task);
|
||||
tlh.LogErrorFromResources (null, null, null, null, 0, 0, 0, 0, null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLogErrorFromResources1 ()
|
||||
{
|
||||
RunAndCheckTaskLoggingHelper (
|
||||
(tlh) => tlh.LogErrorFromResources ("MessageResource1", "foo"),
|
||||
(l) => Assert.IsTrue (l.CheckFullLog ("Message from resources with arg 'foo'") == 0, "Message not found")
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLogErrorFromResourcesNonExistantResourceName ()
|
||||
{
|
||||
RunAndCheckTaskLoggingHelper (
|
||||
(tlh) => tlh.LogErrorFromResources ("NonExistantResourceName", "foo"),
|
||||
null,
|
||||
(p, l) => {
|
||||
Assert.IsFalse (p.Build (), "Build should have failed");
|
||||
Assert.IsTrue (l.CheckFullLog (
|
||||
"Error executing task TestTask: No resource string found for resource named NonExistantResourceName") == 0,
|
||||
"Error not found in the log");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestLogErrorFromResourcesNullSubcategoryResourceName ()
|
||||
{
|
||||
RunAndCheckTaskLoggingHelper (
|
||||
(tlh) => tlh.LogErrorFromResources (null, null, null, null, 0, 0, 0, 0, "MessageResource1", "foo"),
|
||||
(l) => Assert.IsTrue (l.CheckFullLog ("Message from resources with arg 'foo'") == 0, "Message not found")
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException (typeof (ArgumentNullException))]
|
||||
public void TestLogWarningFromResourcesNullMessage ()
|
||||
{
|
||||
tlh = new TaskLoggingHelper (task);
|
||||
tlh.LogWarningFromResources (null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException (typeof (ArgumentNullException))]
|
||||
public void TestLogWarningFromResourcesNullMessage2 ()
|
||||
{
|
||||
tlh = new TaskLoggingHelper (task);
|
||||
tlh.LogWarningFromResources (null, null, null, null, 0, 0, 0, 0, null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLogWarningFromResourcesNullSubcategoryResourceName ()
|
||||
{
|
||||
RunAndCheckTaskLoggingHelper (
|
||||
(tlh) => tlh.LogWarningFromResources (null, null, null, null, 0, 0, 0, 0, "MessageResource1", "foo"),
|
||||
(l) => Assert.IsTrue (l.CheckFullLog ("Message from resources with arg 'foo'") == 0, "Message not found")
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLogWarningFromResources1 ()
|
||||
{
|
||||
RunAndCheckTaskLoggingHelper (
|
||||
(tlh) => tlh.LogWarningFromResources ("MessageResource1", "foo"),
|
||||
(l) => Assert.IsTrue (l.CheckFullLog ("Message from resources with arg 'foo'") == 0, "Message not found")
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLogWarningFromResourcesNonExistantResourceName ()
|
||||
{
|
||||
RunAndCheckTaskLoggingHelper (
|
||||
(tlh) => tlh.LogWarningFromResources ("NonExistantResourceName", "foo"),
|
||||
null,
|
||||
(p, l) => {
|
||||
if (p.Build ()) { l.DumpMessages (); Assert.Fail ("Build should have failed"); }
|
||||
Assert.IsTrue (l.CheckFullLog (
|
||||
"Error executing task TestTask: No resource string found for resource named NonExistantResourceName") == 0,
|
||||
"Error not found in the log");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
[ExpectedException (typeof (ArgumentNullException))]
|
||||
public void TestLogMessageFromResourcesNullMessage ()
|
||||
{
|
||||
tlh = new TaskLoggingHelper (task);
|
||||
tlh.LogMessageFromResources (null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException (typeof (ArgumentNullException))]
|
||||
public void TestLogMessageFromResourcesNullMessage2 ()
|
||||
{
|
||||
tlh = new TaskLoggingHelper (task);
|
||||
tlh.LogMessageFromResources (MessageImportance.Low, null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLogMessageFromResources1 ()
|
||||
{
|
||||
RunAndCheckTaskLoggingHelper (
|
||||
(tlh) => tlh.LogMessageFromResources ("MessageResource1", "foo"),
|
||||
(l) => Assert.IsTrue (l.CheckFullLog ("Message from resources with arg 'foo'") == 0, "Message not found")
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLogMessageFromResourcesNonExistantResourceName ()
|
||||
{
|
||||
RunAndCheckTaskLoggingHelper (
|
||||
(tlh) => tlh.LogMessageFromResources ("NonExistantResourceName", "foo"),
|
||||
null,
|
||||
(p, l) => {
|
||||
if (p.Build ()) { l.DumpMessages (); Assert.Fail ("Build should have failed"); }
|
||||
l.DumpMessages ();
|
||||
Assert.IsTrue (l.CheckFullLog (
|
||||
"Error executing task TestTask: No resource string found for resource named NonExistantResourceName") == 0,
|
||||
"Error not found in the log");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException (typeof (ArgumentNullException))]
|
||||
public void TestFormatResourceString1 ()
|
||||
{
|
||||
tlh = new TaskLoggingHelper (task);
|
||||
tlh.FormatResourceString (null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ExpectedException (typeof (InvalidOperationException))]
|
||||
public void TestFormatResourceString2 ()
|
||||
{
|
||||
tlh = new TaskLoggingHelper (task);
|
||||
tlh.FormatResourceString ("MessageResource1");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFormatResourceString3 ()
|
||||
{
|
||||
RunAndCheckTaskLoggingHelper (
|
||||
(tlh) => tlh.FormatResourceString ("NonExistantResourceName"),
|
||||
null,
|
||||
(p, l) => {
|
||||
if (p.Build ()) { l.DumpMessages (); Assert.Fail ("Build should have failed"); }
|
||||
l.DumpMessages ();
|
||||
Assert.IsTrue (l.CheckFullLog (
|
||||
"Error executing task TestTask: No resource string found for resource named NonExistantResourceName") == 0,
|
||||
"Error not found in the log");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFormatResourceString4 ()
|
||||
{
|
||||
RunAndCheckTaskLoggingHelper (
|
||||
(tlh) => Assert.AreEqual (
|
||||
tlh.FormatResourceString ("MessageResource1", "foo"),
|
||||
"Message from resources with arg 'foo'"),
|
||||
null
|
||||
);
|
||||
}
|
||||
void RunAndCheckTaskLoggingHelper (Action<TaskLoggingHelper> taskAction, Action<TestMessageLogger> loggerAction, Action<Project, TestMessageLogger> projectBuildAction = null)
|
||||
{
|
||||
string asmLocation = typeof (TaskLoggingHelperTest).Assembly.Location;
|
||||
string project_xml = @"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">
|
||||
<UsingTask TaskName='MonoTests.Microsoft.Build.Utilities.TestTask' AssemblyFile='" + asmLocation + @"' />
|
||||
<Target Name=""1"">
|
||||
<TestTask />
|
||||
</Target>
|
||||
</Project>";
|
||||
|
||||
Engine engine = new Engine (Consts.BinPath);
|
||||
Project proj = engine.CreateNewProject ();
|
||||
proj.LoadXml (project_xml);
|
||||
TestMessageLogger logger = new TestMessageLogger ();
|
||||
engine.RegisterLogger (logger);
|
||||
|
||||
TestTask.action = taskAction;
|
||||
|
||||
if (projectBuildAction == null) {
|
||||
if (!proj.Build ("1")) {
|
||||
logger.DumpMessages ();
|
||||
Assert.Fail ("Build failed");
|
||||
}
|
||||
} else
|
||||
projectBuildAction (proj, logger);
|
||||
|
||||
if (loggerAction != null)
|
||||
loggerAction (logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,3 +70,4 @@ using System.Runtime.InteropServices;
|
||||
[assembly: InternalsVisibleTo ("Mono.Security.Providers.OldTls, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")]
|
||||
[assembly: InternalsVisibleTo ("Mono.Security.Providers.DotNet, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")]
|
||||
[assembly: InternalsVisibleTo ("Mono.Security.Providers.NewSystemSource, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")]
|
||||
[assembly: InternalsVisibleTo ("Xamarin.BoringTls, PublicKey=002400000480000094000000060200000024000052534131000400001100000099dd12eda85767ae6f06023ee28e711c7e5a212462095c83868c29db75eddf6d8e296e03824c14fedd5f55553fed0b6173be3cc985a4b7f9fb7c83ccff8ba3938563b3d1f45a81122f12a1bcb73edcaad61a8456c7595a6da5184b4dd9d10f011b949ef1391fccfeab1ba62aa51c267ef8bd57ef1b6ba5a4c515d0badb81a78f")]
|
||||
|
@ -21,5 +21,5 @@ EXTRA_DISTFILES = Mono.Security.Interface/README.md
|
||||
|
||||
#
|
||||
# Update this comment to trigger a build in System
|
||||
# +2
|
||||
# +3
|
||||
#
|
||||
|
@ -95,6 +95,14 @@ namespace Mono.Security.Interface
|
||||
* If @serverMode is true, then we're a server and want to validate a certificate that we received from a client.
|
||||
*/
|
||||
ValidationResult ValidateCertificate (string targetHost, bool serverMode, X509CertificateCollection certificates);
|
||||
}
|
||||
|
||||
internal interface ICertificateValidator2 : ICertificateValidator
|
||||
{
|
||||
/*
|
||||
* Internal use only.
|
||||
*/
|
||||
ValidationResult ValidateCertificate (string targetHost, bool serverMode, X509Certificate leaf, X509Chain chain);
|
||||
|
||||
/*
|
||||
* On OS X and Mobile, the @chain will be initialized with the @certificates, but not actually built.
|
||||
@ -137,25 +145,20 @@ namespace Mono.Security.Interface
|
||||
get { return supportsTrustAnchors; }
|
||||
}
|
||||
|
||||
static ICertificateValidator GetDefaultValidator (MonoTlsProvider provider, MonoTlsSettings settings)
|
||||
{
|
||||
return (ICertificateValidator)NoReflectionHelper.GetDefaultCertificateValidator (provider, settings);
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal API, intended to be used by MonoTlsProvider implementations.
|
||||
*/
|
||||
public static ICertificateValidator GetValidator (MonoTlsProvider provider, MonoTlsSettings settings)
|
||||
internal static ICertificateValidator2 GetDefaultValidator (MonoTlsSettings settings, MonoTlsProvider provider)
|
||||
{
|
||||
return GetDefaultValidator (provider, settings);
|
||||
return (ICertificateValidator2)NoReflectionHelper.GetDefaultCertificateValidator (provider, settings);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use this overloaded version in user code.
|
||||
*/
|
||||
public static ICertificateValidator GetValidator (MonoTlsSettings settings)
|
||||
public static ICertificateValidator GetValidator (MonoTlsSettings settings, MonoTlsProvider provider = null)
|
||||
{
|
||||
return GetDefaultValidator (null, settings);
|
||||
return GetDefaultValidator (settings, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,12 +124,32 @@ namespace Mono.Security.Interface
|
||||
|
||||
#endregion
|
||||
|
||||
#region Native Certificate Implementation
|
||||
|
||||
internal virtual bool HasNativeCertificates {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
internal virtual X509Certificate2Impl GetNativeCertificate (
|
||||
byte[] data, string password, X509KeyStorageFlags flags)
|
||||
{
|
||||
throw new InvalidOperationException ();
|
||||
}
|
||||
|
||||
internal virtual X509Certificate2Impl GetNativeCertificate (
|
||||
X509Certificate certificate)
|
||||
{
|
||||
throw new InvalidOperationException ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Certificate Validation
|
||||
|
||||
/*
|
||||
* Allows a TLS provider to provide a custom system certificiate validator.
|
||||
*/
|
||||
public virtual bool HasCustomSystemCertificateValidator {
|
||||
internal virtual bool HasCustomSystemCertificateValidator {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
@ -142,13 +162,12 @@ namespace Mono.Security.Interface
|
||||
* Returns `true` if certificate validation has been performed and `false` to invoke the
|
||||
* default system validator.
|
||||
*/
|
||||
public virtual bool InvokeSystemCertificateValidator (
|
||||
ICertificateValidator validator, string targetHost, bool serverMode,
|
||||
X509CertificateCollection certificates, X509Chain chain, out bool success,
|
||||
ref MonoSslPolicyErrors errors, ref int status11)
|
||||
internal virtual bool InvokeSystemCertificateValidator (
|
||||
ICertificateValidator2 validator, string targetHost, bool serverMode,
|
||||
X509CertificateCollection certificates, bool wantsChain, ref X509Chain chain,
|
||||
out bool success, ref MonoSslPolicyErrors errors, ref int status11)
|
||||
{
|
||||
success = false;
|
||||
return false;
|
||||
throw new InvalidOperationException ();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -313,6 +313,20 @@ namespace System.Net.Http.Headers
|
||||
start = pos - 1;
|
||||
while (pos < s.Length) {
|
||||
ch = s [pos++];
|
||||
|
||||
//
|
||||
// The backslash character ("\") MAY be used as a single-character
|
||||
// quoting mechanism only within quoted-string
|
||||
//
|
||||
if (ch == '\\') {
|
||||
if (pos + 1 < s.Length) {
|
||||
++pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch == '"') {
|
||||
ttype = Token.Type.QuotedString;
|
||||
break;
|
||||
|
@ -74,6 +74,12 @@ namespace MonoTests.System.Net.Http.Headers
|
||||
Assert.AreEqual ("\"mm\"", res.Tag, "#11");
|
||||
Assert.IsTrue (res.IsWeak, "#12");
|
||||
Assert.AreEqual ("W/\"mm\"", res.ToString (), "#13");
|
||||
|
||||
|
||||
res = EntityTagHeaderValue.Parse ("\"\\\"123\\\"\"");
|
||||
Assert.AreEqual ("\"\\\"123\\\"\"", res.Tag, "#21");
|
||||
Assert.IsFalse (res.IsWeak, "#22");
|
||||
Assert.AreEqual ("\"\\\"123\\\"\"", res.ToString (), "#23");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -152,15 +152,16 @@ namespace MonoTests.System.Net.Http
|
||||
|
||||
const int WaitTimeout = 5000;
|
||||
|
||||
string port, TestHost, LocalServer;
|
||||
string TestHost, LocalServer;
|
||||
int port;
|
||||
|
||||
[SetUp]
|
||||
public void SetupFixture ()
|
||||
{
|
||||
if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
|
||||
port = "810";
|
||||
port = 810;
|
||||
} else {
|
||||
port = "8810";
|
||||
port = 8810;
|
||||
}
|
||||
|
||||
TestHost = "localhost:" + port;
|
||||
@ -1060,9 +1061,20 @@ namespace MonoTests.System.Net.Http
|
||||
var response = l.Response;
|
||||
|
||||
response.StatusCode = (int)HttpStatusCode.Moved;
|
||||
response.RedirectLocation = "http://xamarin.com/";
|
||||
response.RedirectLocation = "http://localhost:8811/";
|
||||
});
|
||||
|
||||
var listener2 = CreateListener (l => {
|
||||
var response = l.Response;
|
||||
|
||||
response.StatusCode = (int)HttpStatusCode.OK;
|
||||
response.OutputStream.WriteByte (0x68);
|
||||
response.OutputStream.WriteByte (0x65);
|
||||
response.OutputStream.WriteByte (0x6c);
|
||||
response.OutputStream.WriteByte (0x6c);
|
||||
response.OutputStream.WriteByte (0x6f);
|
||||
}, 8811);
|
||||
|
||||
try {
|
||||
var chandler = new HttpClientHandler ();
|
||||
chandler.AllowAutoRedirect = true;
|
||||
@ -1071,10 +1083,13 @@ namespace MonoTests.System.Net.Http
|
||||
var r = client.GetAsync (LocalServer);
|
||||
Assert.IsTrue (r.Wait (WaitTimeout), "#1");
|
||||
var resp = r.Result;
|
||||
Assert.AreEqual ("http://xamarin.com/", resp.RequestMessage.RequestUri.AbsoluteUri, "#2");
|
||||
Assert.AreEqual ("http://localhost:8811/", resp.RequestMessage.RequestUri.AbsoluteUri, "#2");
|
||||
Assert.AreEqual ("hello", resp.Content.ReadAsStringAsync ().Result, "#3");
|
||||
} finally {
|
||||
listener.Abort ();
|
||||
listener.Close ();
|
||||
listener2.Abort ();
|
||||
listener2.Close ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1131,6 +1146,11 @@ namespace MonoTests.System.Net.Http
|
||||
}
|
||||
|
||||
HttpListener CreateListener (Action<HttpListenerContext> contextAssert)
|
||||
{
|
||||
return CreateListener (contextAssert, port);
|
||||
}
|
||||
|
||||
HttpListener CreateListener (Action<HttpListenerContext> contextAssert, int port)
|
||||
{
|
||||
var l = new HttpListener ();
|
||||
l.Prefixes.Add (string.Format ("http://+:{0}/", port));
|
||||
|
@ -4,9 +4,13 @@ include ../../build/rules.make
|
||||
|
||||
LIBRARY = System.Runtime.Remoting.dll
|
||||
|
||||
LIB_REFS = System System.Web System.Xml System.Runtime.Serialization.Formatters.Soap
|
||||
LIB_REFS = System System.Xml System.Runtime.Serialization.Formatters.Soap
|
||||
LIB_MCS_FLAGS = /r:$(corlib)
|
||||
|
||||
ifndef NO_SYSTEM_WEB_DEPENDENCY
|
||||
LIB_REFS += System.Web
|
||||
endif
|
||||
|
||||
TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -nowarn:618 /r:System.Runtime.Remoting.dll
|
||||
|
||||
TEST_MONO_PATH = .
|
||||
|
@ -0,0 +1,56 @@
|
||||
Assembly/AssemblyInfo.cs
|
||||
../../build/common/Consts.cs
|
||||
../../build/common/Locale.cs
|
||||
../../build/common/MonoTODOAttribute.cs
|
||||
System.Runtime.Remoting.Channels/BinaryClientFormatterSink.cs
|
||||
System.Runtime.Remoting.Channels/BinaryClientFormatterSinkProvider.cs
|
||||
System.Runtime.Remoting.Channels/BinaryCore.cs
|
||||
System.Runtime.Remoting.Channels/BinaryServerFormatterSink.cs
|
||||
System.Runtime.Remoting.Channels/BinaryServerFormatterSinkProvider.cs
|
||||
System.Runtime.Remoting.Channels/ChannelCore.cs
|
||||
System.Runtime.Remoting.Channels/CommonTransportKeys.cs
|
||||
System.Runtime.Remoting.Channels/IAuthorizeRemotingConnection.cs
|
||||
System.Runtime.Remoting.Channels/RemotingThreadPool.cs
|
||||
System.Runtime.Remoting.Channels/SoapClientFormatterSink.cs
|
||||
System.Runtime.Remoting.Channels/SoapCore.cs
|
||||
System.Runtime.Remoting.Channels/SoapServerFormatterSink.cs
|
||||
System.Runtime.Remoting.Channels/SoapClientFormatterSinkProvider.cs
|
||||
System.Runtime.Remoting.Channels/SoapServerFormatterSinkProvider.cs
|
||||
System.Runtime.Remoting.Channels/SoapMessageFormatter.cs
|
||||
System.Runtime.Remoting.Channels/SocketCachePolicy.cs
|
||||
System.Runtime.Remoting.Channels.Ipc/IpcChannel.cs
|
||||
System.Runtime.Remoting.Channels.Ipc/IpcClientChannel.cs
|
||||
System.Runtime.Remoting.Channels.Ipc/IpcServerChannel.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/IpcTransport.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/IpcChannel.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/IpcChannelHelper.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/IpcClientChannel.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/IpcServerChannel.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeClient.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeException.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeHelper.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeListener.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeStream.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Unix/IpcChannel.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Unix/IpcClientChannel.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Unix/IpcServerChannel.cs
|
||||
System.Runtime.Remoting.Channels.Ipc.Unix/UnixChannelLoader.cs
|
||||
System.Runtime.Remoting.Channels.Tcp/TcpChannel.cs
|
||||
System.Runtime.Remoting.Channels.Tcp/TcpClientChannel.cs
|
||||
System.Runtime.Remoting.Channels.Tcp/TcpMessageIO.cs
|
||||
System.Runtime.Remoting.Channels.Tcp/TcpServerChannel.cs
|
||||
System.Runtime.Remoting.Channels.Tcp/TcpServerTransportSink.cs
|
||||
System.Runtime.Remoting.Channels.Tcp/TcpClientTransportSinkProvider.cs
|
||||
System.Runtime.Remoting.Channels.Tcp/TcpClientTransportSink.cs
|
||||
System.Runtime.Remoting.Channels.Tcp/TcpConnectionPool.cs
|
||||
System.Runtime.Remoting.MetadataServices/MetaData.cs
|
||||
System.Runtime.Remoting.MetadataServices/MetaDataExporter.cs
|
||||
System.Runtime.Remoting.MetadataServices/MetaDataCodeGenerator.cs
|
||||
System.Runtime.Remoting.MetadataServices/SdlChannelSinkProvider.cs
|
||||
System.Runtime.Remoting.MetadataServices/ServiceType.cs
|
||||
System.Runtime.Remoting.MetadataServices/SUDSParserException.cs
|
||||
System.Runtime.Remoting.MetadataServices/SdlChannelSink.cs
|
||||
System.Runtime.Remoting.MetadataServices/SdlType.cs
|
||||
System.Runtime.Remoting.MetadataServices/SUDSGeneratorException.cs
|
||||
System.Runtime.Remoting.Services/RemotingClientProxy.cs
|
@ -65,7 +65,6 @@ namespace System.ServiceModel
|
||||
return new EndpointAddress10 (address);
|
||||
}
|
||||
|
||||
#if !NET_2_1
|
||||
public static XmlQualifiedName GetSchema (XmlSchemaSet xmlSchemaSet)
|
||||
{
|
||||
if (xmlSchemaSet == null)
|
||||
@ -73,7 +72,6 @@ namespace System.ServiceModel
|
||||
xmlSchemaSet.Add (XmlSchema.Read (typeof (EndpointAddress10).Assembly.GetManifestResourceStream ("ws-addr.xsd"), null));
|
||||
return new XmlQualifiedName ("EndpointReferenceType", AddressingVersion.WSAddressing10.Namespace);
|
||||
}
|
||||
#endif
|
||||
|
||||
public EndpointAddress ToEndpointAddress ()
|
||||
{
|
||||
|
@ -166,6 +166,7 @@ System.ServiceModel.Security/SupportingTokenParametersTest.cs
|
||||
System.ServiceModel.Security/TransportSecurityBindingElementTest.cs
|
||||
System.ServiceModel.Security/WSSecurityTokenSerializerTest.cs
|
||||
System.ServiceModel/BasicHttpBindingTest.cs
|
||||
System.ServiceModel/Bug36080Test.cs
|
||||
System.ServiceModel/CallbackBehaviorAttributeTest.cs
|
||||
System.ServiceModel/ChannelFactoryTest.cs
|
||||
System.ServiceModel/ChannelFactory_1Test.cs
|
||||
|
@ -0,0 +1,585 @@
|
||||
//
|
||||
// Author:
|
||||
// Marcos Henrich <marcos.henrich@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2016 Xamarin, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Description;
|
||||
using System.Threading;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
|
||||
using MonoTests.Helpers;
|
||||
|
||||
namespace MonoTests.System.ServiceModel
|
||||
{
|
||||
[TestFixture]
|
||||
public class Bug36080
|
||||
{
|
||||
[Test]
|
||||
public void Bug36080Test ()
|
||||
{
|
||||
int port = NetworkHelpers.FindFreePort ();
|
||||
var url = "http://localhost:" + port + "/HelloWorldService";
|
||||
|
||||
TransportBindingElement element = new HttpTransportBindingElement { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue };
|
||||
Binding binding = new CustomBinding(new BindingElement[]
|
||||
{
|
||||
new TextMessageEncodingBindingElement (MessageVersion.Default, Encoding.UTF8),
|
||||
element
|
||||
});
|
||||
|
||||
#if !MOBILE
|
||||
// Init service
|
||||
ServiceHost serviceHost = new ServiceHost (typeof (HelloWorldServiceImpl), new Uri (url));
|
||||
serviceHost.AddServiceEndpoint (typeof (IHelloWorldService), binding, string.Empty);
|
||||
|
||||
serviceHost.Open ();
|
||||
#endif
|
||||
// In Mobile we still run this tests without any server.
|
||||
// Issue reported in #36080 was occuring before the connections fails.
|
||||
var wait = new ManualResetEvent (false);
|
||||
|
||||
Exception error = null;
|
||||
string result = null;
|
||||
|
||||
try {
|
||||
var client = new HelloWorldServiceClient (binding, new EndpointAddress(url));
|
||||
client.SayHelloToCompleted += delegate (object o, SayHelloToCompletedEventArgs e) {
|
||||
try {
|
||||
error = e.Error;
|
||||
result = e.Error == null ? e.Result : null;
|
||||
} finally {
|
||||
wait.Set ();
|
||||
}
|
||||
};
|
||||
|
||||
var str = "Xamarin";
|
||||
client.SayHelloToAsync(str);
|
||||
|
||||
Assert.IsTrue (wait.WaitOne (TimeSpan.FromSeconds (20)), "timeout");
|
||||
#if MOBILE
|
||||
if (error.GetType() == typeof(EndpointNotFoundException))
|
||||
return;
|
||||
#endif
|
||||
|
||||
Assert.IsNull (error, "#1, inner exception: {0}", error);
|
||||
Assert.AreEqual (str, result, "#2");
|
||||
} finally {
|
||||
#if !MOBILE
|
||||
serviceHost.Close ();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class HelloWorldServiceImpl : IHelloWorldService
|
||||
{
|
||||
Func<string, string> sayHelloToFunc = SayHelloTo;
|
||||
|
||||
static string SayHelloTo (string name)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public IAsyncResult BeginSayHelloTo(string name, AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return sayHelloToFunc.BeginInvoke (name, callback, asyncState);
|
||||
}
|
||||
|
||||
public string EndSayHelloTo(IAsyncResult result)
|
||||
{
|
||||
return sayHelloToFunc.EndInvoke(result);
|
||||
}
|
||||
|
||||
public IAsyncResult BeginGetHelloData(TestXamarin4WCFService.HelloWorldData helloWorldData, AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public TestXamarin4WCFService.HelloWorldData EndGetHelloData(IAsyncResult result)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.18444
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// This code was auto-generated by SlSvcUtil, version 5.0.61118.0
|
||||
//
|
||||
namespace TestXamarin4WCFService
|
||||
{
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute()]
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
|
||||
[System.Runtime.Serialization.DataContractAttribute(Name = "HelloWorldData", Namespace = "http://schemas.datacontract.org/2004/07/TestXamarin4WCFService")]
|
||||
public partial class HelloWorldData : object
|
||||
{
|
||||
|
||||
private string NameField;
|
||||
|
||||
private bool SayHelloField;
|
||||
|
||||
[System.Runtime.Serialization.DataMemberAttribute()]
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.NameField;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.NameField = value;
|
||||
}
|
||||
}
|
||||
|
||||
[System.Runtime.Serialization.DataMemberAttribute()]
|
||||
public bool SayHello
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.SayHelloField;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.SayHelloField = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
|
||||
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="IHelloWorldService")]
|
||||
public interface IHelloWorldService
|
||||
{
|
||||
|
||||
[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IHelloWorldService/SayHelloTo", ReplyAction="http://tempuri.org/IHelloWorldService/SayHelloToResponse")]
|
||||
System.IAsyncResult BeginSayHelloTo(string name, System.AsyncCallback callback, object asyncState);
|
||||
|
||||
string EndSayHelloTo(System.IAsyncResult result);
|
||||
|
||||
[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IHelloWorldService/GetHelloData", ReplyAction="http://tempuri.org/IHelloWorldService/GetHelloDataResponse")]
|
||||
System.IAsyncResult BeginGetHelloData(TestXamarin4WCFService.HelloWorldData helloWorldData, System.AsyncCallback callback, object asyncState);
|
||||
|
||||
TestXamarin4WCFService.HelloWorldData EndGetHelloData(System.IAsyncResult result);
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
|
||||
public interface IHelloWorldServiceChannel : IHelloWorldService, System.ServiceModel.IClientChannel
|
||||
{
|
||||
}
|
||||
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute()]
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
|
||||
public partial class SayHelloToCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
|
||||
{
|
||||
|
||||
private object[] results;
|
||||
|
||||
public SayHelloToCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
|
||||
base(exception, cancelled, userState)
|
||||
{
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
public string Result
|
||||
{
|
||||
get
|
||||
{
|
||||
base.RaiseExceptionIfNecessary();
|
||||
return ((string)(this.results[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute()]
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
|
||||
public partial class GetHelloDataCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
|
||||
{
|
||||
|
||||
private object[] results;
|
||||
|
||||
public GetHelloDataCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
|
||||
base(exception, cancelled, userState)
|
||||
{
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
public TestXamarin4WCFService.HelloWorldData Result
|
||||
{
|
||||
get
|
||||
{
|
||||
base.RaiseExceptionIfNecessary();
|
||||
return ((TestXamarin4WCFService.HelloWorldData)(this.results[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.DebuggerStepThroughAttribute()]
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
|
||||
public partial class HelloWorldServiceClient : System.ServiceModel.ClientBase<IHelloWorldService>, IHelloWorldService
|
||||
{
|
||||
|
||||
private BeginOperationDelegate onBeginSayHelloToDelegate;
|
||||
|
||||
private EndOperationDelegate onEndSayHelloToDelegate;
|
||||
|
||||
private System.Threading.SendOrPostCallback onSayHelloToCompletedDelegate;
|
||||
|
||||
private BeginOperationDelegate onBeginGetHelloDataDelegate;
|
||||
|
||||
private EndOperationDelegate onEndGetHelloDataDelegate;
|
||||
|
||||
private System.Threading.SendOrPostCallback onGetHelloDataCompletedDelegate;
|
||||
|
||||
private BeginOperationDelegate onBeginOpenDelegate;
|
||||
|
||||
private EndOperationDelegate onEndOpenDelegate;
|
||||
|
||||
private System.Threading.SendOrPostCallback onOpenCompletedDelegate;
|
||||
|
||||
private BeginOperationDelegate onBeginCloseDelegate;
|
||||
|
||||
private EndOperationDelegate onEndCloseDelegate;
|
||||
|
||||
private System.Threading.SendOrPostCallback onCloseCompletedDelegate;
|
||||
|
||||
public HelloWorldServiceClient()
|
||||
{
|
||||
}
|
||||
|
||||
public HelloWorldServiceClient(string endpointConfigurationName) :
|
||||
base(endpointConfigurationName)
|
||||
{
|
||||
}
|
||||
|
||||
public HelloWorldServiceClient(string endpointConfigurationName, string remoteAddress) :
|
||||
base(endpointConfigurationName, remoteAddress)
|
||||
{
|
||||
}
|
||||
|
||||
public HelloWorldServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
|
||||
base(endpointConfigurationName, remoteAddress)
|
||||
{
|
||||
}
|
||||
|
||||
public HelloWorldServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
|
||||
base(binding, remoteAddress)
|
||||
{
|
||||
}
|
||||
|
||||
public System.Net.CookieContainer CookieContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
System.ServiceModel.Channels.IHttpCookieContainerManager httpCookieContainerManager = this.InnerChannel.GetProperty<System.ServiceModel.Channels.IHttpCookieContainerManager>();
|
||||
if ((httpCookieContainerManager != null))
|
||||
{
|
||||
return httpCookieContainerManager.CookieContainer;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
System.ServiceModel.Channels.IHttpCookieContainerManager httpCookieContainerManager = this.InnerChannel.GetProperty<System.ServiceModel.Channels.IHttpCookieContainerManager>();
|
||||
if ((httpCookieContainerManager != null))
|
||||
{
|
||||
httpCookieContainerManager.CookieContainer = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new System.InvalidOperationException("Unable to set the CookieContainer. Please make sure the binding contains an HttpC" +
|
||||
"ookieContainerBindingElement.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event System.EventHandler<SayHelloToCompletedEventArgs> SayHelloToCompleted;
|
||||
|
||||
public event System.EventHandler<GetHelloDataCompletedEventArgs> GetHelloDataCompleted;
|
||||
|
||||
public event System.EventHandler<System.ComponentModel.AsyncCompletedEventArgs> OpenCompleted;
|
||||
|
||||
public event System.EventHandler<System.ComponentModel.AsyncCompletedEventArgs> CloseCompleted;
|
||||
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
System.IAsyncResult IHelloWorldService.BeginSayHelloTo(string name, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return base.Channel.BeginSayHelloTo(name, callback, asyncState);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
string IHelloWorldService.EndSayHelloTo(System.IAsyncResult result)
|
||||
{
|
||||
return base.Channel.EndSayHelloTo(result);
|
||||
}
|
||||
|
||||
private System.IAsyncResult OnBeginSayHelloTo(object[] inValues, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
string name = ((string)(inValues[0]));
|
||||
return ((IHelloWorldService)(this)).BeginSayHelloTo(name, callback, asyncState);
|
||||
}
|
||||
|
||||
private object[] OnEndSayHelloTo(System.IAsyncResult result)
|
||||
{
|
||||
string retVal = ((IHelloWorldService)(this)).EndSayHelloTo(result);
|
||||
return new object[] {
|
||||
retVal};
|
||||
}
|
||||
|
||||
private void OnSayHelloToCompleted(object state)
|
||||
{
|
||||
if ((this.SayHelloToCompleted != null))
|
||||
{
|
||||
InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
|
||||
this.SayHelloToCompleted(this, new SayHelloToCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState));
|
||||
}
|
||||
}
|
||||
|
||||
public void SayHelloToAsync(string name)
|
||||
{
|
||||
this.SayHelloToAsync(name, null);
|
||||
}
|
||||
|
||||
public void SayHelloToAsync(string name, object userState)
|
||||
{
|
||||
if ((this.onBeginSayHelloToDelegate == null))
|
||||
{
|
||||
this.onBeginSayHelloToDelegate = new BeginOperationDelegate(this.OnBeginSayHelloTo);
|
||||
}
|
||||
if ((this.onEndSayHelloToDelegate == null))
|
||||
{
|
||||
this.onEndSayHelloToDelegate = new EndOperationDelegate(this.OnEndSayHelloTo);
|
||||
}
|
||||
if ((this.onSayHelloToCompletedDelegate == null))
|
||||
{
|
||||
this.onSayHelloToCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnSayHelloToCompleted);
|
||||
}
|
||||
base.InvokeAsync(this.onBeginSayHelloToDelegate, new object[] {
|
||||
name}, this.onEndSayHelloToDelegate, this.onSayHelloToCompletedDelegate, userState);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
System.IAsyncResult IHelloWorldService.BeginGetHelloData(TestXamarin4WCFService.HelloWorldData helloWorldData, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return base.Channel.BeginGetHelloData(helloWorldData, callback, asyncState);
|
||||
}
|
||||
|
||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
TestXamarin4WCFService.HelloWorldData IHelloWorldService.EndGetHelloData(System.IAsyncResult result)
|
||||
{
|
||||
return base.Channel.EndGetHelloData(result);
|
||||
}
|
||||
|
||||
private System.IAsyncResult OnBeginGetHelloData(object[] inValues, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
TestXamarin4WCFService.HelloWorldData helloWorldData = ((TestXamarin4WCFService.HelloWorldData)(inValues[0]));
|
||||
return ((IHelloWorldService)(this)).BeginGetHelloData(helloWorldData, callback, asyncState);
|
||||
}
|
||||
|
||||
private object[] OnEndGetHelloData(System.IAsyncResult result)
|
||||
{
|
||||
TestXamarin4WCFService.HelloWorldData retVal = ((IHelloWorldService)(this)).EndGetHelloData(result);
|
||||
return new object[] {
|
||||
retVal};
|
||||
}
|
||||
|
||||
private void OnGetHelloDataCompleted(object state)
|
||||
{
|
||||
if ((this.GetHelloDataCompleted != null))
|
||||
{
|
||||
InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
|
||||
this.GetHelloDataCompleted(this, new GetHelloDataCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState));
|
||||
}
|
||||
}
|
||||
|
||||
public void GetHelloDataAsync(TestXamarin4WCFService.HelloWorldData helloWorldData)
|
||||
{
|
||||
this.GetHelloDataAsync(helloWorldData, null);
|
||||
}
|
||||
|
||||
public void GetHelloDataAsync(TestXamarin4WCFService.HelloWorldData helloWorldData, object userState)
|
||||
{
|
||||
if ((this.onBeginGetHelloDataDelegate == null))
|
||||
{
|
||||
this.onBeginGetHelloDataDelegate = new BeginOperationDelegate(this.OnBeginGetHelloData);
|
||||
}
|
||||
if ((this.onEndGetHelloDataDelegate == null))
|
||||
{
|
||||
this.onEndGetHelloDataDelegate = new EndOperationDelegate(this.OnEndGetHelloData);
|
||||
}
|
||||
if ((this.onGetHelloDataCompletedDelegate == null))
|
||||
{
|
||||
this.onGetHelloDataCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnGetHelloDataCompleted);
|
||||
}
|
||||
base.InvokeAsync(this.onBeginGetHelloDataDelegate, new object[] {
|
||||
helloWorldData}, this.onEndGetHelloDataDelegate, this.onGetHelloDataCompletedDelegate, userState);
|
||||
}
|
||||
|
||||
private System.IAsyncResult OnBeginOpen(object[] inValues, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return ((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(callback, asyncState);
|
||||
}
|
||||
|
||||
private object[] OnEndOpen(System.IAsyncResult result)
|
||||
{
|
||||
((System.ServiceModel.ICommunicationObject)(this)).EndOpen(result);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnOpenCompleted(object state)
|
||||
{
|
||||
if ((this.OpenCompleted != null))
|
||||
{
|
||||
InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
|
||||
this.OpenCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenAsync()
|
||||
{
|
||||
this.OpenAsync(null);
|
||||
}
|
||||
|
||||
public void OpenAsync(object userState)
|
||||
{
|
||||
if ((this.onBeginOpenDelegate == null))
|
||||
{
|
||||
this.onBeginOpenDelegate = new BeginOperationDelegate(this.OnBeginOpen);
|
||||
}
|
||||
if ((this.onEndOpenDelegate == null))
|
||||
{
|
||||
this.onEndOpenDelegate = new EndOperationDelegate(this.OnEndOpen);
|
||||
}
|
||||
if ((this.onOpenCompletedDelegate == null))
|
||||
{
|
||||
this.onOpenCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnOpenCompleted);
|
||||
}
|
||||
base.InvokeAsync(this.onBeginOpenDelegate, null, this.onEndOpenDelegate, this.onOpenCompletedDelegate, userState);
|
||||
}
|
||||
|
||||
private System.IAsyncResult OnBeginClose(object[] inValues, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
return ((System.ServiceModel.ICommunicationObject)(this)).BeginClose(callback, asyncState);
|
||||
}
|
||||
|
||||
private object[] OnEndClose(System.IAsyncResult result)
|
||||
{
|
||||
((System.ServiceModel.ICommunicationObject)(this)).EndClose(result);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnCloseCompleted(object state)
|
||||
{
|
||||
if ((this.CloseCompleted != null))
|
||||
{
|
||||
InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
|
||||
this.CloseCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
|
||||
}
|
||||
}
|
||||
|
||||
public void CloseAsync()
|
||||
{
|
||||
this.CloseAsync(null);
|
||||
}
|
||||
|
||||
public void CloseAsync(object userState)
|
||||
{
|
||||
if ((this.onBeginCloseDelegate == null))
|
||||
{
|
||||
this.onBeginCloseDelegate = new BeginOperationDelegate(this.OnBeginClose);
|
||||
}
|
||||
if ((this.onEndCloseDelegate == null))
|
||||
{
|
||||
this.onEndCloseDelegate = new EndOperationDelegate(this.OnEndClose);
|
||||
}
|
||||
if ((this.onCloseCompletedDelegate == null))
|
||||
{
|
||||
this.onCloseCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnCloseCompleted);
|
||||
}
|
||||
base.InvokeAsync(this.onBeginCloseDelegate, null, this.onEndCloseDelegate, this.onCloseCompletedDelegate, userState);
|
||||
}
|
||||
|
||||
protected override IHelloWorldService CreateChannel()
|
||||
{
|
||||
return new HelloWorldServiceClientChannel(this);
|
||||
}
|
||||
|
||||
private class HelloWorldServiceClientChannel : ChannelBase<IHelloWorldService>, IHelloWorldService
|
||||
{
|
||||
|
||||
public HelloWorldServiceClientChannel(System.ServiceModel.ClientBase<IHelloWorldService> client) :
|
||||
base(client)
|
||||
{
|
||||
}
|
||||
|
||||
public System.IAsyncResult BeginSayHelloTo(string name, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
object[] _args = new object[1];
|
||||
_args[0] = name;
|
||||
System.IAsyncResult _result = base.BeginInvoke("SayHelloTo", _args, callback, asyncState);
|
||||
return _result;
|
||||
}
|
||||
|
||||
public string EndSayHelloTo(System.IAsyncResult result)
|
||||
{
|
||||
object[] _args = new object[0];
|
||||
string _result = ((string)(base.EndInvoke("SayHelloTo", _args, result)));
|
||||
return _result;
|
||||
}
|
||||
|
||||
public System.IAsyncResult BeginGetHelloData(TestXamarin4WCFService.HelloWorldData helloWorldData, System.AsyncCallback callback, object asyncState)
|
||||
{
|
||||
object[] _args = new object[1];
|
||||
_args[0] = helloWorldData;
|
||||
System.IAsyncResult _result = base.BeginInvoke("GetHelloData", _args, callback, asyncState);
|
||||
return _result;
|
||||
}
|
||||
|
||||
public TestXamarin4WCFService.HelloWorldData EndGetHelloData(System.IAsyncResult result)
|
||||
{
|
||||
object[] _args = new object[0];
|
||||
TestXamarin4WCFService.HelloWorldData _result = ((TestXamarin4WCFService.HelloWorldData)(base.EndInvoke("GetHelloData", _args, result)));
|
||||
return _result;
|
||||
}
|
||||
}
|
||||
}
|
@ -83,3 +83,5 @@ using System.Runtime.InteropServices;
|
||||
[assembly: InternalsVisibleTo ("Mono.Security.Providers.NewTls, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")]
|
||||
[assembly: InternalsVisibleTo ("Mono.Security.Providers.DotNet, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")]
|
||||
[assembly: InternalsVisibleTo ("Mono.Security, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")]
|
||||
|
||||
[assembly: InternalsVisibleTo ("Xamarin.BoringTls, PublicKey=002400000480000094000000060200000024000052534131000400001100000099dd12eda85767ae6f06023ee28e711c7e5a212462095c83868c29db75eddf6d8e296e03824c14fedd5f55553fed0b6173be3cc985a4b7f9fb7c83ccff8ba3938563b3d1f45a81122f12a1bcb73edcaad61a8456c7595a6da5184b4dd9d10f011b949ef1391fccfeab1ba62aa51c267ef8bd57ef1b6ba5a4c515d0badb81a78f")]
|
||||
|
@ -74,7 +74,7 @@ namespace Mono.Net.Security
|
||||
{
|
||||
internal delegate bool ServerCertValidationCallbackWrapper (ServerCertValidationCallback callback, X509Certificate certificate, X509Chain chain, MonoSslPolicyErrors sslPolicyErrors);
|
||||
|
||||
internal class ChainValidationHelper : ICertificateValidator
|
||||
internal class ChainValidationHelper : ICertificateValidator2
|
||||
{
|
||||
readonly object sender;
|
||||
readonly MonoTlsSettings settings;
|
||||
@ -228,7 +228,7 @@ namespace Mono.Net.Security
|
||||
var certs = new XX509CertificateCollection ();
|
||||
certs.Add (new X509Certificate2 (certificate.GetRawCertData ()));
|
||||
|
||||
var result = ValidateChain (string.Empty, true, certs, (SslPolicyErrors)errors);
|
||||
var result = ValidateChain (string.Empty, true, certificate, null, certs, (SslPolicyErrors)errors);
|
||||
if (result == null)
|
||||
return false;
|
||||
|
||||
@ -238,7 +238,12 @@ namespace Mono.Net.Security
|
||||
public ValidationResult ValidateCertificate (string host, bool serverMode, XX509CertificateCollection certs)
|
||||
{
|
||||
try {
|
||||
var result = ValidateChain (host, serverMode, certs, 0);
|
||||
X509Certificate leaf;
|
||||
if (certs != null && certs.Count != 0)
|
||||
leaf = certs [0];
|
||||
else
|
||||
leaf = null;
|
||||
var result = ValidateChain (host, serverMode, leaf, null, certs, 0);
|
||||
if (tlsStream != null)
|
||||
tlsStream.CertificateValidationFailed = result == null || !result.Trusted || result.UserDenied;
|
||||
return result;
|
||||
@ -249,7 +254,43 @@ namespace Mono.Net.Security
|
||||
}
|
||||
}
|
||||
|
||||
ValidationResult ValidateChain (string host, bool server, XX509CertificateCollection certs, SslPolicyErrors errors)
|
||||
public ValidationResult ValidateCertificate (string host, bool serverMode, X509Certificate leaf, XX509Chain xchain)
|
||||
{
|
||||
try {
|
||||
var chain = (X509Chain)(object)xchain;
|
||||
var result = ValidateChain (host, serverMode, leaf, chain, null, 0);
|
||||
if (tlsStream != null)
|
||||
tlsStream.CertificateValidationFailed = result == null || !result.Trusted || result.UserDenied;
|
||||
return result;
|
||||
} catch {
|
||||
if (tlsStream != null)
|
||||
tlsStream.CertificateValidationFailed = true;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
ValidationResult ValidateChain (string host, bool server, X509Certificate leaf,
|
||||
X509Chain chain, XX509CertificateCollection certs,
|
||||
SslPolicyErrors errors)
|
||||
{
|
||||
var oldChain = chain;
|
||||
var ownsChain = chain == null;
|
||||
try {
|
||||
var result = ValidateChain (host, server, leaf, ref chain, certs, errors);
|
||||
if (chain != oldChain)
|
||||
ownsChain = true;
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
// If ValidateChain() changed the chain, then we need to free it.
|
||||
if (ownsChain && chain != null)
|
||||
chain.Dispose ();
|
||||
}
|
||||
}
|
||||
|
||||
ValidationResult ValidateChain (string host, bool server, X509Certificate leaf,
|
||||
ref X509Chain chain, XX509CertificateCollection certs,
|
||||
SslPolicyErrors errors)
|
||||
{
|
||||
// user_denied is true if the user callback is called and returns false
|
||||
bool user_denied = false;
|
||||
@ -257,12 +298,6 @@ namespace Mono.Net.Security
|
||||
|
||||
var hasCallback = certValidationCallback != null || callbackWrapper != null;
|
||||
|
||||
X509Certificate leaf;
|
||||
if (certs == null || certs.Count == 0)
|
||||
leaf = null;
|
||||
else
|
||||
leaf = certs [0];
|
||||
|
||||
if (tlsStream != null)
|
||||
request.ServicePoint.UpdateServerCertificate (leaf);
|
||||
|
||||
@ -281,7 +316,6 @@ namespace Mono.Net.Security
|
||||
ICertificatePolicy policy = ServicePointManager.GetLegacyCertificatePolicy ();
|
||||
|
||||
int status11 = 0; // Error code passed to the obsolete ICertificatePolicy callback
|
||||
X509Chain chain = null;
|
||||
|
||||
bool wantsChain = SystemCertificateValidator.NeedsChain (settings);
|
||||
if (!wantsChain && hasCallback) {
|
||||
@ -289,18 +323,15 @@ namespace Mono.Net.Security
|
||||
wantsChain = true;
|
||||
}
|
||||
|
||||
if (wantsChain)
|
||||
chain = SystemCertificateValidator.CreateX509Chain (certs);
|
||||
|
||||
if (wantsChain || SystemCertificateValidator.NeedsChain (settings))
|
||||
SystemCertificateValidator.BuildX509Chain (certs, chain, ref errors, ref status11);
|
||||
|
||||
bool providerValidated = false;
|
||||
if (provider != null && provider.HasCustomSystemCertificateValidator) {
|
||||
var xerrors = (MonoSslPolicyErrors)errors;
|
||||
var xchain = (XX509Chain)(object)chain;
|
||||
providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, xchain, out result, ref xerrors, ref status11);
|
||||
providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, wantsChain, ref xchain, out result, ref xerrors, ref status11);
|
||||
chain = (X509Chain)(object)xchain;
|
||||
errors = (SslPolicyErrors)xerrors;
|
||||
} else if (wantsChain) {
|
||||
chain = SystemCertificateValidator.CreateX509Chain (certs);
|
||||
}
|
||||
|
||||
if (!providerValidated)
|
||||
|
@ -69,7 +69,7 @@ namespace Mono.Net.Security
|
||||
return currentProvider;
|
||||
|
||||
try {
|
||||
defaultProvider = CreateDefaultProvider ();
|
||||
defaultProvider = GetDefaultProviderInternal ();
|
||||
} catch (Exception ex) {
|
||||
throw new NotSupportedException ("TLS Support not available.", ex);
|
||||
}
|
||||
@ -174,6 +174,8 @@ namespace Mono.Net.Security
|
||||
providerRegistration = new Dictionary<string,string> ();
|
||||
providerRegistration.Add ("newtls", "Mono.Security.Providers.NewTls.NewTlsProvider, Mono.Security.Providers.NewTls, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756");
|
||||
providerRegistration.Add ("oldtls", "Mono.Security.Providers.OldTls.OldTlsProvider, Mono.Security.Providers.OldTls, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756");
|
||||
providerRegistration.Add ("boringtls", "Xamarin.BoringTls.BoringTlsProvider, Xamarin.BoringTls, Version=4.0.0.0, Culture=neutral, PublicKeyToken=672c06b0b8f05406");
|
||||
X509Helper2.Initialize ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,13 +86,13 @@ namespace Mono.Net.Security
|
||||
return chain;
|
||||
}
|
||||
|
||||
public static bool BuildX509Chain (XX509CertificateCollection certs, X509Chain chain, ref SslPolicyErrors errors, ref int status11)
|
||||
static bool BuildX509Chain (XX509CertificateCollection certs, X509Chain chain, ref SslPolicyErrors errors, ref int status11)
|
||||
{
|
||||
#if MOBILE
|
||||
return true;
|
||||
return false;
|
||||
#else
|
||||
if (is_macosx)
|
||||
return true;
|
||||
return false;
|
||||
|
||||
var leaf = (X509Certificate2)certs [0];
|
||||
|
||||
@ -121,7 +121,9 @@ namespace Mono.Net.Security
|
||||
static bool CheckUsage (XX509CertificateCollection certs, string host, ref SslPolicyErrors errors, ref int status11)
|
||||
{
|
||||
#if !MONOTOUCH
|
||||
var leaf = (X509Certificate2)certs[0];
|
||||
var leaf = certs[0] as X509Certificate2;
|
||||
if (leaf == null)
|
||||
leaf = new X509Certificate2 (certs[0]);
|
||||
// for OSX and iOS we're using the native API to check for the SSL server policy and host names
|
||||
if (!is_macosx) {
|
||||
if (!CheckCertificateUsage (leaf)) {
|
||||
@ -130,7 +132,7 @@ namespace Mono.Net.Security
|
||||
return false;
|
||||
}
|
||||
|
||||
if (host != null && !CheckServerIdentity (leaf, host)) {
|
||||
if (!string.IsNullOrEmpty (host) && !CheckServerIdentity (leaf, host)) {
|
||||
errors |= SslPolicyErrors.RemoteCertificateNameMismatch;
|
||||
status11 = -2146762481; // CERT_E_CN_NO_MATCH 0x800B010F
|
||||
return false;
|
||||
@ -143,7 +145,7 @@ namespace Mono.Net.Security
|
||||
static bool EvaluateSystem (XX509CertificateCollection certs, XX509CertificateCollection anchors, string host, X509Chain chain, ref SslPolicyErrors errors, ref int status11)
|
||||
{
|
||||
var leaf = certs [0];
|
||||
var result = false;
|
||||
bool result;
|
||||
|
||||
#if MONODROID
|
||||
result = AndroidPlatform.TrustEvaluateSsl (certs);
|
||||
@ -166,6 +168,8 @@ namespace Mono.Net.Security
|
||||
result = (trustResult == OSX509Certificates.SecTrustResult.Proceed ||
|
||||
trustResult == OSX509Certificates.SecTrustResult.Unspecified);
|
||||
} catch {
|
||||
result = false;
|
||||
errors |= SslPolicyErrors.RemoteCertificateChainErrors;
|
||||
// Ignore
|
||||
}
|
||||
|
||||
@ -178,6 +182,8 @@ namespace Mono.Net.Security
|
||||
status11 = (int)trustResult;
|
||||
errors |= SslPolicyErrors.RemoteCertificateChainErrors;
|
||||
}
|
||||
} else {
|
||||
result = BuildX509Chain (certs, chain, ref errors, ref status11);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -203,6 +209,8 @@ namespace Mono.Net.Security
|
||||
#if MOBILE
|
||||
return false;
|
||||
#else
|
||||
if (!is_macosx)
|
||||
return true;
|
||||
if (!CertificateValidationHelper.SupportsX509Chain)
|
||||
return false;
|
||||
if (settings != null)
|
||||
|
@ -255,10 +255,10 @@ namespace System.Diagnostics {
|
||||
WritePrefix ();
|
||||
}
|
||||
|
||||
WriteDebugString (message);
|
||||
|
||||
if (Debugger.IsLogging())
|
||||
Debugger.Log (0, null, message);
|
||||
else
|
||||
WriteDebugString (message);
|
||||
|
||||
WriteLogFile (message, LogFileName);
|
||||
}
|
||||
|
@ -52,6 +52,7 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
X500DistinguishedNameFlags.UseT61Encoding | X500DistinguishedNameFlags.ForceUTF8Encoding;
|
||||
|
||||
private string name;
|
||||
private byte[] canonEncoding;
|
||||
|
||||
|
||||
public X500DistinguishedName (AsnEncodedData encodedDistinguishedName)
|
||||
@ -122,6 +123,20 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
name = distinguishedName.name;
|
||||
}
|
||||
|
||||
internal X500DistinguishedName (byte[] encoded, byte[] canonEncoding, string name)
|
||||
: this (encoded)
|
||||
{
|
||||
this.canonEncoding = canonEncoding;
|
||||
this.name = name;
|
||||
|
||||
Oid = new Oid ();
|
||||
RawData = encoded;
|
||||
}
|
||||
|
||||
internal byte[] CanonicalEncoding {
|
||||
get { return canonEncoding; }
|
||||
}
|
||||
|
||||
|
||||
public string Name {
|
||||
get { return name; }
|
||||
@ -215,6 +230,16 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
if (name2 == null)
|
||||
return false;
|
||||
|
||||
if (name1.canonEncoding != null && name2.canonEncoding != null) {
|
||||
if (name1.canonEncoding.Length != name2.canonEncoding.Length)
|
||||
return false;
|
||||
for (int i = 0; i < name1.canonEncoding.Length; i++) {
|
||||
if (name1.canonEncoding[i] != name2.canonEncoding[2])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
X500DistinguishedNameFlags flags = X500DistinguishedNameFlags.UseNewLines | X500DistinguishedNameFlags.DoNotUseQuotes;
|
||||
string[] split = new string[] { Environment.NewLine };
|
||||
string[] parts1 = name1.Decode (flags).Split (split, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
@ -50,6 +50,7 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
|
||||
[Serializable]
|
||||
public class X509Certificate2 : X509Certificate {
|
||||
|
||||
#if !SECURITY_DEP
|
||||
// Used in Mono.Security HttpsClientStream
|
||||
public X509Certificate2 (byte[] rawData)
|
||||
@ -57,24 +58,20 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
}
|
||||
#endif
|
||||
#if SECURITY_DEP
|
||||
private bool _archived;
|
||||
private X509ExtensionCollection _extensions;
|
||||
private string _name = String.Empty;
|
||||
private string _serial;
|
||||
private PublicKey _publicKey;
|
||||
private X500DistinguishedName issuer_name;
|
||||
private X500DistinguishedName subject_name;
|
||||
private Oid signature_algorithm;
|
||||
new internal X509Certificate2Impl Impl {
|
||||
get {
|
||||
var impl2 = base.Impl as X509Certificate2Impl;
|
||||
X509Helper2.ThrowIfContextInvalid (impl2);
|
||||
return impl2;
|
||||
}
|
||||
}
|
||||
|
||||
private MX.X509Certificate _cert;
|
||||
|
||||
private static string empty_error = Locale.GetText ("Certificate instance is empty.");
|
||||
string friendlyName = string.Empty;
|
||||
|
||||
// constructors
|
||||
|
||||
public X509Certificate2 ()
|
||||
{
|
||||
_cert = null;
|
||||
}
|
||||
|
||||
public X509Certificate2 (byte[] rawData)
|
||||
@ -129,206 +126,88 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
|
||||
public X509Certificate2 (IntPtr handle) : base (handle)
|
||||
{
|
||||
_cert = new MX.X509Certificate (base.GetRawCertData ());
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
|
||||
public X509Certificate2 (X509Certificate certificate)
|
||||
: base (certificate)
|
||||
: base (X509Helper2.Import (certificate))
|
||||
{
|
||||
}
|
||||
|
||||
internal X509Certificate2 (X509Certificate2Impl impl)
|
||||
: base (impl)
|
||||
{
|
||||
_cert = new MX.X509Certificate (base.GetRawCertData ());
|
||||
}
|
||||
|
||||
// properties
|
||||
|
||||
public bool Archived {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
return _archived;
|
||||
}
|
||||
set {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
_archived = value;
|
||||
}
|
||||
get { return Impl.Archived; }
|
||||
set { Impl.Archived = true; }
|
||||
}
|
||||
|
||||
public X509ExtensionCollection Extensions {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
if (_extensions == null)
|
||||
_extensions = new X509ExtensionCollection (_cert);
|
||||
return _extensions;
|
||||
}
|
||||
get { return Impl.Extensions; }
|
||||
}
|
||||
|
||||
public string FriendlyName {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
return _name;
|
||||
ThrowIfContextInvalid ();
|
||||
return friendlyName;
|
||||
}
|
||||
set {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
_name = value;
|
||||
ThrowIfContextInvalid ();
|
||||
friendlyName = value;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME - Could be more efficient
|
||||
public bool HasPrivateKey {
|
||||
get { return PrivateKey != null; }
|
||||
get { return Impl.HasPrivateKey; }
|
||||
}
|
||||
|
||||
public X500DistinguishedName IssuerName {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
if (issuer_name == null)
|
||||
issuer_name = new X500DistinguishedName (_cert.GetIssuerName ().GetBytes ());
|
||||
return issuer_name;
|
||||
}
|
||||
get { return Impl.IssuerName; }
|
||||
}
|
||||
|
||||
public DateTime NotAfter {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
return _cert.ValidUntil.ToLocalTime ();
|
||||
}
|
||||
get { return Impl.GetValidUntil ().ToLocalTime (); }
|
||||
}
|
||||
|
||||
public DateTime NotBefore {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
return _cert.ValidFrom.ToLocalTime ();
|
||||
}
|
||||
get { return Impl.GetValidFrom ().ToLocalTime (); }
|
||||
}
|
||||
|
||||
public AsymmetricAlgorithm PrivateKey {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
try {
|
||||
if (_cert.RSA != null) {
|
||||
RSACryptoServiceProvider rcsp = _cert.RSA as RSACryptoServiceProvider;
|
||||
if (rcsp != null)
|
||||
return rcsp.PublicOnly ? null : rcsp;
|
||||
|
||||
RSAManaged rsam = _cert.RSA as RSAManaged;
|
||||
if (rsam != null)
|
||||
return rsam.PublicOnly ? null : rsam;
|
||||
|
||||
_cert.RSA.ExportParameters (true);
|
||||
return _cert.RSA;
|
||||
} else if (_cert.DSA != null) {
|
||||
DSACryptoServiceProvider dcsp = _cert.DSA as DSACryptoServiceProvider;
|
||||
if (dcsp != null)
|
||||
return dcsp.PublicOnly ? null : dcsp;
|
||||
|
||||
_cert.DSA.ExportParameters (true);
|
||||
return _cert.DSA;
|
||||
}
|
||||
}
|
||||
catch {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
set {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
// allow NULL so we can "forget" the key associated to the certificate
|
||||
// e.g. in case we want to export it in another format (see bug #396620)
|
||||
if (value == null) {
|
||||
_cert.RSA = null;
|
||||
_cert.DSA = null;
|
||||
} else if (value is RSA)
|
||||
_cert.RSA = (RSA) value;
|
||||
else if (value is DSA)
|
||||
_cert.DSA = (DSA) value;
|
||||
else
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
get { return Impl.PrivateKey; }
|
||||
set { Impl.PrivateKey = value; }
|
||||
}
|
||||
|
||||
public PublicKey PublicKey {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
if (_publicKey == null) {
|
||||
try {
|
||||
_publicKey = new PublicKey (_cert);
|
||||
}
|
||||
catch (Exception e) {
|
||||
string msg = Locale.GetText ("Unable to decode public key.");
|
||||
throw new CryptographicException (msg, e);
|
||||
}
|
||||
}
|
||||
return _publicKey;
|
||||
}
|
||||
get { return Impl.PublicKey; }
|
||||
}
|
||||
|
||||
public byte[] RawData {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
return base.GetRawCertData ();
|
||||
}
|
||||
get { return GetRawCertData (); }
|
||||
}
|
||||
|
||||
public string SerialNumber {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
if (_serial == null) {
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
byte[] serial = _cert.SerialNumber;
|
||||
for (int i=serial.Length - 1; i >= 0; i--)
|
||||
sb.Append (serial [i].ToString ("X2"));
|
||||
_serial = sb.ToString ();
|
||||
}
|
||||
return _serial;
|
||||
}
|
||||
get { return GetSerialNumberString (); }
|
||||
}
|
||||
|
||||
public Oid SignatureAlgorithm {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
if (signature_algorithm == null)
|
||||
signature_algorithm = new Oid (_cert.SignatureAlgorithm);
|
||||
return signature_algorithm;
|
||||
}
|
||||
get { return Impl.SignatureAlgorithm; }
|
||||
}
|
||||
|
||||
public X500DistinguishedName SubjectName {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
if (subject_name == null)
|
||||
subject_name = new X500DistinguishedName (_cert.GetSubjectName ().GetBytes ());
|
||||
return subject_name;
|
||||
}
|
||||
get { return Impl.SubjectName; }
|
||||
}
|
||||
|
||||
public string Thumbprint {
|
||||
get { return base.GetCertHashString (); }
|
||||
get { return GetCertHashString (); }
|
||||
}
|
||||
|
||||
public int Version {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
return _cert.Version;
|
||||
}
|
||||
get { return Impl.Version; }
|
||||
}
|
||||
|
||||
// methods
|
||||
@ -336,135 +215,7 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
[MonoTODO ("always return String.Empty for UpnName, DnsFromAlternativeName and UrlName")]
|
||||
public string GetNameInfo (X509NameType nameType, bool forIssuer)
|
||||
{
|
||||
switch (nameType) {
|
||||
case X509NameType.SimpleName:
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
// return CN= or, if missing, the first part of the DN
|
||||
ASN1 sn = forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ();
|
||||
ASN1 dn = Find (commonName, sn);
|
||||
if (dn != null)
|
||||
return GetValueAsString (dn);
|
||||
if (sn.Count == 0)
|
||||
return String.Empty;
|
||||
ASN1 last_entry = sn [sn.Count - 1];
|
||||
if (last_entry.Count == 0)
|
||||
return String.Empty;
|
||||
return GetValueAsString (last_entry [0]);
|
||||
case X509NameType.EmailName:
|
||||
// return the E= part of the DN (if present)
|
||||
ASN1 e = Find (email, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
|
||||
if (e != null)
|
||||
return GetValueAsString (e);
|
||||
return String.Empty;
|
||||
case X509NameType.UpnName:
|
||||
// FIXME - must find/create test case
|
||||
return String.Empty;
|
||||
case X509NameType.DnsName:
|
||||
// return the CN= part of the DN (if present)
|
||||
ASN1 cn = Find (commonName, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
|
||||
if (cn != null)
|
||||
return GetValueAsString (cn);
|
||||
return String.Empty;
|
||||
case X509NameType.DnsFromAlternativeName:
|
||||
// FIXME - must find/create test case
|
||||
return String.Empty;
|
||||
case X509NameType.UrlName:
|
||||
// FIXME - must find/create test case
|
||||
return String.Empty;
|
||||
default:
|
||||
throw new ArgumentException ("nameType");
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] commonName = { 0x55, 0x04, 0x03 };
|
||||
static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
|
||||
|
||||
private ASN1 Find (byte[] oid, ASN1 dn)
|
||||
{
|
||||
if (dn.Count == 0)
|
||||
return null;
|
||||
|
||||
// process SET
|
||||
for (int i = 0; i < dn.Count; i++) {
|
||||
ASN1 set = dn [i];
|
||||
for (int j = 0; j < set.Count; j++) {
|
||||
ASN1 pair = set [j];
|
||||
if (pair.Count != 2)
|
||||
continue;
|
||||
|
||||
ASN1 poid = pair [0];
|
||||
if (poid == null)
|
||||
continue;
|
||||
|
||||
if (poid.CompareValue (oid))
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetValueAsString (ASN1 pair)
|
||||
{
|
||||
if (pair.Count != 2)
|
||||
return String.Empty;
|
||||
|
||||
ASN1 value = pair [1];
|
||||
if ((value.Value == null) || (value.Length == 0))
|
||||
return String.Empty;
|
||||
|
||||
if (value.Tag == 0x1E) {
|
||||
// BMPSTRING
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
for (int j = 1; j < value.Value.Length; j += 2)
|
||||
sb.Append ((char)value.Value [j]);
|
||||
return sb.ToString ();
|
||||
} else {
|
||||
return Encoding.UTF8.GetString (value.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private MX.X509Certificate ImportPkcs12 (byte[] rawData, string password)
|
||||
{
|
||||
MX.PKCS12 pfx = null;
|
||||
if (string.IsNullOrEmpty (password)) {
|
||||
try {
|
||||
// Support both unencrypted PKCS#12..
|
||||
pfx = new MX.PKCS12 (rawData, (string)null);
|
||||
} catch {
|
||||
// ..and PKCS#12 encrypted with an empty password
|
||||
pfx = new MX.PKCS12 (rawData, string.Empty);
|
||||
}
|
||||
} else {
|
||||
pfx = new MX.PKCS12 (rawData, password);
|
||||
}
|
||||
|
||||
if (pfx.Certificates.Count == 0) {
|
||||
// no certificate was found
|
||||
return null;
|
||||
} else if (pfx.Keys.Count == 0) {
|
||||
// no key were found - pick the first certificate
|
||||
return pfx.Certificates [0];
|
||||
} else {
|
||||
// find the certificate that match the first key
|
||||
MX.X509Certificate cert = null;
|
||||
var keypair = (pfx.Keys [0] as AsymmetricAlgorithm);
|
||||
string pubkey = keypair.ToXmlString (false);
|
||||
foreach (var c in pfx.Certificates) {
|
||||
if (((c.RSA != null) && (pubkey == c.RSA.ToXmlString (false))) ||
|
||||
((c.DSA != null) && (pubkey == c.DSA.ToXmlString (false)))) {
|
||||
cert = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cert == null) {
|
||||
cert = pfx.Certificates [0]; // no match, pick first certificate without keys
|
||||
} else {
|
||||
cert.RSA = (keypair as RSA);
|
||||
cert.DSA = (keypair as DSA);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
return Impl.GetNameInfo (nameType, forIssuer);
|
||||
}
|
||||
|
||||
public override void Import (byte[] rawData)
|
||||
@ -475,37 +226,8 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
[MonoTODO ("missing KeyStorageFlags support")]
|
||||
public override void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
|
||||
{
|
||||
MX.X509Certificate cert = null;
|
||||
if (password == null) {
|
||||
try {
|
||||
cert = new MX.X509Certificate (rawData);
|
||||
}
|
||||
catch (Exception e) {
|
||||
try {
|
||||
cert = ImportPkcs12 (rawData, null);
|
||||
}
|
||||
catch {
|
||||
string msg = Locale.GetText ("Unable to decode certificate.");
|
||||
// inner exception is the original (not second) exception
|
||||
throw new CryptographicException (msg, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// try PKCS#12
|
||||
try {
|
||||
cert = ImportPkcs12 (rawData, password);
|
||||
}
|
||||
catch {
|
||||
// it's possible to supply a (unrequired/unusued) password
|
||||
// fix bug #79028
|
||||
cert = new MX.X509Certificate (rawData);
|
||||
}
|
||||
}
|
||||
// we do not have to fully re-decode the certificate since X509Certificate does not deal with keys
|
||||
if (cert != null) {
|
||||
base.Import (cert.RawData, (string) null, keyStorageFlags);
|
||||
_cert = cert; // becuase base call will call Reset!
|
||||
}
|
||||
var impl = X509Helper2.Import (rawData, password, keyStorageFlags);
|
||||
ImportHandle (impl);
|
||||
}
|
||||
|
||||
[MonoTODO ("SecureString is incomplete")]
|
||||
@ -537,69 +259,25 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
[MonoTODO ("X509ContentType.SerializedCert is not supported")]
|
||||
public override byte[] Export (X509ContentType contentType, string password)
|
||||
{
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
switch (contentType) {
|
||||
case X509ContentType.Cert:
|
||||
return _cert.RawData;
|
||||
case X509ContentType.Pfx: // this includes Pkcs12
|
||||
return ExportPkcs12 (password);
|
||||
case X509ContentType.SerializedCert:
|
||||
// TODO
|
||||
throw new NotSupportedException ();
|
||||
default:
|
||||
string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
|
||||
throw new CryptographicException (msg);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] ExportPkcs12 (string password)
|
||||
{
|
||||
var pfx = new MX.PKCS12 ();
|
||||
try {
|
||||
var attrs = new Hashtable ();
|
||||
var localKeyId = new ArrayList ();
|
||||
localKeyId.Add (new byte[] { 1, 0, 0, 0 });
|
||||
attrs.Add (MX.PKCS9.localKeyId, localKeyId);
|
||||
|
||||
if (password != null)
|
||||
pfx.Password = password;
|
||||
pfx.AddCertificate (_cert, attrs);
|
||||
var privateKey = PrivateKey;
|
||||
if (privateKey != null)
|
||||
pfx.AddPkcs8ShroudedKeyBag (privateKey, attrs);
|
||||
return pfx.GetBytes ();
|
||||
} finally {
|
||||
pfx.Password = null;
|
||||
}
|
||||
return Impl.Export (contentType, password);
|
||||
}
|
||||
|
||||
public override void Reset ()
|
||||
{
|
||||
_cert = null;
|
||||
_archived = false;
|
||||
_extensions = null;
|
||||
_name = String.Empty;
|
||||
_serial = null;
|
||||
_publicKey = null;
|
||||
issuer_name = null;
|
||||
subject_name = null;
|
||||
signature_algorithm = null;
|
||||
friendlyName = string.Empty;
|
||||
base.Reset ();
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
if (_cert == null)
|
||||
if (!IsValid)
|
||||
return "System.Security.Cryptography.X509Certificates.X509Certificate2";
|
||||
|
||||
return base.ToString (true);
|
||||
}
|
||||
|
||||
public override string ToString (bool verbose)
|
||||
{
|
||||
if (_cert == null)
|
||||
if (!IsValid)
|
||||
return "System.Security.Cryptography.X509Certificates.X509Certificate2";
|
||||
|
||||
// the non-verbose X509Certificate2 == verbose X509Certificate
|
||||
@ -649,14 +327,7 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
[MonoTODO ("by default this depends on the incomplete X509Chain")]
|
||||
public bool Verify ()
|
||||
{
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
X509Chain chain = X509Chain.Create ();
|
||||
if (!chain.Build (this))
|
||||
return false;
|
||||
// TODO - check chain and other stuff ???
|
||||
return true;
|
||||
return Impl.Verify (this);
|
||||
}
|
||||
|
||||
// static methods
|
||||
@ -723,8 +394,14 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
// internal stuff because X509Certificate2 isn't complete enough
|
||||
// (maybe X509Certificate3 will be better?)
|
||||
|
||||
[Obsolete ("KILL")]
|
||||
internal MX.X509Certificate MonoCertificate {
|
||||
get { return _cert; }
|
||||
get {
|
||||
var monoImpl = Impl as X509Certificate2ImplMono;
|
||||
if (monoImpl == null)
|
||||
throw new NotSupportedException ();
|
||||
return monoImpl.MonoCertificate;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -0,0 +1,82 @@
|
||||
//
|
||||
// X509Certificate2Impl.cs
|
||||
//
|
||||
// Authors:
|
||||
// Martin Baulig <martin.baulig@xamarin.com>
|
||||
//
|
||||
// Copyright (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
namespace System.Security.Cryptography.X509Certificates
|
||||
{
|
||||
internal abstract class X509Certificate2Impl : X509CertificateImpl
|
||||
{
|
||||
#if SECURITY_DEP
|
||||
|
||||
public abstract bool Archived {
|
||||
get; set;
|
||||
}
|
||||
|
||||
public abstract X509ExtensionCollection Extensions {
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract bool HasPrivateKey {
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract X500DistinguishedName IssuerName {
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract AsymmetricAlgorithm PrivateKey {
|
||||
get; set;
|
||||
}
|
||||
|
||||
public abstract PublicKey PublicKey {
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract Oid SignatureAlgorithm {
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract X500DistinguishedName SubjectName {
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract int Version {
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract string GetNameInfo (X509NameType nameType, bool forIssuer);
|
||||
|
||||
public abstract void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags);
|
||||
|
||||
public abstract byte[] Export (X509ContentType contentType, string password);
|
||||
|
||||
public abstract bool Verify (X509Certificate2 thisCertificate);
|
||||
|
||||
public abstract void Reset ();
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
@ -0,0 +1,694 @@
|
||||
//
|
||||
// X509Certificate2ImplMono
|
||||
//
|
||||
// Authors:
|
||||
// Sebastien Pouliot <sebastien@xamarin.com>
|
||||
// Martin Baulig <martin.baulig@xamarin.com>
|
||||
//
|
||||
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
|
||||
// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
|
||||
// Copyright (C) 2015-2016 Xamarin, Inc. (http://www.xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if SECURITY_DEP
|
||||
|
||||
#if MONO_SECURITY_ALIAS
|
||||
extern alias MonoSecurity;
|
||||
using MonoSecurity::Mono.Security;
|
||||
using MonoSecurity::Mono.Security.Cryptography;
|
||||
using MX = MonoSecurity::Mono.Security.X509;
|
||||
#else
|
||||
using Mono.Security;
|
||||
using Mono.Security.Cryptography;
|
||||
using MX = Mono.Security.X509;
|
||||
#endif
|
||||
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
|
||||
namespace System.Security.Cryptography.X509Certificates
|
||||
{
|
||||
internal class X509Certificate2ImplMono : X509Certificate2Impl
|
||||
{
|
||||
bool _archived;
|
||||
X509ExtensionCollection _extensions;
|
||||
string _serial;
|
||||
PublicKey _publicKey;
|
||||
X500DistinguishedName issuer_name;
|
||||
X500DistinguishedName subject_name;
|
||||
Oid signature_algorithm;
|
||||
|
||||
MX.X509Certificate _cert;
|
||||
|
||||
static string empty_error = Locale.GetText ("Certificate instance is empty.");
|
||||
|
||||
public override bool IsValid {
|
||||
get {
|
||||
return _cert != null;
|
||||
}
|
||||
}
|
||||
|
||||
public override IntPtr Handle {
|
||||
get { return IntPtr.Zero; }
|
||||
}
|
||||
|
||||
internal X509Certificate2ImplMono (MX.X509Certificate cert)
|
||||
{
|
||||
this._cert = cert;
|
||||
}
|
||||
|
||||
public override X509CertificateImpl Clone ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return new X509Certificate2ImplMono (_cert);
|
||||
}
|
||||
|
||||
#region Implemented X509CertificateImpl members
|
||||
|
||||
public override string GetIssuerName (bool legacyV1Mode)
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
if (legacyV1Mode)
|
||||
return _cert.IssuerName;
|
||||
else
|
||||
return MX.X501.ToString (_cert.GetIssuerName (), true, ", ", true);
|
||||
}
|
||||
|
||||
public override string GetSubjectName (bool legacyV1Mode)
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
if (legacyV1Mode)
|
||||
return _cert.SubjectName;
|
||||
else
|
||||
return MX.X501.ToString (_cert.GetSubjectName (), true, ", ", true);
|
||||
}
|
||||
|
||||
public override byte[] GetRawCertData ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return _cert.RawData;
|
||||
}
|
||||
|
||||
protected override byte[] GetCertHash (bool lazy)
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
SHA1 sha = SHA1.Create ();
|
||||
return sha.ComputeHash (_cert.RawData);
|
||||
}
|
||||
|
||||
public override DateTime GetValidFrom ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return _cert.ValidFrom;
|
||||
}
|
||||
|
||||
public override DateTime GetValidUntil ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return _cert.ValidUntil;
|
||||
}
|
||||
|
||||
public override bool Equals (X509CertificateImpl other, out bool result)
|
||||
{
|
||||
// Use default implementation
|
||||
result = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GetKeyAlgorithm ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return _cert.KeyAlgorithm;
|
||||
}
|
||||
|
||||
public override byte[] GetKeyAlgorithmParameters ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return _cert.KeyAlgorithmParameters;
|
||||
}
|
||||
|
||||
public override byte[] GetPublicKey ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return _cert.PublicKey;
|
||||
}
|
||||
|
||||
public override byte[] GetSerialNumber ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return _cert.SerialNumber;
|
||||
}
|
||||
|
||||
public override byte[] Export (X509ContentType contentType, byte[] password)
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
|
||||
switch (contentType) {
|
||||
case X509ContentType.Cert:
|
||||
return GetRawCertData ();
|
||||
case X509ContentType.Pfx: // this includes Pkcs12
|
||||
// TODO
|
||||
throw new NotSupportedException ();
|
||||
case X509ContentType.SerializedCert:
|
||||
// TODO
|
||||
throw new NotSupportedException ();
|
||||
default:
|
||||
string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
|
||||
throw new CryptographicException (msg);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// constructors
|
||||
|
||||
public X509Certificate2ImplMono ()
|
||||
{
|
||||
_cert = null;
|
||||
}
|
||||
|
||||
// properties
|
||||
|
||||
public override bool Archived {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
return _archived;
|
||||
}
|
||||
set {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
_archived = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override X509ExtensionCollection Extensions {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
if (_extensions == null)
|
||||
_extensions = new X509ExtensionCollection (_cert);
|
||||
return _extensions;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME - Could be more efficient
|
||||
public override bool HasPrivateKey {
|
||||
get { return PrivateKey != null; }
|
||||
}
|
||||
|
||||
public override X500DistinguishedName IssuerName {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
if (issuer_name == null)
|
||||
issuer_name = new X500DistinguishedName (_cert.GetIssuerName ().GetBytes ());
|
||||
return issuer_name;
|
||||
}
|
||||
}
|
||||
|
||||
public override AsymmetricAlgorithm PrivateKey {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
try {
|
||||
if (_cert.RSA != null) {
|
||||
RSACryptoServiceProvider rcsp = _cert.RSA as RSACryptoServiceProvider;
|
||||
if (rcsp != null)
|
||||
return rcsp.PublicOnly ? null : rcsp;
|
||||
|
||||
RSAManaged rsam = _cert.RSA as RSAManaged;
|
||||
if (rsam != null)
|
||||
return rsam.PublicOnly ? null : rsam;
|
||||
|
||||
_cert.RSA.ExportParameters (true);
|
||||
return _cert.RSA;
|
||||
} else if (_cert.DSA != null) {
|
||||
DSACryptoServiceProvider dcsp = _cert.DSA as DSACryptoServiceProvider;
|
||||
if (dcsp != null)
|
||||
return dcsp.PublicOnly ? null : dcsp;
|
||||
|
||||
_cert.DSA.ExportParameters (true);
|
||||
return _cert.DSA;
|
||||
}
|
||||
}
|
||||
catch {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
set {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
// allow NULL so we can "forget" the key associated to the certificate
|
||||
// e.g. in case we want to export it in another format (see bug #396620)
|
||||
if (value == null) {
|
||||
_cert.RSA = null;
|
||||
_cert.DSA = null;
|
||||
} else if (value is RSA)
|
||||
_cert.RSA = (RSA) value;
|
||||
else if (value is DSA)
|
||||
_cert.DSA = (DSA) value;
|
||||
else
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
}
|
||||
|
||||
public override PublicKey PublicKey {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
if (_publicKey == null) {
|
||||
try {
|
||||
_publicKey = new PublicKey (_cert);
|
||||
}
|
||||
catch (Exception e) {
|
||||
string msg = Locale.GetText ("Unable to decode public key.");
|
||||
throw new CryptographicException (msg, e);
|
||||
}
|
||||
}
|
||||
return _publicKey;
|
||||
}
|
||||
}
|
||||
|
||||
public override Oid SignatureAlgorithm {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
if (signature_algorithm == null)
|
||||
signature_algorithm = new Oid (_cert.SignatureAlgorithm);
|
||||
return signature_algorithm;
|
||||
}
|
||||
}
|
||||
|
||||
public override X500DistinguishedName SubjectName {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
if (subject_name == null)
|
||||
subject_name = new X500DistinguishedName (_cert.GetSubjectName ().GetBytes ());
|
||||
return subject_name;
|
||||
}
|
||||
}
|
||||
|
||||
public override int Version {
|
||||
get {
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
return _cert.Version;
|
||||
}
|
||||
}
|
||||
|
||||
// methods
|
||||
|
||||
[MonoTODO ("always return String.Empty for UpnName, DnsFromAlternativeName and UrlName")]
|
||||
public override string GetNameInfo (X509NameType nameType, bool forIssuer)
|
||||
{
|
||||
switch (nameType) {
|
||||
case X509NameType.SimpleName:
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
// return CN= or, if missing, the first part of the DN
|
||||
ASN1 sn = forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ();
|
||||
ASN1 dn = Find (commonName, sn);
|
||||
if (dn != null)
|
||||
return GetValueAsString (dn);
|
||||
if (sn.Count == 0)
|
||||
return String.Empty;
|
||||
ASN1 last_entry = sn [sn.Count - 1];
|
||||
if (last_entry.Count == 0)
|
||||
return String.Empty;
|
||||
return GetValueAsString (last_entry [0]);
|
||||
case X509NameType.EmailName:
|
||||
// return the E= part of the DN (if present)
|
||||
ASN1 e = Find (email, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
|
||||
if (e != null)
|
||||
return GetValueAsString (e);
|
||||
return String.Empty;
|
||||
case X509NameType.UpnName:
|
||||
// FIXME - must find/create test case
|
||||
return String.Empty;
|
||||
case X509NameType.DnsName:
|
||||
// return the CN= part of the DN (if present)
|
||||
ASN1 cn = Find (commonName, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
|
||||
if (cn != null)
|
||||
return GetValueAsString (cn);
|
||||
return String.Empty;
|
||||
case X509NameType.DnsFromAlternativeName:
|
||||
// FIXME - must find/create test case
|
||||
return String.Empty;
|
||||
case X509NameType.UrlName:
|
||||
// FIXME - must find/create test case
|
||||
return String.Empty;
|
||||
default:
|
||||
throw new ArgumentException ("nameType");
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] commonName = { 0x55, 0x04, 0x03 };
|
||||
static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
|
||||
|
||||
private ASN1 Find (byte[] oid, ASN1 dn)
|
||||
{
|
||||
if (dn.Count == 0)
|
||||
return null;
|
||||
|
||||
// process SET
|
||||
for (int i = 0; i < dn.Count; i++) {
|
||||
ASN1 set = dn [i];
|
||||
for (int j = 0; j < set.Count; j++) {
|
||||
ASN1 pair = set [j];
|
||||
if (pair.Count != 2)
|
||||
continue;
|
||||
|
||||
ASN1 poid = pair [0];
|
||||
if (poid == null)
|
||||
continue;
|
||||
|
||||
if (poid.CompareValue (oid))
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetValueAsString (ASN1 pair)
|
||||
{
|
||||
if (pair.Count != 2)
|
||||
return String.Empty;
|
||||
|
||||
ASN1 value = pair [1];
|
||||
if ((value.Value == null) || (value.Length == 0))
|
||||
return String.Empty;
|
||||
|
||||
if (value.Tag == 0x1E) {
|
||||
// BMPSTRING
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
for (int j = 1; j < value.Value.Length; j += 2)
|
||||
sb.Append ((char)value.Value [j]);
|
||||
return sb.ToString ();
|
||||
} else {
|
||||
return Encoding.UTF8.GetString (value.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private MX.X509Certificate ImportPkcs12 (byte[] rawData, string password)
|
||||
{
|
||||
MX.PKCS12 pfx = null;
|
||||
if (string.IsNullOrEmpty (password)) {
|
||||
try {
|
||||
// Support both unencrypted PKCS#12..
|
||||
pfx = new MX.PKCS12 (rawData, (string)null);
|
||||
} catch {
|
||||
// ..and PKCS#12 encrypted with an empty password
|
||||
pfx = new MX.PKCS12 (rawData, string.Empty);
|
||||
}
|
||||
} else {
|
||||
pfx = new MX.PKCS12 (rawData, password);
|
||||
}
|
||||
|
||||
if (pfx.Certificates.Count == 0) {
|
||||
// no certificate was found
|
||||
return null;
|
||||
} else if (pfx.Keys.Count == 0) {
|
||||
// no key were found - pick the first certificate
|
||||
return pfx.Certificates [0];
|
||||
} else {
|
||||
// find the certificate that match the first key
|
||||
MX.X509Certificate cert = null;
|
||||
var keypair = (pfx.Keys [0] as AsymmetricAlgorithm);
|
||||
string pubkey = keypair.ToXmlString (false);
|
||||
foreach (var c in pfx.Certificates) {
|
||||
if (((c.RSA != null) && (pubkey == c.RSA.ToXmlString (false))) ||
|
||||
((c.DSA != null) && (pubkey == c.DSA.ToXmlString (false)))) {
|
||||
cert = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cert == null) {
|
||||
cert = pfx.Certificates [0]; // no match, pick first certificate without keys
|
||||
} else {
|
||||
cert.RSA = (keypair as RSA);
|
||||
cert.DSA = (keypair as DSA);
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
}
|
||||
|
||||
[MonoTODO ("missing KeyStorageFlags support")]
|
||||
public override void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
|
||||
{
|
||||
MX.X509Certificate cert = null;
|
||||
if (password == null) {
|
||||
try {
|
||||
cert = new MX.X509Certificate (rawData);
|
||||
}
|
||||
catch (Exception e) {
|
||||
try {
|
||||
cert = ImportPkcs12 (rawData, null);
|
||||
}
|
||||
catch {
|
||||
string msg = Locale.GetText ("Unable to decode certificate.");
|
||||
// inner exception is the original (not second) exception
|
||||
throw new CryptographicException (msg, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// try PKCS#12
|
||||
try {
|
||||
cert = ImportPkcs12 (rawData, password);
|
||||
}
|
||||
catch {
|
||||
// it's possible to supply a (unrequired/unusued) password
|
||||
// fix bug #79028
|
||||
cert = new MX.X509Certificate (rawData);
|
||||
}
|
||||
}
|
||||
_cert = cert;
|
||||
}
|
||||
|
||||
[MonoTODO ("X509ContentType.SerializedCert is not supported")]
|
||||
public override byte[] Export (X509ContentType contentType, string password)
|
||||
{
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
switch (contentType) {
|
||||
case X509ContentType.Cert:
|
||||
return _cert.RawData;
|
||||
case X509ContentType.Pfx: // this includes Pkcs12
|
||||
return ExportPkcs12 (password);
|
||||
case X509ContentType.SerializedCert:
|
||||
// TODO
|
||||
throw new NotSupportedException ();
|
||||
default:
|
||||
string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
|
||||
throw new CryptographicException (msg);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] ExportPkcs12 (string password)
|
||||
{
|
||||
var pfx = new MX.PKCS12 ();
|
||||
try {
|
||||
var attrs = new Hashtable ();
|
||||
var localKeyId = new ArrayList ();
|
||||
localKeyId.Add (new byte[] { 1, 0, 0, 0 });
|
||||
attrs.Add (MX.PKCS9.localKeyId, localKeyId);
|
||||
|
||||
if (password != null)
|
||||
pfx.Password = password;
|
||||
pfx.AddCertificate (_cert, attrs);
|
||||
var privateKey = PrivateKey;
|
||||
if (privateKey != null)
|
||||
pfx.AddPkcs8ShroudedKeyBag (privateKey, attrs);
|
||||
return pfx.GetBytes ();
|
||||
} finally {
|
||||
pfx.Password = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Reset ()
|
||||
{
|
||||
_cert = null;
|
||||
_archived = false;
|
||||
_extensions = null;
|
||||
_serial = null;
|
||||
_publicKey = null;
|
||||
issuer_name = null;
|
||||
subject_name = null;
|
||||
signature_algorithm = null;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
if (_cert == null)
|
||||
return "System.Security.Cryptography.X509Certificates.X509Certificate2";
|
||||
|
||||
return ToString (true);
|
||||
}
|
||||
|
||||
public override string ToString (bool verbose)
|
||||
{
|
||||
if (_cert == null)
|
||||
return "System.Security.Cryptography.X509Certificates.X509Certificate2";
|
||||
|
||||
string nl = Environment.NewLine;
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
|
||||
// the non-verbose X509Certificate2 == verbose X509Certificate
|
||||
if (!verbose) {
|
||||
sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false));
|
||||
sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false));
|
||||
sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ());
|
||||
sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ());
|
||||
sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
|
||||
sb.Append (nl);
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
sb.AppendFormat ("[Version]{0} V{1}{0}{0}", nl, Version);
|
||||
sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false));
|
||||
sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false));
|
||||
sb.AppendFormat ("[Serial Number]{0} {1}{0}{0}", nl, GetSerialNumber ());
|
||||
sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ());
|
||||
sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ());
|
||||
sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
|
||||
sb.AppendFormat ("[Signature Algorithm]{0} {1}({2}){0}{0}", nl, SignatureAlgorithm.FriendlyName,
|
||||
SignatureAlgorithm.Value);
|
||||
|
||||
AsymmetricAlgorithm key = PublicKey.Key;
|
||||
sb.AppendFormat ("[Public Key]{0} Algorithm: ", nl);
|
||||
if (key is RSA)
|
||||
sb.Append ("RSA");
|
||||
else if (key is DSA)
|
||||
sb.Append ("DSA");
|
||||
else
|
||||
sb.Append (key.ToString ());
|
||||
sb.AppendFormat ("{0} Length: {1}{0} Key Blob: ", nl, key.KeySize);
|
||||
AppendBuffer (sb, PublicKey.EncodedKeyValue.RawData);
|
||||
sb.AppendFormat ("{0} Parameters: ", nl);
|
||||
AppendBuffer (sb, PublicKey.EncodedParameters.RawData);
|
||||
sb.Append (nl);
|
||||
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
private static void AppendBuffer (StringBuilder sb, byte[] buffer)
|
||||
{
|
||||
if (buffer == null)
|
||||
return;
|
||||
for (int i=0; i < buffer.Length; i++) {
|
||||
sb.Append (buffer [i].ToString ("x2"));
|
||||
if (i < buffer.Length - 1)
|
||||
sb.Append (" ");
|
||||
}
|
||||
}
|
||||
|
||||
[MonoTODO ("by default this depends on the incomplete X509Chain")]
|
||||
public override bool Verify (X509Certificate2 thisCertificate)
|
||||
{
|
||||
if (_cert == null)
|
||||
throw new CryptographicException (empty_error);
|
||||
|
||||
X509Chain chain = X509Chain.Create ();
|
||||
if (!chain.Build (thisCertificate))
|
||||
return false;
|
||||
// TODO - check chain and other stuff ???
|
||||
return true;
|
||||
}
|
||||
|
||||
// static methods
|
||||
|
||||
private static byte[] signedData = new byte[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02 };
|
||||
|
||||
[MonoTODO ("Detection limited to Cert, Pfx, Pkcs12, Pkcs7 and Unknown")]
|
||||
public static X509ContentType GetCertContentType (byte[] rawData)
|
||||
{
|
||||
if ((rawData == null) || (rawData.Length == 0))
|
||||
throw new ArgumentException ("rawData");
|
||||
|
||||
X509ContentType type = X509ContentType.Unknown;
|
||||
try {
|
||||
ASN1 data = new ASN1 (rawData);
|
||||
if (data.Tag != 0x30) {
|
||||
string msg = Locale.GetText ("Unable to decode certificate.");
|
||||
throw new CryptographicException (msg);
|
||||
}
|
||||
|
||||
if (data.Count == 0)
|
||||
return type;
|
||||
|
||||
if (data.Count == 3) {
|
||||
switch (data [0].Tag) {
|
||||
case 0x30:
|
||||
// SEQUENCE / SEQUENCE / BITSTRING
|
||||
if ((data [1].Tag == 0x30) && (data [2].Tag == 0x03))
|
||||
type = X509ContentType.Cert;
|
||||
break;
|
||||
case 0x02:
|
||||
// INTEGER / SEQUENCE / SEQUENCE
|
||||
if ((data [1].Tag == 0x30) && (data [2].Tag == 0x30))
|
||||
type = X509ContentType.Pkcs12;
|
||||
// note: Pfx == Pkcs12
|
||||
break;
|
||||
}
|
||||
}
|
||||
// check for PKCS#7 (count unknown but greater than 0)
|
||||
// SEQUENCE / OID (signedData)
|
||||
if ((data [0].Tag == 0x06) && data [0].CompareValue (signedData))
|
||||
type = X509ContentType.Pkcs7;
|
||||
}
|
||||
catch (Exception e) {
|
||||
string msg = Locale.GetText ("Unable to decode certificate.");
|
||||
throw new CryptographicException (msg, e);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
[MonoTODO ("Detection limited to Cert, Pfx, Pkcs12 and Unknown")]
|
||||
public static X509ContentType GetCertContentType (string fileName)
|
||||
{
|
||||
if (fileName == null)
|
||||
throw new ArgumentNullException ("fileName");
|
||||
if (fileName.Length == 0)
|
||||
throw new ArgumentException ("fileName");
|
||||
|
||||
byte[] data = File.ReadAllBytes (fileName);
|
||||
return GetCertContentType (data);
|
||||
}
|
||||
|
||||
// internal stuff because X509Certificate2 isn't complete enough
|
||||
// (maybe X509Certificate3 will be better?)
|
||||
|
||||
internal MX.X509Certificate MonoCertificate {
|
||||
get { return _cert; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -42,23 +42,27 @@ using System.Text;
|
||||
|
||||
namespace System.Security.Cryptography.X509Certificates {
|
||||
|
||||
public class X509Chain {
|
||||
public class X509Chain : IDisposable {
|
||||
|
||||
private StoreLocation location;
|
||||
private X509ChainElementCollection elements;
|
||||
private X509ChainPolicy policy;
|
||||
private X509ChainStatus[] status;
|
||||
X509ChainImpl impl;
|
||||
|
||||
static X509ChainStatus[] Empty = new X509ChainStatus [0];
|
||||
|
||||
// RFC3280 variables
|
||||
private int max_path_length;
|
||||
private X500DistinguishedName working_issuer_name;
|
||||
// private string working_public_key_algorithm;
|
||||
private AsymmetricAlgorithm working_public_key;
|
||||
internal X509ChainImpl Impl {
|
||||
get {
|
||||
X509Helper2.ThrowIfContextInvalid (impl);
|
||||
return impl;
|
||||
}
|
||||
}
|
||||
|
||||
// other flags
|
||||
private X509ChainElement bce_restriction;
|
||||
internal bool IsValid {
|
||||
get { return X509Helper2.IsValid (impl); }
|
||||
}
|
||||
|
||||
internal void ThrowIfContextInvalid ()
|
||||
{
|
||||
X509Helper2.ThrowIfContextInvalid (impl);
|
||||
}
|
||||
|
||||
// constructors
|
||||
|
||||
@ -69,9 +73,13 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
|
||||
public X509Chain (bool useMachineContext)
|
||||
{
|
||||
location = useMachineContext ? StoreLocation.LocalMachine : StoreLocation.CurrentUser;
|
||||
elements = new X509ChainElementCollection ();
|
||||
policy = new X509ChainPolicy ();
|
||||
impl = X509Helper2.CreateChainImpl (useMachineContext);
|
||||
}
|
||||
|
||||
internal X509Chain (X509ChainImpl impl)
|
||||
{
|
||||
X509Helper2.ThrowIfContextInvalid (impl);
|
||||
this.impl = impl;
|
||||
}
|
||||
|
||||
[MonoTODO ("Mono's X509Chain is fully managed. All handles are invalid.")]
|
||||
@ -85,24 +93,24 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
|
||||
[MonoTODO ("Mono's X509Chain is fully managed. Always returns IntPtr.Zero.")]
|
||||
public IntPtr ChainContext {
|
||||
get { return IntPtr.Zero; }
|
||||
get {
|
||||
if (impl != null && impl.IsValid)
|
||||
return impl.Handle;
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public X509ChainElementCollection ChainElements {
|
||||
get { return elements; }
|
||||
get { return Impl.ChainElements; }
|
||||
}
|
||||
|
||||
public X509ChainPolicy ChainPolicy {
|
||||
get { return policy; }
|
||||
set { policy = value; }
|
||||
get { return Impl.ChainPolicy; }
|
||||
set { Impl.ChainPolicy = value; }
|
||||
}
|
||||
|
||||
public X509ChainStatus[] ChainStatus {
|
||||
get {
|
||||
if (status == null)
|
||||
return Empty;
|
||||
return status;
|
||||
}
|
||||
get { return Impl.ChainStatus; }
|
||||
}
|
||||
|
||||
// methods
|
||||
@ -110,128 +118,12 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
[MonoTODO ("Not totally RFC3280 compliant, but neither is MS implementation...")]
|
||||
public bool Build (X509Certificate2 certificate)
|
||||
{
|
||||
if (certificate == null)
|
||||
throw new ArgumentException ("certificate");
|
||||
|
||||
Reset ();
|
||||
X509ChainStatusFlags flag;
|
||||
try {
|
||||
flag = BuildChainFrom (certificate);
|
||||
ValidateChain (flag);
|
||||
}
|
||||
catch (CryptographicException ce) {
|
||||
throw new ArgumentException ("certificate", ce);
|
||||
}
|
||||
|
||||
X509ChainStatusFlags total = X509ChainStatusFlags.NoError;
|
||||
ArrayList list = new ArrayList ();
|
||||
// build "global" ChainStatus from the ChainStatus of every ChainElements
|
||||
foreach (X509ChainElement ce in elements) {
|
||||
foreach (X509ChainStatus cs in ce.ChainElementStatus) {
|
||||
// we MUST avoid duplicates in the "global" list
|
||||
if ((total & cs.Status) != cs.Status) {
|
||||
list.Add (cs);
|
||||
total |= cs.Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
// and if required add some
|
||||
if (flag != X509ChainStatusFlags.NoError) {
|
||||
list.Insert (0, new X509ChainStatus (flag));
|
||||
}
|
||||
status = (X509ChainStatus[]) list.ToArray (typeof (X509ChainStatus));
|
||||
|
||||
// (fast path) this ignore everything we have checked
|
||||
if ((status.Length == 0) || (ChainPolicy.VerificationFlags == X509VerificationFlags.AllFlags))
|
||||
return true;
|
||||
|
||||
bool result = true;
|
||||
// now check if exclude some verification for the "end result" (boolean)
|
||||
foreach (X509ChainStatus cs in status) {
|
||||
switch (cs.Status) {
|
||||
case X509ChainStatusFlags.UntrustedRoot:
|
||||
case X509ChainStatusFlags.PartialChain:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.AllowUnknownCertificateAuthority) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.NotTimeValid:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeValid) != 0);
|
||||
break;
|
||||
// FIXME - from here we needs new test cases for all cases
|
||||
case X509ChainStatusFlags.NotTimeNested:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeNested) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.InvalidBasicConstraints:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidBasicConstraints) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.InvalidPolicyConstraints:
|
||||
case X509ChainStatusFlags.NoIssuanceChainPolicy:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidPolicy) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.InvalidNameConstraints:
|
||||
case X509ChainStatusFlags.HasNotSupportedNameConstraint:
|
||||
case X509ChainStatusFlags.HasNotPermittedNameConstraint:
|
||||
case X509ChainStatusFlags.HasExcludedNameConstraint:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidName) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.InvalidExtension:
|
||||
// not sure ?!?
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
|
||||
break;
|
||||
//
|
||||
// ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreRootRevocationUnknown) != 0)
|
||||
// ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreEndRevocationUnknown) != 0)
|
||||
case X509ChainStatusFlags.CtlNotTimeValid:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlNotTimeValid) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.CtlNotSignatureValid:
|
||||
// ?
|
||||
break;
|
||||
// ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlSignerRevocationUnknown) != 0);
|
||||
case X509ChainStatusFlags.CtlNotValidForUsage:
|
||||
// FIXME - does IgnoreWrongUsage apply to CTL (it doesn't have Ctl in it's name like the others)
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
|
||||
break;
|
||||
default:
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
// once we have one failure there's no need to check further
|
||||
if (!result)
|
||||
return false;
|
||||
}
|
||||
|
||||
// every "problem" was excluded
|
||||
return true;
|
||||
return Impl.Build (certificate);
|
||||
}
|
||||
|
||||
public void Reset ()
|
||||
{
|
||||
// note: this call doesn't Reset the X509ChainPolicy
|
||||
if ((status != null) && (status.Length != 0))
|
||||
status = null;
|
||||
if (elements.Count > 0)
|
||||
elements.Clear ();
|
||||
if (user_root_store != null) {
|
||||
user_root_store.Close ();
|
||||
user_root_store = null;
|
||||
}
|
||||
if (root_store != null) {
|
||||
root_store.Close ();
|
||||
root_store = null;
|
||||
}
|
||||
if (user_ca_store != null) {
|
||||
user_ca_store.Close ();
|
||||
user_ca_store = null;
|
||||
}
|
||||
if (ca_store != null) {
|
||||
ca_store.Close ();
|
||||
ca_store = null;
|
||||
}
|
||||
roots = null;
|
||||
cas = null;
|
||||
collection = null;
|
||||
bce_restriction = null;
|
||||
working_public_key = null;
|
||||
Impl.Reset ();
|
||||
}
|
||||
|
||||
// static methods
|
||||
@ -245,717 +137,23 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
#endif
|
||||
}
|
||||
|
||||
// private stuff
|
||||
|
||||
private X509Certificate2Collection roots;
|
||||
private X509Certificate2Collection cas;
|
||||
private X509Store root_store;
|
||||
private X509Store ca_store;
|
||||
private X509Store user_root_store;
|
||||
private X509Store user_ca_store;
|
||||
|
||||
private X509Certificate2Collection Roots {
|
||||
get {
|
||||
if (roots == null) {
|
||||
X509Certificate2Collection c = new X509Certificate2Collection ();
|
||||
X509Store store = LMRootStore;
|
||||
if (location == StoreLocation.CurrentUser)
|
||||
c.AddRange (UserRootStore.Certificates);
|
||||
c.AddRange (store.Certificates);
|
||||
roots = c;
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Certificate2Collection CertificateAuthorities {
|
||||
get {
|
||||
if (cas == null) {
|
||||
X509Certificate2Collection c = new X509Certificate2Collection ();
|
||||
X509Store store = LMCAStore;
|
||||
if (location == StoreLocation.CurrentUser)
|
||||
c.AddRange (UserCAStore.Certificates);
|
||||
c.AddRange (store.Certificates);
|
||||
cas = c;
|
||||
}
|
||||
return cas;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Store LMRootStore {
|
||||
get {
|
||||
if (root_store == null) {
|
||||
root_store = new X509Store (StoreName.Root, StoreLocation.LocalMachine);
|
||||
try {
|
||||
root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
return root_store;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Store UserRootStore {
|
||||
get {
|
||||
if (user_root_store == null) {
|
||||
user_root_store = new X509Store (StoreName.Root, StoreLocation.CurrentUser);
|
||||
try {
|
||||
user_root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
return user_root_store;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Store LMCAStore {
|
||||
get {
|
||||
if (ca_store == null) {
|
||||
ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.LocalMachine);
|
||||
try {
|
||||
ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
return ca_store;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Store UserCAStore {
|
||||
get {
|
||||
if (user_ca_store == null) {
|
||||
user_ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.CurrentUser);
|
||||
try {
|
||||
user_ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
return user_ca_store;
|
||||
}
|
||||
}
|
||||
// *** certificate chain/path building stuff ***
|
||||
|
||||
private X509Certificate2Collection collection;
|
||||
|
||||
// we search local user (default) or machine certificate store
|
||||
// and in the extra certificate supplied in ChainPolicy.ExtraStore
|
||||
private X509Certificate2Collection CertificateCollection {
|
||||
get {
|
||||
if (collection == null) {
|
||||
collection = new X509Certificate2Collection (ChainPolicy.ExtraStore);
|
||||
collection.AddRange (Roots);
|
||||
collection.AddRange (CertificateAuthorities);
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a non-recursive chain/path building algorithm.
|
||||
//
|
||||
// At this stage we only checks for PartialChain, Cyclic and UntrustedRoot errors are they
|
||||
// affect the path building (other errors are verification errors).
|
||||
//
|
||||
// Note that the order match the one we need to match MS and not the one defined in RFC3280,
|
||||
// we also include the trusted root certificate (trust anchor in RFC3280) in the list.
|
||||
// (this isn't an issue, just keep that in mind if you look at the source and the RFC)
|
||||
private X509ChainStatusFlags BuildChainFrom (X509Certificate2 certificate)
|
||||
public void Dispose ()
|
||||
{
|
||||
elements.Add (certificate);
|
||||
|
||||
while (!IsChainComplete (certificate)) {
|
||||
certificate = FindParent (certificate);
|
||||
|
||||
if (certificate == null)
|
||||
return X509ChainStatusFlags.PartialChain;
|
||||
|
||||
if (elements.Contains (certificate))
|
||||
return X509ChainStatusFlags.Cyclic;
|
||||
|
||||
elements.Add (certificate);
|
||||
}
|
||||
|
||||
// roots may be supplied (e.g. in the ExtraStore) so we need to confirm their
|
||||
// trustiness (what a cute word) in the trusted root collection
|
||||
if (!Roots.Contains (certificate))
|
||||
elements [elements.Count - 1].StatusFlags |= X509ChainStatusFlags.UntrustedRoot;
|
||||
|
||||
return X509ChainStatusFlags.NoError;
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
|
||||
private X509Certificate2 SelectBestFromCollection (X509Certificate2 child, X509Certificate2Collection c)
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
switch (c.Count) {
|
||||
case 0:
|
||||
return null;
|
||||
case 1:
|
||||
return c [0];
|
||||
default:
|
||||
// multiple candidate, keep only the ones that are still valid
|
||||
X509Certificate2Collection time_valid = c.Find (X509FindType.FindByTimeValid, ChainPolicy.VerificationTime, false);
|
||||
switch (time_valid.Count) {
|
||||
case 0:
|
||||
// that's too restrictive, let's revert and try another thing...
|
||||
time_valid = c;
|
||||
break;
|
||||
case 1:
|
||||
return time_valid [0];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// again multiple candidates, let's find the AKI that match the SKI (if we have one)
|
||||
string aki = GetAuthorityKeyIdentifier (child);
|
||||
if (String.IsNullOrEmpty (aki)) {
|
||||
return time_valid [0]; // FIXME: out of luck, you get the first one
|
||||
}
|
||||
foreach (X509Certificate2 parent in time_valid) {
|
||||
string ski = GetSubjectKeyIdentifier (parent);
|
||||
// if both id are available then they must match
|
||||
if (aki == ski)
|
||||
return parent;
|
||||
}
|
||||
return time_valid [0]; // FIXME: out of luck, you get the first one
|
||||
if (impl != null) {
|
||||
impl.Dispose ();
|
||||
impl = null;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Certificate2 FindParent (X509Certificate2 certificate)
|
||||
~X509Chain ()
|
||||
{
|
||||
X509Certificate2Collection subset = CertificateCollection.Find (X509FindType.FindBySubjectDistinguishedName, certificate.Issuer, false);
|
||||
string aki = GetAuthorityKeyIdentifier (certificate);
|
||||
if ((aki != null) && (aki.Length > 0)) {
|
||||
subset.AddRange (CertificateCollection.Find (X509FindType.FindBySubjectKeyIdentifier, aki, false));
|
||||
}
|
||||
X509Certificate2 parent = SelectBestFromCollection (certificate, subset);
|
||||
// if parent==certificate we're looping but it's not (probably) a bug and not a true cyclic (over n certs)
|
||||
return certificate.Equals (parent) ? null : parent;
|
||||
}
|
||||
|
||||
private bool IsChainComplete (X509Certificate2 certificate)
|
||||
{
|
||||
// the chain is complete if we have a self-signed certificate
|
||||
if (!IsSelfIssued (certificate))
|
||||
return false;
|
||||
|
||||
// we're very limited to what we can do without certificate extensions
|
||||
if (certificate.Version < 3)
|
||||
return true;
|
||||
|
||||
// check that Authority Key Identifier == Subject Key Identifier
|
||||
// e.g. it will be different if a self-signed certificate is part (not the end) of the chain
|
||||
string ski = GetSubjectKeyIdentifier (certificate);
|
||||
if (String.IsNullOrEmpty (ski))
|
||||
return true;
|
||||
string aki = GetAuthorityKeyIdentifier (certificate);
|
||||
if (String.IsNullOrEmpty (aki))
|
||||
return true;
|
||||
// if both id are available then they must match
|
||||
return (aki == ski);
|
||||
}
|
||||
|
||||
// check for "self-issued" certificate - without verifying the signature
|
||||
// note that self-issued doesn't always mean it's a root certificate!
|
||||
private bool IsSelfIssued (X509Certificate2 certificate)
|
||||
{
|
||||
return (certificate.Issuer == certificate.Subject);
|
||||
}
|
||||
|
||||
|
||||
// *** certificate chain/path validation stuff ***
|
||||
|
||||
// Currently a subset of RFC3280 (hopefully a full implementation someday)
|
||||
private void ValidateChain (X509ChainStatusFlags flag)
|
||||
{
|
||||
// 'n' should be the root certificate...
|
||||
int n = elements.Count - 1;
|
||||
X509Certificate2 certificate = elements [n].Certificate;
|
||||
|
||||
// ... and, if so, must be treated outside the chain...
|
||||
if (((flag & X509ChainStatusFlags.PartialChain) == 0)) {
|
||||
Process (n);
|
||||
// deal with the case where the chain == the root certificate
|
||||
// (which isn't for RFC3280) part of the chain
|
||||
if (n == 0) {
|
||||
elements [0].UncompressFlags ();
|
||||
return;
|
||||
}
|
||||
// skip the root certificate when processing the chain (in 6.1.3)
|
||||
n--;
|
||||
}
|
||||
// ... unless the chain is a partial one (then we start with that one)
|
||||
|
||||
// 6.1.1 - Inputs
|
||||
// 6.1.1.a - a prospective certificate path of length n (i.e. elements)
|
||||
// 6.1.1.b - the current date/time (i.e. ChainPolicy.VerificationTime)
|
||||
// 6.1.1.c - user-initial-policy-set (i.e. ChainPolicy.CertificatePolicy)
|
||||
// 6.1.1.d - the trust anchor information (i.e. certificate, unless it's a partial chain)
|
||||
// 6.1.1.e - initial-policy-mapping-inhibit (NOT SUPPORTED BY THE API)
|
||||
// 6.1.1.f - initial-explicit-policy (NOT SUPPORTED BY THE API)
|
||||
// 6.1.1.g - initial-any-policy-inhibit (NOT SUPPORTED BY THE API)
|
||||
|
||||
// 6.1.2 - Initialization (incomplete)
|
||||
// 6.1.2.a-f - policy stuff, some TODO, some not supported
|
||||
// 6.1.2.g - working public key algorithm
|
||||
// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
|
||||
// 6.1.2.h-i - our key contains both the "working public key" and "working public key parameters" data
|
||||
working_public_key = certificate.PublicKey.Key;
|
||||
// 6.1.2.j - working issuer name
|
||||
working_issuer_name = certificate.IssuerName;
|
||||
// 6.1.2.k - this integer is initialized to n, is decremented for each non-self-issued, certificate and
|
||||
// may be reduced to the value in the path length constraint field
|
||||
max_path_length = n;
|
||||
|
||||
// 6.1.3 - Basic Certificate Processing
|
||||
// note: loop looks reversed (the list is) but we process this part just like RFC3280 does
|
||||
for (int i = n; i > 0; i--) {
|
||||
Process (i);
|
||||
// 6.1.4 - preparation for certificate i+1 (for not with i+1, or i-1 in our loop)
|
||||
PrepareForNextCertificate (i);
|
||||
}
|
||||
Process (0);
|
||||
|
||||
// 6.1.3.a.3 - revocation checks
|
||||
CheckRevocationOnChain (flag);
|
||||
|
||||
// 6.1.5 - Wrap-up procedure
|
||||
WrapUp ();
|
||||
}
|
||||
|
||||
private void Process (int n)
|
||||
{
|
||||
X509ChainElement element = elements [n];
|
||||
X509Certificate2 certificate = element.Certificate;
|
||||
|
||||
// pre-step: DSA certificates may inherit the parameters of their CA
|
||||
if ((n != elements.Count - 1) && (certificate.MonoCertificate.KeyAlgorithm == "1.2.840.10040.4.1")) {
|
||||
if (certificate.MonoCertificate.KeyAlgorithmParameters == null) {
|
||||
X509Certificate2 parent = elements [n+1].Certificate;
|
||||
certificate.MonoCertificate.KeyAlgorithmParameters = parent.MonoCertificate.KeyAlgorithmParameters;
|
||||
}
|
||||
}
|
||||
|
||||
bool root = (working_public_key == null);
|
||||
// 6.1.3.a.1 - check signature (with special case to deal with root certificates)
|
||||
if (!IsSignedWith (certificate, root ? certificate.PublicKey.Key : working_public_key)) {
|
||||
// another special case where only an end-entity is available and can't be verified.
|
||||
// In this case we do not report an invalid signature (since this is unknown)
|
||||
if (root || (n != elements.Count - 1) || IsSelfIssued (certificate)) {
|
||||
element.StatusFlags |= X509ChainStatusFlags.NotSignatureValid;
|
||||
}
|
||||
}
|
||||
|
||||
// 6.1.3.a.2 - check validity period
|
||||
if ((ChainPolicy.VerificationTime < certificate.NotBefore) ||
|
||||
(ChainPolicy.VerificationTime > certificate.NotAfter)) {
|
||||
element.StatusFlags |= X509ChainStatusFlags.NotTimeValid;
|
||||
}
|
||||
// TODO - for X509ChainStatusFlags.NotTimeNested (needs global structure)
|
||||
|
||||
// note: most of them don't apply to the root certificate
|
||||
if (root) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 6.1.3.a.3 - revocation check (we're doing at the last stage)
|
||||
// note: you revoke a trusted root by removing it from your trusted store (i.e. no CRL can do this job)
|
||||
|
||||
// 6.1.3.a.4 - check certificate issuer name
|
||||
if (!X500DistinguishedName.AreEqual (certificate.IssuerName, working_issuer_name)) {
|
||||
// NOTE: this is not the "right" error flag, but it's the closest one defined
|
||||
element.StatusFlags |= X509ChainStatusFlags.InvalidNameConstraints;
|
||||
}
|
||||
|
||||
if (!IsSelfIssued (certificate) && (n != 0)) {
|
||||
// TODO 6.1.3.b - subject name in the permitted_subtrees ...
|
||||
// TODO 6.1.3.c - subject name not within excluded_subtrees...
|
||||
|
||||
// TODO - check for X509ChainStatusFlags.InvalidNameConstraint
|
||||
// TODO - check for X509ChainStatusFlags.HasNotSupportedNameConstraint
|
||||
// TODO - check for X509ChainStatusFlags.HasNotPermittedNameConstraint
|
||||
// TODO - check for X509ChainStatusFlags.HasExcludedNameConstraint
|
||||
}
|
||||
|
||||
// TODO 6.1.3.d - check if certificate policies extension is present
|
||||
//if (false) {
|
||||
// TODO - for X509ChainStatusFlags.InvalidPolicyConstraints
|
||||
// using X509ChainPolicy.ApplicationPolicy and X509ChainPolicy.CertificatePolicy
|
||||
|
||||
// TODO - check for X509ChainStatusFlags.NoIssuanceChainPolicy
|
||||
|
||||
//} else {
|
||||
// TODO 6.1.3.e - set valid_policy_tree to NULL
|
||||
//}
|
||||
|
||||
// TODO 6.1.3.f - verify explict_policy > 0 if valid_policy_tree != NULL
|
||||
}
|
||||
|
||||
// CTL == Certificate Trust List / NOT SUPPORTED
|
||||
// TODO - check for X509ChainStatusFlags.CtlNotTimeValid
|
||||
// TODO - check for X509ChainStatusFlags.CtlNotSignatureValid
|
||||
// TODO - check for X509ChainStatusFlags.CtlNotValidForUsage
|
||||
|
||||
private void PrepareForNextCertificate (int n)
|
||||
{
|
||||
X509ChainElement element = elements [n];
|
||||
X509Certificate2 certificate = element.Certificate;
|
||||
|
||||
// TODO 6.1.4.a-b
|
||||
|
||||
// 6.1.4.c
|
||||
working_issuer_name = certificate.SubjectName;
|
||||
// 6.1.4.d-e - our key includes both the public key and it's parameters
|
||||
working_public_key = certificate.PublicKey.Key;
|
||||
// 6.1.4.f
|
||||
// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
|
||||
|
||||
// TODO 6.1.4.g-j
|
||||
|
||||
// 6.1.4.k - Verify that the certificate is a CA certificate
|
||||
X509BasicConstraintsExtension bce = (certificate.Extensions["2.5.29.19"] as X509BasicConstraintsExtension);
|
||||
if (bce != null) {
|
||||
if (!bce.CertificateAuthority) {
|
||||
element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
|
||||
}
|
||||
} else if (certificate.Version >= 3) {
|
||||
// recent (v3+) CA certificates must include BCE
|
||||
element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
|
||||
}
|
||||
|
||||
// 6.1.4.l - if the certificate isn't self-issued...
|
||||
if (!IsSelfIssued (certificate)) {
|
||||
// ... verify that max_path_length > 0
|
||||
if (max_path_length > 0) {
|
||||
max_path_length--;
|
||||
} else {
|
||||
// to match MS the reported status must be against the certificate
|
||||
// with the BCE and not where the path is too long. It also means
|
||||
// that this condition has to be reported only once
|
||||
if (bce_restriction != null) {
|
||||
bce_restriction.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6.1.4.m - if pathLengthConstraint is present...
|
||||
if ((bce != null) && (bce.HasPathLengthConstraint)) {
|
||||
// ... and is less that max_path_length, set max_path_length to it's value
|
||||
if (bce.PathLengthConstraint < max_path_length) {
|
||||
max_path_length = bce.PathLengthConstraint;
|
||||
bce_restriction = element;
|
||||
}
|
||||
}
|
||||
|
||||
// 6.1.4.n - if key usage extension is present...
|
||||
X509KeyUsageExtension kue = (certificate.Extensions["2.5.29.15"] as X509KeyUsageExtension);
|
||||
if (kue != null) {
|
||||
// ... verify keyCertSign is set
|
||||
X509KeyUsageFlags success = X509KeyUsageFlags.KeyCertSign;
|
||||
if ((kue.KeyUsages & success) != success)
|
||||
element.StatusFlags |= X509ChainStatusFlags.NotValidForUsage;
|
||||
}
|
||||
|
||||
// 6.1.4.o - recognize and process other critical extension present in the certificate
|
||||
ProcessCertificateExtensions (element);
|
||||
}
|
||||
|
||||
private void WrapUp ()
|
||||
{
|
||||
X509ChainElement element = elements [0];
|
||||
X509Certificate2 certificate = element.Certificate;
|
||||
|
||||
// 6.1.5.a - TODO if certificate n (our 0) wasn't self issued and explicit_policy != 0
|
||||
if (IsSelfIssued (certificate)) {
|
||||
// TODO... decrement explicit_policy by 1
|
||||
}
|
||||
|
||||
// 6.1.5.b - TODO
|
||||
|
||||
// 6.1.5.c,d,e - not required by the X509Chain implementation
|
||||
|
||||
// 6.1.5.f - recognize and process other critical extension present in the certificate
|
||||
ProcessCertificateExtensions (element);
|
||||
|
||||
// 6.1.5.g - TODO
|
||||
|
||||
// uncompressed the flags into several elements
|
||||
for (int i = elements.Count - 1; i >= 0; i--) {
|
||||
elements [i].UncompressFlags ();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessCertificateExtensions (X509ChainElement element)
|
||||
{
|
||||
foreach (X509Extension ext in element.Certificate.Extensions) {
|
||||
if (ext.Critical) {
|
||||
switch (ext.Oid.Value) {
|
||||
case "2.5.29.15": // X509KeyUsageExtension
|
||||
case "2.5.29.19": // X509BasicConstraintsExtension
|
||||
// we processed this extension
|
||||
break;
|
||||
default:
|
||||
// note: Under Windows XP MS implementation seems to ignore
|
||||
// certificate with unknown critical extensions.
|
||||
element.StatusFlags |= X509ChainStatusFlags.InvalidExtension;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSignedWith (X509Certificate2 signed, AsymmetricAlgorithm pubkey)
|
||||
{
|
||||
if (pubkey == null)
|
||||
return false;
|
||||
// Sadly X509Certificate2 doesn't expose the signature nor the tbs (to be signed) structure
|
||||
MX.X509Certificate mx = signed.MonoCertificate;
|
||||
return (mx.VerifySignature (pubkey));
|
||||
}
|
||||
|
||||
private string GetSubjectKeyIdentifier (X509Certificate2 certificate)
|
||||
{
|
||||
X509SubjectKeyIdentifierExtension ski = (certificate.Extensions["2.5.29.14"] as X509SubjectKeyIdentifierExtension);
|
||||
return (ski == null) ? String.Empty : ski.SubjectKeyIdentifier;
|
||||
}
|
||||
|
||||
// System.dll v2 doesn't have a class to deal with the AuthorityKeyIdentifier extension
|
||||
static string GetAuthorityKeyIdentifier (X509Certificate2 certificate)
|
||||
{
|
||||
return GetAuthorityKeyIdentifier (certificate.MonoCertificate.Extensions ["2.5.29.35"]);
|
||||
}
|
||||
|
||||
// but anyway System.dll v2 doesn't expose CRL in any way so...
|
||||
static string GetAuthorityKeyIdentifier (MX.X509Crl crl)
|
||||
{
|
||||
return GetAuthorityKeyIdentifier (crl.Extensions ["2.5.29.35"]);
|
||||
}
|
||||
|
||||
static string GetAuthorityKeyIdentifier (MX.X509Extension ext)
|
||||
{
|
||||
if (ext == null)
|
||||
return String.Empty;
|
||||
MX.Extensions.AuthorityKeyIdentifierExtension aki = new MX.Extensions.AuthorityKeyIdentifierExtension (ext);
|
||||
byte[] id = aki.Identifier;
|
||||
if (id == null)
|
||||
return String.Empty;
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
foreach (byte b in id)
|
||||
sb.Append (b.ToString ("X02"));
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
// we check the revocation only once we have built the complete chain
|
||||
private void CheckRevocationOnChain (X509ChainStatusFlags flag)
|
||||
{
|
||||
bool partial = ((flag & X509ChainStatusFlags.PartialChain) != 0);
|
||||
bool online;
|
||||
|
||||
switch (ChainPolicy.RevocationMode) {
|
||||
case X509RevocationMode.Online:
|
||||
// default
|
||||
online = true;
|
||||
break;
|
||||
case X509RevocationMode.Offline:
|
||||
online = false;
|
||||
break;
|
||||
case X509RevocationMode.NoCheck:
|
||||
return;
|
||||
default:
|
||||
throw new InvalidOperationException (Locale.GetText ("Invalid revocation mode."));
|
||||
}
|
||||
|
||||
bool unknown = partial;
|
||||
// from the root down to the end-entity
|
||||
for (int i = elements.Count - 1; i >= 0; i--) {
|
||||
bool check = true;
|
||||
|
||||
switch (ChainPolicy.RevocationFlag) {
|
||||
case X509RevocationFlag.EndCertificateOnly:
|
||||
check = (i == 0);
|
||||
break;
|
||||
case X509RevocationFlag.EntireChain:
|
||||
check = true;
|
||||
break;
|
||||
case X509RevocationFlag.ExcludeRoot:
|
||||
// default
|
||||
check = (i != (elements.Count - 1));
|
||||
// anyway, who's gonna sign that the root is invalid ?
|
||||
break;
|
||||
}
|
||||
|
||||
X509ChainElement element = elements [i];
|
||||
|
||||
// we can't assume the revocation status if the certificate is bad (e.g. invalid signature)
|
||||
if (!unknown)
|
||||
unknown |= ((element.StatusFlags & X509ChainStatusFlags.NotSignatureValid) != 0);
|
||||
|
||||
if (unknown) {
|
||||
// we can skip the revocation checks as we can't be sure of them anyway
|
||||
element.StatusFlags |= X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
element.StatusFlags |= X509ChainStatusFlags.OfflineRevocation;
|
||||
} else if (check && !partial && !IsSelfIssued (element.Certificate)) {
|
||||
// check for revocation (except for the trusted root and self-issued certs)
|
||||
element.StatusFlags |= CheckRevocation (element.Certificate, i+1, online);
|
||||
// if revoked, then all others following in the chain are unknown...
|
||||
unknown |= ((element.StatusFlags & X509ChainStatusFlags.Revoked) != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This isn't how RFC3280 (section 6.3) deals with CRL, but then we don't (yet) support DP, deltas...
|
||||
private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, int ca, bool online)
|
||||
{
|
||||
X509ChainStatusFlags result = X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
X509ChainElement element = elements [ca];
|
||||
X509Certificate2 ca_cert = element.Certificate;
|
||||
|
||||
// find the CRL from the "right" CA
|
||||
while (IsSelfIssued (ca_cert) && (ca < elements.Count - 1)) {
|
||||
// try with this self-issued
|
||||
result = CheckRevocation (certificate, ca_cert, online);
|
||||
if (result != X509ChainStatusFlags.RevocationStatusUnknown)
|
||||
break;
|
||||
ca++;
|
||||
element = elements [ca];
|
||||
ca_cert = element.Certificate;
|
||||
}
|
||||
if (result == X509ChainStatusFlags.RevocationStatusUnknown)
|
||||
result = CheckRevocation (certificate, ca_cert, online);
|
||||
return result;
|
||||
}
|
||||
|
||||
private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, X509Certificate2 ca_cert, bool online)
|
||||
{
|
||||
// change this if/when we support OCSP
|
||||
X509KeyUsageExtension kue = (ca_cert.Extensions["2.5.29.15"] as X509KeyUsageExtension);
|
||||
if (kue != null) {
|
||||
// ... verify CrlSign is set
|
||||
X509KeyUsageFlags success = X509KeyUsageFlags.CrlSign;
|
||||
if ((kue.KeyUsages & success) != success) {
|
||||
// FIXME - we should try to find an alternative CA that has the CrlSign bit
|
||||
return X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
MX.X509Crl crl = FindCrl (ca_cert);
|
||||
|
||||
if ((crl == null) && online) {
|
||||
// FIXME - download and install new CRL
|
||||
// then you get a second chance
|
||||
// crl = FindCrl (ca_cert, ref valid, ref out_of_date);
|
||||
|
||||
// We need to get the subjectAltName and an URI from there (or use OCSP)
|
||||
// X509KeyUsageExtension subjectAltName = (ca_cert.Extensions["2.5.29.17"] as X509KeyUsageExtension);
|
||||
}
|
||||
|
||||
if (crl != null) {
|
||||
// validate the digital signature on the CRL using the CA public key
|
||||
// note #1: we can't use X509Crl.VerifySignature(X509Certificate) because it duplicates
|
||||
// checks and we loose the "why" of the failure
|
||||
// note #2: we do this before other tests as an invalid signature could be a hacked CRL
|
||||
// (so anything within can't be trusted)
|
||||
if (!crl.VerifySignature (ca_cert.PublicKey.Key)) {
|
||||
return X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
}
|
||||
|
||||
MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry (certificate.MonoCertificate);
|
||||
if (entry != null) {
|
||||
// We have an entry for this CRL that includes an unknown CRITICAL extension
|
||||
// See [X.509 7.3] NOTE 4
|
||||
if (!ProcessCrlEntryExtensions (entry))
|
||||
return X509ChainStatusFlags.Revoked;
|
||||
|
||||
// FIXME - a little more is involved
|
||||
if (entry.RevocationDate <= ChainPolicy.VerificationTime)
|
||||
return X509ChainStatusFlags.Revoked;
|
||||
}
|
||||
|
||||
// are we overdue for a CRL update ? if so we can't be sure of any certificate status
|
||||
if (crl.NextUpdate < ChainPolicy.VerificationTime)
|
||||
return X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation;
|
||||
|
||||
// we have a CRL that includes an unknown CRITICAL extension
|
||||
// we put this check at the end so we do not "hide" any Revoked flags
|
||||
if (!ProcessCrlExtensions (crl)) {
|
||||
return X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
}
|
||||
} else {
|
||||
return X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
}
|
||||
|
||||
return X509ChainStatusFlags.NoError;
|
||||
}
|
||||
|
||||
static MX.X509Crl CheckCrls (string subject, string ski, MX.X509Store store)
|
||||
{
|
||||
if (store == null)
|
||||
return null;
|
||||
|
||||
var crls = store.Crls;
|
||||
foreach (MX.X509Crl crl in crls) {
|
||||
if (crl.IssuerName == subject && (ski.Length == 0 || ski == GetAuthorityKeyIdentifier (crl)))
|
||||
return crl;
|
||||
}
|
||||
return null; // No CRL found
|
||||
}
|
||||
|
||||
private MX.X509Crl FindCrl (X509Certificate2 caCertificate)
|
||||
{
|
||||
string subject = caCertificate.SubjectName.Decode (X500DistinguishedNameFlags.None);
|
||||
string ski = GetSubjectKeyIdentifier (caCertificate);
|
||||
|
||||
// consider that the LocalMachine directories could not exists... and cannot be created by the user
|
||||
MX.X509Crl result = CheckCrls (subject, ski, LMCAStore.Store);
|
||||
if (result != null)
|
||||
return result;
|
||||
if (location == StoreLocation.CurrentUser) {
|
||||
result = CheckCrls (subject, ski, UserCAStore.Store);
|
||||
if (result != null)
|
||||
return result;
|
||||
}
|
||||
|
||||
// consider that the LocalMachine directories could not exists... and cannot be created by the user
|
||||
result = CheckCrls (subject, ski, LMRootStore.Store);
|
||||
if (result != null)
|
||||
return result;
|
||||
if (location == StoreLocation.CurrentUser) {
|
||||
result = CheckCrls (subject, ski, UserRootStore.Store);
|
||||
if (result != null)
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool ProcessCrlExtensions (MX.X509Crl crl)
|
||||
{
|
||||
foreach (MX.X509Extension ext in crl.Extensions) {
|
||||
if (ext.Critical) {
|
||||
switch (ext.Oid) {
|
||||
case "2.5.29.20": // cRLNumber
|
||||
case "2.5.29.35": // authorityKeyIdentifier
|
||||
// we processed/know about this extension
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessCrlEntryExtensions (MX.X509Crl.X509CrlEntry entry)
|
||||
{
|
||||
foreach (MX.X509Extension ext in entry.Extensions) {
|
||||
if (ext.Critical) {
|
||||
switch (ext.Oid) {
|
||||
case "2.5.29.21": // cRLReason
|
||||
// we processed/know about this extension
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
Dispose (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,81 @@
|
||||
//
|
||||
// X509ChainImpl.cs
|
||||
//
|
||||
// Authors:
|
||||
// Martin Baulig <martin.baulig@xamarin.com>
|
||||
//
|
||||
// Copyright (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
#if SECURITY_DEP
|
||||
|
||||
namespace System.Security.Cryptography.X509Certificates
|
||||
{
|
||||
internal abstract class X509ChainImpl : IDisposable
|
||||
{
|
||||
public abstract bool IsValid {
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract IntPtr Handle {
|
||||
get;
|
||||
}
|
||||
|
||||
protected void ThrowIfContextInvalid ()
|
||||
{
|
||||
if (!IsValid)
|
||||
throw X509Helper2.GetInvalidChainContextException ();
|
||||
}
|
||||
|
||||
public abstract X509ChainElementCollection ChainElements {
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract X509ChainPolicy ChainPolicy {
|
||||
get; set;
|
||||
}
|
||||
|
||||
public abstract X509ChainStatus[] ChainStatus {
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract bool Build (X509Certificate2 certificate);
|
||||
|
||||
public abstract void Reset ();
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
}
|
||||
|
||||
~X509ChainImpl ()
|
||||
{
|
||||
Dispose (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,954 @@
|
||||
//
|
||||
// System.Security.Cryptography.X509Certificates.X509ChainImplMono
|
||||
//
|
||||
// Author:
|
||||
// Sebastien Pouliot <sebastien@ximian.com>
|
||||
//
|
||||
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
|
||||
// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
|
||||
// Copyright (C) 2011 Xamarin Inc. (http://www.xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if SECURITY_DEP
|
||||
|
||||
#if MONO_SECURITY_ALIAS
|
||||
extern alias MonoSecurity;
|
||||
using MX = MonoSecurity::Mono.Security.X509;
|
||||
#else
|
||||
using MX = Mono.Security.X509;
|
||||
#endif
|
||||
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Security.Cryptography.X509Certificates {
|
||||
|
||||
internal class X509ChainImplMono : X509ChainImpl
|
||||
{
|
||||
private StoreLocation location;
|
||||
private X509ChainElementCollection elements;
|
||||
private X509ChainPolicy policy;
|
||||
private X509ChainStatus[] status;
|
||||
|
||||
static X509ChainStatus[] Empty = new X509ChainStatus [0];
|
||||
|
||||
// RFC3280 variables
|
||||
private int max_path_length;
|
||||
private X500DistinguishedName working_issuer_name;
|
||||
// private string working_public_key_algorithm;
|
||||
private AsymmetricAlgorithm working_public_key;
|
||||
|
||||
// other flags
|
||||
private X509ChainElement bce_restriction;
|
||||
|
||||
// constructors
|
||||
|
||||
public X509ChainImplMono ()
|
||||
: this (false)
|
||||
{
|
||||
}
|
||||
|
||||
public X509ChainImplMono (bool useMachineContext)
|
||||
{
|
||||
location = useMachineContext ? StoreLocation.LocalMachine : StoreLocation.CurrentUser;
|
||||
elements = new X509ChainElementCollection ();
|
||||
policy = new X509ChainPolicy ();
|
||||
}
|
||||
|
||||
[MonoTODO ("Mono's X509Chain is fully managed. All handles are invalid.")]
|
||||
public X509ChainImplMono (IntPtr chainContext)
|
||||
{
|
||||
// CryptoAPI compatibility (unmanaged handle)
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
public override bool IsValid {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override IntPtr Handle {
|
||||
get { return IntPtr.Zero; }
|
||||
}
|
||||
|
||||
// properties
|
||||
|
||||
public override X509ChainElementCollection ChainElements {
|
||||
get { return elements; }
|
||||
}
|
||||
|
||||
public override X509ChainPolicy ChainPolicy {
|
||||
get { return policy; }
|
||||
set { policy = value; }
|
||||
}
|
||||
|
||||
public override X509ChainStatus[] ChainStatus {
|
||||
get {
|
||||
if (status == null)
|
||||
return Empty;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// methods
|
||||
|
||||
[MonoTODO ("Not totally RFC3280 compliant, but neither is MS implementation...")]
|
||||
public override bool Build (X509Certificate2 certificate)
|
||||
{
|
||||
if (certificate == null)
|
||||
throw new ArgumentException ("certificate");
|
||||
|
||||
Reset ();
|
||||
X509ChainStatusFlags flag;
|
||||
try {
|
||||
flag = BuildChainFrom (certificate);
|
||||
ValidateChain (flag);
|
||||
}
|
||||
catch (CryptographicException ce) {
|
||||
throw new ArgumentException ("certificate", ce);
|
||||
}
|
||||
|
||||
X509ChainStatusFlags total = X509ChainStatusFlags.NoError;
|
||||
ArrayList list = new ArrayList ();
|
||||
// build "global" ChainStatus from the ChainStatus of every ChainElements
|
||||
foreach (X509ChainElement ce in elements) {
|
||||
foreach (X509ChainStatus cs in ce.ChainElementStatus) {
|
||||
// we MUST avoid duplicates in the "global" list
|
||||
if ((total & cs.Status) != cs.Status) {
|
||||
list.Add (cs);
|
||||
total |= cs.Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
// and if required add some
|
||||
if (flag != X509ChainStatusFlags.NoError) {
|
||||
list.Insert (0, new X509ChainStatus (flag));
|
||||
}
|
||||
status = (X509ChainStatus[]) list.ToArray (typeof (X509ChainStatus));
|
||||
|
||||
// (fast path) this ignore everything we have checked
|
||||
if ((status.Length == 0) || (ChainPolicy.VerificationFlags == X509VerificationFlags.AllFlags))
|
||||
return true;
|
||||
|
||||
bool result = true;
|
||||
// now check if exclude some verification for the "end result" (boolean)
|
||||
foreach (X509ChainStatus cs in status) {
|
||||
switch (cs.Status) {
|
||||
case X509ChainStatusFlags.UntrustedRoot:
|
||||
case X509ChainStatusFlags.PartialChain:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.AllowUnknownCertificateAuthority) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.NotTimeValid:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeValid) != 0);
|
||||
break;
|
||||
// FIXME - from here we needs new test cases for all cases
|
||||
case X509ChainStatusFlags.NotTimeNested:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeNested) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.InvalidBasicConstraints:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidBasicConstraints) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.InvalidPolicyConstraints:
|
||||
case X509ChainStatusFlags.NoIssuanceChainPolicy:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidPolicy) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.InvalidNameConstraints:
|
||||
case X509ChainStatusFlags.HasNotSupportedNameConstraint:
|
||||
case X509ChainStatusFlags.HasNotPermittedNameConstraint:
|
||||
case X509ChainStatusFlags.HasExcludedNameConstraint:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidName) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.InvalidExtension:
|
||||
// not sure ?!?
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
|
||||
break;
|
||||
//
|
||||
// ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreRootRevocationUnknown) != 0)
|
||||
// ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreEndRevocationUnknown) != 0)
|
||||
case X509ChainStatusFlags.CtlNotTimeValid:
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlNotTimeValid) != 0);
|
||||
break;
|
||||
case X509ChainStatusFlags.CtlNotSignatureValid:
|
||||
// ?
|
||||
break;
|
||||
// ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlSignerRevocationUnknown) != 0);
|
||||
case X509ChainStatusFlags.CtlNotValidForUsage:
|
||||
// FIXME - does IgnoreWrongUsage apply to CTL (it doesn't have Ctl in it's name like the others)
|
||||
result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
|
||||
break;
|
||||
default:
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
// once we have one failure there's no need to check further
|
||||
if (!result)
|
||||
return false;
|
||||
}
|
||||
|
||||
// every "problem" was excluded
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Reset ()
|
||||
{
|
||||
// note: this call doesn't Reset the X509ChainPolicy
|
||||
if ((status != null) && (status.Length != 0))
|
||||
status = null;
|
||||
if (elements.Count > 0)
|
||||
elements.Clear ();
|
||||
if (user_root_store != null) {
|
||||
user_root_store.Close ();
|
||||
user_root_store = null;
|
||||
}
|
||||
if (root_store != null) {
|
||||
root_store.Close ();
|
||||
root_store = null;
|
||||
}
|
||||
if (user_ca_store != null) {
|
||||
user_ca_store.Close ();
|
||||
user_ca_store = null;
|
||||
}
|
||||
if (ca_store != null) {
|
||||
ca_store.Close ();
|
||||
ca_store = null;
|
||||
}
|
||||
roots = null;
|
||||
cas = null;
|
||||
collection = null;
|
||||
bce_restriction = null;
|
||||
working_public_key = null;
|
||||
}
|
||||
|
||||
// private stuff
|
||||
|
||||
private X509Certificate2Collection roots;
|
||||
private X509Certificate2Collection cas;
|
||||
private X509Store root_store;
|
||||
private X509Store ca_store;
|
||||
private X509Store user_root_store;
|
||||
private X509Store user_ca_store;
|
||||
|
||||
private X509Certificate2Collection Roots {
|
||||
get {
|
||||
if (roots == null) {
|
||||
X509Certificate2Collection c = new X509Certificate2Collection ();
|
||||
X509Store store = LMRootStore;
|
||||
if (location == StoreLocation.CurrentUser)
|
||||
c.AddRange (UserRootStore.Certificates);
|
||||
c.AddRange (store.Certificates);
|
||||
roots = c;
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Certificate2Collection CertificateAuthorities {
|
||||
get {
|
||||
if (cas == null) {
|
||||
X509Certificate2Collection c = new X509Certificate2Collection ();
|
||||
X509Store store = LMCAStore;
|
||||
if (location == StoreLocation.CurrentUser)
|
||||
c.AddRange (UserCAStore.Certificates);
|
||||
c.AddRange (store.Certificates);
|
||||
cas = c;
|
||||
}
|
||||
return cas;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Store LMRootStore {
|
||||
get {
|
||||
if (root_store == null) {
|
||||
root_store = new X509Store (StoreName.Root, StoreLocation.LocalMachine);
|
||||
try {
|
||||
root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
return root_store;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Store UserRootStore {
|
||||
get {
|
||||
if (user_root_store == null) {
|
||||
user_root_store = new X509Store (StoreName.Root, StoreLocation.CurrentUser);
|
||||
try {
|
||||
user_root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
return user_root_store;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Store LMCAStore {
|
||||
get {
|
||||
if (ca_store == null) {
|
||||
ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.LocalMachine);
|
||||
try {
|
||||
ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
return ca_store;
|
||||
}
|
||||
}
|
||||
|
||||
private X509Store UserCAStore {
|
||||
get {
|
||||
if (user_ca_store == null) {
|
||||
user_ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.CurrentUser);
|
||||
try {
|
||||
user_ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
return user_ca_store;
|
||||
}
|
||||
}
|
||||
// *** certificate chain/path building stuff ***
|
||||
|
||||
private X509Certificate2Collection collection;
|
||||
|
||||
// we search local user (default) or machine certificate store
|
||||
// and in the extra certificate supplied in ChainPolicy.ExtraStore
|
||||
private X509Certificate2Collection CertificateCollection {
|
||||
get {
|
||||
if (collection == null) {
|
||||
collection = new X509Certificate2Collection (ChainPolicy.ExtraStore);
|
||||
collection.AddRange (Roots);
|
||||
collection.AddRange (CertificateAuthorities);
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a non-recursive chain/path building algorithm.
|
||||
//
|
||||
// At this stage we only checks for PartialChain, Cyclic and UntrustedRoot errors are they
|
||||
// affect the path building (other errors are verification errors).
|
||||
//
|
||||
// Note that the order match the one we need to match MS and not the one defined in RFC3280,
|
||||
// we also include the trusted root certificate (trust anchor in RFC3280) in the list.
|
||||
// (this isn't an issue, just keep that in mind if you look at the source and the RFC)
|
||||
private X509ChainStatusFlags BuildChainFrom (X509Certificate2 certificate)
|
||||
{
|
||||
elements.Add (certificate);
|
||||
|
||||
while (!IsChainComplete (certificate)) {
|
||||
certificate = FindParent (certificate);
|
||||
|
||||
if (certificate == null)
|
||||
return X509ChainStatusFlags.PartialChain;
|
||||
|
||||
if (elements.Contains (certificate))
|
||||
return X509ChainStatusFlags.Cyclic;
|
||||
|
||||
elements.Add (certificate);
|
||||
}
|
||||
|
||||
// roots may be supplied (e.g. in the ExtraStore) so we need to confirm their
|
||||
// trustiness (what a cute word) in the trusted root collection
|
||||
if (!Roots.Contains (certificate))
|
||||
elements [elements.Count - 1].StatusFlags |= X509ChainStatusFlags.UntrustedRoot;
|
||||
|
||||
return X509ChainStatusFlags.NoError;
|
||||
}
|
||||
|
||||
|
||||
private X509Certificate2 SelectBestFromCollection (X509Certificate2 child, X509Certificate2Collection c)
|
||||
{
|
||||
switch (c.Count) {
|
||||
case 0:
|
||||
return null;
|
||||
case 1:
|
||||
return c [0];
|
||||
default:
|
||||
// multiple candidate, keep only the ones that are still valid
|
||||
X509Certificate2Collection time_valid = c.Find (X509FindType.FindByTimeValid, ChainPolicy.VerificationTime, false);
|
||||
switch (time_valid.Count) {
|
||||
case 0:
|
||||
// that's too restrictive, let's revert and try another thing...
|
||||
time_valid = c;
|
||||
break;
|
||||
case 1:
|
||||
return time_valid [0];
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// again multiple candidates, let's find the AKI that match the SKI (if we have one)
|
||||
string aki = GetAuthorityKeyIdentifier (child);
|
||||
if (String.IsNullOrEmpty (aki)) {
|
||||
return time_valid [0]; // FIXME: out of luck, you get the first one
|
||||
}
|
||||
foreach (X509Certificate2 parent in time_valid) {
|
||||
string ski = GetSubjectKeyIdentifier (parent);
|
||||
// if both id are available then they must match
|
||||
if (aki == ski)
|
||||
return parent;
|
||||
}
|
||||
return time_valid [0]; // FIXME: out of luck, you get the first one
|
||||
}
|
||||
}
|
||||
|
||||
private X509Certificate2 FindParent (X509Certificate2 certificate)
|
||||
{
|
||||
X509Certificate2Collection subset = CertificateCollection.Find (X509FindType.FindBySubjectDistinguishedName, certificate.Issuer, false);
|
||||
string aki = GetAuthorityKeyIdentifier (certificate);
|
||||
if ((aki != null) && (aki.Length > 0)) {
|
||||
subset.AddRange (CertificateCollection.Find (X509FindType.FindBySubjectKeyIdentifier, aki, false));
|
||||
}
|
||||
X509Certificate2 parent = SelectBestFromCollection (certificate, subset);
|
||||
// if parent==certificate we're looping but it's not (probably) a bug and not a true cyclic (over n certs)
|
||||
return certificate.Equals (parent) ? null : parent;
|
||||
}
|
||||
|
||||
private bool IsChainComplete (X509Certificate2 certificate)
|
||||
{
|
||||
// the chain is complete if we have a self-signed certificate
|
||||
if (!IsSelfIssued (certificate))
|
||||
return false;
|
||||
|
||||
// we're very limited to what we can do without certificate extensions
|
||||
if (certificate.Version < 3)
|
||||
return true;
|
||||
|
||||
// check that Authority Key Identifier == Subject Key Identifier
|
||||
// e.g. it will be different if a self-signed certificate is part (not the end) of the chain
|
||||
string ski = GetSubjectKeyIdentifier (certificate);
|
||||
if (String.IsNullOrEmpty (ski))
|
||||
return true;
|
||||
string aki = GetAuthorityKeyIdentifier (certificate);
|
||||
if (String.IsNullOrEmpty (aki))
|
||||
return true;
|
||||
// if both id are available then they must match
|
||||
return (aki == ski);
|
||||
}
|
||||
|
||||
// check for "self-issued" certificate - without verifying the signature
|
||||
// note that self-issued doesn't always mean it's a root certificate!
|
||||
private bool IsSelfIssued (X509Certificate2 certificate)
|
||||
{
|
||||
return (certificate.Issuer == certificate.Subject);
|
||||
}
|
||||
|
||||
|
||||
// *** certificate chain/path validation stuff ***
|
||||
|
||||
// Currently a subset of RFC3280 (hopefully a full implementation someday)
|
||||
private void ValidateChain (X509ChainStatusFlags flag)
|
||||
{
|
||||
// 'n' should be the root certificate...
|
||||
int n = elements.Count - 1;
|
||||
X509Certificate2 certificate = elements [n].Certificate;
|
||||
|
||||
// ... and, if so, must be treated outside the chain...
|
||||
if (((flag & X509ChainStatusFlags.PartialChain) == 0)) {
|
||||
Process (n);
|
||||
// deal with the case where the chain == the root certificate
|
||||
// (which isn't for RFC3280) part of the chain
|
||||
if (n == 0) {
|
||||
elements [0].UncompressFlags ();
|
||||
return;
|
||||
}
|
||||
// skip the root certificate when processing the chain (in 6.1.3)
|
||||
n--;
|
||||
}
|
||||
// ... unless the chain is a partial one (then we start with that one)
|
||||
|
||||
// 6.1.1 - Inputs
|
||||
// 6.1.1.a - a prospective certificate path of length n (i.e. elements)
|
||||
// 6.1.1.b - the current date/time (i.e. ChainPolicy.VerificationTime)
|
||||
// 6.1.1.c - user-initial-policy-set (i.e. ChainPolicy.CertificatePolicy)
|
||||
// 6.1.1.d - the trust anchor information (i.e. certificate, unless it's a partial chain)
|
||||
// 6.1.1.e - initial-policy-mapping-inhibit (NOT SUPPORTED BY THE API)
|
||||
// 6.1.1.f - initial-explicit-policy (NOT SUPPORTED BY THE API)
|
||||
// 6.1.1.g - initial-any-policy-inhibit (NOT SUPPORTED BY THE API)
|
||||
|
||||
// 6.1.2 - Initialization (incomplete)
|
||||
// 6.1.2.a-f - policy stuff, some TODO, some not supported
|
||||
// 6.1.2.g - working public key algorithm
|
||||
// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
|
||||
// 6.1.2.h-i - our key contains both the "working public key" and "working public key parameters" data
|
||||
working_public_key = certificate.PublicKey.Key;
|
||||
// 6.1.2.j - working issuer name
|
||||
working_issuer_name = certificate.IssuerName;
|
||||
// 6.1.2.k - this integer is initialized to n, is decremented for each non-self-issued, certificate and
|
||||
// may be reduced to the value in the path length constraint field
|
||||
max_path_length = n;
|
||||
|
||||
// 6.1.3 - Basic Certificate Processing
|
||||
// note: loop looks reversed (the list is) but we process this part just like RFC3280 does
|
||||
for (int i = n; i > 0; i--) {
|
||||
Process (i);
|
||||
// 6.1.4 - preparation for certificate i+1 (for not with i+1, or i-1 in our loop)
|
||||
PrepareForNextCertificate (i);
|
||||
}
|
||||
Process (0);
|
||||
|
||||
// 6.1.3.a.3 - revocation checks
|
||||
CheckRevocationOnChain (flag);
|
||||
|
||||
// 6.1.5 - Wrap-up procedure
|
||||
WrapUp ();
|
||||
}
|
||||
|
||||
private void Process (int n)
|
||||
{
|
||||
X509ChainElement element = elements [n];
|
||||
X509Certificate2 certificate = element.Certificate;
|
||||
|
||||
// pre-step: DSA certificates may inherit the parameters of their CA
|
||||
if ((n != elements.Count - 1) && (certificate.MonoCertificate.KeyAlgorithm == "1.2.840.10040.4.1")) {
|
||||
if (certificate.MonoCertificate.KeyAlgorithmParameters == null) {
|
||||
X509Certificate2 parent = elements [n+1].Certificate;
|
||||
certificate.MonoCertificate.KeyAlgorithmParameters = parent.MonoCertificate.KeyAlgorithmParameters;
|
||||
}
|
||||
}
|
||||
|
||||
bool root = (working_public_key == null);
|
||||
// 6.1.3.a.1 - check signature (with special case to deal with root certificates)
|
||||
if (!IsSignedWith (certificate, root ? certificate.PublicKey.Key : working_public_key)) {
|
||||
// another special case where only an end-entity is available and can't be verified.
|
||||
// In this case we do not report an invalid signature (since this is unknown)
|
||||
if (root || (n != elements.Count - 1) || IsSelfIssued (certificate)) {
|
||||
element.StatusFlags |= X509ChainStatusFlags.NotSignatureValid;
|
||||
}
|
||||
}
|
||||
|
||||
// 6.1.3.a.2 - check validity period
|
||||
if ((ChainPolicy.VerificationTime < certificate.NotBefore) ||
|
||||
(ChainPolicy.VerificationTime > certificate.NotAfter)) {
|
||||
element.StatusFlags |= X509ChainStatusFlags.NotTimeValid;
|
||||
}
|
||||
// TODO - for X509ChainStatusFlags.NotTimeNested (needs global structure)
|
||||
|
||||
// note: most of them don't apply to the root certificate
|
||||
if (root) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 6.1.3.a.3 - revocation check (we're doing at the last stage)
|
||||
// note: you revoke a trusted root by removing it from your trusted store (i.e. no CRL can do this job)
|
||||
|
||||
// 6.1.3.a.4 - check certificate issuer name
|
||||
if (!X500DistinguishedName.AreEqual (certificate.IssuerName, working_issuer_name)) {
|
||||
// NOTE: this is not the "right" error flag, but it's the closest one defined
|
||||
element.StatusFlags |= X509ChainStatusFlags.InvalidNameConstraints;
|
||||
}
|
||||
|
||||
if (!IsSelfIssued (certificate) && (n != 0)) {
|
||||
// TODO 6.1.3.b - subject name in the permitted_subtrees ...
|
||||
// TODO 6.1.3.c - subject name not within excluded_subtrees...
|
||||
|
||||
// TODO - check for X509ChainStatusFlags.InvalidNameConstraint
|
||||
// TODO - check for X509ChainStatusFlags.HasNotSupportedNameConstraint
|
||||
// TODO - check for X509ChainStatusFlags.HasNotPermittedNameConstraint
|
||||
// TODO - check for X509ChainStatusFlags.HasExcludedNameConstraint
|
||||
}
|
||||
|
||||
// TODO 6.1.3.d - check if certificate policies extension is present
|
||||
//if (false) {
|
||||
// TODO - for X509ChainStatusFlags.InvalidPolicyConstraints
|
||||
// using X509ChainPolicy.ApplicationPolicy and X509ChainPolicy.CertificatePolicy
|
||||
|
||||
// TODO - check for X509ChainStatusFlags.NoIssuanceChainPolicy
|
||||
|
||||
//} else {
|
||||
// TODO 6.1.3.e - set valid_policy_tree to NULL
|
||||
//}
|
||||
|
||||
// TODO 6.1.3.f - verify explict_policy > 0 if valid_policy_tree != NULL
|
||||
}
|
||||
|
||||
// CTL == Certificate Trust List / NOT SUPPORTED
|
||||
// TODO - check for X509ChainStatusFlags.CtlNotTimeValid
|
||||
// TODO - check for X509ChainStatusFlags.CtlNotSignatureValid
|
||||
// TODO - check for X509ChainStatusFlags.CtlNotValidForUsage
|
||||
|
||||
private void PrepareForNextCertificate (int n)
|
||||
{
|
||||
X509ChainElement element = elements [n];
|
||||
X509Certificate2 certificate = element.Certificate;
|
||||
|
||||
// TODO 6.1.4.a-b
|
||||
|
||||
// 6.1.4.c
|
||||
working_issuer_name = certificate.SubjectName;
|
||||
// 6.1.4.d-e - our key includes both the public key and it's parameters
|
||||
working_public_key = certificate.PublicKey.Key;
|
||||
// 6.1.4.f
|
||||
// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
|
||||
|
||||
// TODO 6.1.4.g-j
|
||||
|
||||
// 6.1.4.k - Verify that the certificate is a CA certificate
|
||||
X509BasicConstraintsExtension bce = (certificate.Extensions["2.5.29.19"] as X509BasicConstraintsExtension);
|
||||
if (bce != null) {
|
||||
if (!bce.CertificateAuthority) {
|
||||
element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
|
||||
}
|
||||
} else if (certificate.Version >= 3) {
|
||||
// recent (v3+) CA certificates must include BCE
|
||||
element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
|
||||
}
|
||||
|
||||
// 6.1.4.l - if the certificate isn't self-issued...
|
||||
if (!IsSelfIssued (certificate)) {
|
||||
// ... verify that max_path_length > 0
|
||||
if (max_path_length > 0) {
|
||||
max_path_length--;
|
||||
} else {
|
||||
// to match MS the reported status must be against the certificate
|
||||
// with the BCE and not where the path is too long. It also means
|
||||
// that this condition has to be reported only once
|
||||
if (bce_restriction != null) {
|
||||
bce_restriction.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6.1.4.m - if pathLengthConstraint is present...
|
||||
if ((bce != null) && (bce.HasPathLengthConstraint)) {
|
||||
// ... and is less that max_path_length, set max_path_length to it's value
|
||||
if (bce.PathLengthConstraint < max_path_length) {
|
||||
max_path_length = bce.PathLengthConstraint;
|
||||
bce_restriction = element;
|
||||
}
|
||||
}
|
||||
|
||||
// 6.1.4.n - if key usage extension is present...
|
||||
X509KeyUsageExtension kue = (certificate.Extensions["2.5.29.15"] as X509KeyUsageExtension);
|
||||
if (kue != null) {
|
||||
// ... verify keyCertSign is set
|
||||
X509KeyUsageFlags success = X509KeyUsageFlags.KeyCertSign;
|
||||
if ((kue.KeyUsages & success) != success)
|
||||
element.StatusFlags |= X509ChainStatusFlags.NotValidForUsage;
|
||||
}
|
||||
|
||||
// 6.1.4.o - recognize and process other critical extension present in the certificate
|
||||
ProcessCertificateExtensions (element);
|
||||
}
|
||||
|
||||
private void WrapUp ()
|
||||
{
|
||||
X509ChainElement element = elements [0];
|
||||
X509Certificate2 certificate = element.Certificate;
|
||||
|
||||
// 6.1.5.a - TODO if certificate n (our 0) wasn't self issued and explicit_policy != 0
|
||||
if (IsSelfIssued (certificate)) {
|
||||
// TODO... decrement explicit_policy by 1
|
||||
}
|
||||
|
||||
// 6.1.5.b - TODO
|
||||
|
||||
// 6.1.5.c,d,e - not required by the X509Chain implementation
|
||||
|
||||
// 6.1.5.f - recognize and process other critical extension present in the certificate
|
||||
ProcessCertificateExtensions (element);
|
||||
|
||||
// 6.1.5.g - TODO
|
||||
|
||||
// uncompressed the flags into several elements
|
||||
for (int i = elements.Count - 1; i >= 0; i--) {
|
||||
elements [i].UncompressFlags ();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessCertificateExtensions (X509ChainElement element)
|
||||
{
|
||||
foreach (X509Extension ext in element.Certificate.Extensions) {
|
||||
if (ext.Critical) {
|
||||
switch (ext.Oid.Value) {
|
||||
case "2.5.29.15": // X509KeyUsageExtension
|
||||
case "2.5.29.19": // X509BasicConstraintsExtension
|
||||
// we processed this extension
|
||||
break;
|
||||
default:
|
||||
// note: Under Windows XP MS implementation seems to ignore
|
||||
// certificate with unknown critical extensions.
|
||||
element.StatusFlags |= X509ChainStatusFlags.InvalidExtension;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsSignedWith (X509Certificate2 signed, AsymmetricAlgorithm pubkey)
|
||||
{
|
||||
if (pubkey == null)
|
||||
return false;
|
||||
// Sadly X509Certificate2 doesn't expose the signature nor the tbs (to be signed) structure
|
||||
MX.X509Certificate mx = signed.MonoCertificate;
|
||||
return (mx.VerifySignature (pubkey));
|
||||
}
|
||||
|
||||
private string GetSubjectKeyIdentifier (X509Certificate2 certificate)
|
||||
{
|
||||
X509SubjectKeyIdentifierExtension ski = (certificate.Extensions["2.5.29.14"] as X509SubjectKeyIdentifierExtension);
|
||||
return (ski == null) ? String.Empty : ski.SubjectKeyIdentifier;
|
||||
}
|
||||
|
||||
// System.dll v2 doesn't have a class to deal with the AuthorityKeyIdentifier extension
|
||||
static string GetAuthorityKeyIdentifier (X509Certificate2 certificate)
|
||||
{
|
||||
return GetAuthorityKeyIdentifier (certificate.MonoCertificate.Extensions ["2.5.29.35"]);
|
||||
}
|
||||
|
||||
// but anyway System.dll v2 doesn't expose CRL in any way so...
|
||||
static string GetAuthorityKeyIdentifier (MX.X509Crl crl)
|
||||
{
|
||||
return GetAuthorityKeyIdentifier (crl.Extensions ["2.5.29.35"]);
|
||||
}
|
||||
|
||||
static string GetAuthorityKeyIdentifier (MX.X509Extension ext)
|
||||
{
|
||||
if (ext == null)
|
||||
return String.Empty;
|
||||
MX.Extensions.AuthorityKeyIdentifierExtension aki = new MX.Extensions.AuthorityKeyIdentifierExtension (ext);
|
||||
byte[] id = aki.Identifier;
|
||||
if (id == null)
|
||||
return String.Empty;
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
foreach (byte b in id)
|
||||
sb.Append (b.ToString ("X02"));
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
// we check the revocation only once we have built the complete chain
|
||||
private void CheckRevocationOnChain (X509ChainStatusFlags flag)
|
||||
{
|
||||
bool partial = ((flag & X509ChainStatusFlags.PartialChain) != 0);
|
||||
bool online;
|
||||
|
||||
switch (ChainPolicy.RevocationMode) {
|
||||
case X509RevocationMode.Online:
|
||||
// default
|
||||
online = true;
|
||||
break;
|
||||
case X509RevocationMode.Offline:
|
||||
online = false;
|
||||
break;
|
||||
case X509RevocationMode.NoCheck:
|
||||
return;
|
||||
default:
|
||||
throw new InvalidOperationException (Locale.GetText ("Invalid revocation mode."));
|
||||
}
|
||||
|
||||
bool unknown = partial;
|
||||
// from the root down to the end-entity
|
||||
for (int i = elements.Count - 1; i >= 0; i--) {
|
||||
bool check = true;
|
||||
|
||||
switch (ChainPolicy.RevocationFlag) {
|
||||
case X509RevocationFlag.EndCertificateOnly:
|
||||
check = (i == 0);
|
||||
break;
|
||||
case X509RevocationFlag.EntireChain:
|
||||
check = true;
|
||||
break;
|
||||
case X509RevocationFlag.ExcludeRoot:
|
||||
// default
|
||||
check = (i != (elements.Count - 1));
|
||||
// anyway, who's gonna sign that the root is invalid ?
|
||||
break;
|
||||
}
|
||||
|
||||
X509ChainElement element = elements [i];
|
||||
|
||||
// we can't assume the revocation status if the certificate is bad (e.g. invalid signature)
|
||||
if (!unknown)
|
||||
unknown |= ((element.StatusFlags & X509ChainStatusFlags.NotSignatureValid) != 0);
|
||||
|
||||
if (unknown) {
|
||||
// we can skip the revocation checks as we can't be sure of them anyway
|
||||
element.StatusFlags |= X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
element.StatusFlags |= X509ChainStatusFlags.OfflineRevocation;
|
||||
} else if (check && !partial && !IsSelfIssued (element.Certificate)) {
|
||||
// check for revocation (except for the trusted root and self-issued certs)
|
||||
element.StatusFlags |= CheckRevocation (element.Certificate, i+1, online);
|
||||
// if revoked, then all others following in the chain are unknown...
|
||||
unknown |= ((element.StatusFlags & X509ChainStatusFlags.Revoked) != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This isn't how RFC3280 (section 6.3) deals with CRL, but then we don't (yet) support DP, deltas...
|
||||
private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, int ca, bool online)
|
||||
{
|
||||
X509ChainStatusFlags result = X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
X509ChainElement element = elements [ca];
|
||||
X509Certificate2 ca_cert = element.Certificate;
|
||||
|
||||
// find the CRL from the "right" CA
|
||||
while (IsSelfIssued (ca_cert) && (ca < elements.Count - 1)) {
|
||||
// try with this self-issued
|
||||
result = CheckRevocation (certificate, ca_cert, online);
|
||||
if (result != X509ChainStatusFlags.RevocationStatusUnknown)
|
||||
break;
|
||||
ca++;
|
||||
element = elements [ca];
|
||||
ca_cert = element.Certificate;
|
||||
}
|
||||
if (result == X509ChainStatusFlags.RevocationStatusUnknown)
|
||||
result = CheckRevocation (certificate, ca_cert, online);
|
||||
return result;
|
||||
}
|
||||
|
||||
private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, X509Certificate2 ca_cert, bool online)
|
||||
{
|
||||
// change this if/when we support OCSP
|
||||
X509KeyUsageExtension kue = (ca_cert.Extensions["2.5.29.15"] as X509KeyUsageExtension);
|
||||
if (kue != null) {
|
||||
// ... verify CrlSign is set
|
||||
X509KeyUsageFlags success = X509KeyUsageFlags.CrlSign;
|
||||
if ((kue.KeyUsages & success) != success) {
|
||||
// FIXME - we should try to find an alternative CA that has the CrlSign bit
|
||||
return X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
MX.X509Crl crl = FindCrl (ca_cert);
|
||||
|
||||
if ((crl == null) && online) {
|
||||
// FIXME - download and install new CRL
|
||||
// then you get a second chance
|
||||
// crl = FindCrl (ca_cert, ref valid, ref out_of_date);
|
||||
|
||||
// We need to get the subjectAltName and an URI from there (or use OCSP)
|
||||
// X509KeyUsageExtension subjectAltName = (ca_cert.Extensions["2.5.29.17"] as X509KeyUsageExtension);
|
||||
}
|
||||
|
||||
if (crl != null) {
|
||||
// validate the digital signature on the CRL using the CA public key
|
||||
// note #1: we can't use X509Crl.VerifySignature(X509Certificate) because it duplicates
|
||||
// checks and we loose the "why" of the failure
|
||||
// note #2: we do this before other tests as an invalid signature could be a hacked CRL
|
||||
// (so anything within can't be trusted)
|
||||
if (!crl.VerifySignature (ca_cert.PublicKey.Key)) {
|
||||
return X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
}
|
||||
|
||||
MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry (certificate.MonoCertificate);
|
||||
if (entry != null) {
|
||||
// We have an entry for this CRL that includes an unknown CRITICAL extension
|
||||
// See [X.509 7.3] NOTE 4
|
||||
if (!ProcessCrlEntryExtensions (entry))
|
||||
return X509ChainStatusFlags.Revoked;
|
||||
|
||||
// FIXME - a little more is involved
|
||||
if (entry.RevocationDate <= ChainPolicy.VerificationTime)
|
||||
return X509ChainStatusFlags.Revoked;
|
||||
}
|
||||
|
||||
// are we overdue for a CRL update ? if so we can't be sure of any certificate status
|
||||
if (crl.NextUpdate < ChainPolicy.VerificationTime)
|
||||
return X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation;
|
||||
|
||||
// we have a CRL that includes an unknown CRITICAL extension
|
||||
// we put this check at the end so we do not "hide" any Revoked flags
|
||||
if (!ProcessCrlExtensions (crl)) {
|
||||
return X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
}
|
||||
} else {
|
||||
return X509ChainStatusFlags.RevocationStatusUnknown;
|
||||
}
|
||||
|
||||
return X509ChainStatusFlags.NoError;
|
||||
}
|
||||
|
||||
static MX.X509Crl CheckCrls (string subject, string ski, MX.X509Store store)
|
||||
{
|
||||
if (store == null)
|
||||
return null;
|
||||
|
||||
var crls = store.Crls;
|
||||
foreach (MX.X509Crl crl in crls) {
|
||||
if (crl.IssuerName == subject && (ski.Length == 0 || ski == GetAuthorityKeyIdentifier (crl)))
|
||||
return crl;
|
||||
}
|
||||
return null; // No CRL found
|
||||
}
|
||||
|
||||
private MX.X509Crl FindCrl (X509Certificate2 caCertificate)
|
||||
{
|
||||
string subject = caCertificate.SubjectName.Decode (X500DistinguishedNameFlags.None);
|
||||
string ski = GetSubjectKeyIdentifier (caCertificate);
|
||||
|
||||
// consider that the LocalMachine directories could not exists... and cannot be created by the user
|
||||
MX.X509Crl result = CheckCrls (subject, ski, LMCAStore.Store);
|
||||
if (result != null)
|
||||
return result;
|
||||
if (location == StoreLocation.CurrentUser) {
|
||||
result = CheckCrls (subject, ski, UserCAStore.Store);
|
||||
if (result != null)
|
||||
return result;
|
||||
}
|
||||
|
||||
// consider that the LocalMachine directories could not exists... and cannot be created by the user
|
||||
result = CheckCrls (subject, ski, LMRootStore.Store);
|
||||
if (result != null)
|
||||
return result;
|
||||
if (location == StoreLocation.CurrentUser) {
|
||||
result = CheckCrls (subject, ski, UserRootStore.Store);
|
||||
if (result != null)
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool ProcessCrlExtensions (MX.X509Crl crl)
|
||||
{
|
||||
foreach (MX.X509Extension ext in crl.Extensions) {
|
||||
if (ext.Critical) {
|
||||
switch (ext.Oid) {
|
||||
case "2.5.29.20": // cRLNumber
|
||||
case "2.5.29.35": // authorityKeyIdentifier
|
||||
// we processed/know about this extension
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ProcessCrlEntryExtensions (MX.X509Crl.X509CrlEntry entry)
|
||||
{
|
||||
foreach (MX.X509Extension ext in entry.Extensions) {
|
||||
if (ext.Critical) {
|
||||
switch (ext.Oid) {
|
||||
case "2.5.29.21": // cRLReason
|
||||
// we processed/know about this extension
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -0,0 +1,119 @@
|
||||
//
|
||||
// X509Helper2.cs
|
||||
//
|
||||
// Authors:
|
||||
// Martin Baulig <martin.baulig@xamarin.com>
|
||||
//
|
||||
// Copyright (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if SECURITY_DEP
|
||||
#if MONO_SECURITY_ALIAS
|
||||
extern alias MonoSecurity;
|
||||
#endif
|
||||
#if MONO_X509_ALIAS
|
||||
extern alias PrebuiltSystem;
|
||||
#endif
|
||||
|
||||
#if MONO_SECURITY_ALIAS
|
||||
using MonoSecurity::Mono.Security.Interface;
|
||||
#else
|
||||
using Mono.Security.Interface;
|
||||
#endif
|
||||
|
||||
namespace System.Security.Cryptography.X509Certificates
|
||||
{
|
||||
internal static class X509Helper2
|
||||
{
|
||||
internal static void Initialize ()
|
||||
{
|
||||
X509Helper.InstallNativeHelper (new MyNativeHelper ());
|
||||
}
|
||||
|
||||
internal static void ThrowIfContextInvalid (X509CertificateImpl impl)
|
||||
{
|
||||
X509Helper.ThrowIfContextInvalid (impl);
|
||||
}
|
||||
|
||||
internal static X509Certificate2Impl Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
|
||||
{
|
||||
var provider = MonoTlsProviderFactory.GetProvider ();
|
||||
if (provider.HasNativeCertificates) {
|
||||
var impl = provider.GetNativeCertificate (rawData, password, keyStorageFlags);
|
||||
return (X509Certificate2Impl)(object)impl;
|
||||
} else {
|
||||
var impl = new X509Certificate2ImplMono ();
|
||||
impl.Import (rawData, password, keyStorageFlags);
|
||||
return impl;
|
||||
}
|
||||
}
|
||||
|
||||
internal static X509Certificate2Impl Import (X509Certificate cert)
|
||||
{
|
||||
var provider = MonoTlsProviderFactory.GetProvider ();
|
||||
if (provider.HasNativeCertificates) {
|
||||
var impl = provider.GetNativeCertificate (cert);
|
||||
return (X509Certificate2Impl)(object)impl;
|
||||
}
|
||||
var impl2 = cert.Impl as X509Certificate2Impl;
|
||||
if (impl2 != null)
|
||||
return (X509Certificate2Impl)impl2.Clone ();
|
||||
return Import (cert.GetRawCertData (), null, X509KeyStorageFlags.DefaultKeySet);
|
||||
}
|
||||
|
||||
internal static X509ChainImpl CreateChainImpl (bool useMachineContext)
|
||||
{
|
||||
return new X509ChainImplMono (useMachineContext);
|
||||
}
|
||||
|
||||
public static bool IsValid (X509ChainImpl impl)
|
||||
{
|
||||
return impl != null && impl.IsValid;
|
||||
}
|
||||
|
||||
internal static void ThrowIfContextInvalid (X509ChainImpl impl)
|
||||
{
|
||||
if (!IsValid (impl))
|
||||
throw GetInvalidChainContextException ();
|
||||
}
|
||||
|
||||
internal static Exception GetInvalidChainContextException ()
|
||||
{
|
||||
return new CryptographicException (Locale.GetText ("Chain instance is empty."));
|
||||
}
|
||||
|
||||
class MyNativeHelper : INativeCertificateHelper
|
||||
{
|
||||
public X509CertificateImpl Import (
|
||||
byte[] data, string password, X509KeyStorageFlags flags)
|
||||
{
|
||||
return X509Helper2.Import (data, password, flags);
|
||||
}
|
||||
|
||||
public X509CertificateImpl Import (X509Certificate cert)
|
||||
{
|
||||
return X509Helper2.Import (cert);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -536,11 +536,15 @@ System.Security.Cryptography.X509Certificates/X509BasicConstraintsExtension.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate2Collection.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate2.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate2Enumerator.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs
|
||||
System.Security.Cryptography.X509Certificates/X509CertificateCollection.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Chain.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainElementCollection.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainElement.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainElementEnumerator.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainImpl.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainImplMono.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainPolicy.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainStatus.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainStatusFlags.cs
|
||||
@ -550,6 +554,7 @@ System.Security.Cryptography.X509Certificates/X509Extension.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ExtensionEnumerator.cs
|
||||
System.Security.Cryptography.X509Certificates/X509FindType.cs
|
||||
System.Security.Cryptography.X509Certificates/X509IncludeOption.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Helper2.cs
|
||||
System.Security.Cryptography.X509Certificates/X509KeyUsageExtension.cs
|
||||
System.Security.Cryptography.X509Certificates/X509KeyUsageFlags.cs
|
||||
System.Security.Cryptography.X509Certificates/X509NameType.cs
|
||||
|
@ -1 +1 @@
|
||||
e642d688f3c59c8d62dd075b49ad48e36176f470
|
||||
a7e48646d05dcf3b87af070d4ee4cb66ac045634
|
@ -300,11 +300,15 @@ System.Security.Cryptography.X509Certificates/X509BasicConstraintsExtension.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate2.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate2Collection.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate2Enumerator.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs
|
||||
System.Security.Cryptography.X509Certificates/X509CertificateCollection.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Chain.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainElement.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainElementCollection.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainElementEnumerator.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainImpl.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainImplMono.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainPolicy.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainStatus.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ChainStatusFlags.cs
|
||||
@ -314,6 +318,7 @@ System.Security.Cryptography.X509Certificates/X509ExtensionCollection.cs
|
||||
System.Security.Cryptography.X509Certificates/X509ExtensionEnumerator.cs
|
||||
System.Security.Cryptography.X509Certificates/X509FindType.cs
|
||||
System.Security.Cryptography.X509Certificates/X509IncludeOption.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Helper2.cs
|
||||
System.Security.Cryptography.X509Certificates/X509KeyUsageExtension.cs
|
||||
System.Security.Cryptography.X509Certificates/X509KeyUsageFlags.cs
|
||||
System.Security.Cryptography.X509Certificates/X509NameType.cs
|
||||
|
@ -98,4 +98,5 @@ using System.Runtime.InteropServices;
|
||||
[assembly: InternalsVisibleTo ("Xamarin.Mac, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
|
||||
#endif
|
||||
|
||||
[assembly: InternalsVisibleTo ("Xamarin.BoringTls, PublicKey=002400000480000094000000060200000024000052534131000400001100000099dd12eda85767ae6f06023ee28e711c7e5a212462095c83868c29db75eddf6d8e296e03824c14fedd5f55553fed0b6173be3cc985a4b7f9fb7c83ccff8ba3938563b3d1f45a81122f12a1bcb73edcaad61a8456c7595a6da5184b4dd9d10f011b949ef1391fccfeab1ba62aa51c267ef8bd57ef1b6ba5a4c515d0badb81a78f")]
|
||||
[assembly: Guid ("BED7F4EA-1A96-11D2-8F08-00A0C9A6186D")]
|
||||
|
@ -1,74 +0,0 @@
|
||||
//
|
||||
// System.Runtime.InteropServices/RuntimeEnvironment.cs
|
||||
//
|
||||
// Authors:
|
||||
// Dominik Fretz (roboto@gmx.net)
|
||||
// Sebastien Pouliot (sebastien@ximian.com)
|
||||
//
|
||||
// (C) 2003 Dominik Fretz
|
||||
// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace System.Runtime.InteropServices
|
||||
{
|
||||
[ComVisible (true)]
|
||||
public class RuntimeEnvironment
|
||||
{
|
||||
public RuntimeEnvironment ()
|
||||
{
|
||||
}
|
||||
|
||||
public static string SystemConfigurationFile {
|
||||
get {
|
||||
// GetMachineConfigPath is internal and not protected by CAS
|
||||
string path = Environment.GetMachineConfigPath ();
|
||||
if (SecurityManager.SecurityEnabled) {
|
||||
new FileIOPermission (FileIOPermissionAccess.PathDiscovery, path).Demand ();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool FromGlobalAccessCache (Assembly a)
|
||||
{
|
||||
// yes, this will throw a NullReferenceException (just like MS, reported as ...)
|
||||
return a.GlobalAssemblyCache;
|
||||
}
|
||||
|
||||
public static string GetRuntimeDirectory ()
|
||||
{
|
||||
return Path.GetDirectoryName (typeof (int).Assembly.Location);
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static string GetSystemVersion ()
|
||||
{
|
||||
return "v" + Environment.Version.Major + "." + Environment.Version.Minor + "." + Environment.Version.Build;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
//
|
||||
// INativeCertificateHelper.cs
|
||||
//
|
||||
// Author:
|
||||
// Martin Baulig <martin.baulig@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2016 Xamarin, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
namespace System.Security.Cryptography.X509Certificates
|
||||
{
|
||||
internal interface INativeCertificateHelper
|
||||
{
|
||||
X509CertificateImpl Import (byte[] data, string password, X509KeyStorageFlags flags);
|
||||
|
||||
X509CertificateImpl Import (X509Certificate cert);
|
||||
}
|
||||
}
|
@ -109,17 +109,44 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
impl = X509Helper.InitFromHandle (handle);
|
||||
}
|
||||
|
||||
internal X509Certificate (X509CertificateImpl impl)
|
||||
{
|
||||
if (impl == null)
|
||||
throw new ArgumentNullException ("impl");
|
||||
|
||||
this.impl = X509Helper.InitFromCertificate (impl);
|
||||
}
|
||||
|
||||
public X509Certificate (System.Security.Cryptography.X509Certificates.X509Certificate cert)
|
||||
{
|
||||
if (cert == null)
|
||||
throw new ArgumentNullException ("cert");
|
||||
|
||||
X509Helper.ThrowIfContextInvalid (cert.impl);
|
||||
|
||||
impl = X509Helper.InitFromCertificate (cert.impl);
|
||||
impl = X509Helper.InitFromCertificate (cert);
|
||||
hideDates = false;
|
||||
}
|
||||
|
||||
internal void ImportHandle (X509CertificateImpl impl)
|
||||
{
|
||||
Reset ();
|
||||
this.impl = impl;
|
||||
}
|
||||
|
||||
internal X509CertificateImpl Impl {
|
||||
get {
|
||||
X509Helper.ThrowIfContextInvalid (impl);
|
||||
return impl;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsValid {
|
||||
get { return X509Helper.IsValid (impl); }
|
||||
}
|
||||
|
||||
internal void ThrowIfContextInvalid ()
|
||||
{
|
||||
X509Helper.ThrowIfContextInvalid (impl);
|
||||
}
|
||||
|
||||
// public methods
|
||||
|
||||
@ -161,7 +188,7 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
return null;
|
||||
X509Helper.ThrowIfContextInvalid (impl);
|
||||
|
||||
return impl.GetEffectiveDateString ().ToString ();
|
||||
return impl.GetValidFrom ().ToLocalTime ().ToString ();
|
||||
}
|
||||
|
||||
// strangly there are no DateTime returning function
|
||||
@ -171,7 +198,7 @@ namespace System.Security.Cryptography.X509Certificates {
|
||||
return null;
|
||||
X509Helper.ThrowIfContextInvalid (impl);
|
||||
|
||||
return impl.GetExpirationDateString ().ToString ();
|
||||
return impl.GetValidUntil ().ToLocalTime ().ToString ();
|
||||
}
|
||||
|
||||
// well maybe someday there'll be support for PGP or SPKI ?
|
||||
|
@ -45,17 +45,15 @@ namespace System.Security.Cryptography.X509Certificates
|
||||
|
||||
public abstract X509CertificateImpl Clone ();
|
||||
|
||||
public abstract string GetSubjectSummary ();
|
||||
|
||||
public abstract string GetIssuerName (bool legacyV1Mode);
|
||||
|
||||
public abstract string GetSubjectName (bool legacyV1Mode);
|
||||
|
||||
public abstract byte[] GetRawCertData ();
|
||||
|
||||
public abstract DateTime GetEffectiveDateString ();
|
||||
public abstract DateTime GetValidFrom ();
|
||||
|
||||
public abstract DateTime GetExpirationDateString ();
|
||||
public abstract DateTime GetValidUntil ();
|
||||
|
||||
byte[] cachedCertificateHash;
|
||||
|
||||
|
@ -66,12 +66,6 @@ namespace System.Security.Cryptography.X509Certificates
|
||||
return MX.X501.ToString (x509.GetIssuerName (), true, ", ", true);
|
||||
}
|
||||
|
||||
public override string GetSubjectSummary ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return x509.SubjectName;
|
||||
}
|
||||
|
||||
public override string GetSubjectName (bool legacyV1Mode)
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
@ -94,16 +88,16 @@ namespace System.Security.Cryptography.X509Certificates
|
||||
return sha.ComputeHash (x509.RawData);
|
||||
}
|
||||
|
||||
public override DateTime GetEffectiveDateString ()
|
||||
public override DateTime GetValidFrom ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return x509.ValidFrom.ToLocalTime ();
|
||||
return x509.ValidFrom;
|
||||
}
|
||||
|
||||
public override DateTime GetExpirationDateString ()
|
||||
public override DateTime GetValidUntil ()
|
||||
{
|
||||
ThrowIfContextInvalid ();
|
||||
return x509.ValidUntil.ToLocalTime ();
|
||||
return x509.ValidUntil;
|
||||
}
|
||||
|
||||
public override bool Equals (X509CertificateImpl other, out bool result)
|
||||
@ -164,8 +158,8 @@ namespace System.Security.Cryptography.X509Certificates
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false));
|
||||
sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false));
|
||||
sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetEffectiveDateString ());
|
||||
sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetExpirationDateString ());
|
||||
sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ());
|
||||
sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ());
|
||||
sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
|
||||
sb.Append (nl);
|
||||
return sb.ToString ();
|
||||
|
@ -30,6 +30,7 @@
|
||||
//
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
#if !NET_2_1
|
||||
using System.Security.Permissions;
|
||||
@ -40,6 +41,14 @@ namespace System.Security.Cryptography.X509Certificates
|
||||
{
|
||||
static partial class X509Helper
|
||||
{
|
||||
static INativeCertificateHelper nativeHelper;
|
||||
|
||||
internal static void InstallNativeHelper (INativeCertificateHelper helper)
|
||||
{
|
||||
if (nativeHelper == null)
|
||||
Interlocked.CompareExchange (ref nativeHelper, helper, null);
|
||||
}
|
||||
|
||||
#if !NET_2_1
|
||||
// typedef struct _CERT_CONTEXT {
|
||||
// DWORD dwCertEncodingType;
|
||||
@ -77,6 +86,14 @@ namespace System.Security.Cryptography.X509Certificates
|
||||
}
|
||||
#endif
|
||||
|
||||
public static X509CertificateImpl InitFromCertificate (X509Certificate cert)
|
||||
{
|
||||
if (nativeHelper != null)
|
||||
return nativeHelper.Import (cert);
|
||||
|
||||
return InitFromCertificate (cert.Impl);
|
||||
}
|
||||
|
||||
public static X509CertificateImpl InitFromCertificate (X509CertificateImpl impl)
|
||||
{
|
||||
ThrowIfContextInvalid (impl);
|
||||
@ -134,6 +151,9 @@ namespace System.Security.Cryptography.X509Certificates
|
||||
#if !MONOTOUCH && !XAMMAC
|
||||
public static X509CertificateImpl Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
|
||||
{
|
||||
if (nativeHelper != null)
|
||||
return nativeHelper.Import (rawData, password, keyStorageFlags);
|
||||
|
||||
MX.X509Certificate x509;
|
||||
if (password == null) {
|
||||
try {
|
||||
|
@ -96,11 +96,6 @@ namespace System
|
||||
|
||||
static Console ()
|
||||
{
|
||||
#if NET_2_1
|
||||
Encoding inputEncoding;
|
||||
Encoding outputEncoding;
|
||||
#endif
|
||||
|
||||
if (Environment.IsRunningOnWindows) {
|
||||
//
|
||||
// On Windows, follow the Windows tradition
|
||||
@ -540,7 +535,6 @@ namespace System
|
||||
|
||||
#endif
|
||||
|
||||
#if !NET_2_1
|
||||
// FIXME: Console should use these encodings when changed
|
||||
static Encoding inputEncoding;
|
||||
static Encoding outputEncoding;
|
||||
@ -561,6 +555,7 @@ namespace System
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET_2_1
|
||||
public static ConsoleColor BackgroundColor {
|
||||
get { return ConsoleDriver.BackgroundColor; }
|
||||
set { ConsoleDriver.BackgroundColor = value; }
|
||||
|
@ -218,7 +218,7 @@ namespace System {
|
||||
if (typeName == null)
|
||||
throw new ArgumentNullException ("typeName");
|
||||
|
||||
TypeSpec res = Parse (typeName, ref pos, false, false);
|
||||
TypeSpec res = Parse (typeName, ref pos, false, true);
|
||||
if (pos < typeName.Length)
|
||||
throw new ArgumentException ("Count not parse the whole type name", "typeName");
|
||||
return res;
|
||||
@ -287,7 +287,7 @@ namespace System {
|
||||
{
|
||||
Assembly asm = null;
|
||||
if (assemblyResolver == null && typeResolver == null)
|
||||
return Type.GetType (name.DisplayName, throwOnError, ignoreCase);
|
||||
return Type.GetType (DisplayFullName, throwOnError, ignoreCase);
|
||||
|
||||
if (assembly_name != null) {
|
||||
if (assemblyResolver != null)
|
||||
@ -376,6 +376,12 @@ namespace System {
|
||||
pos = p;
|
||||
}
|
||||
|
||||
static void BoundCheck (int idx, string s)
|
||||
{
|
||||
if (idx >= s.Length)
|
||||
throw new ArgumentException ("Invalid generic arguments spec", "typeName");
|
||||
}
|
||||
|
||||
static TypeIdentifier ParsedTypeIdentifier (string displayName)
|
||||
{
|
||||
return TypeIdentifiers.FromDisplay(displayName);
|
||||
@ -383,6 +389,17 @@ namespace System {
|
||||
|
||||
static TypeSpec Parse (string name, ref int p, bool is_recurse, bool allow_aqn)
|
||||
{
|
||||
// Invariants:
|
||||
// - On exit p, is updated to pos the current unconsumed character.
|
||||
//
|
||||
// - The callee peeks at but does not consume delimiters following
|
||||
// recurisve parse (so for a recursive call like the args of "Foo[P,Q]"
|
||||
// we'll return with p either on ',' or on ']'. If the name was aqn'd
|
||||
// "Foo[[P,assmblystuff],Q]" on return p with be on the ']' just
|
||||
// after the "assmblystuff")
|
||||
//
|
||||
// - If allow_aqn is True, assembly qualification is optional.
|
||||
// If allow_aqn is False, assembly qualification is prohibited.
|
||||
int pos = p;
|
||||
int name_start;
|
||||
bool in_modifiers = false;
|
||||
@ -450,18 +467,24 @@ namespace System {
|
||||
data.AddModifier (new PointerSpec(pointer_level));
|
||||
break;
|
||||
case ',':
|
||||
if (is_recurse) {
|
||||
if (is_recurse && allow_aqn) {
|
||||
int end = pos;
|
||||
while (end < name.Length && name [end] != ']')
|
||||
++end;
|
||||
if (end >= name.Length)
|
||||
throw new ArgumentException ("Unmatched ']' while parsing generic argument assembly name");
|
||||
data.assembly_name = name.Substring (pos + 1, end - pos - 1).Trim ();
|
||||
p = end + 1;
|
||||
p = end;
|
||||
return data;
|
||||
}
|
||||
data.assembly_name = name.Substring (pos + 1).Trim ();
|
||||
pos = name.Length;
|
||||
if (is_recurse) {
|
||||
p = pos;
|
||||
return data;
|
||||
}
|
||||
if (allow_aqn) {
|
||||
data.assembly_name = name.Substring (pos + 1).Trim ();
|
||||
pos = name.Length;
|
||||
}
|
||||
break;
|
||||
case '[':
|
||||
if (data.is_byref)
|
||||
@ -482,11 +505,17 @@ namespace System {
|
||||
if (aqn)
|
||||
++pos; //skip '[' to the start of the type
|
||||
args.Add (Parse (name, ref pos, true, aqn));
|
||||
if (pos >= name.Length)
|
||||
throw new ArgumentException ("Invalid generic arguments spec", "typeName");
|
||||
BoundCheck (pos, name);
|
||||
if (aqn) {
|
||||
if (name [pos] == ']')
|
||||
++pos;
|
||||
else
|
||||
throw new ArgumentException ("Unclosed assembly-qualified type name at " + name[pos], "typeName");
|
||||
BoundCheck (pos, name);
|
||||
}
|
||||
|
||||
if (name [pos] == ']')
|
||||
break;
|
||||
break;
|
||||
if (name [pos] == ',')
|
||||
++pos; // skip ',' to the start of the next arg
|
||||
else
|
||||
@ -523,7 +552,7 @@ namespace System {
|
||||
break;
|
||||
case ']':
|
||||
if (is_recurse) {
|
||||
p = pos + 1;
|
||||
p = pos;
|
||||
return data;
|
||||
}
|
||||
throw new ArgumentException ("Unmatched ']'", "typeName");
|
||||
|
@ -35,6 +35,7 @@ using System.Diagnostics;
|
||||
namespace MonoTests.System.Runtime.ExceptionServices
|
||||
{
|
||||
[TestFixture]
|
||||
[Category ("BitcodeNotWorking")]
|
||||
public class ExceptionDispatchInfoTest
|
||||
{
|
||||
[Test]
|
||||
|
@ -1 +1 @@
|
||||
19dbff4804c0ea37f0033f0911c3674f4bf65b90
|
||||
541acb6afb71ee34f37b1aa52431ed984f0cbca2
|
@ -403,7 +403,6 @@ System.Runtime.InteropServices/RegistrationConnectionType.cs
|
||||
System.Runtime.InteropServices/SEHException.cs
|
||||
System.Runtime.InteropServices/STATSTG.cs
|
||||
System.Runtime.InteropServices/RegistrationServices.cs
|
||||
System.Runtime.InteropServices/RuntimeEnvironment.cs
|
||||
System.Runtime.InteropServices/SafeArrayRankMismatchException.cs
|
||||
System.Runtime.InteropServices/SafeArrayTypeMismatchException.cs
|
||||
System.Runtime.InteropServices/SafeBuffer.cs
|
||||
@ -733,6 +732,7 @@ System.Security.Cryptography/RSAPKCS1SignatureDeformatter.cs
|
||||
System.Security.Cryptography/RSAPKCS1SignatureFormatter.cs
|
||||
System.Security.Cryptography/SHA1CryptoServiceProvider.cs
|
||||
System.Security.Cryptography/TripleDESCryptoServiceProvider.cs
|
||||
System.Security.Cryptography.X509Certificates/INativeCertificateHelper.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate.cs
|
||||
System.Security.Cryptography.X509Certificates/X509Certificate20.cs
|
||||
System.Security.Cryptography.X509Certificates/X509CertificateImpl.cs
|
||||
@ -1280,6 +1280,7 @@ ReferenceSources/SecurityContext.cs
|
||||
../../../external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs
|
||||
|
||||
../../../external/referencesource/mscorlib/system/runtime/interopservices/attributes.cs
|
||||
../../../external/referencesource/mscorlib/system/runtime/interopservices/runtimeenvironment.cs
|
||||
../../../external/referencesource/mscorlib/system/runtime/interopservices/safehandle.cs
|
||||
../../../external/referencesource/mscorlib/system/runtime/interopservices/ucomienumconnections.cs
|
||||
|
||||
|
@ -1 +1 @@
|
||||
362e108c1374bb987f401f2b4d420b050a031231
|
||||
cda5f1e52d7ff05ac3c67c95adb635880bcd8928
|
@ -1 +1 @@
|
||||
42eaf0337c8b492035f2d3bcd22cdbd06a9d1428
|
||||
28d0cee3d630bf94dfea9611a14d38b8287e32ac
|
@ -1 +1 @@
|
||||
2968266af5fb7b1521b79ce929b2fb27097233aa
|
||||
1123b73866732a094cf1c7bdcf6e3a92e8f34df7
|
@ -1 +1 @@
|
||||
24979c09819a656e19fc58fcf19e9b5a16584075
|
||||
8e64e5a6758d73dbf3d8c6fb3eb48c076357b70d
|
@ -1 +1 @@
|
||||
bd4b36083e46dd607da7e0ec9922f22c312cf270
|
||||
5de7e54e585f6b49306081a2d825a268eae55a8b
|
@ -1 +1 @@
|
||||
2caa7c6153cffdaf2f9392820e8c2468e5b287af
|
||||
7b90f739b90808c54955991f2ee7ade80d218166
|
@ -2245,7 +2245,7 @@ namespace Mono.CSharp {
|
||||
return IsLeftResolvedExpressionValid (dmb.Arguments [0].Expr);
|
||||
}
|
||||
|
||||
if (expr is ConstantExpr || expr is TypeExpr || expr is NamespaceExpression || expr is This)
|
||||
if (expr is ConstantExpr || expr is TypeExpr || expr is NamespaceExpression || expr is VariableReference)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -901,7 +901,7 @@ namespace Mono.CSharp
|
||||
|
||||
public override void Emit ()
|
||||
{
|
||||
if ((AccessorFirst.ModFlags & (Modifiers.STATIC | Modifiers.COMPILER_GENERATED)) == Modifiers.COMPILER_GENERATED && Parent.PartialContainer.HasExplicitLayout) {
|
||||
if ((AccessorFirst.ModFlags & (Modifiers.STATIC | Modifiers.AutoProperty)) == Modifiers.AutoProperty && Parent.PartialContainer.HasExplicitLayout) {
|
||||
Report.Error (842, Location,
|
||||
"Automatically implemented property `{0}' cannot be used inside a type with an explicit StructLayout attribute",
|
||||
GetSignatureForError ());
|
||||
|
@ -1211,13 +1211,29 @@ namespace Mono.CSharp {
|
||||
return ParseResult.Success;
|
||||
|
||||
// csc options that we don't support
|
||||
case "/utf8output":
|
||||
case "/subsystemversion":
|
||||
case "/analyzer":
|
||||
case "/appconfig":
|
||||
case "/baseaddress":
|
||||
case "/deterministic":
|
||||
case "/errorendlocation":
|
||||
case "/errorlog":
|
||||
case "/features":
|
||||
case "/highentropyva":
|
||||
case "/highentropyva+":
|
||||
case "/highentropyva-":
|
||||
case "/win32manifest":
|
||||
case "/link":
|
||||
case "/moduleassemblyname":
|
||||
case "/nowin32manifest":
|
||||
case "/pathmap":
|
||||
case "/pdb":
|
||||
case "/preferreduilang":
|
||||
case "/publicsign":
|
||||
case "/reportanalyzer":
|
||||
case "/ruleset":
|
||||
case "/sqmsessionguid":
|
||||
case "/subsystemversion":
|
||||
case "/utf8output":
|
||||
case "/win32manifest":
|
||||
return ParseResult.Success;
|
||||
|
||||
default:
|
||||
|
17
mcs/tests/test-expression-bodied-02.cs
Normal file
17
mcs/tests/test-expression-bodied-02.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 8)]
|
||||
public struct Cs0842ExpressionBodyGetterBug
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int DummyVariable;
|
||||
|
||||
public int MyGetter => 5;
|
||||
}
|
||||
|
||||
class C
|
||||
{
|
||||
public static void Main ()
|
||||
{
|
||||
}
|
||||
}
|
@ -29,6 +29,11 @@ public class MainClass
|
||||
public static event Action Act = null;
|
||||
public static dynamic BBB = null;
|
||||
|
||||
void ParameterTest (Person ParPerson)
|
||||
{
|
||||
Console.WriteLine (nameof (ParPerson.MyCar.Year));
|
||||
}
|
||||
|
||||
public static int Main ()
|
||||
{
|
||||
string name;
|
||||
@ -61,6 +66,11 @@ public class MainClass
|
||||
if (name != "ToString")
|
||||
return 7;
|
||||
|
||||
Person LocPerson = null;
|
||||
name = nameof (LocPerson.MyCar.Year);
|
||||
if (name != "Year")
|
||||
return 8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
55a55a8ce00b5f19846f2a4e0df099c17d0799cd
|
||||
de9fea39fc570d60a08eeeba6e5eef06352b9197
|
@ -12,6 +12,7 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Security.Cryptography;
|
||||
@ -19,6 +20,7 @@ using System.Text;
|
||||
using System.Configuration.Assemblies;
|
||||
|
||||
using Mono.Security.Cryptography;
|
||||
using IKR = IKVM.Reflection;
|
||||
|
||||
namespace Mono.AssemblyLinker
|
||||
{
|
||||
@ -591,46 +593,8 @@ namespace Mono.AssemblyLinker
|
||||
* Emit Manifest
|
||||
* */
|
||||
|
||||
if (isTemplateFile) {
|
||||
// LAMESPEC: according to MSDN, the template assembly must have a
|
||||
// strong name but this is not enforced
|
||||
Assembly assembly = Assembly.LoadFrom (templateFile);
|
||||
|
||||
// inherit signing related settings from template, but do not
|
||||
// override command-line options
|
||||
object [] attrs = assembly.GetCustomAttributes (true);
|
||||
foreach (object o in attrs) {
|
||||
if (o is AssemblyKeyFileAttribute) {
|
||||
if (keyfile != null)
|
||||
// ignore if specified on command line
|
||||
continue;
|
||||
AssemblyKeyFileAttribute keyFileAttr = (AssemblyKeyFileAttribute) o;
|
||||
// ignore null or zero-length keyfile
|
||||
if (keyFileAttr.KeyFile == null || keyFileAttr.KeyFile.Length == 0)
|
||||
continue;
|
||||
keyfile = Path.Combine (Path.GetDirectoryName(templateFile),
|
||||
keyFileAttr.KeyFile);
|
||||
} else if (o is AssemblyDelaySignAttribute) {
|
||||
if (delaysign != DelaySign.NotSet)
|
||||
// ignore if specified on command line
|
||||
continue;
|
||||
AssemblyDelaySignAttribute delaySignAttr = (AssemblyDelaySignAttribute) o;
|
||||
delaysign = delaySignAttr.DelaySign ? DelaySign.Yes :
|
||||
DelaySign.No;
|
||||
} else if (o is AssemblyKeyNameAttribute) {
|
||||
if (keyname != null)
|
||||
// ignore if specified on command line
|
||||
continue;
|
||||
AssemblyKeyNameAttribute keynameAttr = (AssemblyKeyNameAttribute) o;
|
||||
// ignore null or zero-length keyname
|
||||
if (keynameAttr.KeyName == null || keynameAttr.KeyName.Length == 0)
|
||||
continue;
|
||||
keyname = keynameAttr.KeyName;
|
||||
}
|
||||
}
|
||||
aname.Version = assembly.GetName().Version;
|
||||
aname.HashAlgorithm = assembly.GetName().HashAlgorithm;
|
||||
}
|
||||
if (isTemplateFile)
|
||||
aname = ReadCustomAttributesFromTemplateFile (templateFile, aname);
|
||||
|
||||
SetKeyPair (aname);
|
||||
|
||||
@ -765,6 +729,85 @@ namespace Mono.AssemblyLinker
|
||||
}
|
||||
}
|
||||
|
||||
private AssemblyName ReadCustomAttributesFromTemplateFile (string templateFile, AssemblyName aname)
|
||||
{
|
||||
// LAMESPEC: according to MSDN, the template assembly must have a
|
||||
// strong name but this is not enforced
|
||||
const IKR.UniverseOptions options = IKR.UniverseOptions.MetadataOnly;
|
||||
|
||||
var universe = new IKR.Universe (options);
|
||||
var asm = universe.LoadFile (templateFile);
|
||||
|
||||
// Create missing assemblies, we don't want to load them!
|
||||
// Code taken from ikdasm
|
||||
var names = new HashSet<string> ();
|
||||
IKR.AssemblyName[] assembly_refs = asm.ManifestModule.__GetReferencedAssemblies ();
|
||||
|
||||
var resolved_assemblies = new IKR.Assembly [assembly_refs.Length];
|
||||
for (int i = 0; i < resolved_assemblies.Length; i++) {
|
||||
string name = assembly_refs [i].Name;
|
||||
|
||||
while (names.Contains (name)) {
|
||||
name = name + "_" + i;
|
||||
}
|
||||
names.Add (name);
|
||||
resolved_assemblies [i] = universe.CreateMissingAssembly (assembly_refs [i].FullName);
|
||||
}
|
||||
asm.ManifestModule.__ResolveReferencedAssemblies (resolved_assemblies);
|
||||
|
||||
foreach (var attr_data in asm.__GetCustomAttributes (null, false)) {
|
||||
string asm_name = attr_data.AttributeType.Assembly.GetName ().Name;
|
||||
if (asm_name != "mscorlib")
|
||||
continue;
|
||||
|
||||
switch (attr_data.AttributeType.FullName) {
|
||||
case "System.Reflection.AssemblyKeyFileAttribute": {
|
||||
if (keyfile != null)
|
||||
// ignore if specified on command line
|
||||
continue;
|
||||
|
||||
// / AssemblyKeyFileAttribute .ctor(string keyFile)
|
||||
string key_file_value = (string) attr_data.ConstructorArguments [0].Value;
|
||||
|
||||
if (!String.IsNullOrEmpty (key_file_value))
|
||||
keyfile = Path.Combine (Path.GetDirectoryName (templateFile), key_file_value);
|
||||
}
|
||||
break;
|
||||
|
||||
case "System.Reflection.AssemblyDelaySignAttribute": {
|
||||
if (delaysign != DelaySign.NotSet)
|
||||
// ignore if specified on command line
|
||||
continue;
|
||||
|
||||
// AssemblyDelaySignAttribute .ctor(bool delaySign)
|
||||
bool delay_sign_value = (bool) attr_data.ConstructorArguments [0].Value;
|
||||
delaysign = delay_sign_value ? DelaySign.Yes : DelaySign.No;
|
||||
}
|
||||
break;
|
||||
|
||||
case "System.Reflection.AssemblyKeyNameAttribute": {
|
||||
if (keyname != null)
|
||||
// ignore if specified on command line
|
||||
continue;
|
||||
|
||||
// AssemblyKeyNameAttribute .ctor(string keyName)
|
||||
string key_name_value = (string) attr_data.ConstructorArguments [0].Value;
|
||||
|
||||
// ignore null or zero-length keyname
|
||||
if (!String.IsNullOrEmpty (key_name_value))
|
||||
keyname = key_name_value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var asm_name_for_template_file = asm.GetName ();
|
||||
aname.Version = asm_name_for_template_file.Version;
|
||||
aname.HashAlgorithm = asm_name_for_template_file.HashAlgorithm;
|
||||
|
||||
return aname;
|
||||
}
|
||||
|
||||
private void LoadArgs (string file, ArrayList args) {
|
||||
StreamReader f = null;
|
||||
string line;
|
||||
|
@ -2,7 +2,7 @@ thisdir = tools/al
|
||||
SUBDIRS =
|
||||
include ../../build/rules.make
|
||||
|
||||
LOCAL_MCS_FLAGS = -r:Mono.Security.dll
|
||||
LOCAL_MCS_FLAGS = -r:Mono.Security.dll -r:System.Security.dll -r:Mono.CompilerServices.SymbolWriter
|
||||
PROGRAM = al.exe
|
||||
|
||||
CLEAN_FILES = al.exe al.exe.mdb
|
||||
|
@ -1,2 +1,9 @@
|
||||
Al.cs
|
||||
../../build/common/Consts.cs
|
||||
../../../external/ikvm/reflect/*.cs
|
||||
../../../external/ikvm/reflect/Emit/*.cs
|
||||
../../../external/ikvm/reflect/Metadata/*.cs
|
||||
../../../external/ikvm/reflect/Reader/*.cs
|
||||
../../../external/ikvm/reflect/Writer/*.cs
|
||||
../../../external/ikvm/reflect/Impl/*.cs
|
||||
../../../external/ikvm/reflect/Properties/*.cs
|
||||
|
@ -596,6 +596,7 @@ namespace Mono.Terminal {
|
||||
|
||||
if (completions.Length == 1){
|
||||
InsertTextAtCursor (completions [0]);
|
||||
HideCompletions ();
|
||||
} else {
|
||||
int last = -1;
|
||||
|
||||
|
@ -404,7 +404,7 @@ namespace Mono {
|
||||
static void EscapeString (TextWriter output, string s)
|
||||
{
|
||||
foreach (var c in s){
|
||||
if (c > 32){
|
||||
if (c >= 32){
|
||||
output.Write (c);
|
||||
continue;
|
||||
}
|
||||
@ -416,7 +416,7 @@ namespace Mono {
|
||||
case '\b':
|
||||
output.Write ("\\b"); break;
|
||||
case '\n':
|
||||
output.Write ("\\n");
|
||||
output.Write ("\n");
|
||||
break;
|
||||
|
||||
case '\v':
|
||||
@ -448,7 +448,7 @@ namespace Mono {
|
||||
output.Write ("'\\''");
|
||||
return;
|
||||
}
|
||||
if (c > 32){
|
||||
if (c >= 32){
|
||||
output.Write ("'{0}'", c);
|
||||
return;
|
||||
}
|
||||
@ -482,7 +482,7 @@ namespace Mono {
|
||||
break;
|
||||
|
||||
default:
|
||||
output.Write ("'\\x{0:x}", (int) c);
|
||||
output.Write ("'\\x{0:x}'", (int) c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -510,8 +510,8 @@ namespace Mono.XBuild.CommandLine {
|
||||
if (solutionTarget.Configuration == targetInfo.Key.Configuration &&
|
||||
solutionTarget.Platform == targetInfo.Key.Platform) {
|
||||
solutionConfigurationContents.AppendFormat (
|
||||
"<ProjectConfiguration Project=\"{0}\">{1}|{2}</ProjectConfiguration>",
|
||||
guid.ToString ("B").ToUpper (), targetInfo.Value.Configuration, targetInfo.Value.Platform);
|
||||
"<ProjectConfiguration Project=\"{0}\" AbsolutePath=\"{1}\">{2}|{3}</ProjectConfiguration>",
|
||||
guid.ToString ("B").ToUpper (), projectInfo.FileName, targetInfo.Value.Configuration, targetInfo.Value.Platform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,10 +49,12 @@
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
/* AssemblyVersionMap: an assembly name and the assembly version set on which it is based */
|
||||
/* AssemblyVersionMap: an assembly name, the assembly version set on which it is based, the assembly name it is replaced with and whether only versions lower than the current runtime version should be remapped */
|
||||
typedef struct {
|
||||
const char* assembly_name;
|
||||
guint8 version_set_index;
|
||||
const char* new_assembly_name;
|
||||
gboolean only_lower_versions;
|
||||
} AssemblyVersionMap;
|
||||
|
||||
/* the default search path is empty, the first slot is replaced with the computed value */
|
||||
@ -88,8 +90,12 @@ static const AssemblyVersionMap framework_assemblies [] = {
|
||||
{"I18N.Other", 0},
|
||||
{"I18N.Rare", 0},
|
||||
{"I18N.West", 0},
|
||||
{"Microsoft.Build.Engine", 2},
|
||||
{"Microsoft.Build.Framework", 2},
|
||||
{"Microsoft.Build.Engine", 2, NULL, TRUE},
|
||||
{"Microsoft.Build.Framework", 2, NULL, TRUE},
|
||||
{"Microsoft.Build.Tasks", 2, "Microsoft.Build.Tasks.v4.0"},
|
||||
{"Microsoft.Build.Tasks.v3.5", 2, "Microsoft.Build.Tasks.v4.0"},
|
||||
{"Microsoft.Build.Utilities", 2, "Microsoft.Build.Utilities.v4.0"},
|
||||
{"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"},
|
||||
{"Microsoft.VisualBasic", 1},
|
||||
{"Microsoft.VisualC", 1},
|
||||
{"Mono.Cairo", 0},
|
||||
@ -1013,6 +1019,9 @@ mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_ana
|
||||
aname->build == vset->build && aname->revision == vset->revision)
|
||||
return aname;
|
||||
|
||||
if (framework_assemblies[pos].only_lower_versions && compare_versions ((AssemblyVersionSet*)vset, aname) < 0)
|
||||
return aname;
|
||||
|
||||
if ((aname->major | aname->minor | aname->build | aname->revision) != 0)
|
||||
mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
|
||||
"The request to load the assembly %s v%d.%d.%d.%d was remapped to v%d.%d.%d.%d",
|
||||
@ -1026,6 +1035,13 @@ mono_assembly_remap_version (MonoAssemblyName *aname, MonoAssemblyName *dest_ana
|
||||
dest_aname->minor = vset->minor;
|
||||
dest_aname->build = vset->build;
|
||||
dest_aname->revision = vset->revision;
|
||||
if (framework_assemblies[pos].new_assembly_name != NULL) {
|
||||
dest_aname->name = framework_assemblies[pos].new_assembly_name;
|
||||
mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_ASSEMBLY,
|
||||
"The assembly name %s was remapped to %s",
|
||||
aname->name,
|
||||
dest_aname->name);
|
||||
}
|
||||
return dest_aname;
|
||||
} else if (res < 0) {
|
||||
last = pos - 1;
|
||||
@ -2546,8 +2562,9 @@ mono_assembly_load_publisher_policy (MonoAssemblyName *aname)
|
||||
|
||||
if (strstr (aname->name, ".dll")) {
|
||||
len = strlen (aname->name) - 4;
|
||||
name = (gchar *)g_malloc (len);
|
||||
name = (gchar *)g_malloc (len + 1);
|
||||
strncpy (name, aname->name, len);
|
||||
name[len] = 0;
|
||||
} else
|
||||
name = g_strdup (aname->name);
|
||||
|
||||
@ -2857,8 +2874,9 @@ mono_assembly_load_from_gac (MonoAssemblyName *aname, gchar *filename, MonoImag
|
||||
|
||||
if (strstr (aname->name, ".dll")) {
|
||||
len = strlen (filename) - 4;
|
||||
name = (gchar *)g_malloc (len);
|
||||
name = (gchar *)g_malloc (len + 1);
|
||||
strncpy (name, aname->name, len);
|
||||
name[len] = 0;
|
||||
} else {
|
||||
name = g_strdup (aname->name);
|
||||
}
|
||||
|
@ -517,7 +517,6 @@ struct _MonoMethodInflated {
|
||||
MonoMethod method;
|
||||
MonoMethodPInvoke pinvoke;
|
||||
} method;
|
||||
MonoMethodHeader *header;
|
||||
MonoMethod *declaring; /* the generic method definition. */
|
||||
MonoGenericContext context; /* The current instantiation */
|
||||
MonoImageSet *owner; /* The image set that the inflated method belongs to. */
|
||||
|
@ -935,8 +935,8 @@ mono_cleanup (void)
|
||||
mono_loader_cleanup ();
|
||||
mono_classes_cleanup ();
|
||||
mono_assemblies_cleanup ();
|
||||
mono_images_cleanup ();
|
||||
mono_debug_cleanup ();
|
||||
mono_images_cleanup ();
|
||||
mono_metadata_cleanup ();
|
||||
|
||||
mono_native_tls_free (appdomain_thread_id);
|
||||
|
@ -1 +1 @@
|
||||
e48934f8d82dd4794e2fc56288e9dd994bc370a8
|
||||
6f8827dfb84f99f9c320aaf3b0ab5c9ac82e720e
|
@ -509,9 +509,19 @@ load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
|
||||
|
||||
i = ((MonoImageLoader*)image->loader)->load_tables (image);
|
||||
g_assert (image->heap_guid.data);
|
||||
g_assert (image->heap_guid.size >= 16);
|
||||
|
||||
image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
|
||||
if (!image->metadata_only) {
|
||||
g_assert (image->heap_guid.size >= 16);
|
||||
|
||||
image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
|
||||
} else {
|
||||
/* PPDB files have no guid */
|
||||
guint8 empty_guid [16];
|
||||
|
||||
memset (empty_guid, 0, sizeof (empty_guid));
|
||||
|
||||
image->guid = mono_guid_to_string (empty_guid);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
@ -873,21 +873,25 @@ mono_inflate_generic_signature (MonoMethodSignature *sig, MonoGenericContext *co
|
||||
static MonoMethodHeader*
|
||||
inflate_generic_header (MonoMethodHeader *header, MonoGenericContext *context)
|
||||
{
|
||||
MonoMethodHeader *res;
|
||||
int i;
|
||||
res = (MonoMethodHeader *)g_malloc0 (MONO_SIZEOF_METHOD_HEADER + sizeof (gpointer) * header->num_locals);
|
||||
size_t locals_size = sizeof (gpointer) * header->num_locals;
|
||||
size_t clauses_size = header->num_clauses * sizeof (MonoExceptionClause);
|
||||
size_t header_size = MONO_SIZEOF_METHOD_HEADER + locals_size + clauses_size;
|
||||
MonoMethodHeader *res = (MonoMethodHeader *)g_malloc0 (header_size);
|
||||
res->num_locals = header->num_locals;
|
||||
res->clauses = (MonoExceptionClause *) &res->locals [res->num_locals] ;
|
||||
memcpy (res->clauses, header->clauses, clauses_size);
|
||||
|
||||
res->code = header->code;
|
||||
res->code_size = header->code_size;
|
||||
res->max_stack = header->max_stack;
|
||||
res->num_clauses = header->num_clauses;
|
||||
res->init_locals = header->init_locals;
|
||||
res->num_locals = header->num_locals;
|
||||
res->clauses = header->clauses;
|
||||
for (i = 0; i < header->num_locals; ++i)
|
||||
|
||||
res->is_transient = TRUE;
|
||||
for (int i = 0; i < header->num_locals; ++i)
|
||||
res->locals [i] = mono_class_inflate_generic_type (header->locals [i], context);
|
||||
if (res->num_clauses) {
|
||||
res->clauses = (MonoExceptionClause *)g_memdup (header->clauses, sizeof (MonoExceptionClause) * res->num_clauses);
|
||||
for (i = 0; i < header->num_clauses; ++i) {
|
||||
for (int i = 0; i < header->num_clauses; ++i) {
|
||||
MonoExceptionClause *clause = &res->clauses [i];
|
||||
if (clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
|
||||
continue;
|
||||
@ -2821,20 +2825,7 @@ mono_method_get_header (MonoMethod *method)
|
||||
iheader = inflate_generic_header (header, mono_method_get_context (method));
|
||||
mono_metadata_free_mh (header);
|
||||
|
||||
mono_image_lock (img);
|
||||
|
||||
if (imethod->header) {
|
||||
mono_metadata_free_mh (iheader);
|
||||
mono_image_unlock (img);
|
||||
return imethod->header;
|
||||
}
|
||||
|
||||
mono_memory_barrier ();
|
||||
imethod->header = iheader;
|
||||
|
||||
mono_image_unlock (img);
|
||||
|
||||
return imethod->header;
|
||||
return iheader;
|
||||
}
|
||||
|
||||
if (method->wrapper_type != MONO_WRAPPER_NONE || method->sre_method) {
|
||||
|
@ -1 +1 @@
|
||||
e50ad0288c968135460f054b7e73e34f5406f363
|
||||
a4ff3a17390cd25aa67e4084019cd0777669b06d
|
@ -239,6 +239,8 @@ bb_split (MonoSimpleBasicBlock *first, MonoSimpleBasicBlock *hint, MonoSimpleBas
|
||||
{
|
||||
MonoSimpleBasicBlock *res, *bb = first;
|
||||
|
||||
mono_error_init (error);
|
||||
|
||||
if (bb_idx_is_contained (hint, target)) {
|
||||
first = hint;
|
||||
} else if (hint->next && bb_idx_is_contained (hint->next, target)) {
|
||||
@ -335,6 +337,8 @@ bb_formation_il_pass (const unsigned char *start, const unsigned char *end, Mono
|
||||
MonoSimpleBasicBlock *branch, *next, *current;
|
||||
const MonoOpcode *opcode;
|
||||
|
||||
mono_error_init (error);
|
||||
|
||||
current = bb;
|
||||
|
||||
while (ip < end) {
|
||||
@ -463,6 +467,9 @@ bb_formation_eh_pass (MonoMethodHeader *header, MonoSimpleBasicBlock *bb, MonoSi
|
||||
{
|
||||
int i;
|
||||
int end = header->code_size;
|
||||
|
||||
mono_error_init (error);
|
||||
|
||||
/*We must split at all points to verify for targets in the middle of an instruction*/
|
||||
for (i = 0; i < header->num_clauses; ++i) {
|
||||
MonoExceptionClause *clause = header->clauses + i;
|
||||
@ -514,19 +521,13 @@ mono_basic_block_free (MonoSimpleBasicBlock *bb)
|
||||
* Return the list of basic blocks of method. Return NULL on failure and set @error.
|
||||
*/
|
||||
MonoSimpleBasicBlock*
|
||||
mono_basic_block_split (MonoMethod *method, MonoError *error)
|
||||
mono_basic_block_split (MonoMethod *method, MonoError *error, MonoMethodHeader *header)
|
||||
{
|
||||
MonoSimpleBasicBlock *bb, *root;
|
||||
const unsigned char *start, *end;
|
||||
MonoMethodHeader *header = mono_method_get_header (method);
|
||||
|
||||
mono_error_init (error);
|
||||
|
||||
if (!header) {
|
||||
mono_error_set_not_verifiable (error, method, "Could not decode header");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
start = header->code;
|
||||
end = start + header->code_size;
|
||||
|
||||
@ -551,11 +552,9 @@ mono_basic_block_split (MonoMethod *method, MonoError *error)
|
||||
dump_bb_list (bb, &root, g_strdup_printf("AFTER LIVENESS %s", mono_method_full_name (method, TRUE)));
|
||||
#endif
|
||||
|
||||
mono_metadata_free_mh (header);
|
||||
return bb;
|
||||
|
||||
fail:
|
||||
mono_metadata_free_mh (header);
|
||||
mono_basic_block_free (bb);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ struct _MonoSimpleBasicBlock {
|
||||
};
|
||||
|
||||
MonoSimpleBasicBlock*
|
||||
mono_basic_block_split (MonoMethod *method, MonoError *error);
|
||||
mono_basic_block_split (MonoMethod *method, MonoError *error, MonoMethodHeader *header);
|
||||
|
||||
void
|
||||
mono_basic_block_free (MonoSimpleBasicBlock *bb);
|
||||
|
@ -285,8 +285,8 @@ dllmap_start (gpointer user_data,
|
||||
char *result;
|
||||
|
||||
result = (char *)g_malloc (libdir_len-strlen("$mono_libdir")+strlen(attribute_values[i])+1);
|
||||
strncpy (result, attribute_names[i], p-attribute_values[i]);
|
||||
strcat (result, libdir);
|
||||
strncpy (result, attribute_values[i], p-attribute_values[i]);
|
||||
strcpy (result+(p-attribute_values[i]), libdir);
|
||||
strcat (result, p+strlen("$mono_libdir"));
|
||||
info->target = result;
|
||||
} else
|
||||
|
@ -867,7 +867,7 @@ gint64 ves_icall_System_Diagnostics_Process_StartTime_internal (HANDLE process)
|
||||
|
||||
gint32 ves_icall_System_Diagnostics_Process_ExitCode_internal (HANDLE process)
|
||||
{
|
||||
DWORD code;
|
||||
DWORD code = 0;
|
||||
|
||||
GetExitCodeProcess (process, &code);
|
||||
|
||||
|
@ -8,6 +8,9 @@
|
||||
#include <mono/utils/mono-compiler.h>
|
||||
#include <mono/utils/mono-error.h>
|
||||
|
||||
MonoType*
|
||||
mono_reflection_get_type_checked (MonoImage *rootimage, MonoImage* image, MonoTypeNameParse *info, mono_bool ignorecase, mono_bool *type_resolve);
|
||||
|
||||
MonoObject*
|
||||
mono_custom_attrs_get_attr_checked (MonoCustomAttrInfo *ainfo, MonoClass *attr_klass, MonoError *error);
|
||||
|
||||
|
@ -1 +1 @@
|
||||
9765c61de2ebb89a23549f49a6cafb7c0c0ca36d
|
||||
258308a0a883826613bae9322e5a1463ac1a5a2c
|
@ -522,7 +522,7 @@ worker_park (void)
|
||||
if (interrupted)
|
||||
goto done;
|
||||
|
||||
if (mono_coop_cond_timedwait (&threadpool->parked_threads_cond, &threadpool->active_threads_lock, rand_next ((void **)rand_handle, 5 * 1000, 60 * 1000)) != 0)
|
||||
if (mono_coop_cond_timedwait (&threadpool->parked_threads_cond, &threadpool->active_threads_lock, rand_next (&rand_handle, 5 * 1000, 60 * 1000)) != 0)
|
||||
timeout = TRUE;
|
||||
|
||||
mono_thread_info_uninstall_interrupt (&interrupted);
|
||||
|
@ -1 +1 @@
|
||||
e9af9516a1b4652f3e43ca9b3dd254addad43a0f
|
||||
711107ac5200b078d25785ce5854a2ab4ef20e5e
|
@ -801,7 +801,7 @@ EXTRA_DIST = TestDriver.cs \
|
||||
Makefile.am.in
|
||||
|
||||
version.h: Makefile
|
||||
echo "#define FULL_VERSION \"Stable 4.4.0.40/f8474c4\"" > version.h
|
||||
echo "#define FULL_VERSION \"Stable 4.4.0.122/a3fabf1\"" > version.h
|
||||
|
||||
# Utility target for patching libtool to speed up linking
|
||||
patch-libtool:
|
||||
|
@ -801,7 +801,7 @@ EXTRA_DIST = TestDriver.cs \
|
||||
Makefile.am.in
|
||||
|
||||
version.h: Makefile
|
||||
echo "#define FULL_VERSION \"Stable 4.4.0.40/f8474c4\"" > version.h
|
||||
echo "#define FULL_VERSION \"Stable 4.4.0.122/a3fabf1\"" > version.h
|
||||
|
||||
# Utility target for patching libtool to speed up linking
|
||||
patch-libtool:
|
||||
|
@ -1 +1 @@
|
||||
feaddf3ea0bb6cd34b061a30d89031f0d11d66ec
|
||||
c30141f67c9a2e03366c40284ff6f85c7ec12f08
|
@ -1 +1 @@
|
||||
26979427a0ebbb4e979939dad6a0e766cc2b6917
|
||||
c40ca98ce5a35a78b5c13a82796c7d90c988d66e
|
@ -1 +1 @@
|
||||
26d4d91456e706536c43cb083afe6adde5d651e0
|
||||
1c829de55ab1a77e98f4eee2f2db9532481d0839
|
@ -1 +1 @@
|
||||
a8e6b3920eb370ed43e229f6f4ce9d1317dffe39
|
||||
02c5187dfa1b7625b82adf66c91c0f619f144302
|
@ -1176,6 +1176,8 @@ mini_usage_jitdeveloper (void)
|
||||
" --agent=ASSEMBLY[:ARG] Loads the specific agent assembly and executes its Main method with the given argument before loading the main assembly.\n"
|
||||
" --no-x86-stack-align Don't align stack on x86\n"
|
||||
"\n"
|
||||
"The options supported by MONO_DEBUG can also be passed on the command line.\n"
|
||||
"\n"
|
||||
"Other options:\n"
|
||||
" --graph[=TYPE] METHOD Draws a graph of the specified method:\n");
|
||||
|
||||
@ -1425,6 +1427,7 @@ mono_jit_parse_options (int argc, char * argv[])
|
||||
#else
|
||||
mono_use_llvm = TRUE;
|
||||
#endif
|
||||
} else if (argv [i][0] == '-' && argv [i][1] == '-' && mini_parse_debug_option (argv [i] + 2)) {
|
||||
} else {
|
||||
fprintf (stderr, "Unsupported command line option: '%s'\n", argv [i]);
|
||||
exit (1);
|
||||
@ -1897,6 +1900,7 @@ mono_main (int argc, char* argv[])
|
||||
} else if (strcmp (argv [i], "--nacl-null-checks-off") == 0){
|
||||
nacl_null_checks_off = TRUE;
|
||||
#endif
|
||||
} else if (argv [i][0] == '-' && argv [i][1] == '-' && mini_parse_debug_option (argv [i] + 2)) {
|
||||
} else {
|
||||
fprintf (stderr, "Unknown command line option: '%s'\n", argv [i]);
|
||||
return 1;
|
||||
|
@ -165,12 +165,13 @@ mono_arm_throw_exception (MonoObject *exc, mgreg_t pc, mgreg_t sp, mgreg_t *int_
|
||||
}
|
||||
|
||||
void
|
||||
mono_arm_throw_exception_by_token (guint32 type_token, mgreg_t pc, mgreg_t sp, mgreg_t *int_regs, gdouble *fp_regs)
|
||||
mono_arm_throw_exception_by_token (guint32 ex_token_index, mgreg_t pc, mgreg_t sp, mgreg_t *int_regs, gdouble *fp_regs)
|
||||
{
|
||||
guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
|
||||
/* Clear thumb bit */
|
||||
pc &= ~1;
|
||||
|
||||
mono_arm_throw_exception ((MonoObject*)mono_exception_from_token (mono_defaults.corlib, type_token), pc, sp, int_regs, fp_regs);
|
||||
mono_arm_throw_exception ((MonoObject*)mono_exception_from_token (mono_defaults.corlib, ex_token), pc, sp, int_regs, fp_regs);
|
||||
}
|
||||
|
||||
void
|
||||
@ -245,9 +246,15 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm
|
||||
/* exc is already in place in r0 */
|
||||
if (corlib) {
|
||||
/* The caller ip is already in R1 */
|
||||
if (llvm)
|
||||
/* Negate the ip adjustment done in mono_arm_throw_exception */
|
||||
ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4);
|
||||
if (llvm) {
|
||||
/*
|
||||
* The address passed by llvm might point to before the call,
|
||||
* thus outside the eh range recorded by llvm. Use the return
|
||||
* address instead.
|
||||
* FIXME: Do this on more platforms.
|
||||
*/
|
||||
ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */
|
||||
}
|
||||
} else {
|
||||
ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */
|
||||
}
|
||||
|
@ -1695,6 +1695,23 @@ public class Tests
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface ISmallArg {
|
||||
T foo<T> (string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8,
|
||||
string s9, string s10, string s11, string s12, string s13, T t);
|
||||
}
|
||||
|
||||
class SmallArgClass : ISmallArg {
|
||||
public T foo<T> (string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8,
|
||||
string s9, string s10, string s11, string s12, string s13, T t) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
public static int test_1_small_gsharedvt_stack_arg_ios () {
|
||||
ISmallArg o = new SmallArgClass ();
|
||||
return o.foo<int> ("", "", "", "", "", "", "", "", "", "", "", "", "", 1);
|
||||
}
|
||||
|
||||
// Passing vtype normal arguments on the stack
|
||||
public static int test_0_arm64_vtype_stack_args () {
|
||||
IFoo3<EmptyStruct> o = (IFoo3<EmptyStruct>)Activator.CreateInstance (typeof (Foo3<>).MakeGenericType (new Type [] { typeof (EmptyStruct) }));
|
||||
|
@ -1686,6 +1686,9 @@ bin_writer_emit_writeout (MonoImageWriter *acfg)
|
||||
static void
|
||||
asm_writer_emit_start (MonoImageWriter *acfg)
|
||||
{
|
||||
#if defined(TARGET_ASM_APPLE)
|
||||
fprintf (acfg->fp, ".subsections_via_symbols\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1 +1 @@
|
||||
1dcf73164eccdc0c7389a06bee320745cebfb29d
|
||||
56f60c91e1860a8b1b0a68b5453db395488f781c
|
@ -1 +1 @@
|
||||
9560b157d9f99e89f4b495f3e0c5995a3b7d44ca
|
||||
5a157904b92a0c6d2f071e57cdd8ec33eea80842
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user