diff --git a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/BuildItem.cs b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/BuildItem.cs
index f663120bf7..82af83b152 100644
--- a/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/BuildItem.cs
+++ b/mcs/class/Microsoft.Build.Engine/Microsoft.Build.BuildEngine/BuildItem.cs
@@ -226,6 +226,14 @@ namespace Microsoft.Build.BuildEngine {
public void SetMetadata (string metadataName,
string metadataValue,
bool treatMetadataValueAsLiteral)
+ {
+ SetMetadata (metadataName, metadataValue, treatMetadataValueAsLiteral, false);
+ }
+
+ void SetMetadata (string metadataName,
+ string metadataValue,
+ bool treatMetadataValueAsLiteral,
+ bool fromDynamicItem)
{
if (metadataName == null)
throw new ArgumentNullException ("metadataName");
@@ -251,9 +259,11 @@ namespace Microsoft.Build.BuildEngine {
} else if (HasParentItem) {
if (parent_item.child_items.Count > 1)
SplitParentItem ();
- parent_item.SetMetadata (metadataName, metadataValue, treatMetadataValueAsLiteral);
+ parent_item.SetMetadata (metadataName, metadataValue, treatMetadataValueAsLiteral, fromDynamicItem);
}
- if (FromXml || HasParentItem) {
+
+ // We don't want to reevalute the project for dynamic items
+ if (!fromDynamicItem && !IsDynamic && (FromXml || HasParentItem)) {
parent_item_group.ParentProject.MarkProjectAsDirty ();
parent_item_group.ParentProject.NeedToReevaluate ();
}
@@ -374,7 +384,7 @@ namespace Microsoft.Build.BuildEngine {
continue;
foreach (string name in evaluatedMetadata.Keys) {
- item.SetMetadata (name, (string)evaluatedMetadata [name]);
+ item.SetMetadata (name, (string)evaluatedMetadata [name], false, IsDynamic);
}
AddAndRemoveMetadata (project, item);
diff --git a/mcs/class/Microsoft.Build.Engine/Test/Microsoft.Build.BuildEngine/TargetTest.cs b/mcs/class/Microsoft.Build.Engine/Test/Microsoft.Build.BuildEngine/TargetTest.cs
index 6c7919e6ae..c709615d25 100644
--- a/mcs/class/Microsoft.Build.Engine/Test/Microsoft.Build.BuildEngine/TargetTest.cs
+++ b/mcs/class/Microsoft.Build.Engine/Test/Microsoft.Build.BuildEngine/TargetTest.cs
@@ -697,6 +697,33 @@ namespace MonoTests.Microsoft.Build.BuildEngine {
", "D");
}
+ [Test]
+ public void ItemGroupInsideTarget_UpdateMetadata ()
+ {
+ ItemGroupInsideTarget (
+ @"
+
+
+
+
+
+
+
+
+ A=b
+
+
+
+
+
+
+
+ Bar01
+
+
+ ", 2, "Before: Bar01", "After: Bar01");
+ }
+
[Test]
public void ItemGroupInsideTarget_Batching ()
{
diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
index cc2ab66960..e4817ee4be 100644
--- a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
+++ b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
@@ -430,6 +430,7 @@ public class Tests : TestsBase, ITest2
ss_recursive2 (1);
ss_recursive_chaotic ();
ss_fp_clobber ();
+ ss_no_frames ();
}
[MethodImplAttribute (MethodImplOptions.NoInlining)]
@@ -679,6 +680,25 @@ public class Tests : TestsBase, ITest2
public static void ss_fp_clobber_2 (double d) {
}
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static void ss_no_frames () {
+ Action a = ss_no_frames_2;
+ var ar = a.BeginInvoke (null, null);
+ ar.AsyncWaitHandle.WaitOne ();
+ // Avoid waiting every time this runs
+ if (static_i == 56)
+ Thread.Sleep (200);
+ ss_no_frames_3 ();
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static void ss_no_frames_2 () {
+ }
+
+ [MethodImplAttribute (MethodImplOptions.NoInlining)]
+ public static void ss_no_frames_3 () {
+ }
+
[MethodImplAttribute (MethodImplOptions.NoInlining)]
public static bool is_even (int i) {
return i % 2 == 0;
diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs.REMOVED.git-id b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs.REMOVED.git-id
index 61183f89b1..8fe451930e 100644
--- a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs.REMOVED.git-id
+++ b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs.REMOVED.git-id
@@ -1 +1 @@
-1933fc5e827372129731655297986401622ff064
\ No newline at end of file
+8f929048d1b17809b27dc30940c81b379f1ec129
\ No newline at end of file
diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/MessageFault.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/MessageFault.cs
index e8e1053358..8527e5c313 100644
--- a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/MessageFault.cs
+++ b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/MessageFault.cs
@@ -53,7 +53,7 @@ namespace System.ServiceModel.Channels
{
FaultCode fc = null;
FaultReason fr = null;
- object details = null;
+ string actor = null;
XmlDictionaryReader r = message.GetReaderAtBodyContents ();
r.ReadStartElement ("Fault", message.Version.Envelope.Namespace);
r.MoveToContent ();
@@ -66,11 +66,13 @@ namespace System.ServiceModel.Channels
case "faultstring":
fr = new FaultReason (r.ReadElementContentAsString());
break;
- case "detail":
- return new XmlReaderDetailMessageFault (message, r, fc, fr, null, null);
case "faultactor":
+ actor = r.ReadElementContentAsString();
+ break;
+ case "detail":
+ return new XmlReaderDetailMessageFault (message, r, fc, fr, actor, null);
default:
- throw new NotImplementedException ();
+ throw new XmlException (String.Format ("Unexpected node {0} name {1}", r.NodeType, r.Name));
}
r.MoveToContent ();
}
@@ -79,9 +81,7 @@ namespace System.ServiceModel.Channels
if (fr == null)
throw new XmlException ("Reason is missing in the Fault message");
- if (details == null)
- return CreateFault (fc, fr);
- return CreateFault (fc, fr, details);
+ return new SimpleMessageFault (fc, fr, false, null, null, actor, null);
}
static MessageFault CreateFault12 (Message message, int maxBufferSize)
diff --git a/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageFaultTest.cs b/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageFaultTest.cs
index eae3d7ca74..5c73c05932 100644
--- a/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageFaultTest.cs
+++ b/mcs/class/System.ServiceModel/Test/System.ServiceModel.Channels/MessageFaultTest.cs
@@ -71,6 +71,7 @@ namespace MonoTests.System.ServiceModel.Channels
a:ActionNotSupported
some error
+ Random
";
diff --git a/mcs/class/System.XML/System.Xml.Serialization/TypeData.cs b/mcs/class/System.XML/System.Xml.Serialization/TypeData.cs
index f32bb39e09..55de52a778 100644
--- a/mcs/class/System.XML/System.Xml.Serialization/TypeData.cs
+++ b/mcs/class/System.XML/System.Xml.Serialization/TypeData.cs
@@ -135,10 +135,16 @@ namespace System.Xml.Serialization
void LookupTypeConvertor ()
{
- // We only need this for System.Xml.Linq.
- var convertor = type.GetCustomAttribute ();
- if (convertor != null)
- typeConvertor = type.GetMethod (convertor.Method, BindingFlags.Static | BindingFlags.NonPublic);
+ // We only need this for System.Xml.Linq
+ var t = type;
+ // HACK: because interpreter array handling is so bad
+ if (t.IsArray)
+ t = t.GetElementType ();
+
+ var convertor = t.GetCustomAttribute ();
+ if (convertor != null) {
+ typeConvertor = t.GetMethod (convertor.Method, BindingFlags.Static | BindingFlags.NonPublic);
+ }
}
internal void ConvertForAssignment (ref object value)
diff --git a/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs b/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs
index 5d9e4b24f3..d03dea1ff0 100644
--- a/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs
+++ b/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationReaderInterpreter.cs
@@ -737,7 +737,8 @@ namespace System.Xml.Serialization
Type type = listType.Type;
if (type.IsArray)
{
- list = EnsureArrayIndex ((Array)list, index, type.GetElementType());
+ list = EnsureArrayIndex ((Array)list, index, type.GetElementType ());
+ listType.ConvertForAssignment (ref value);
((Array)list).SetValue (value, index);
}
else // Must be IEnumerable
diff --git a/mcs/class/System.Xml.Linq/Test/System.Xml.Linq/XElementTest.cs.REMOVED.git-id b/mcs/class/System.Xml.Linq/Test/System.Xml.Linq/XElementTest.cs.REMOVED.git-id
index 2d558c5525..335c9b0a25 100644
--- a/mcs/class/System.Xml.Linq/Test/System.Xml.Linq/XElementTest.cs.REMOVED.git-id
+++ b/mcs/class/System.Xml.Linq/Test/System.Xml.Linq/XElementTest.cs.REMOVED.git-id
@@ -1 +1 @@
-5415ff8e50a4beb760cc5825406fd6e49e7a3989
\ No newline at end of file
+f93bbabc3d88e21bca92fc48e741c150f261a945
\ No newline at end of file
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsContext.cs b/mcs/class/System/Mono.Btls/MonoBtlsContext.cs
index 2df24d9793..a926124bb5 100644
--- a/mcs/class/System/Mono.Btls/MonoBtlsContext.cs
+++ b/mcs/class/System/Mono.Btls/MonoBtlsContext.cs
@@ -135,7 +135,7 @@ namespace Mono.Btls
if (IsServer) {
SetPrivateCertificate (nativeServerCertificate);
} else {
- ssl.SetServerName (TargetHost);
+ ssl.SetServerName (ServerName);
}
}
@@ -236,14 +236,7 @@ namespace Mono.Btls
if (!IsServer)
ctx.SetSelectCallback (SelectCallback);
- var host = TargetHost;
- if (!string.IsNullOrEmpty (host)) {
- var pos = TargetHost.IndexOf (':');
- if (pos > 0)
- host = host.Substring (0, pos);
- }
-
- ctx.SetVerifyParam (MonoBtlsProvider.GetVerifyParam (host, IsServer));
+ ctx.SetVerifyParam (MonoBtlsProvider.GetVerifyParam (ServerName, IsServer));
TlsProtocolCode minProtocol, maxProtocol;
GetProtocolVersions (out minProtocol, out maxProtocol);
diff --git a/mcs/class/System/Mono.Net.Security/MobileTlsContext.cs b/mcs/class/System/Mono.Net.Security/MobileTlsContext.cs
index f051a5fcbc..79f0468d46 100644
--- a/mcs/class/System/Mono.Net.Security/MobileTlsContext.cs
+++ b/mcs/class/System/Mono.Net.Security/MobileTlsContext.cs
@@ -35,6 +35,7 @@ namespace Mono.Net.Security
MobileAuthenticatedStream parent;
bool serverMode;
string targetHost;
+ string serverName;
SslProtocols enabledProtocols;
X509Certificate serverCertificate;
X509CertificateCollection clientCertificates;
@@ -54,6 +55,13 @@ namespace Mono.Net.Security
this.clientCertificates = clientCertificates;
this.askForClientCert = askForClientCert;
+ serverName = targetHost;
+ if (!string.IsNullOrEmpty (serverName)) {
+ var pos = serverName.IndexOf (':');
+ if (pos > 0)
+ serverName = serverName.Substring (0, pos);
+ }
+
certificateValidator = CertificateValidationHelper.GetInternalValidator (
parent.Settings, parent.Provider);
}
@@ -92,6 +100,10 @@ namespace Mono.Net.Security
get { return targetHost; }
}
+ protected string ServerName {
+ get { return serverName; }
+ }
+
protected bool AskForClientCertificate {
get { return askForClientCert; }
}
diff --git a/mcs/class/System/System.Net.Sockets/TcpListener.platformnotsupported.cs b/mcs/class/System/System.Net.Sockets/TcpListener.platformnotsupported.cs
index 7b64967345..76941fc7ce 100644
--- a/mcs/class/System/System.Net.Sockets/TcpListener.platformnotsupported.cs
+++ b/mcs/class/System/System.Net.Sockets/TcpListener.platformnotsupported.cs
@@ -78,6 +78,16 @@ namespace System.Net.Sockets
throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
}
+ public void AllowNatTraversal (bool allowed)
+ {
+ throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+ }
+
+ public static TcpListener Create (int port)
+ {
+ throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+ }
+
~TcpListener ()
{
}
diff --git a/mcs/class/System/System.Net.Sockets/UdpClient.platformnotsupported.cs b/mcs/class/System/System.Net.Sockets/UdpClient.platformnotsupported.cs
index 953350146d..7a5e2dd740 100644
--- a/mcs/class/System/System.Net.Sockets/UdpClient.platformnotsupported.cs
+++ b/mcs/class/System/System.Net.Sockets/UdpClient.platformnotsupported.cs
@@ -204,6 +204,11 @@ namespace System.Net.Sockets
set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
}
+ public void AllowNatTraversal (bool allowed)
+ {
+ throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+ }
+
public void Dispose ()
{
throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
diff --git a/mcs/class/System/System.Net/HttpListener.platformnotsupported.cs b/mcs/class/System/System.Net/HttpListener.platformnotsupported.cs
index bffdfbc701..88ae1d361e 100644
--- a/mcs/class/System/System.Net/HttpListener.platformnotsupported.cs
+++ b/mcs/class/System/System.Net/HttpListener.platformnotsupported.cs
@@ -26,6 +26,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
+using System.Security.Authentication.ExtendedProtection;
using System.Threading.Tasks;
namespace System.Net {
@@ -33,6 +34,8 @@ namespace System.Net {
{
internal const string EXCEPTION_MESSAGE = "System.Net.HttpListener is not supported on the current platform.";
+ public delegate ExtendedProtectionPolicy ExtendedProtectionSelector (HttpListenerRequest request);
+
public HttpListener ()
{
throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
@@ -75,6 +78,27 @@ namespace System.Net {
set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
}
+ public HttpListenerTimeoutManager TimeoutManager {
+ get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+ }
+
+ public ExtendedProtectionPolicy ExtendedProtectionPolicy
+ {
+ get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+ set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+ }
+
+ public ExtendedProtectionSelector ExtendedProtectionSelectorDelegate
+ {
+ get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+ set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+ }
+
+ public ServiceNameCollection DefaultServiceNames
+ {
+ get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+ }
+
public void Abort ()
{
throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
diff --git a/mcs/class/System/System.Net/HttpListenerContext.platformnotsupported.cs b/mcs/class/System/System.Net/HttpListenerContext.platformnotsupported.cs
index 4c729de26c..275d6d4ad1 100644
--- a/mcs/class/System/System.Net/HttpListenerContext.platformnotsupported.cs
+++ b/mcs/class/System/System.Net/HttpListenerContext.platformnotsupported.cs
@@ -55,6 +55,11 @@ namespace System.Net {
throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
}
+ public Task AcceptWebSocketAsync (string subProtocol, TimeSpan keepAliveInterval)
+ {
+ throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+ }
+
public Task AcceptWebSocketAsync (string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval)
{
throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
diff --git a/mcs/class/System/System.Net/HttpWebRequest.platformnotsupported.cs b/mcs/class/System/System.Net/HttpWebRequest.platformnotsupported.cs
index 3977c7bad9..590c82b0bd 100644
--- a/mcs/class/System/System.Net/HttpWebRequest.platformnotsupported.cs
+++ b/mcs/class/System/System.Net/HttpWebRequest.platformnotsupported.cs
@@ -67,12 +67,12 @@ namespace System.Net
get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
}
- public bool AllowAutoRedirect {
+ public virtual bool AllowAutoRedirect {
get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
}
- public bool AllowWriteStreamBuffering {
+ public virtual bool AllowWriteStreamBuffering {
get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
}
@@ -360,6 +360,11 @@ namespace System.Net
throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
}
+ public System.IO.Stream GetRequestStream (out TransportContext context)
+ {
+ throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+ }
+
public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state)
{
throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
diff --git a/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs b/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs
index d7128abc33..453735cf84 100644
--- a/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs
+++ b/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs
@@ -74,6 +74,13 @@ namespace System.Runtime.InteropServices
return false;
}
+ [MonoTODO]
+ public static void CleanupUnusedObjectsInCurrentContext ()
+ {
+ if (Environment.IsRunningOnWindows)
+ throw new PlatformNotSupportedException ();
+ }
+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern static IntPtr AllocCoTaskMem (int cb);
@@ -769,15 +776,8 @@ namespace System.Runtime.InteropServices
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern static string PtrToStringUni (IntPtr ptr, int len);
-#if !MOBILE
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern static string PtrToStringBSTR (IntPtr ptr);
-#else
- public static string PtrToStringBSTR (IntPtr ptr)
- {
- throw new NotImplementedException ();
- }
-#endif
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[ComVisible (true)]
diff --git a/mcs/class/corlib/Test/System/TypeTest.cs.REMOVED.git-id b/mcs/class/corlib/Test/System/TypeTest.cs.REMOVED.git-id
index cfabe9c21a..83cb6c2631 100644
--- a/mcs/class/corlib/Test/System/TypeTest.cs.REMOVED.git-id
+++ b/mcs/class/corlib/Test/System/TypeTest.cs.REMOVED.git-id
@@ -1 +1 @@
-d9eea5672d519baa2abbb431cd364b9620888b26
\ No newline at end of file
+e275634bc2c909abbe355a3fe2f75b1a08b25558
\ No newline at end of file
diff --git a/mcs/class/lib/monolite/System.dll.REMOVED.git-id b/mcs/class/lib/monolite/System.dll.REMOVED.git-id
index 386249ad7e..1e783ef089 100644
--- a/mcs/class/lib/monolite/System.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite/System.dll.REMOVED.git-id
@@ -1 +1 @@
-4300ee601c5a3c592bf6808619b626189da4347f
\ No newline at end of file
+8fb76ec050d22e5bb67a5dab3635c1998608ec6a
\ No newline at end of file
diff --git a/mcs/class/lib/monolite/mscorlib.dll.REMOVED.git-id b/mcs/class/lib/monolite/mscorlib.dll.REMOVED.git-id
index c75cc51845..796f6abff3 100644
--- a/mcs/class/lib/monolite/mscorlib.dll.REMOVED.git-id
+++ b/mcs/class/lib/monolite/mscorlib.dll.REMOVED.git-id
@@ -1 +1 @@
-4a5d937cf3124b7461317b6d951a881da4f0a453
\ No newline at end of file
+1035eebc45f582696603f7c18625e71de46627a7
\ No newline at end of file
diff --git a/mono/btls/CMakeLists.txt b/mono/btls/CMakeLists.txt
new file mode 100644
index 0000000000..133f5e3272
--- /dev/null
+++ b/mono/btls/CMakeLists.txt
@@ -0,0 +1,94 @@
+cmake_minimum_required (VERSION 2.8.10)
+
+project (mono-btls)
+
+if(POLICY CMP0026)
+cmake_policy(SET CMP0026 NEW)
+endif()
+if(POLICY CMP0042)
+cmake_policy(SET CMP0042 NEW)
+endif()
+
+enable_language(C)
+enable_language(CXX)
+
+# FIXME: cmake's asm detection is broken when using xcrun.
+set (CMAKE_ASM_COMPILER "${CMAKE_C_COMPILER}")
+set (CMAKE_ASM_COMPILER_ARG1 "${CMAKE_C_COMPILER_ARG1}")
+set (CMAKE_ASM_COMPILER_ID "${CMAKE_C_COMPILER_ID}")
+enable_language(ASM)
+
+if (NOT "${BTLS_ARCH}" STREQUAL "")
+ message (WARNING "SET ARCH: ${BTLS_ARCH}")
+ set (CMAKE_SYSTEM_PROCESSOR "${BTLS_ARCH}")
+endif ()
+set (C_CXX_FLAGS "-Wall -Wsign-compare -Wmissing-field-initializers -ggdb -fvisibility=hidden")
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_CXX_FLAGS} ${BTLS_CFLAGS}")
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_CXX_FLAGS} ${BTLS_CFLAGS}")
+set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${BTLS_CFLAGS}")
+set (CMAKE_MACOSX_RPATH 1)
+set (MONO_BTLS 1)
+
+add_subdirectory (${BTLS_ROOT} boringssl)
+
+include_directories (
+ ${SRC_DIR}
+ ${BTLS_ROOT}/include
+)
+
+set (
+ MONO_BTLS_SOURCES
+
+ btls-bio.c
+ btls-bio.h
+ btls-error.c
+ btls-error.h
+ btls-key.c
+ btls-key.h
+ btls-pkcs12.c
+ btls-pkcs12.h
+ btls-ssl-ctx.c
+ btls-ssl-ctx.h
+ btls-ssl.c
+ btls-ssl.h
+ btls-time64.c
+ btls-util.c
+ btls-util.h
+ btls-x509-chain.c
+ btls-x509-chain.h
+ btls-x509-crl.c
+ btls-x509-crl.h
+ btls-x509-lookup.c
+ btls-x509-lookup.h
+ btls-x509-lookup-mono.c
+ btls-x509-lookup-mono.h
+ btls-x509-name.c
+ btls-x509-name.h
+ btls-x509-revoked.c
+ btls-x509-revoked.h
+ btls-x509-store-ctx.c
+ btls-x509-store-ctx.h
+ btls-x509-store.c
+ btls-x509-store.h
+ btls-x509-verify-param.c
+ btls-x509-verify-param.h
+ btls-x509.c
+ btls-x509.h
+
+ ${BORINGSSL_OBJECTS}
+)
+
+if (BUILD_DYNAMIC_BTLS)
+ add_library (mono-btls-shared SHARED ${MONO_BTLS_SOURCES})
+elseif (BUILD_SHARED_LIBS)
+ add_library (mono-btls-shared SHARED ${MONO_BTLS_SOURCES})
+ set_target_properties (mono-btls-shared PROPERTIES RULE_LAUNCH_LINK
+ "${PROJECT_SOURCE_DIR}/create-object-library.sh ${CMAKE_BINARY_DIR} mono-btls-shared.txt mono-btls-shared-lo.txt libmono-btls-shared.a shared ${CMAKE_AR} ${CMAKE_RANLIB} --"
+ )
+else ()
+ add_library (mono-btls-static STATIC ${MONO_BTLS_SOURCES})
+ set_target_properties (mono-btls-static PROPERTIES RULE_LAUNCH_LINK
+ "${PROJECT_SOURCE_DIR}/create-object-library.sh ${CMAKE_BINARY_DIR} mono-btls-static.txt mono-btls-static-lo.txt libmono-btls-static.a static ${CMAKE_AR} ${CMAKE_RANLIB} --"
+ )
+endif ()
+
diff --git a/mono/btls/Makefile.am b/mono/btls/Makefile.am
index fa4a949b5f..6a5b106132 100644
--- a/mono/btls/Makefile.am
+++ b/mono/btls/Makefile.am
@@ -1,7 +1,44 @@
BTLS_STATIC_LIST = build-static/mono-btls-static-lo.txt
BTLS_SHARED_LIST = build-shared/mono-btls-shared-lo.txt
-BTLS_DEPS = $(BTLS_LIBS) build-shared/Makefile build-static/Makefile
+EXTRA_DIST = \
+ btls-bio.c \
+ btls-bio.h \
+ btls-error.c \
+ btls-error.h \
+ btls-key.c \
+ btls-key.h \
+ btls-pkcs12.c \
+ btls-pkcs12.h \
+ btls-ssl.c \
+ btls-ssl-ctx.c \
+ btls-ssl-ctx.h \
+ btls-ssl.h \
+ btls-time64.c \
+ btls-util.c \
+ btls-util.h \
+ btls-x509.c \
+ btls-x509-chain.c \
+ btls-x509-chain.h \
+ btls-x509-crl.c \
+ btls-x509-crl.h \
+ btls-x509.h \
+ btls-x509-lookup.c \
+ btls-x509-lookup.h \
+ btls-x509-lookup-mono.c \
+ btls-x509-lookup-mono.h \
+ btls-x509-name.c \
+ btls-x509-name.h \
+ btls-x509-revoked.c \
+ btls-x509-revoked.h \
+ btls-x509-store.c \
+ btls-x509-store-ctx.c \
+ btls-x509-store-ctx.h \
+ btls-x509-store.h \
+ btls-x509-verify-param.c \
+ btls-x509-verify-param.h \
+ CMakeLists.txt \
+ create-object-library.sh
CMAKE_VERBOSE=$(if $(V),VERBOSE=1,)
diff --git a/mono/btls/Makefile.in b/mono/btls/Makefile.in
index 72ffa1eaea..b070c75002 100644
--- a/mono/btls/Makefile.in
+++ b/mono/btls/Makefile.in
@@ -332,7 +332,45 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
BTLS_STATIC_LIST = build-static/mono-btls-static-lo.txt
BTLS_SHARED_LIST = build-shared/mono-btls-shared-lo.txt
-BTLS_DEPS = $(BTLS_LIBS) build-shared/Makefile build-static/Makefile
+EXTRA_DIST = \
+ btls-bio.c \
+ btls-bio.h \
+ btls-error.c \
+ btls-error.h \
+ btls-key.c \
+ btls-key.h \
+ btls-pkcs12.c \
+ btls-pkcs12.h \
+ btls-ssl.c \
+ btls-ssl-ctx.c \
+ btls-ssl-ctx.h \
+ btls-ssl.h \
+ btls-time64.c \
+ btls-util.c \
+ btls-util.h \
+ btls-x509.c \
+ btls-x509-chain.c \
+ btls-x509-chain.h \
+ btls-x509-crl.c \
+ btls-x509-crl.h \
+ btls-x509.h \
+ btls-x509-lookup.c \
+ btls-x509-lookup.h \
+ btls-x509-lookup-mono.c \
+ btls-x509-lookup-mono.h \
+ btls-x509-name.c \
+ btls-x509-name.h \
+ btls-x509-revoked.c \
+ btls-x509-revoked.h \
+ btls-x509-store.c \
+ btls-x509-store-ctx.c \
+ btls-x509-store-ctx.h \
+ btls-x509-store.h \
+ btls-x509-verify-param.c \
+ btls-x509-verify-param.h \
+ CMakeLists.txt \
+ create-object-library.sh
+
CMAKE_VERBOSE = $(if $(V),VERBOSE=1,)
CMAKE_ARGS = -D CMAKE_INSTALL_PREFIX:PATH=$(prefix) -D BTLS_ROOT:PATH=$(BTLS_ROOT) \
-D SRC_DIR:PATH=$(abs_top_srcdir)/mono/btls -D BTLS_CFLAGS:STRING="$(BTLS_CFLAGS)"
diff --git a/mono/btls/btls-bio.c b/mono/btls/btls-bio.c
new file mode 100644
index 0000000000..a35582a3b5
--- /dev/null
+++ b/mono/btls/btls-bio.c
@@ -0,0 +1,206 @@
+//
+// btls-bio.c
+// MonoBtls
+//
+// Created by Martin Baulig on 14/11/15.
+// Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#include
+#include
+#include
+
+struct MonoBtlsBio {
+ const void *instance;
+ MonoBtlsReadFunc read_func;
+ MonoBtlsWriteFunc write_func;
+ MonoBtlsControlFunc control_func;
+};
+
+#if 0
+static void
+mono_debug (const char *message)
+{
+ BIO *bio_err;
+ bio_err = BIO_new_fp (stderr, BIO_NOCLOSE);
+ fprintf (stderr, "DEBUG: %s\n", message);
+ ERR_print_errors (bio_err);
+}
+#endif
+
+static int
+mono_read (BIO *bio, char *out, int outl)
+{
+ MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
+ int ret, wantMore;
+
+ if (!mono)
+ return -1;
+
+ ret = mono->read_func (mono->instance, out, outl, &wantMore);
+
+ if (ret < 0)
+ return -1;
+ if (ret > 0)
+ return ret;
+
+ if (wantMore) {
+ errno = EAGAIN;
+ BIO_set_retry_read (bio);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+mono_write (BIO *bio, const char *in, int inl)
+{
+ MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
+
+ if (!mono)
+ return -1;
+
+ return mono->write_func (mono->instance, in, inl);
+}
+
+static int64_t
+mono_ctrl (BIO *bio, int cmd, int64_t num, void *ptr)
+{
+ MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
+
+ if (!mono)
+ return -1;
+
+ // fprintf (stderr, "mono_ctrl: %x - %lx - %p\n", cmd, num, ptr);
+ switch (cmd) {
+ case BIO_CTRL_FLUSH:
+ return mono->control_func (mono->instance, MONO_BTLS_CONTROL_COMMAND_FLUSH, 0);
+ default:
+ return -1;
+ }
+ return -1;
+}
+
+static int
+mono_new (BIO *bio)
+{
+ // mono_debug("mono_new!\n");
+ bio->init = 0;
+ bio->num = -1;
+ bio->flags = 0;
+ return 1;
+}
+
+static int
+mono_free (BIO *bio)
+{
+ // mono_debug ("mono_free!\n");
+ if (bio->ptr) {
+ MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
+
+ bio->ptr = NULL;
+ mono->instance = NULL;
+ mono->read_func = NULL;
+ mono->write_func = NULL;
+ mono->control_func = NULL;
+ free (mono);
+ }
+ return 1;
+}
+
+static const BIO_METHOD mono_method = {
+ BIO_TYPE_NONE, "mono", mono_write, mono_read,
+ NULL, NULL, mono_ctrl, mono_new, mono_free, NULL
+};
+
+MONO_API BIO *
+mono_btls_bio_mono_new (void)
+{
+ BIO *bio;
+ MonoBtlsBio *monoBio;
+
+ bio = BIO_new (&mono_method);
+ if (!bio)
+ return NULL;
+
+ monoBio = calloc (1, sizeof (MonoBtlsBio));
+ if (!monoBio) {
+ BIO_free (bio);
+ return NULL;
+ }
+
+ bio->ptr = monoBio;
+ bio->init = 0;
+
+ return bio;
+}
+
+MONO_API void
+mono_btls_bio_mono_initialize (BIO *bio, const void *instance,
+ MonoBtlsReadFunc read_func, MonoBtlsWriteFunc write_func,
+ MonoBtlsControlFunc control_func)
+{
+ MonoBtlsBio *monoBio = bio->ptr;
+
+ monoBio->instance = instance;
+ monoBio->read_func = read_func;
+ monoBio->write_func = write_func;
+ monoBio->control_func = control_func;
+
+ bio->init = 1;
+}
+
+MONO_API int
+mono_btls_bio_read (BIO *bio, void *data, int len)
+{
+ return BIO_read (bio, data, len);
+}
+
+MONO_API int
+mono_btls_bio_write (BIO *bio, const void *data, int len)
+{
+ return BIO_write (bio, data, len);
+}
+
+MONO_API int
+mono_btls_bio_flush (BIO *bio)
+{
+ return BIO_flush (bio);
+}
+
+MONO_API int
+mono_btls_bio_indent (BIO *bio, unsigned indent, unsigned max_indent)
+{
+ return BIO_indent (bio, indent, max_indent);
+}
+
+MONO_API int
+mono_btls_bio_hexdump (BIO *bio, const uint8_t *data, int len, unsigned indent)
+{
+ return BIO_hexdump (bio, data, len, indent);
+}
+
+MONO_API void
+mono_btls_bio_print_errors (BIO *bio)
+{
+ BIO_print_errors (bio);
+}
+
+MONO_API void
+mono_btls_bio_free (BIO *bio)
+{
+ BIO_free (bio);
+}
+
+MONO_API BIO *
+mono_btls_bio_mem_new (void)
+{
+ return BIO_new (BIO_s_mem ());
+}
+
+MONO_API int
+mono_btls_bio_mem_get_data (BIO *bio, void **data)
+{
+ return (int)BIO_get_mem_data (bio, (char**)data);
+}
diff --git a/mono/btls/btls-bio.h b/mono/btls/btls-bio.h
new file mode 100644
index 0000000000..0795ef0f2b
--- /dev/null
+++ b/mono/btls/btls-bio.h
@@ -0,0 +1,58 @@
+//
+// btls-bio.h
+// MonoBtls
+//
+// Created by Martin Baulig on 14/11/15.
+// Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_bio__
+#define __btls__btls_bio__
+
+#include
+#include
+
+typedef enum {
+ MONO_BTLS_CONTROL_COMMAND_FLUSH = 1
+} MonoBtlsControlCommand;
+
+typedef int (* MonoBtlsReadFunc) (const void *instance, const void *buf, int size, int *wantMore);
+typedef int (* MonoBtlsWriteFunc) (const void *instance, const void *buf, int size);
+typedef int64_t (* MonoBtlsControlFunc) (const void *instance, MonoBtlsControlCommand command, int64_t arg);
+
+BIO *
+mono_btls_bio_mono_new (void);
+
+void
+mono_btls_bio_mono_initialize (BIO *bio, const void *instance,
+ MonoBtlsReadFunc read_func, MonoBtlsWriteFunc write_func,
+ MonoBtlsControlFunc control_func);
+
+int
+mono_btls_bio_read (BIO *bio, void *data, int len);
+
+int
+mono_btls_bio_write (BIO *bio, const void *data, int len);
+
+int
+mono_btls_bio_flush (BIO *bio);
+
+int
+mono_btls_bio_indent (BIO *bio, unsigned indent, unsigned max_indent);
+
+int
+mono_btls_bio_hexdump (BIO *bio, const uint8_t *data, int len, unsigned indent);
+
+void
+mono_btls_bio_print_errors (BIO *bio);
+
+void
+mono_btls_bio_free (BIO *bio);
+
+BIO *
+mono_btls_bio_mem_new (void);
+
+int
+mono_btls_bio_mem_get_data (BIO *bio, void **data);
+
+#endif /* defined(__btls__btls_bio__) */
diff --git a/mono/btls/btls-error.c b/mono/btls/btls-error.c
new file mode 100644
index 0000000000..75252162a2
--- /dev/null
+++ b/mono/btls/btls-error.c
@@ -0,0 +1,36 @@
+//
+// btls-error.c
+// MonoBtls
+//
+// Created by Martin Baulig on 6/19/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+#include
+#include
+
+MONO_API int
+mono_btls_error_peek_error (void)
+{
+ return ERR_peek_error ();
+}
+
+MONO_API int
+mono_btls_error_get_error (void)
+{
+ return ERR_get_error ();
+}
+
+MONO_API void
+mono_btls_error_clear_error (void)
+{
+ ERR_clear_error ();
+}
+
+MONO_API void
+mono_btls_error_get_error_string_n (int error, char *buf, int len)
+{
+ ERR_error_string_n (error, buf, len);
+}
+
diff --git a/mono/btls/btls-error.h b/mono/btls/btls-error.h
new file mode 100644
index 0000000000..6f791c372a
--- /dev/null
+++ b/mono/btls/btls-error.h
@@ -0,0 +1,29 @@
+//
+// btls-util.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/23/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_error__
+#define __btls__btls_error__
+
+#include
+#include
+#include
+#include
+
+int
+mono_btls_error_peek_error (void);
+
+int
+mono_btls_error_get_error (void);
+
+void
+mono_btls_error_clear_error (void);
+
+void
+mono_btls_error_get_error_string_n (int error, char *buf, int len);
+
+#endif /* __btls__btls_error__ */
diff --git a/mono/btls/btls-key.c b/mono/btls/btls-key.c
new file mode 100644
index 0000000000..65909a527d
--- /dev/null
+++ b/mono/btls/btls-key.c
@@ -0,0 +1,62 @@
+//
+// btls-key.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/7/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+
+MONO_API void
+mono_btls_key_free (EVP_PKEY *pkey)
+{
+ EVP_PKEY_free (pkey);
+}
+
+MONO_API EVP_PKEY *
+mono_btls_key_up_ref (EVP_PKEY *pkey)
+{
+ return EVP_PKEY_up_ref (pkey);
+}
+
+MONO_API int
+mono_btls_key_get_bits (EVP_PKEY *pkey)
+{
+ return EVP_PKEY_bits (pkey);
+}
+
+MONO_API int
+mono_btls_key_is_rsa (EVP_PKEY *pkey)
+{
+ return pkey->type == EVP_PKEY_RSA;
+}
+
+MONO_API int
+mono_btls_key_get_bytes (EVP_PKEY *pkey, uint8_t **buffer, int *size, int include_private_bits)
+{
+ size_t len;
+ RSA *rsa;
+ int ret;
+
+ *size = 0;
+ *buffer = NULL;
+
+ if (pkey->type != EVP_PKEY_RSA)
+ return 0;
+
+ rsa = EVP_PKEY_get1_RSA (pkey);
+ if (!rsa)
+ return 0;
+
+ if (include_private_bits)
+ ret = RSA_private_key_to_bytes (buffer, &len, rsa);
+ else
+ ret = RSA_public_key_to_bytes (buffer, &len, rsa);
+
+ if (ret != 1)
+ return 0;
+
+ *size = (int)len;
+ return 1;
+}
diff --git a/mono/btls/btls-key.h b/mono/btls/btls-key.h
new file mode 100644
index 0000000000..85ee5b2f58
--- /dev/null
+++ b/mono/btls/btls-key.h
@@ -0,0 +1,32 @@
+//
+// btls-key.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/7/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_key__
+#define __btls__btls_key__
+
+#include
+#include
+#include
+
+void
+mono_btls_key_free (EVP_PKEY *pkey);
+
+EVP_PKEY *
+mono_btls_key_up_ref (EVP_PKEY *pkey);
+
+int
+mono_btls_key_get_bits (EVP_PKEY *pkey);
+
+int
+mono_btls_key_is_rsa (EVP_PKEY *pkey);
+
+int
+mono_btls_key_get_bytes (EVP_PKEY *pkey, uint8_t **buffer, int *size, int include_private_bits);
+
+#endif /* __btls__btls_key__ */
+
diff --git a/mono/btls/btls-pkcs12.c b/mono/btls/btls-pkcs12.c
new file mode 100644
index 0000000000..6e1a79e60b
--- /dev/null
+++ b/mono/btls/btls-pkcs12.c
@@ -0,0 +1,101 @@
+//
+// btls-pkcs12.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/8/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+#include
+
+struct MonoBtlsPkcs12 {
+ STACK_OF(X509) *certs;
+ EVP_PKEY *private_key;
+ CRYPTO_refcount_t references;
+};
+
+MONO_API MonoBtlsPkcs12 *
+mono_btls_pkcs12_new (void)
+{
+ MonoBtlsPkcs12 *pkcs12 = (MonoBtlsPkcs12 *)OPENSSL_malloc (sizeof (MonoBtlsPkcs12));
+ if (pkcs12 == NULL)
+ return NULL;
+
+ memset (pkcs12, 0, sizeof(MonoBtlsPkcs12));
+ pkcs12->certs = sk_X509_new_null ();
+ pkcs12->references = 1;
+ return pkcs12;
+}
+
+MONO_API int
+mono_btls_pkcs12_get_count (MonoBtlsPkcs12 *pkcs12)
+{
+ return (int)sk_X509_num (pkcs12->certs);
+}
+
+MONO_API X509 *
+mono_btls_pkcs12_get_cert (MonoBtlsPkcs12 *pkcs12, int index)
+{
+ X509 *cert;
+
+ if ((size_t)index >= sk_X509_num (pkcs12->certs))
+ return NULL;
+ cert = sk_X509_value (pkcs12->certs, index);
+ if (cert)
+ X509_up_ref (cert);
+ return cert;
+}
+
+MONO_API STACK_OF(X509) *
+mono_btls_pkcs12_get_certs (MonoBtlsPkcs12 *pkcs12)
+{
+ return pkcs12->certs;
+}
+
+MONO_API int
+mono_btls_pkcs12_free (MonoBtlsPkcs12 *pkcs12)
+{
+ if (!CRYPTO_refcount_dec_and_test_zero (&pkcs12->references))
+ return 0;
+
+ sk_X509_pop_free (pkcs12->certs, X509_free);
+ OPENSSL_free (pkcs12);
+ return 1;
+}
+
+MONO_API MonoBtlsPkcs12 *
+mono_btls_pkcs12_up_ref (MonoBtlsPkcs12 *pkcs12)
+{
+ CRYPTO_refcount_inc (&pkcs12->references);
+ return pkcs12;
+}
+
+MONO_API void
+mono_btls_pkcs12_add_cert (MonoBtlsPkcs12 *pkcs12, X509 *x509)
+{
+ X509_up_ref (x509);
+ sk_X509_push (pkcs12->certs, x509);
+}
+
+MONO_API int
+mono_btls_pkcs12_import (MonoBtlsPkcs12 *pkcs12, const void *data, int len, const void *password)
+{
+ CBS cbs;
+ CBS_init (&cbs, data, len);
+ return PKCS12_get_key_and_certs (&pkcs12->private_key, pkcs12->certs, &cbs, password);
+}
+
+MONO_API int
+mono_btls_pkcs12_has_private_key (MonoBtlsPkcs12 *pkcs12)
+{
+ return pkcs12->private_key != NULL;
+}
+
+MONO_API EVP_PKEY *
+mono_btls_pkcs12_get_private_key (MonoBtlsPkcs12 *pkcs12)
+{
+ if (!pkcs12->private_key)
+ return NULL;
+ return EVP_PKEY_up_ref (pkcs12->private_key);
+}
diff --git a/mono/btls/btls-pkcs12.h b/mono/btls/btls-pkcs12.h
new file mode 100644
index 0000000000..20c4fd9c4e
--- /dev/null
+++ b/mono/btls/btls-pkcs12.h
@@ -0,0 +1,46 @@
+//
+// btls-pkcs12.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/8/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_pkcs12__
+#define __btls__btls_pkcs12__
+
+#include
+#include
+#include
+
+MonoBtlsPkcs12 *
+mono_btls_pkcs12_new (void);
+
+int
+mono_btls_pkcs12_get_count (MonoBtlsPkcs12 *pkcs12);
+
+X509 *
+mono_btls_pkcs12_get_cert (MonoBtlsPkcs12 *pkcs12, int index);
+
+STACK_OF(X509) *
+mono_btls_pkcs12_get_certs (MonoBtlsPkcs12 *pkcs12);
+
+int
+mono_btls_pkcs12_free (MonoBtlsPkcs12 *pkcs12);
+
+MonoBtlsPkcs12 *
+mono_btls_pkcs12_up_ref (MonoBtlsPkcs12 *pkcs12);
+
+void
+mono_btls_pkcs12_add_cert (MonoBtlsPkcs12 *pkcs12, X509 *x509);
+
+int
+mono_btls_pkcs12_import (MonoBtlsPkcs12 *pkcs12, const void *data, int len, const void *password);
+
+int
+mono_btls_pkcs12_has_private_key (MonoBtlsPkcs12 *pkcs12);
+
+EVP_PKEY *
+mono_btls_pkcs12_get_private_key (MonoBtlsPkcs12 *pkcs12);
+
+#endif /* __btls__btls_pkcs12__ */
diff --git a/mono/btls/btls-ssl-ctx.c b/mono/btls/btls-ssl-ctx.c
new file mode 100644
index 0000000000..1f9d43c536
--- /dev/null
+++ b/mono/btls/btls-ssl-ctx.c
@@ -0,0 +1,255 @@
+//
+// btls-ssl-ctx.c
+// MonoBtls
+//
+// Created by Martin Baulig on 4/11/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+#include
+
+struct MonoBtlsSslCtx {
+ CRYPTO_refcount_t references;
+ SSL_CTX *ctx;
+ BIO *bio;
+ BIO *debug_bio;
+ void *instance;
+ MonoBtlsVerifyFunc verify_func;
+ MonoBtlsSelectFunc select_func;
+};
+
+#define debug_print(ptr,message) \
+do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr)) \
+mono_btls_ssl_ctx_debug_printf (ptr, "%s:%d:%s(): " message, __FILE__, __LINE__, \
+ __func__); } while (0)
+
+#define debug_printf(ptr,fmt, ...) \
+do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr)) \
+mono_btls_ssl_ctx_debug_printf (ptr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, \
+ __func__, __VA_ARGS__); } while (0)
+
+void ssl_cipher_preference_list_free (struct ssl_cipher_preference_list_st *cipher_list);
+
+MONO_API int
+mono_btls_ssl_ctx_is_debug_enabled (MonoBtlsSslCtx *ctx)
+{
+ return ctx->debug_bio != NULL;
+}
+
+MONO_API int
+mono_btls_ssl_ctx_debug_printf (MonoBtlsSslCtx *ctx, const char *format, ...)
+{
+ va_list args;
+ int ret;
+
+ if (!ctx->debug_bio)
+ return 0;
+
+ va_start (args, format);
+ ret = mono_btls_debug_printf (ctx->debug_bio, format, args);
+ va_end (args);
+ return ret;
+}
+
+MONO_API MonoBtlsSslCtx *
+mono_btls_ssl_ctx_new (void)
+{
+ MonoBtlsSslCtx *ctx;
+
+ ctx = OPENSSL_malloc (sizeof (MonoBtlsSslCtx));
+ if (!ctx)
+ return NULL;
+
+ memset (ctx, 0, sizeof (MonoBtlsSslCtx));
+ ctx->references = 1;
+ ctx->ctx = SSL_CTX_new (TLS_method ());
+ return ctx;
+}
+
+MONO_API MonoBtlsSslCtx *
+mono_btls_ssl_ctx_up_ref (MonoBtlsSslCtx *ctx)
+{
+ CRYPTO_refcount_inc (&ctx->references);
+ return ctx;
+}
+
+MONO_API int
+mono_btls_ssl_ctx_free (MonoBtlsSslCtx *ctx)
+{
+ if (!CRYPTO_refcount_dec_and_test_zero (&ctx->references))
+ return 0;
+ SSL_CTX_free (ctx->ctx);
+ ctx->instance = NULL;
+ OPENSSL_free (ctx);
+ return 1;
+}
+
+MONO_API SSL_CTX *
+mono_btls_ssl_ctx_get_ctx (MonoBtlsSslCtx *ctx)
+{
+ return ctx->ctx;
+}
+
+MONO_API void
+mono_btls_ssl_ctx_set_debug_bio (MonoBtlsSslCtx *ctx, BIO *debug_bio)
+{
+ if (debug_bio)
+ ctx->debug_bio = BIO_up_ref(debug_bio);
+ else
+ ctx->debug_bio = NULL;
+}
+
+MONO_API void
+mono_btls_ssl_ctx_initialize (MonoBtlsSslCtx *ctx, void *instance)
+{
+ ctx->instance = instance;
+}
+
+static int
+cert_verify_callback (X509_STORE_CTX *storeCtx, void *arg)
+{
+ MonoBtlsSslCtx *ptr = (MonoBtlsSslCtx*)arg;
+ int ret;
+
+ debug_printf (ptr, "cert_verify_callback(): %p\n", ptr->verify_func);
+ ret = X509_verify_cert (storeCtx);
+ debug_printf (ptr, "cert_verify_callback() #1: %d\n", ret);
+
+ if (ptr->verify_func)
+ ret = ptr->verify_func (ptr->instance, ret, storeCtx);
+
+ return ret;
+}
+
+MONO_API void
+mono_btls_ssl_ctx_set_cert_verify_callback (MonoBtlsSslCtx *ptr, MonoBtlsVerifyFunc func, int cert_required)
+{
+ int mode;
+
+ ptr->verify_func = func;
+ SSL_CTX_set_cert_verify_callback (ptr->ctx, cert_verify_callback, ptr);
+
+ mode = SSL_VERIFY_PEER;
+ if (cert_required)
+ mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+
+ SSL_CTX_set_verify (ptr->ctx, mode, NULL);
+}
+
+static int
+cert_select_callback (SSL *ssl, void *arg)
+{
+ MonoBtlsSslCtx *ptr = (MonoBtlsSslCtx*)arg;
+ int ret = 1;
+
+ debug_printf (ptr, "cert_select_callback(): %p\n", ptr->select_func);
+ if (ptr->select_func)
+ ret = ptr->select_func (ptr->instance);
+ debug_printf (ptr, "cert_select_callback() #1: %d\n", ret);
+
+ return ret;
+}
+
+MONO_API void
+mono_btls_ssl_ctx_set_cert_select_callback (MonoBtlsSslCtx *ptr, MonoBtlsSelectFunc func)
+{
+ ptr->select_func = func;
+ SSL_CTX_set_cert_cb (ptr->ctx, cert_select_callback, ptr);
+}
+
+MONO_API X509_STORE *
+mono_btls_ssl_ctx_peek_store (MonoBtlsSslCtx *ctx)
+{
+ return SSL_CTX_get_cert_store (ctx->ctx);
+}
+
+MONO_API void
+mono_btls_ssl_ctx_set_min_version (MonoBtlsSslCtx *ctx, int version)
+{
+ SSL_CTX_set_min_version (ctx->ctx, version);
+}
+
+MONO_API void
+mono_btls_ssl_ctx_set_max_version (MonoBtlsSslCtx *ctx, int version)
+{
+ SSL_CTX_set_max_version (ctx->ctx, version);
+}
+
+MONO_API int
+mono_btls_ssl_ctx_is_cipher_supported (MonoBtlsSslCtx *ctx, uint16_t value)
+{
+ const SSL_CIPHER *cipher;
+
+ cipher = SSL_get_cipher_by_value (value);
+ return cipher != NULL;
+}
+
+MONO_API int
+mono_btls_ssl_ctx_set_ciphers (MonoBtlsSslCtx *ctx, int count, const uint16_t *data,
+ int allow_unsupported)
+{
+ STACK_OF(SSL_CIPHER) *ciphers = NULL;
+ struct ssl_cipher_preference_list_st *pref_list = NULL;
+ uint8_t *in_group_flags = NULL;
+ int i;
+
+ ciphers = sk_SSL_CIPHER_new_null ();
+ if (!ciphers)
+ goto err;
+
+ for (i = 0; i < count; i++) {
+ const SSL_CIPHER *cipher = SSL_get_cipher_by_value (data [i]);
+ if (!cipher) {
+ debug_printf (ctx, "mono_btls_ssl_ctx_set_ciphers(): unknown cipher %02x", data [i]);
+ if (!allow_unsupported)
+ goto err;
+ continue;
+ }
+ if (!sk_SSL_CIPHER_push (ciphers, cipher))
+ goto err;
+ }
+
+ pref_list = OPENSSL_malloc (sizeof (struct ssl_cipher_preference_list_st));
+ if (!pref_list)
+ goto err;
+
+ memset (pref_list, 0, sizeof (struct ssl_cipher_preference_list_st));
+ pref_list->ciphers = sk_SSL_CIPHER_dup (ciphers);
+ if (!pref_list->ciphers)
+ goto err;
+ pref_list->in_group_flags = OPENSSL_malloc (sk_SSL_CIPHER_num (ciphers));
+ if (!pref_list->in_group_flags)
+ goto err;
+
+ if (ctx->ctx->cipher_list)
+ ssl_cipher_preference_list_free (ctx->ctx->cipher_list);
+ if (ctx->ctx->cipher_list_by_id)
+ sk_SSL_CIPHER_free (ctx->ctx->cipher_list_by_id);
+ if (ctx->ctx->cipher_list_tls10) {
+ ssl_cipher_preference_list_free (ctx->ctx->cipher_list_tls10);
+ ctx->ctx->cipher_list_tls10 = NULL;
+ }
+ if (ctx->ctx->cipher_list_tls11) {
+ ssl_cipher_preference_list_free (ctx->ctx->cipher_list_tls11);
+ ctx->ctx->cipher_list_tls11 = NULL;
+ }
+
+ ctx->ctx->cipher_list = pref_list;
+ ctx->ctx->cipher_list_by_id = ciphers;
+
+ return (int)sk_SSL_CIPHER_num (ciphers);
+
+err:
+ sk_SSL_CIPHER_free (ciphers);
+ OPENSSL_free (pref_list);
+ OPENSSL_free (in_group_flags);
+ return 0;
+}
+
+MONO_API int
+mono_btls_ssl_ctx_set_verify_param (MonoBtlsSslCtx *ctx, const MonoBtlsX509VerifyParam *param)
+{
+ return SSL_CTX_set1_param (ctx->ctx, mono_btls_x509_verify_param_peek_param (param));
+}
+
diff --git a/mono/btls/btls-ssl-ctx.h b/mono/btls/btls-ssl-ctx.h
new file mode 100644
index 0000000000..0954192709
--- /dev/null
+++ b/mono/btls/btls-ssl-ctx.h
@@ -0,0 +1,84 @@
+//
+// btls-ssl-ctx.h
+// MonoBtls
+//
+// Created by Martin Baulig on 4/11/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls_ssl_ctx__btls_ssl_ctx__
+#define __btls_ssl_ctx__btls_ssl_ctx__
+
+#include
+#include
+#include
+#include
+#include
+
+typedef struct MonoBtlsBio MonoBtlsBio;
+typedef struct MonoBtlsX509Chain MonoBtlsX509Chain;
+typedef struct MonoBtlsX509Crl MonoBtlsX509Crl;
+typedef struct MonoBtlsX509Lookup MonoBtlsX509Lookup;
+typedef struct MonoBtlsX509LookupMono MonoBtlsX509LookupMono;
+typedef struct MonoBtlsX509Name MonoBtlsX509Name;
+typedef struct MonoBtlsX509Store MonoBtlsX509Store;
+typedef struct MonoBtlsX509StoreCtx MonoBtlsX509StoreCtx;
+typedef struct MonoBtlsX509Revoked MonoBtlsX509Revoked;
+typedef struct MonoBtlsX509VerifyParam MonoBtlsX509VerifyParam;
+typedef struct MonoBtlsPkcs12 MonoBtlsPkcs12;
+typedef struct MonoBtlsSsl MonoBtlsSsl;
+typedef struct MonoBtlsSslCtx MonoBtlsSslCtx;
+
+typedef int (* MonoBtlsVerifyFunc) (void *instance, int preverify_ok, X509_STORE_CTX *ctx);
+typedef int (* MonoBtlsSelectFunc) (void *instance);
+
+MonoBtlsSslCtx *
+mono_btls_ssl_ctx_new (void);
+
+MonoBtlsSslCtx *
+mono_btls_ssl_ctx_up_ref (MonoBtlsSslCtx *ctx);
+
+int
+mono_btls_ssl_ctx_free (MonoBtlsSslCtx *ctx);
+
+void
+mono_btls_ssl_ctx_initialize (MonoBtlsSslCtx *ctx, void *instance);
+
+SSL_CTX *
+mono_btls_ssl_ctx_get_ctx (MonoBtlsSslCtx *ctx);
+
+int
+mono_btls_ssl_ctx_debug_printf (MonoBtlsSslCtx *ctx, const char *format, ...);
+
+int
+mono_btls_ssl_ctx_is_debug_enabled (MonoBtlsSslCtx *ctx);
+
+void
+mono_btls_ssl_ctx_set_cert_verify_callback (MonoBtlsSslCtx *ptr, MonoBtlsVerifyFunc func, int cert_required);
+
+void
+mono_btls_ssl_ctx_set_cert_select_callback (MonoBtlsSslCtx *ptr, MonoBtlsSelectFunc func);
+
+void
+mono_btls_ssl_ctx_set_debug_bio (MonoBtlsSslCtx *ctx, BIO *debug_bio);
+
+X509_STORE *
+mono_btls_ssl_ctx_peek_store (MonoBtlsSslCtx *ctx);
+
+void
+mono_btls_ssl_ctx_set_min_version (MonoBtlsSslCtx *ctx, int version);
+
+void
+mono_btls_ssl_ctx_set_max_version (MonoBtlsSslCtx *ctx, int version);
+
+int
+mono_btls_ssl_ctx_is_cipher_supported (MonoBtlsSslCtx *ctx, uint16_t value);
+
+int
+mono_btls_ssl_ctx_set_ciphers (MonoBtlsSslCtx *ctx, int count, const uint16_t *data,
+ int allow_unsupported);
+
+int
+mono_btls_ssl_ctx_set_verify_param (MonoBtlsSslCtx *ctx, const MonoBtlsX509VerifyParam *param);
+
+#endif /* __btls_ssl_ctx__btls_ssl_ctx__ */
diff --git a/mono/btls/btls-ssl.c b/mono/btls/btls-ssl.c
new file mode 100644
index 0000000000..f18d6c1924
--- /dev/null
+++ b/mono/btls/btls-ssl.c
@@ -0,0 +1,209 @@
+//
+// btls-ssl.c
+// MonoBtls
+//
+// Created by Martin Baulig on 14/11/15.
+// Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#include
+#include
+
+struct MonoBtlsSsl {
+ MonoBtlsSslCtx *ctx;
+ SSL *ssl;
+};
+
+#define debug_print(ptr,message) \
+do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr->ctx)) \
+mono_btls_ssl_ctx_debug_printf (ptr->ctx, "%s:%d:%s(): " message, __FILE__, __LINE__, \
+__func__); } while (0)
+
+#define debug_printf(ptr,fmt, ...) \
+do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr->ctx)) \
+mono_btls_ssl_ctx_debug_printf (ptr->ctx, "%s:%d:%s(): " fmt, __FILE__, __LINE__, \
+__func__, __VA_ARGS__); } while (0)
+
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list (SSL *s, const CBS *cbs);
+
+MONO_API MonoBtlsSsl *
+mono_btls_ssl_new (MonoBtlsSslCtx *ctx)
+{
+ MonoBtlsSsl *ptr;
+
+ ptr = calloc (1, sizeof (MonoBtlsSsl));
+
+ ptr->ctx = mono_btls_ssl_ctx_up_ref (ctx);
+ ptr->ssl = SSL_new (mono_btls_ssl_ctx_get_ctx (ptr->ctx));
+
+ SSL_set_options (ptr->ssl, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+
+ return ptr;
+}
+
+MONO_API void
+mono_btls_ssl_destroy (MonoBtlsSsl *ptr)
+{
+ mono_btls_ssl_close (ptr);
+ if (ptr->ssl) {
+ SSL_free (ptr->ssl);
+ ptr->ssl = NULL;
+ }
+ if (ptr->ctx) {
+ mono_btls_ssl_ctx_free (ptr->ctx);
+ ptr->ctx = NULL;
+ }
+ free (ptr);
+}
+
+MONO_API void
+mono_btls_ssl_close (MonoBtlsSsl *ptr)
+{
+ ;
+}
+
+MONO_API void
+mono_btls_ssl_set_bio (MonoBtlsSsl *ptr, BIO *bio)
+{
+ BIO_up_ref (bio);
+ SSL_set_bio (ptr->ssl, bio, bio);
+}
+
+MONO_API void
+mono_btls_ssl_print_errors_cb (ERR_print_errors_callback_t callback, void *ctx)
+{
+ ERR_print_errors_cb (callback, ctx);
+}
+
+MONO_API int
+mono_btls_ssl_use_certificate (MonoBtlsSsl *ptr, X509 *x509)
+{
+ return SSL_use_certificate (ptr->ssl, x509);
+}
+
+MONO_API int
+mono_btls_ssl_use_private_key (MonoBtlsSsl *ptr, EVP_PKEY *key)
+{
+ return SSL_use_PrivateKey (ptr->ssl, key);
+}
+
+MONO_API int
+mono_btls_ssl_add_chain_certificate (MonoBtlsSsl *ptr, X509 *x509)
+{
+ return SSL_add1_chain_cert (ptr->ssl, x509);
+}
+
+MONO_API int
+mono_btls_ssl_accept (MonoBtlsSsl *ptr)
+{
+ return SSL_accept (ptr->ssl);
+}
+
+MONO_API int
+mono_btls_ssl_connect (MonoBtlsSsl *ptr)
+{
+ return SSL_connect (ptr->ssl);
+}
+
+MONO_API int
+mono_btls_ssl_handshake (MonoBtlsSsl *ptr)
+{
+ return SSL_do_handshake (ptr->ssl);
+}
+
+MONO_API int
+mono_btls_ssl_read (MonoBtlsSsl *ptr, void *buf, int count)
+{
+ return SSL_read (ptr->ssl, buf, count);
+}
+
+MONO_API int
+mono_btls_ssl_write (MonoBtlsSsl *ptr, void *buf, int count)
+{
+ return SSL_write (ptr->ssl, buf, count);
+}
+
+MONO_API int
+mono_btls_ssl_get_version (MonoBtlsSsl *ptr)
+{
+ return SSL_version (ptr->ssl);
+}
+
+MONO_API void
+mono_btls_ssl_set_min_version (MonoBtlsSsl *ptr, int version)
+{
+ SSL_set_min_version (ptr->ssl, version);
+}
+
+MONO_API void
+mono_btls_ssl_set_max_version (MonoBtlsSsl *ptr, int version)
+{
+ SSL_set_max_version (ptr->ssl, version);
+}
+
+MONO_API int
+mono_btls_ssl_get_cipher (MonoBtlsSsl *ptr)
+{
+ const SSL_CIPHER *cipher;
+
+ cipher = SSL_get_current_cipher (ptr->ssl);
+ if (!cipher)
+ return 0;
+ return (uint16_t)SSL_CIPHER_get_id (cipher);
+}
+
+MONO_API int
+mono_btls_ssl_set_cipher_list (MonoBtlsSsl *ptr, const char *str)
+{
+ return SSL_set_cipher_list(ptr->ssl, str);
+}
+
+MONO_API int
+mono_btls_ssl_get_ciphers (MonoBtlsSsl *ptr, uint16_t **data)
+{
+ STACK_OF(SSL_CIPHER) *ciphers;
+ int count, i;
+
+ *data = NULL;
+
+ ciphers = SSL_get_ciphers (ptr->ssl);
+ if (!ciphers)
+ return 0;
+
+ count = (int)sk_SSL_CIPHER_num (ciphers);
+
+ *data = OPENSSL_malloc (2 * count);
+ if (!*data)
+ return 0;
+
+ for (i = 0; i < count; i++) {
+ const SSL_CIPHER *cipher = sk_SSL_CIPHER_value (ciphers, i);
+ (*data) [i] = (uint16_t) SSL_CIPHER_get_id (cipher);
+ }
+
+ return count;
+}
+
+MONO_API X509 *
+mono_btls_ssl_get_peer_certificate (MonoBtlsSsl *ptr)
+{
+ return SSL_get_peer_certificate (ptr->ssl);
+}
+
+MONO_API int
+mono_btls_ssl_get_error (MonoBtlsSsl *ptr, int ret_code)
+{
+ return SSL_get_error (ptr->ssl, ret_code);
+}
+
+MONO_API int
+mono_btls_ssl_set_verify_param (MonoBtlsSsl *ptr, const MonoBtlsX509VerifyParam *param)
+{
+ return SSL_set1_param (ptr->ssl, mono_btls_x509_verify_param_peek_param (param));
+}
+
+MONO_API int
+mono_btls_ssl_set_server_name (MonoBtlsSsl *ptr, const char *name)
+{
+ return SSL_set_tlsext_host_name (ptr->ssl, name);
+}
diff --git a/mono/btls/btls-ssl.h b/mono/btls/btls-ssl.h
new file mode 100644
index 0000000000..10da436488
--- /dev/null
+++ b/mono/btls/btls-ssl.h
@@ -0,0 +1,83 @@
+//
+// btls-ssl.h
+// MonoBtls
+//
+// Created by Martin Baulig on 14/11/15.
+// Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_ssl__
+#define __btls__btls_ssl__
+
+#include
+
+MonoBtlsSsl *
+mono_btls_ssl_new (MonoBtlsSslCtx *ctx);
+
+int
+mono_btls_ssl_use_certificate (MonoBtlsSsl *ptr, X509 *x509);
+
+int
+mono_btls_ssl_use_private_key (MonoBtlsSsl *ptr, EVP_PKEY *key);
+
+int
+mono_btls_ssl_add_chain_certificate (MonoBtlsSsl *ptr, X509 *x509);
+
+int
+mono_btls_ssl_accept (MonoBtlsSsl *ptr);
+
+int
+mono_btls_ssl_connect (MonoBtlsSsl *ptr);
+
+int
+mono_btls_ssl_handshake (MonoBtlsSsl *ptr);
+
+void
+mono_btls_ssl_print_errors_cb (ERR_print_errors_callback_t callback, void *ctx);
+
+void
+mono_btls_ssl_set_bio (MonoBtlsSsl *ptr, BIO *bio);
+
+int
+mono_btls_ssl_read (MonoBtlsSsl *ptr, void *buf, int count);
+
+int
+mono_btls_ssl_write (MonoBtlsSsl *ptr, void *buf, int count);
+
+int
+mono_btls_ssl_get_version (MonoBtlsSsl *ptr);
+
+void
+mono_btls_ssl_set_min_version (MonoBtlsSsl *ptr, int version);
+
+void
+mono_btls_ssl_set_max_version (MonoBtlsSsl *ptr, int version);
+
+int
+mono_btls_ssl_get_cipher (MonoBtlsSsl *ptr);
+
+int
+mono_btls_ssl_set_cipher_list (MonoBtlsSsl *ptr, const char *str);
+
+int
+mono_btls_ssl_get_ciphers (MonoBtlsSsl *ptr, uint16_t **data);
+
+X509 *
+mono_btls_ssl_get_peer_certificate (MonoBtlsSsl *ptr);
+
+void
+mono_btls_ssl_close (MonoBtlsSsl *ptr);
+
+int
+mono_btls_ssl_get_error (MonoBtlsSsl *ptr, int ret_code);
+
+int
+mono_btls_ssl_set_verify_param (MonoBtlsSsl *ptr, const MonoBtlsX509VerifyParam *param);
+
+int
+mono_btls_ssl_set_server_name (MonoBtlsSsl *ptr, const char *name);
+
+void
+mono_btls_ssl_destroy (MonoBtlsSsl *ptr);
+
+#endif /* defined(__btls__btls_ssl__) */
diff --git a/mono/btls/btls-time64.c b/mono/btls/btls-time64.c
new file mode 100644
index 0000000000..5c67546911
--- /dev/null
+++ b/mono/btls/btls-time64.c
@@ -0,0 +1,158 @@
+/*
+
+Copyright (c) 2007-2008 Michael G Schwern
+
+This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
+
+The MIT License:
+
+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.
+
+*/
+
+/* See http://code.google.com/p/y2038 for this code's origin */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Spec says except for stftime() and the _r() functions, these
+ all return static memory. Stabbings! */
+static struct tm Static_Return_Date;
+static char Static_Return_String[35];
+
+static const int days_in_month[2][12] = {
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+};
+
+static const int julian_days_by_month[2][12] = {
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
+};
+
+static char const wday_name[7][3] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+static char const mon_name[12][3] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static const int length_of_year[2] = { 365, 366 };
+
+/* Some numbers relating to the gregorian cycle */
+static const int64_t years_in_gregorian_cycle = 400;
+#define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1)
+static const int64_t seconds_in_gregorian_cycle = days_in_gregorian_cycle * 60LL * 60LL * 24LL;
+
+/* Year range we can trust the time funcitons with */
+#define MAX_SAFE_YEAR 2037
+#define MIN_SAFE_YEAR 1971
+
+/* 28 year Julian calendar cycle */
+#define SOLAR_CYCLE_LENGTH 28
+
+/* Year cycle from MAX_SAFE_YEAR down. */
+static const int safe_years_high[SOLAR_CYCLE_LENGTH] = {
+ 2016, 2017, 2018, 2019,
+ 2020, 2021, 2022, 2023,
+ 2024, 2025, 2026, 2027,
+ 2028, 2029, 2030, 2031,
+ 2032, 2033, 2034, 2035,
+ 2036, 2037, 2010, 2011,
+ 2012, 2013, 2014, 2015
+};
+
+/* Year cycle from MIN_SAFE_YEAR up */
+static const int safe_years_low[SOLAR_CYCLE_LENGTH] = {
+ 1996, 1997, 1998, 1971,
+ 1972, 1973, 1974, 1975,
+ 1976, 1977, 1978, 1979,
+ 1980, 1981, 1982, 1983,
+ 1984, 1985, 1986, 1987,
+ 1988, 1989, 1990, 1991,
+ 1992, 1993, 1994, 1995,
+};
+
+/* Let's assume people are going to be looking for dates in the future.
+ Let's provide some cheats so you can skip ahead.
+ This has a 4x speed boost when near 2008.
+*/
+/* Number of days since epoch on Jan 1st, 2008 GMT */
+#define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
+#define CHEAT_YEARS 108
+
+#define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)
+#define WRAP(a,b,m) ((a) = ((a) < 0 ) ? ((b)--, (a) + (m)) : (a))
+
+/* timegm() is not in the C or POSIX spec, but it is such a useful
+ extension I would be remiss in leaving it out. Also I need it
+ for localtime64()
+*/
+int64_t btls_timegm64(const struct tm *date) {
+ int64_t days = 0;
+ int64_t seconds = 0;
+ int64_t year;
+ int64_t orig_year = (int64_t)date->tm_year;
+ int cycles = 0;
+
+ if( orig_year > 100 ) {
+ cycles = (orig_year - 100) / 400;
+ orig_year -= cycles * 400;
+ days += (int64_t)cycles * days_in_gregorian_cycle;
+ }
+ else if( orig_year < -300 ) {
+ cycles = (orig_year - 100) / 400;
+ orig_year -= cycles * 400;
+ days += (int64_t)cycles * days_in_gregorian_cycle;
+ }
+
+ if( orig_year > 70 ) {
+ year = 70;
+ while( year < orig_year ) {
+ days += length_of_year[IS_LEAP(year)];
+ year++;
+ }
+ }
+ else if ( orig_year < 70 ) {
+ year = 69;
+ do {
+ days -= length_of_year[IS_LEAP(year)];
+ year--;
+ } while( year >= orig_year );
+ }
+
+
+ days += julian_days_by_month[IS_LEAP(orig_year)][date->tm_mon];
+ days += date->tm_mday - 1;
+
+ seconds = days * 60 * 60 * 24;
+
+ seconds += date->tm_hour * 60 * 60;
+ seconds += date->tm_min * 60;
+ seconds += date->tm_sec;
+
+ return(seconds);
+}
diff --git a/mono/btls/btls-util.c b/mono/btls/btls-util.c
new file mode 100644
index 0000000000..7c7f4ca5b4
--- /dev/null
+++ b/mono/btls/btls-util.c
@@ -0,0 +1,77 @@
+//
+// btls-util.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/23/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+#include
+// #include
+
+extern int asn1_generalizedtime_to_tm (struct tm *tm, const ASN1_GENERALIZEDTIME *d);
+
+extern int64_t btls_timegm64 (const struct tm *date);
+
+
+MONO_API void
+mono_btls_free (void *data)
+{
+ OPENSSL_free (data);
+}
+
+int64_t
+mono_btls_util_asn1_time_to_ticks (ASN1_TIME *time)
+{
+ ASN1_GENERALIZEDTIME *gtime;
+ struct tm tm;
+ int64_t epoch;
+ int ret;
+
+ memset (&tm, 0, sizeof (tm));
+
+ gtime = ASN1_TIME_to_generalizedtime (time, NULL);
+ ret = asn1_generalizedtime_to_tm (&tm, gtime);
+ ASN1_GENERALIZEDTIME_free (gtime);
+ epoch = btls_timegm64 (&tm);
+
+ return epoch;
+}
+
+// Copied from crypto/bio/printf.c, takes va_list
+int
+mono_btls_debug_printf (BIO *bio, const char *format, va_list args)
+{
+ char buf[256], *out, out_malloced = 0;
+ int out_len, ret;
+
+ out_len = vsnprintf (buf, sizeof(buf), format, args);
+ if (out_len < 0) {
+ return -1;
+ }
+
+ if ((size_t) out_len >= sizeof(buf)) {
+ const int requested_len = out_len;
+ /* The output was truncated. Note that vsnprintf's return value
+ * does not include a trailing NUL, but the buffer must be sized
+ * for it. */
+ out = OPENSSL_malloc (requested_len + 1);
+ out_malloced = 1;
+ if (out == NULL) {
+ OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ out_len = vsnprintf (out, requested_len + 1, format, args);
+ assert(out_len == requested_len);
+ } else {
+ out = buf;
+ }
+
+ ret = BIO_write(bio, out, out_len);
+ if (out_malloced) {
+ OPENSSL_free(out);
+ }
+
+ return ret;
+}
diff --git a/mono/btls/btls-util.h b/mono/btls/btls-util.h
new file mode 100644
index 0000000000..a1b165235b
--- /dev/null
+++ b/mono/btls/btls-util.h
@@ -0,0 +1,45 @@
+//
+// btls-util.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/23/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_util__
+#define __btls__btls_util__
+
+#include
+#include
+#include
+#include
+
+#ifndef MONO_API
+#if defined(_MSC_VER)
+
+#define MONO_API __declspec(dllexport)
+
+#else
+
+#ifdef __GNUC__
+#define MONO_API __attribute__ ((visibility ("default")))
+#else
+#define MONO_API
+#endif
+
+#endif
+#endif
+
+void
+mono_btls_free (void *data);
+
+int64_t
+mono_btls_util_asn1_time_to_ticks (ASN1_TIME *time);
+
+int
+mono_btls_debug_printf (BIO *bio, const char *format, va_list args);
+
+OPENSSL_EXPORT void CRYPTO_refcount_inc(CRYPTO_refcount_t *count);
+OPENSSL_EXPORT int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count);
+
+#endif /* __btls__btls_util__ */
diff --git a/mono/btls/btls-x509-chain.c b/mono/btls/btls-x509-chain.c
new file mode 100644
index 0000000000..5b7082ddb1
--- /dev/null
+++ b/mono/btls/btls-x509-chain.c
@@ -0,0 +1,96 @@
+//
+// btls-x509-chain.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/3/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+
+struct MonoBtlsX509Chain {
+ STACK_OF(X509) *certs;
+ CRYPTO_refcount_t references;
+};
+
+MONO_API MonoBtlsX509Chain *
+mono_btls_x509_chain_new (void)
+{
+ MonoBtlsX509Chain *chain = (MonoBtlsX509Chain *)OPENSSL_malloc (sizeof (MonoBtlsX509Chain));
+ if (chain == NULL)
+ return NULL;
+
+ memset(chain, 0, sizeof(MonoBtlsX509Chain));
+ chain->certs = sk_X509_new_null ();
+ chain->references = 1;
+ return chain;
+}
+
+MONO_API MonoBtlsX509Chain *
+mono_btls_x509_chain_from_certs (STACK_OF(X509) *certs)
+{
+ MonoBtlsX509Chain *chain = (MonoBtlsX509Chain *)OPENSSL_malloc (sizeof (MonoBtlsX509Chain));
+ if (chain == NULL)
+ return NULL;
+
+ memset(chain, 0, sizeof(MonoBtlsX509Chain));
+ chain->certs = X509_chain_up_ref(certs);
+ chain->references = 1;
+ return chain;
+}
+
+MONO_API STACK_OF(X509) *
+mono_btls_x509_chain_peek_certs (MonoBtlsX509Chain *chain)
+{
+ return chain->certs;
+}
+
+MONO_API int
+mono_btls_x509_chain_get_count (MonoBtlsX509Chain *chain)
+{
+ return (int)sk_X509_num(chain->certs);
+}
+
+MONO_API X509 *
+mono_btls_x509_chain_get_cert (MonoBtlsX509Chain *chain, int index)
+{
+ X509 *cert;
+
+ if ((size_t)index >= sk_X509_num(chain->certs))
+ return NULL;
+ cert = sk_X509_value(chain->certs, index);
+ if (cert)
+ X509_up_ref(cert);
+ return cert;
+}
+
+MONO_API STACK_OF(X509) *
+mono_btls_x509_chain_get_certs (MonoBtlsX509Chain *chain)
+{
+ return chain->certs;
+}
+
+MONO_API int
+mono_btls_x509_chain_free (MonoBtlsX509Chain *chain)
+{
+ if (!CRYPTO_refcount_dec_and_test_zero(&chain->references))
+ return 0;
+
+ sk_X509_pop_free(chain->certs, X509_free);
+ OPENSSL_free (chain);
+ return 1;
+}
+
+MONO_API MonoBtlsX509Chain *
+mono_btls_x509_chain_up_ref (MonoBtlsX509Chain *chain)
+{
+ CRYPTO_refcount_inc(&chain->references);
+ return chain;
+}
+
+MONO_API void
+mono_btls_x509_chain_add_cert (MonoBtlsX509Chain *chain, X509 *x509)
+{
+ X509_up_ref(x509);
+ sk_X509_push(chain->certs, x509);
+}
diff --git a/mono/btls/btls-x509-chain.h b/mono/btls/btls-x509-chain.h
new file mode 100644
index 0000000000..68ef5773ba
--- /dev/null
+++ b/mono/btls/btls-x509-chain.h
@@ -0,0 +1,41 @@
+//
+// btls-x509-chain.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/3/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_chain__
+#define __btls__btls_x509_chain__
+
+#include
+#include
+#include
+
+MonoBtlsX509Chain *
+mono_btls_x509_chain_new (void);
+
+MonoBtlsX509Chain *
+mono_btls_x509_chain_from_certs (STACK_OF(X509) *certs);
+
+STACK_OF(X509) *
+mono_btls_x509_chain_peek_certs (MonoBtlsX509Chain *chain);
+
+int
+mono_btls_x509_chain_get_count (MonoBtlsX509Chain *chain);
+
+X509 *
+mono_btls_x509_chain_get_cert (MonoBtlsX509Chain *chain, int index);
+
+MonoBtlsX509Chain *
+mono_btls_x509_chain_up_ref (MonoBtlsX509Chain *chain);
+
+int
+mono_btls_x509_chain_free (MonoBtlsX509Chain *chain);
+
+void
+mono_btls_x509_chain_add_cert (MonoBtlsX509Chain *chain, X509 *x509);
+
+#endif /* defined(__btls__btls_x509_chain__) */
+
diff --git a/mono/btls/btls-x509-crl.c b/mono/btls/btls-x509-crl.c
new file mode 100644
index 0000000000..d496c072f1
--- /dev/null
+++ b/mono/btls/btls-x509-crl.c
@@ -0,0 +1,150 @@
+//
+// btls-x509-crl.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/23/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+#include
+
+struct MonoBtlsX509Crl {
+ X509_CRL *crl;
+ CRYPTO_refcount_t references;
+};
+
+MONO_API MonoBtlsX509Crl *
+mono_btls_x509_crl_from_data (const void *buf, int len, MonoBtlsX509Format format)
+{
+ MonoBtlsX509Crl *crl;
+ BIO *bio;
+
+ crl = OPENSSL_malloc (sizeof (MonoBtlsX509Crl));
+ memset (crl, 0, sizeof(MonoBtlsX509Crl));
+ crl->references = 1;
+
+ bio = BIO_new_mem_buf ((void *)buf, len);
+ switch (format) {
+ case MONO_BTLS_X509_FORMAT_DER:
+ crl->crl = d2i_X509_CRL_bio (bio, NULL);
+ break;
+ case MONO_BTLS_X509_FORMAT_PEM:
+ crl->crl = PEM_read_bio_X509_CRL (bio, NULL, NULL, NULL);
+ break;
+ }
+ BIO_free (bio);
+
+ if (!crl->crl) {
+ OPENSSL_free (crl);
+ return NULL;
+ }
+
+ return crl;
+}
+
+MONO_API MonoBtlsX509Crl *
+mono_btls_x509_crl_ref (MonoBtlsX509Crl *crl)
+{
+ CRYPTO_refcount_inc (&crl->references);
+ return crl;
+}
+
+MONO_API int
+mono_btls_x509_crl_free (MonoBtlsX509Crl *crl)
+{
+ if (!CRYPTO_refcount_dec_and_test_zero (&crl->references))
+ return 0;
+
+ X509_CRL_free (crl->crl);
+ OPENSSL_free (crl);
+ return 1;
+}
+
+MONO_API MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_by_cert (MonoBtlsX509Crl *crl, X509 *x509)
+{
+ X509_REVOKED *revoked;
+ int ret;
+
+ revoked = NULL;
+ ret = X509_CRL_get0_by_cert (crl->crl, &revoked, x509);
+ fprintf (stderr, "mono_btls_x509_crl_get_by_cert: %d - %p\n", ret, revoked);
+
+ if (!ret || !revoked)
+ return NULL;
+
+ return mono_btls_x509_revoked_new (crl, revoked);
+}
+
+MONO_API MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_by_serial (MonoBtlsX509Crl *crl, void *serial, int len)
+{
+ ASN1_INTEGER si;
+ X509_REVOKED *revoked;
+ int ret;
+
+ si.type = V_ASN1_INTEGER;
+ si.length = len;
+ si.data = serial;
+
+ revoked = NULL;
+ ret = X509_CRL_get0_by_serial (crl->crl, &revoked, &si);
+ fprintf (stderr, "mono_btls_x509_crl_get_by_serial: %d - %p\n", ret, revoked);
+
+ if (!ret || !revoked)
+ return NULL;
+
+ return mono_btls_x509_revoked_new (crl, revoked);
+}
+
+MONO_API int
+mono_btls_x509_crl_get_revoked_count (MonoBtlsX509Crl *crl)
+{
+ STACK_OF(X509_REVOKED) *stack;
+
+ stack = X509_CRL_get_REVOKED (crl->crl);
+ return (int)sk_X509_REVOKED_num (stack);
+}
+
+MONO_API MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_revoked (MonoBtlsX509Crl *crl, int index)
+{
+ STACK_OF(X509_REVOKED) *stack;
+ X509_REVOKED *revoked;
+
+ stack = X509_CRL_get_REVOKED (crl->crl);
+ if ((size_t)index >= sk_X509_REVOKED_num (stack))
+ return NULL;
+
+ revoked = sk_X509_REVOKED_value (stack, index);
+ if (!revoked)
+ return NULL;
+
+ return mono_btls_x509_revoked_new (crl, revoked);
+}
+
+MONO_API int64_t
+mono_btls_x509_crl_get_last_update (MonoBtlsX509Crl *crl)
+{
+ return mono_btls_util_asn1_time_to_ticks (X509_CRL_get_lastUpdate (crl->crl));
+}
+
+MONO_API int64_t
+mono_btls_x509_crl_get_next_update (MonoBtlsX509Crl *crl)
+{
+ return mono_btls_util_asn1_time_to_ticks (X509_CRL_get_nextUpdate (crl->crl));
+}
+
+MONO_API int64_t
+mono_btls_x509_crl_get_version (MonoBtlsX509Crl *crl)
+{
+ return X509_CRL_get_version (crl->crl);
+}
+
+MONO_API MonoBtlsX509Name *
+mono_btls_x509_crl_get_issuer (MonoBtlsX509Crl *crl)
+{
+ return mono_btls_x509_name_copy (X509_CRL_get_issuer (crl->crl));
+}
+
diff --git a/mono/btls/btls-x509-crl.h b/mono/btls/btls-x509-crl.h
new file mode 100644
index 0000000000..625037d99a
--- /dev/null
+++ b/mono/btls/btls-x509-crl.h
@@ -0,0 +1,49 @@
+//
+// btls-x509-crl.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/23/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_crl__
+#define __btls__btls_x509_crl__
+
+#include
+#include
+#include
+
+MonoBtlsX509Crl *
+mono_btls_x509_crl_from_data (const void *buf, int len, MonoBtlsX509Format format);
+
+MonoBtlsX509Crl *
+mono_btls_x509_crl_ref (MonoBtlsX509Crl *crl);
+
+int
+mono_btls_x509_crl_free (MonoBtlsX509Crl *crl);
+
+MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_by_cert (MonoBtlsX509Crl *crl, X509 *x509);
+
+MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_by_serial (MonoBtlsX509Crl *crl, void *serial, int len);
+
+int
+mono_btls_x509_crl_get_revoked_count (MonoBtlsX509Crl *crl);
+
+MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_revoked (MonoBtlsX509Crl *crl, int index);
+
+int64_t
+mono_btls_x509_crl_get_last_update (MonoBtlsX509Crl *crl);
+
+int64_t
+mono_btls_x509_crl_get_next_update (MonoBtlsX509Crl *crl);
+
+int64_t
+mono_btls_x509_crl_get_version (MonoBtlsX509Crl *crl);
+
+MonoBtlsX509Name *
+mono_btls_x509_crl_get_issuer (MonoBtlsX509Crl *crl);
+
+#endif /* __btls__btls_x509_crl__ */
diff --git a/mono/btls/btls-x509-lookup-mono.c b/mono/btls/btls-x509-lookup-mono.c
new file mode 100644
index 0000000000..6d9d69a16f
--- /dev/null
+++ b/mono/btls/btls-x509-lookup-mono.c
@@ -0,0 +1,228 @@
+//
+// btls-x509-lookup-mono.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/6/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+#include
+#include
+
+// random high number
+#define MONO_BTLS_X509_L_MONO_ADD 36292
+
+typedef struct MonoLookupNode MonoLookupNode;
+struct MonoLookupNode {
+ MonoBtlsX509LookupMono *mono;
+ MonoLookupNode *next;
+};
+
+typedef struct {
+ MonoLookupNode *nodes;
+} MonoLookup;
+
+struct MonoBtlsX509LookupMono {
+ const void *instance;
+ MonoBtlsX509LookupMono_BySubject by_subject_func;
+ MonoLookup *lookup;
+};
+
+MONO_API MonoBtlsX509LookupMono *
+mono_btls_x509_lookup_mono_new (void)
+{
+ MonoBtlsX509LookupMono *mono;
+
+ mono = OPENSSL_malloc (sizeof (MonoBtlsX509LookupMono));
+ if (!mono)
+ return NULL;
+
+ memset (mono, 0, sizeof (MonoBtlsX509LookupMono));
+ return mono;
+}
+
+MONO_API void
+mono_btls_x509_lookup_mono_init (MonoBtlsX509LookupMono *mono, const void *instance,
+ MonoBtlsX509LookupMono_BySubject by_subject_func)
+{
+ mono->instance = instance;
+ mono->by_subject_func = by_subject_func;
+}
+
+static int
+mono_lookup_install (MonoLookup *lookup, MonoBtlsX509LookupMono *mono)
+{
+ MonoLookupNode *node;
+
+ node = OPENSSL_malloc (sizeof (MonoLookupNode));
+ if (!node)
+ return 0;
+
+ memset (node, 0, sizeof (MonoLookupNode));
+ mono->lookup = lookup;
+ node->mono = mono;
+ node->next = lookup->nodes;
+ lookup->nodes = node;
+ return 1;
+}
+
+static int
+mono_lookup_uninstall (MonoBtlsX509LookupMono *mono)
+{
+ MonoLookupNode **ptr;
+
+ if (!mono->lookup)
+ return 0;
+
+ for (ptr = &mono->lookup->nodes; *ptr; ptr = &(*ptr)->next) {
+ if ((*ptr)->mono == mono) {
+ *ptr = (*ptr)->next;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+MONO_API int
+mono_btls_x509_lookup_mono_free (MonoBtlsX509LookupMono *mono)
+{
+ mono->instance = NULL;
+ mono->by_subject_func = NULL;
+
+ if (mono->lookup) {
+ if (!mono_lookup_uninstall (mono))
+ return 0;
+ }
+
+ mono->lookup = NULL;
+
+ OPENSSL_free (mono);
+ return 1;
+}
+
+static int
+mono_lookup_ctrl (X509_LOOKUP *ctx, int cmd, const char *argp, int64_t argl, char **ret)
+{
+ MonoLookup *lookup = (MonoLookup*)ctx->method_data;
+ MonoBtlsX509LookupMono *mono = (MonoBtlsX509LookupMono*)argp;
+
+ if (!lookup || cmd != MONO_BTLS_X509_L_MONO_ADD)
+ return 0;
+ if (!mono || mono->lookup)
+ return 0;
+
+ return mono_lookup_install (lookup, mono);
+}
+
+static int
+mono_lookup_new (X509_LOOKUP *ctx)
+{
+ MonoLookup *data;
+
+ data = OPENSSL_malloc (sizeof (MonoLookup));
+ if (!data)
+ return 0;
+
+ memset (data, 0, sizeof (MonoLookup));
+ ctx->method_data = (void *)data;
+ return 1;
+}
+
+static void
+mono_lookup_free (X509_LOOKUP *ctx)
+{
+ MonoLookup *lookup;
+ MonoLookupNode *ptr;
+
+ lookup = (MonoLookup *)ctx->method_data;
+ ctx->method_data = NULL;
+ if (!lookup)
+ return;
+
+ ptr = lookup->nodes;
+ lookup->nodes = NULL;
+
+ while (ptr) {
+ MonoLookupNode *node = ptr;
+ ptr = ptr->next;
+
+ if (node->mono)
+ node->mono->lookup = NULL;
+ node->mono = NULL;
+ node->next = NULL;
+ OPENSSL_free (node);
+ }
+
+ OPENSSL_free (lookup);
+}
+
+static int
+mono_lookup_get_by_subject (X509_LOOKUP *ctx, int type, X509_NAME *name, X509_OBJECT *obj_ret)
+{
+ MonoLookup *lookup;
+ MonoBtlsX509Name *name_obj;
+ MonoLookupNode *node;
+ X509 *x509 = NULL;
+ int ret = 0;
+
+ lookup = (MonoLookup *)ctx->method_data;
+
+ if (!lookup || !lookup->nodes)
+ return 0;
+ if (type != X509_LU_X509)
+ return 0;
+
+ name_obj = mono_btls_x509_name_from_name (name);
+ x509 = NULL;
+
+ for (node = lookup->nodes; node; node = node->next) {
+ if (!node->mono || !node->mono->by_subject_func)
+ continue;
+ ret = (* node->mono->by_subject_func) (node->mono->instance, name_obj, &x509);
+ if (ret)
+ break;
+ }
+
+ mono_btls_x509_name_free (name_obj);
+
+ if (!ret) {
+ if (x509)
+ X509_free(x509);
+ return 0;
+ }
+
+ obj_ret->type = X509_LU_X509;
+ obj_ret->data.x509 = x509;
+ return 1;
+}
+
+static X509_LOOKUP_METHOD mono_lookup_method = {
+ "Mono lookup method",
+ mono_lookup_new, /* new */
+ mono_lookup_free, /* free */
+ NULL, /* init */
+ NULL, /* shutdown */
+ mono_lookup_ctrl, /* ctrl */
+ mono_lookup_get_by_subject, /* get_by_subject */
+ NULL, /* get_by_issuer_serial */
+ NULL, /* get_by_fingerprint */
+ NULL, /* get_by_alias */
+};
+
+MONO_API X509_LOOKUP_METHOD *
+mono_btls_x509_lookup_mono_method (void)
+{
+ return &mono_lookup_method;
+}
+
+MONO_API int
+mono_btls_x509_lookup_add_mono (MonoBtlsX509Lookup *lookup, MonoBtlsX509LookupMono *mono)
+{
+ if (mono_btls_x509_lookup_get_type (lookup) != MONO_BTLS_X509_LOOKUP_TYPE_MONO)
+ return 0;
+ return X509_LOOKUP_ctrl (mono_btls_x509_lookup_peek_lookup (lookup),
+ MONO_BTLS_X509_L_MONO_ADD,
+ (void*)mono, 0, NULL);
+}
diff --git a/mono/btls/btls-x509-lookup-mono.h b/mono/btls/btls-x509-lookup-mono.h
new file mode 100644
index 0000000000..06df552c0f
--- /dev/null
+++ b/mono/btls/btls-x509-lookup-mono.h
@@ -0,0 +1,36 @@
+//
+// btls-x509-lookup-mono.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/3/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_lookup_mono__
+#define __btls__btls_x509_lookup_mono__
+
+#include
+#include
+#include
+#include
+
+typedef int (* MonoBtlsX509LookupMono_BySubject) (const void *instance, MonoBtlsX509Name *name, X509 **ret);
+
+MonoBtlsX509LookupMono *
+mono_btls_x509_lookup_mono_new (void);
+
+int
+mono_btls_x509_lookup_mono_free (MonoBtlsX509LookupMono *mono);
+
+void
+mono_btls_x509_lookup_mono_init (MonoBtlsX509LookupMono *mono, const void *instance,
+ MonoBtlsX509LookupMono_BySubject by_subject_func);
+
+int
+mono_btls_x509_lookup_add_mono (MonoBtlsX509Lookup *lookup, MonoBtlsX509LookupMono *mono);
+
+X509_LOOKUP_METHOD *
+mono_btls_x509_lookup_mono_method (void);
+
+#endif /* defined(__btls__btls_x509_lookup_mono__) */
+
diff --git a/mono/btls/btls-x509-lookup.c b/mono/btls/btls-x509-lookup.c
new file mode 100644
index 0000000000..567d19c237
--- /dev/null
+++ b/mono/btls/btls-x509-lookup.c
@@ -0,0 +1,160 @@
+//
+// btls-x509-lookup.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/6/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+#include
+
+struct MonoBtlsX509Lookup {
+ MonoBtlsX509LookupType type;
+ X509_LOOKUP *lookup;
+ int owns_lookup;
+ MonoBtlsX509Store *store;
+ CRYPTO_refcount_t references;
+};
+
+static X509_LOOKUP_METHOD *
+get_lookup_method (MonoBtlsX509LookupType type)
+{
+ switch (type) {
+ case MONO_BTLS_X509_LOOKUP_TYPE_FILE:
+ return X509_LOOKUP_file ();
+ case MONO_BTLS_X509_LOOKUP_TYPE_HASH_DIR:
+ return X509_LOOKUP_hash_dir ();
+ case MONO_BTLS_X509_LOOKUP_TYPE_MONO:
+ return mono_btls_x509_lookup_mono_method ();
+ default:
+ return NULL;
+ }
+}
+
+MONO_API MonoBtlsX509Lookup *
+mono_btls_x509_lookup_new (MonoBtlsX509Store *store, MonoBtlsX509LookupType type)
+{
+ MonoBtlsX509Lookup *lookup;
+ X509_LOOKUP *store_lookup;
+ X509_LOOKUP_METHOD *method;
+
+ method = get_lookup_method (type);
+ if (!method)
+ return NULL;
+
+ lookup = OPENSSL_malloc (sizeof(MonoBtlsX509Lookup));
+ if (!lookup)
+ return NULL;
+
+ store_lookup = X509_STORE_add_lookup (mono_btls_x509_store_peek_store (store), method);
+ if (!store_lookup)
+ return NULL;
+
+ memset (lookup, 0, sizeof(MonoBtlsX509Lookup));
+ // The X509_STORE owns the X509_LOOKUP.
+ lookup->store = mono_btls_x509_store_up_ref (store);
+ lookup->lookup = store_lookup;
+ lookup->owns_lookup = 0;
+ lookup->references = 1;
+ lookup->type = type;
+ return lookup;
+}
+
+MONO_API int
+mono_btls_x509_lookup_load_file (MonoBtlsX509Lookup *lookup, const char *file, MonoBtlsX509FileType type)
+{
+ return X509_LOOKUP_load_file (lookup->lookup, file, type);
+}
+
+MONO_API int
+mono_btls_x509_lookup_add_dir (MonoBtlsX509Lookup *lookup, const char *dir, MonoBtlsX509FileType type)
+{
+ return X509_LOOKUP_add_dir (lookup->lookup, dir, type);
+}
+
+MONO_API MonoBtlsX509Lookup *
+mono_btls_x509_lookup_up_ref (MonoBtlsX509Lookup *lookup)
+{
+ CRYPTO_refcount_inc (&lookup->references);
+ return lookup;
+}
+
+MONO_API int
+mono_btls_x509_lookup_free (MonoBtlsX509Lookup *lookup)
+{
+ if (!CRYPTO_refcount_dec_and_test_zero (&lookup->references))
+ return 0;
+
+ if (lookup->store) {
+ mono_btls_x509_store_free (lookup->store);
+ lookup->store = NULL;
+ }
+
+ if (lookup->lookup) {
+ if (lookup->owns_lookup)
+ X509_LOOKUP_free (lookup->lookup);
+ lookup->lookup = NULL;
+ }
+
+ OPENSSL_free (lookup);
+ return 1;
+}
+
+MONO_API int
+mono_btls_x509_lookup_init (MonoBtlsX509Lookup *lookup)
+{
+ return X509_LOOKUP_init (lookup->lookup);
+}
+
+MONO_API int
+mono_btls_x509_lookup_shutdown (MonoBtlsX509Lookup *lookup)
+{
+ return X509_LOOKUP_shutdown (lookup->lookup);
+}
+
+MONO_API MonoBtlsX509LookupType
+mono_btls_x509_lookup_get_type (MonoBtlsX509Lookup *lookup)
+{
+ return lookup->type;
+}
+
+MONO_API X509_LOOKUP *
+mono_btls_x509_lookup_peek_lookup (MonoBtlsX509Lookup *lookup)
+{
+ return lookup->lookup;
+}
+
+MONO_API X509 *
+mono_btls_x509_lookup_by_subject (MonoBtlsX509Lookup *lookup, MonoBtlsX509Name *name)
+{
+ X509_OBJECT obj;
+ X509 *x509;
+ int ret;
+
+ ret = X509_LOOKUP_by_subject (lookup->lookup, X509_LU_X509, mono_btls_x509_name_peek_name (name), &obj);
+ if (ret != X509_LU_X509) {
+ X509_OBJECT_free_contents (&obj);
+ return NULL;
+ }
+
+ x509 = X509_up_ref (obj.data.x509);
+ return x509;
+}
+
+MONO_API X509 *
+mono_btls_x509_lookup_by_fingerprint (MonoBtlsX509Lookup *lookup, unsigned char *bytes, int len)
+{
+ X509_OBJECT obj;
+ X509 *x509;
+ int ret;
+
+ ret = X509_LOOKUP_by_fingerprint (lookup->lookup, X509_LU_X509, bytes, len, &obj);
+ if (ret != X509_LU_X509) {
+ X509_OBJECT_free_contents (&obj);
+ return NULL;
+ }
+
+ x509 = X509_up_ref (obj.data.x509);
+ return x509;
+}
diff --git a/mono/btls/btls-x509-lookup.h b/mono/btls/btls-x509-lookup.h
new file mode 100644
index 0000000000..df3d37f1ce
--- /dev/null
+++ b/mono/btls/btls-x509-lookup.h
@@ -0,0 +1,58 @@
+//
+// btls-x509-lookup.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/3/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_lookup__
+#define __btls__btls_x509_lookup__
+
+#include
+#include
+#include
+#include
+
+typedef enum {
+ MONO_BTLS_X509_LOOKUP_TYPE_UNKNOWN = 0,
+ MONO_BTLS_X509_LOOKUP_TYPE_FILE,
+ MONO_BTLS_X509_LOOKUP_TYPE_HASH_DIR,
+ MONO_BTLS_X509_LOOKUP_TYPE_MONO
+} MonoBtlsX509LookupType;
+
+MonoBtlsX509Lookup *
+mono_btls_x509_lookup_new (MonoBtlsX509Store *store, MonoBtlsX509LookupType type);
+
+int
+mono_btls_x509_lookup_load_file (MonoBtlsX509Lookup *lookup, const char *file, MonoBtlsX509FileType type);
+
+int
+mono_btls_x509_lookup_add_dir (MonoBtlsX509Lookup *lookup, const char *dir, MonoBtlsX509FileType type);
+
+MonoBtlsX509Lookup *
+mono_btls_x509_lookup_up_ref (MonoBtlsX509Lookup *lookup);
+
+int
+mono_btls_x509_lookup_free (MonoBtlsX509Lookup *lookup);
+
+int
+mono_btls_x509_lookup_init (MonoBtlsX509Lookup *lookup);
+
+MonoBtlsX509LookupType
+mono_btls_x509_lookup_get_type (MonoBtlsX509Lookup *lookup);
+
+X509_LOOKUP *
+mono_btls_x509_lookup_peek_lookup (MonoBtlsX509Lookup *lookup);
+
+int
+mono_btls_x509_lookup_shutdown (MonoBtlsX509Lookup *lookup);
+
+X509 *
+mono_btls_x509_lookup_by_subject (MonoBtlsX509Lookup *lookup, MonoBtlsX509Name *name);
+
+X509 *
+mono_btls_x509_lookup_by_fingerprint (MonoBtlsX509Lookup *lookup, unsigned char *bytes, int len);
+
+#endif /* defined(__btls__btls_x509_lookup__) */
+
diff --git a/mono/btls/btls-x509-name.c b/mono/btls/btls-x509-name.c
new file mode 100644
index 0000000000..7f98758800
--- /dev/null
+++ b/mono/btls/btls-x509-name.c
@@ -0,0 +1,296 @@
+//
+// btls-x509-name.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/5/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+
+struct MonoBtlsX509Name {
+ int owns;
+ X509_NAME *name;
+};
+
+MONO_API MonoBtlsX509Name *
+mono_btls_x509_name_from_name (X509_NAME *xn)
+{
+ MonoBtlsX509Name *name;
+
+ name = OPENSSL_malloc (sizeof (MonoBtlsX509Name));
+ if (!name)
+ return NULL;
+
+ memset(name, 0, sizeof(MonoBtlsX509Name));
+ name->name = xn;
+ return name;
+}
+
+MONO_API MonoBtlsX509Name *
+mono_btls_x509_name_copy (X509_NAME *xn)
+{
+ MonoBtlsX509Name *name;
+
+ name = OPENSSL_malloc (sizeof (MonoBtlsX509Name));
+ if (!name)
+ return NULL;
+
+ memset(name, 0, sizeof(MonoBtlsX509Name));
+ name->name = X509_NAME_dup(xn);
+ name->owns = 1;
+ return name;
+}
+
+MONO_API void
+mono_btls_x509_name_free (MonoBtlsX509Name *name)
+{
+ if (name->owns) {
+ if (name->name) {
+ X509_NAME_free(name->name);
+ name->name = NULL;
+ }
+ }
+ OPENSSL_free(name);
+}
+
+MONO_API X509_NAME *
+mono_btls_x509_name_peek_name (MonoBtlsX509Name *name)
+{
+ return name->name;
+}
+
+MONO_API int
+mono_btls_x509_name_print_bio (MonoBtlsX509Name *name, BIO *bio)
+{
+ return X509_NAME_print_ex (bio, name->name, 0, ASN1_STRFLGS_RFC2253 | XN_FLAG_FN_SN | XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_DN_REV);
+}
+
+MONO_API int
+mono_btls_x509_name_get_raw_data (MonoBtlsX509Name *name, void **buffer, int use_canon_enc)
+{
+ int len;
+ void *ptr;
+
+ if (use_canon_enc) {
+ // make sure canon_enc is initialized.
+ i2d_X509_NAME (name->name, NULL);
+
+ len = name->name->canon_enclen;
+ ptr = name->name->canon_enc;
+ } else {
+ len = (int)name->name->bytes->length;
+ ptr = name->name->bytes->data;
+ }
+
+ *buffer = OPENSSL_malloc (len);
+ if (!*buffer)
+ return 0;
+
+ memcpy (*buffer, ptr, len);
+ return len;
+}
+
+MONO_API MonoBtlsX509Name *
+mono_btls_x509_name_from_data (const void *data, int len, int use_canon_enc)
+{
+ MonoBtlsX509Name *name;
+ uint8_t *buf;
+ const unsigned char *ptr;
+ X509_NAME *ret;
+
+ name = OPENSSL_malloc (sizeof (MonoBtlsX509Name));
+ if (!name)
+ return NULL;
+
+ memset (name, 0, sizeof(MonoBtlsX509Name));
+ name->owns = 1;
+
+ name->name = X509_NAME_new ();
+ if (!name->name) {
+ OPENSSL_free (name);
+ return NULL;
+ }
+
+ if (use_canon_enc) {
+ CBB cbb, contents;
+ size_t buf_len;
+
+ // re-add ASN1 SEQUENCE header.
+ CBB_init(&cbb, 0);
+ if (!CBB_add_asn1(&cbb, &contents, 0x30) ||
+ !CBB_add_bytes(&contents, data, len) ||
+ !CBB_finish(&cbb, &buf, &buf_len)) {
+ CBB_cleanup (&cbb);
+ mono_btls_x509_name_free (name);
+ return NULL;
+ }
+
+ ptr = buf;
+ len = (int)buf_len;
+ } else {
+ ptr = data;
+ buf = NULL;
+ }
+
+ ret = d2i_X509_NAME (&name->name, &ptr, len);
+
+ if (buf)
+ OPENSSL_free (buf);
+
+ if (ret != name->name) {
+ mono_btls_x509_name_free (name);
+ return NULL;
+ }
+
+ return name;
+}
+
+MONO_API int
+mono_btls_x509_name_print_string (MonoBtlsX509Name *name, char *buffer, int size)
+{
+ *buffer = 0;
+ return X509_NAME_oneline (name->name, buffer, size) != NULL;
+}
+
+MONO_API int64_t
+mono_btls_x509_name_hash (MonoBtlsX509Name *name)
+{
+ return X509_NAME_hash (name->name);
+}
+
+MONO_API int64_t
+mono_btls_x509_name_hash_old (MonoBtlsX509Name *name)
+{
+ return X509_NAME_hash_old (name->name);
+}
+
+MONO_API int
+mono_btls_x509_name_get_entry_count (MonoBtlsX509Name *name)
+{
+ return X509_NAME_entry_count (name->name);
+}
+
+static MonoBtlsX509NameEntryType
+nid2mono (int nid)
+{
+ switch (nid) {
+ case NID_countryName:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_COUNTRY_NAME;
+ case NID_organizationName:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_ORGANIZATION_NAME;
+ case NID_organizationalUnitName:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_ORGANIZATIONAL_UNIT_NAME;
+ case NID_commonName:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_COMMON_NAME;
+ case NID_localityName:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_LOCALITY_NAME;
+ case NID_stateOrProvinceName:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_STATE_OR_PROVINCE_NAME;
+ case NID_streetAddress:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_STREET_ADDRESS;
+ case NID_serialNumber:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_SERIAL_NUMBER;
+ case NID_domainComponent:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_DOMAIN_COMPONENT;
+ case NID_userId:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_USER_ID;
+ case NID_dnQualifier:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_DN_QUALIFIER;
+ case NID_title:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_TITLE;
+ case NID_surname:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_SURNAME;
+ case NID_givenName:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_GIVEN_NAME;
+ case NID_initials:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_INITIAL;
+ default:
+ return MONO_BTLS_X509_NAME_ENTRY_TYPE_UNKNOWN;
+ }
+}
+
+MONO_API MonoBtlsX509NameEntryType
+mono_btls_x509_name_get_entry_type (MonoBtlsX509Name *name, int index)
+{
+ X509_NAME_ENTRY *entry;
+ ASN1_OBJECT *obj;
+
+ if (index >= X509_NAME_entry_count (name->name))
+ return -1;
+
+ entry = X509_NAME_get_entry (name->name, index);
+ if (!entry)
+ return -1;
+
+ obj = X509_NAME_ENTRY_get_object (entry);
+ if (!obj)
+ return -1;
+
+ return nid2mono (OBJ_obj2nid (obj));
+}
+
+MONO_API int
+mono_btls_x509_name_get_entry_oid (MonoBtlsX509Name *name, int index, char *buffer, int size)
+{
+ X509_NAME_ENTRY *entry;
+ ASN1_OBJECT *obj;
+
+ if (index >= X509_NAME_entry_count (name->name))
+ return 0;
+
+ entry = X509_NAME_get_entry (name->name, index);
+ if (!entry)
+ return 0;
+
+ obj = X509_NAME_ENTRY_get_object (entry);
+ if (!obj)
+ return 0;
+
+ return OBJ_obj2txt (buffer, size, obj, 1);
+}
+
+MONO_API int
+mono_btls_x509_name_get_entry_oid_data (MonoBtlsX509Name *name, int index, const void **data)
+{
+ X509_NAME_ENTRY *entry;
+ ASN1_OBJECT *obj;
+
+ if (index >= X509_NAME_entry_count (name->name))
+ return -1;
+
+ entry = X509_NAME_get_entry (name->name, index);
+ if (!entry)
+ return -1;
+
+ obj = X509_NAME_ENTRY_get_object (entry);
+ if (!obj)
+ return -1;
+
+ *data = obj->data;
+ return obj->length;
+}
+
+MONO_API int
+mono_btls_x509_name_get_entry_value (MonoBtlsX509Name *name, int index, int *tag, unsigned char **str)
+{
+ X509_NAME_ENTRY *entry;
+ ASN1_STRING *data;
+
+ *str = NULL;
+ *tag = 0;
+
+ if (index >= X509_NAME_entry_count (name->name))
+ return 0;
+
+ entry = X509_NAME_get_entry (name->name, index);
+ if (!entry)
+ return 0;
+
+ data = X509_NAME_ENTRY_get_data (entry);
+ if (!data)
+ return 0;
+
+ *tag = data->type;
+ return ASN1_STRING_to_UTF8 (str, data);
+}
diff --git a/mono/btls/btls-x509-name.h b/mono/btls/btls-x509-name.h
new file mode 100644
index 0000000000..9d43bc6499
--- /dev/null
+++ b/mono/btls/btls-x509-name.h
@@ -0,0 +1,80 @@
+//
+// btls-x509-name.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/5/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_name__
+#define __btls__btls_x509_name__
+
+#include
+#include
+
+typedef enum {
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_UNKNOWN = 0,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_COUNTRY_NAME,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_ORGANIZATION_NAME,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_ORGANIZATIONAL_UNIT_NAME,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_COMMON_NAME,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_LOCALITY_NAME,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_STATE_OR_PROVINCE_NAME,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_STREET_ADDRESS,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_SERIAL_NUMBER,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_DOMAIN_COMPONENT,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_USER_ID,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_EMAIL,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_DN_QUALIFIER,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_TITLE,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_SURNAME,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_GIVEN_NAME,
+ MONO_BTLS_X509_NAME_ENTRY_TYPE_INITIAL
+} MonoBtlsX509NameEntryType;
+
+MonoBtlsX509Name *
+mono_btls_x509_name_from_name (X509_NAME *name);
+
+MonoBtlsX509Name *
+mono_btls_x509_name_copy (X509_NAME *xn);
+
+void
+mono_btls_x509_name_free (MonoBtlsX509Name *name);
+
+X509_NAME *
+mono_btls_x509_name_peek_name (MonoBtlsX509Name *name);
+
+MonoBtlsX509Name *
+mono_btls_x509_name_from_data (const void *data, int len, int use_canon_enc);
+
+int
+mono_btls_x509_name_print_bio (MonoBtlsX509Name *name, BIO *bio);
+
+int
+mono_btls_x509_name_print_string (MonoBtlsX509Name *name, char *buffer, int size);
+
+int
+mono_btls_x509_name_get_raw_data (MonoBtlsX509Name *name, void **buffer, int use_canon_enc);
+
+int64_t
+mono_btls_x509_name_hash (MonoBtlsX509Name *name);
+
+int64_t
+mono_btls_x509_name_hash_old (MonoBtlsX509Name *name);
+
+int
+mono_btls_x509_name_get_entry_count (MonoBtlsX509Name *name);
+
+MonoBtlsX509NameEntryType
+mono_btls_x509_name_get_entry_type (MonoBtlsX509Name *name, int index);
+
+int
+mono_btls_x509_name_get_entry_oid (MonoBtlsX509Name *name, int index, char *buffer, int size);
+
+int
+mono_btls_x509_name_get_entry_oid_data (MonoBtlsX509Name *name, int index, const void **data);
+
+int
+mono_btls_x509_name_get_entry_value (MonoBtlsX509Name *name, int index, int *tag, unsigned char **str);
+
+#endif /* __btls__btls_x509_name__ */
diff --git a/mono/btls/btls-x509-revoked.c b/mono/btls/btls-x509-revoked.c
new file mode 100644
index 0000000000..bf9af79de4
--- /dev/null
+++ b/mono/btls/btls-x509-revoked.c
@@ -0,0 +1,72 @@
+//
+// btls-x509-revoked.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/23/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+
+struct MonoBtlsX509Revoked {
+ MonoBtlsX509Crl *owner;
+ X509_REVOKED *revoked;
+};
+
+MONO_API MonoBtlsX509Revoked *
+mono_btls_x509_revoked_new (MonoBtlsX509Crl *owner, X509_REVOKED *revoked)
+{
+ MonoBtlsX509Revoked *instance;
+
+ instance = OPENSSL_malloc (sizeof (MonoBtlsX509Revoked));
+ memset (instance, 0, sizeof (MonoBtlsX509Revoked));
+
+ instance->owner = mono_btls_x509_crl_ref (owner);
+ instance->revoked = revoked;
+ return instance;
+}
+
+MONO_API void
+mono_btls_x509_revoked_free (MonoBtlsX509Revoked *revoked)
+{
+ mono_btls_x509_crl_free (revoked->owner);
+ OPENSSL_free (revoked);
+}
+
+MONO_API int
+mono_btls_x509_revoked_get_serial_number (MonoBtlsX509Revoked *revoked, char *buffer, int size)
+{
+ ASN1_INTEGER *serial;
+
+ serial = revoked->revoked->serialNumber;
+ if (serial->length == 0 || serial->length+1 > size)
+ return 0;
+
+ memcpy (buffer, serial->data, serial->length);
+ return serial->length;
+}
+
+MONO_API int64_t
+mono_btls_x509_revoked_get_revocation_date (MonoBtlsX509Revoked *revoked)
+{
+ ASN1_TIME *date;
+
+ date = revoked->revoked->revocationDate;
+ if (!date)
+ return 0;
+
+ return mono_btls_util_asn1_time_to_ticks (date);
+}
+
+MONO_API int
+mono_btls_x509_revoked_get_reason (MonoBtlsX509Revoked *revoked)
+{
+ return revoked->revoked->reason;
+}
+
+MONO_API int
+mono_btls_x509_revoked_get_sequence (MonoBtlsX509Revoked *revoked)
+{
+ return revoked->revoked->sequence;
+}
+
diff --git a/mono/btls/btls-x509-revoked.h b/mono/btls/btls-x509-revoked.h
new file mode 100644
index 0000000000..592fc9316a
--- /dev/null
+++ b/mono/btls/btls-x509-revoked.h
@@ -0,0 +1,34 @@
+//
+// btls-x509-revoked.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/23/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_revoked__
+#define __btls__btls_x509_revoked__
+
+#include
+#include
+#include
+
+MonoBtlsX509Revoked *
+mono_btls_x509_revoked_new (MonoBtlsX509Crl *owner, X509_REVOKED *revoked);
+
+void
+mono_btls_x509_revoked_free (MonoBtlsX509Revoked *revoked);
+
+int
+mono_btls_x509_revoked_get_serial_number (MonoBtlsX509Revoked *revoked, char *buffer, int size);
+
+int64_t
+mono_btls_x509_revoked_get_revocation_date (MonoBtlsX509Revoked *revoked);
+
+int
+mono_btls_x509_revoked_get_reason (MonoBtlsX509Revoked *revoked);
+
+int
+mono_btls_x509_revoked_get_sequence (MonoBtlsX509Revoked *revoked);
+
+#endif /* __btls__btls_x509_revoked__ */
diff --git a/mono/btls/btls-x509-store-ctx.c b/mono/btls/btls-x509-store-ctx.c
new file mode 100644
index 0000000000..8bbb732ac7
--- /dev/null
+++ b/mono/btls/btls-x509-store-ctx.c
@@ -0,0 +1,217 @@
+//
+// btls-x509-store-ctx.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/5/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+
+struct MonoBtlsX509StoreCtx {
+ int owns;
+ X509_STORE_CTX *ctx;
+ CRYPTO_refcount_t references;
+ MonoBtlsX509Store *store;
+ MonoBtlsX509Chain *chain;
+};
+
+MONO_API MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_from_ptr (X509_STORE_CTX *ptr)
+{
+ MonoBtlsX509StoreCtx *ctx;
+
+ ctx = OPENSSL_malloc (sizeof(MonoBtlsX509StoreCtx));
+ if (!ctx)
+ return NULL;
+
+ memset (ctx, 0, sizeof (MonoBtlsX509StoreCtx));
+ ctx->ctx = ptr;
+ ctx->references = 1;
+ return ctx;
+}
+
+MONO_API MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_new (void)
+{
+ MonoBtlsX509StoreCtx *ctx;
+
+ ctx = OPENSSL_malloc (sizeof(MonoBtlsX509StoreCtx));
+ if (!ctx)
+ return NULL;
+
+ memset (ctx, 0, sizeof (MonoBtlsX509StoreCtx));
+ ctx->ctx = X509_STORE_CTX_new ();
+ ctx->references = 1;
+ ctx->owns = 1;
+ return ctx;
+}
+
+MONO_API MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_up_ref (MonoBtlsX509StoreCtx *ctx)
+{
+ CRYPTO_refcount_inc (&ctx->references);
+ return ctx;
+}
+
+MONO_API int
+mono_btls_x509_store_ctx_free (MonoBtlsX509StoreCtx *ctx)
+{
+ if (!CRYPTO_refcount_dec_and_test_zero (&ctx->references))
+ return 0;
+
+ if (ctx->owns) {
+ X509_STORE_CTX_cleanup (ctx->ctx);
+ X509_STORE_CTX_free (ctx->ctx);
+ ctx->owns = 0;
+ }
+ if (ctx->store) {
+ mono_btls_x509_store_free (ctx->store);
+ ctx->store = NULL;
+ }
+ if (ctx->chain) {
+ mono_btls_x509_chain_free (ctx->chain);
+ ctx->chain = NULL;
+ }
+ OPENSSL_free (ctx);
+ return 1;
+}
+
+MONO_API int
+mono_btls_x509_store_ctx_get_error (MonoBtlsX509StoreCtx *ctx, const char **error_string)
+{
+ int error;
+
+ error = X509_STORE_CTX_get_error (ctx->ctx);
+ if (error_string)
+ *error_string = X509_verify_cert_error_string (error);
+ return error;
+}
+
+MONO_API int
+mono_btls_x509_store_ctx_get_error_depth (MonoBtlsX509StoreCtx *ctx)
+{
+ return X509_STORE_CTX_get_error_depth (ctx->ctx);
+}
+
+MONO_API MonoBtlsX509Chain *
+mono_btls_x509_store_ctx_get_chain (MonoBtlsX509StoreCtx *ctx)
+{
+ STACK_OF(X509) *certs;
+
+ certs = X509_STORE_CTX_get_chain (ctx->ctx);
+ if (!certs)
+ return NULL;
+
+ return mono_btls_x509_chain_from_certs (certs);
+}
+
+MONO_API MonoBtlsX509Chain *
+mono_btls_x509_store_ctx_get_untrusted (MonoBtlsX509StoreCtx *ctx)
+{
+ STACK_OF(X509) *untrusted;
+
+ /*
+ * Unfortunately, there is no accessor function for this.
+ *
+ * This is the set of certificate that's passed in by
+ * X509_STORE_CTX_init() and X509_STORE_CTX_set_chain().
+ */
+ untrusted = ctx->ctx->untrusted;
+ if (!untrusted)
+ return NULL;
+
+ return mono_btls_x509_chain_from_certs (untrusted);
+}
+
+MONO_API int
+mono_btls_x509_store_ctx_init (MonoBtlsX509StoreCtx *ctx,
+ MonoBtlsX509Store *store, MonoBtlsX509Chain *chain)
+{
+ STACK_OF(X509) *certs;
+ X509 *leaf;
+ int ret;
+
+ if (ctx->store)
+ return 0;
+
+ certs = mono_btls_x509_chain_peek_certs (chain);
+ if (!certs || !sk_X509_num (certs))
+ return 0;
+
+ ctx->store = mono_btls_x509_store_up_ref(store);
+ ctx->chain = mono_btls_x509_chain_up_ref(chain);
+
+ leaf = sk_X509_value (certs, 0);
+ ret = X509_STORE_CTX_init (ctx->ctx, mono_btls_x509_store_peek_store (store), leaf, certs);
+ if (ret != 1)
+ return ret;
+
+ X509_STORE_CTX_set_app_data (ctx->ctx, ctx);
+ return 1;
+}
+
+MONO_API int
+mono_btls_x509_store_ctx_set_param (MonoBtlsX509StoreCtx *ctx, MonoBtlsX509VerifyParam *param)
+{
+ return X509_VERIFY_PARAM_set1 (X509_STORE_CTX_get0_param (ctx->ctx), mono_btls_x509_verify_param_peek_param (param));
+}
+
+MONO_API int
+mono_btls_x509_store_ctx_verify_cert (MonoBtlsX509StoreCtx *ctx)
+{
+ return X509_verify_cert (ctx->ctx);
+}
+
+MONO_API X509 *
+mono_btls_x509_store_ctx_get_by_subject (MonoBtlsX509StoreCtx *ctx, MonoBtlsX509Name *name)
+{
+ X509_OBJECT obj;
+ X509 *x509;
+ int ret;
+
+ ret = X509_STORE_get_by_subject (ctx->ctx, X509_LU_X509, mono_btls_x509_name_peek_name (name), &obj);
+ if (ret != X509_LU_X509) {
+ X509_OBJECT_free_contents (&obj);
+ return NULL;
+ }
+
+ x509 = X509_up_ref (obj.data.x509);
+ return x509;
+}
+
+MONO_API X509 *
+mono_btls_x509_store_ctx_get_current_cert (MonoBtlsX509StoreCtx *ctx)
+{
+ X509 *x509 = X509_STORE_CTX_get_current_cert (ctx->ctx);
+ if (!x509)
+ return NULL;
+ return X509_up_ref (x509);
+}
+
+MONO_API X509 *
+mono_btls_x509_store_ctx_get_current_issuer (MonoBtlsX509StoreCtx *ctx)
+{
+ X509 *x509 = X509_STORE_CTX_get0_current_issuer (ctx->ctx);
+ if (!x509)
+ return NULL;
+ return X509_up_ref (x509);
+}
+
+MONO_API MonoBtlsX509VerifyParam *
+mono_btls_x509_store_ctx_get_verify_param (MonoBtlsX509StoreCtx *ctx)
+{
+ X509_VERIFY_PARAM *param;
+
+ param = X509_STORE_CTX_get0_param (ctx->ctx);
+ if (!param)
+ return NULL;
+
+ return mono_btls_x509_verify_param_from_store_ctx (ctx, param);
+}
+
+MONO_API int
+mono_btls_x509_store_ctx_get_foo (MonoBtlsX509StoreCtx *ctx)
+{
+ return 0;
+}
diff --git a/mono/btls/btls-x509-store-ctx.h b/mono/btls/btls-x509-store-ctx.h
new file mode 100644
index 0000000000..188092e0cd
--- /dev/null
+++ b/mono/btls/btls-x509-store-ctx.h
@@ -0,0 +1,66 @@
+//
+// btls-x509-store-ctx.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/3/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_store_ctx__
+#define __btls__btls_x509_store_ctx__
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_from_ptr (X509_STORE_CTX *ptr);
+
+MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_new (void);
+
+MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_up_ref (MonoBtlsX509StoreCtx *ctx);
+
+int
+mono_btls_x509_store_ctx_free (MonoBtlsX509StoreCtx *ctx);
+
+int
+mono_btls_x509_store_ctx_get_error (MonoBtlsX509StoreCtx *ctx, const char **error_string);
+
+int
+mono_btls_x509_store_ctx_get_error_depth (MonoBtlsX509StoreCtx *ctx);
+
+MonoBtlsX509Chain *
+mono_btls_x509_store_ctx_get_chain (MonoBtlsX509StoreCtx *ctx);
+
+X509 *
+mono_btls_x509_store_ctx_get_current_cert (MonoBtlsX509StoreCtx *ctx);
+
+X509 *
+mono_btls_x509_store_ctx_get_current_issuer (MonoBtlsX509StoreCtx *ctx);
+
+int
+mono_btls_x509_store_ctx_init (MonoBtlsX509StoreCtx *ctx,
+ MonoBtlsX509Store *store, MonoBtlsX509Chain *chain);
+
+int
+mono_btls_x509_store_ctx_set_param (MonoBtlsX509StoreCtx *ctx, MonoBtlsX509VerifyParam *param);
+
+X509 *
+mono_btls_x509_store_ctx_get_by_subject (MonoBtlsX509StoreCtx *ctx, MonoBtlsX509Name *name);
+
+int
+mono_btls_x509_store_ctx_verify_cert (MonoBtlsX509StoreCtx *ctx);
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_store_ctx_get_verify_param (MonoBtlsX509StoreCtx *ctx);
+
+MonoBtlsX509Chain *
+mono_btls_x509_store_ctx_get_untrusted (MonoBtlsX509StoreCtx *ctx);
+
+#endif /* defined(__btls__btls_x509_store_ctx__) */
+
diff --git a/mono/btls/btls-x509-store.c b/mono/btls/btls-x509-store.c
new file mode 100644
index 0000000000..3534739a6e
--- /dev/null
+++ b/mono/btls/btls-x509-store.c
@@ -0,0 +1,110 @@
+//
+// btls-x509-store.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/3/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+
+struct MonoBtlsX509Store {
+ X509_STORE *store;
+ CRYPTO_refcount_t references;
+};
+
+MONO_API MonoBtlsX509Store *
+mono_btls_x509_store_from_store (X509_STORE *ctx)
+{
+ MonoBtlsX509Store *store;
+
+ store = OPENSSL_malloc (sizeof(MonoBtlsX509Store));
+ if (!store)
+ return NULL;
+
+ memset (store, 0, sizeof(MonoBtlsX509Store));
+ store->store = ctx;
+ CRYPTO_refcount_inc (&store->store->references);
+ store->references = 1;
+ return store;
+}
+
+MONO_API MonoBtlsX509Store *
+mono_btls_x509_store_from_ctx (X509_STORE_CTX *ctx)
+{
+ return mono_btls_x509_store_from_store (ctx->ctx);
+}
+
+MONO_API MonoBtlsX509Store *
+mono_btls_x509_store_new (void)
+{
+ MonoBtlsX509Store *store;
+
+ store = OPENSSL_malloc (sizeof(MonoBtlsX509Store));
+ if (!store)
+ return NULL;
+
+ memset (store, 0, sizeof(MonoBtlsX509Store));
+ store->store = X509_STORE_new ();
+ store->references = 1;
+ return store;
+}
+
+MONO_API X509_STORE *
+mono_btls_x509_store_peek_store (MonoBtlsX509Store *store)
+{
+ return store->store;
+}
+
+MONO_API MonoBtlsX509Store *
+mono_btls_x509_store_from_ssl_ctx (MonoBtlsSslCtx *ctx)
+{
+ X509_STORE *store = mono_btls_ssl_ctx_peek_store (ctx);
+ return mono_btls_x509_store_from_store (store);
+}
+
+MONO_API int
+mono_btls_x509_store_free (MonoBtlsX509Store *store)
+{
+ if (!CRYPTO_refcount_dec_and_test_zero(&store->references))
+ return 0;
+
+ if (store->store) {
+ X509_STORE_free (store->store);
+ store->store = NULL;
+ }
+ OPENSSL_free (store);
+ return 1;
+}
+
+MONO_API MonoBtlsX509Store *
+mono_btls_x509_store_up_ref (MonoBtlsX509Store *store)
+{
+ CRYPTO_refcount_inc (&store->references);
+ return store;
+}
+
+MONO_API int
+mono_btls_x509_store_add_cert (MonoBtlsX509Store *store, X509 *cert)
+{
+ return X509_STORE_add_cert (store->store, cert);
+}
+
+MONO_API int
+mono_btls_x509_store_load_locations (MonoBtlsX509Store *store, const char *file, const char *path)
+{
+ return X509_STORE_load_locations (store->store, file, path);
+}
+
+MONO_API int
+mono_btls_x509_store_set_default_paths (MonoBtlsX509Store *store)
+{
+ return X509_STORE_set_default_paths (store->store);
+}
+
+MONO_API int
+mono_btls_x509_store_get_count (MonoBtlsX509Store *store)
+{
+ return (int)sk_X509_OBJECT_num (store->store->objs);
+}
+
diff --git a/mono/btls/btls-x509-store.h b/mono/btls/btls-x509-store.h
new file mode 100644
index 0000000000..67ffe00cd3
--- /dev/null
+++ b/mono/btls/btls-x509-store.h
@@ -0,0 +1,46 @@
+//
+// btls-x509-store.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/3/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_store__
+#define __btls__btls_x509_store__
+
+#include
+#include
+
+MonoBtlsX509Store *
+mono_btls_x509_store_new (void);
+
+MonoBtlsX509Store *
+mono_btls_x509_store_from_ctx (X509_STORE_CTX *ctx);
+
+MonoBtlsX509Store *
+mono_btls_x509_store_from_ssl_ctx (MonoBtlsSslCtx *ctx);
+
+MonoBtlsX509Store *
+mono_btls_x509_store_up_ref (MonoBtlsX509Store *store);
+
+int
+mono_btls_x509_store_free (MonoBtlsX509Store *store);
+
+X509_STORE *
+mono_btls_x509_store_peek_store (MonoBtlsX509Store *store);
+
+int
+mono_btls_x509_store_add_cert (MonoBtlsX509Store *store, X509 *cert);
+
+int
+mono_btls_x509_store_load_locations (MonoBtlsX509Store *store, const char *file, const char *path);
+
+int
+mono_btls_x509_store_set_default_paths (MonoBtlsX509Store *store);
+
+int
+mono_btls_x509_store_get_count (MonoBtlsX509Store *store);
+
+#endif /* defined(__btls__btls_x509_store__) */
+
diff --git a/mono/btls/btls-x509-verify-param.c b/mono/btls/btls-x509-verify-param.c
new file mode 100644
index 0000000000..24be3da8ca
--- /dev/null
+++ b/mono/btls/btls-x509-verify-param.c
@@ -0,0 +1,221 @@
+//
+// btls-x509-verify-param.c
+// MonoBtls
+//
+// Created by Martin Baulig on 3/5/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include
+#include
+
+struct MonoBtlsX509VerifyParam {
+ int owns;
+ MonoBtlsX509StoreCtx *owner;
+ X509_VERIFY_PARAM *param;
+};
+
+MONO_API MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_new (void)
+{
+ MonoBtlsX509VerifyParam *param;
+
+ param = OPENSSL_malloc (sizeof(MonoBtlsX509VerifyParam));
+ if (!param)
+ return NULL;
+ memset (param, 0, sizeof (MonoBtlsX509VerifyParam));
+ param->param = X509_VERIFY_PARAM_new();
+ param->owns = 1;
+ return param;
+}
+
+MONO_API MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_from_store_ctx (MonoBtlsX509StoreCtx *ctx, X509_VERIFY_PARAM *param)
+{
+ MonoBtlsX509VerifyParam *instance;
+
+ instance = OPENSSL_malloc (sizeof(MonoBtlsX509VerifyParam));
+ if (!instance)
+ return NULL;
+ memset (instance, 0, sizeof (MonoBtlsX509VerifyParam));
+ instance->param = param;
+ instance->owner = mono_btls_x509_store_ctx_up_ref (ctx);
+ return instance;
+}
+
+MONO_API MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_copy (const MonoBtlsX509VerifyParam *from)
+{
+ MonoBtlsX509VerifyParam *param;
+
+ param = mono_btls_x509_verify_param_new ();
+ if (!param)
+ return NULL;
+
+ X509_VERIFY_PARAM_set1 (param->param, from->param);
+ return param;
+}
+
+MONO_API const X509_VERIFY_PARAM *
+mono_btls_x509_verify_param_peek_param (const MonoBtlsX509VerifyParam *param)
+{
+ return param->param;
+}
+
+MONO_API int
+mono_btls_x509_verify_param_can_modify (MonoBtlsX509VerifyParam *param)
+{
+ return param->owns;
+}
+
+MONO_API MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_lookup (const char *name)
+{
+ MonoBtlsX509VerifyParam *param;
+ const X509_VERIFY_PARAM *p;
+
+ p = X509_VERIFY_PARAM_lookup(name);
+ if (!p)
+ return NULL;
+
+ param = OPENSSL_malloc (sizeof(MonoBtlsX509VerifyParam));
+ if (!param)
+ return NULL;
+ memset (param, 0, sizeof (MonoBtlsX509VerifyParam));
+ param->param = (X509_VERIFY_PARAM *)p;
+ return param;
+}
+
+MONO_API void
+mono_btls_x509_verify_param_free (MonoBtlsX509VerifyParam *param)
+{
+ if (param->owns) {
+ if (param->param) {
+ X509_VERIFY_PARAM_free (param->param);
+ param->param = NULL;
+ }
+ }
+ if (param->owner) {
+ mono_btls_x509_store_ctx_free (param->owner);
+ param->owner = NULL;
+ }
+ OPENSSL_free (param);
+}
+
+MONO_API int
+mono_btls_x509_verify_param_set_name (MonoBtlsX509VerifyParam *param, const char *name)
+{
+ if (!param->owns)
+ return -1;
+ return X509_VERIFY_PARAM_set1_name (param->param, name);
+}
+
+MONO_API int
+mono_btls_x509_verify_param_set_host (MonoBtlsX509VerifyParam *param, const char *host, int namelen)
+{
+ if (!param->owns)
+ return -1;
+ return X509_VERIFY_PARAM_set1_host (param->param, host, namelen);
+}
+
+MONO_API int
+mono_btls_x509_verify_param_add_host (MonoBtlsX509VerifyParam *param, const char *host, int namelen)
+{
+ if (!param->owns)
+ return -1;
+ return X509_VERIFY_PARAM_set1_host (param->param, host, namelen);
+}
+
+MONO_API uint64_t
+mono_btls_x509_verify_param_get_flags (MonoBtlsX509VerifyParam *param)
+{
+ return X509_VERIFY_PARAM_get_flags (param->param);
+}
+
+MONO_API int
+mono_btls_x509_verify_param_set_flags (MonoBtlsX509VerifyParam *param, uint64_t flags)
+{
+ if (!param->owns)
+ return -1;
+ return X509_VERIFY_PARAM_set_flags (param->param, flags);
+}
+
+MONO_API MonoBtlsX509VerifyFlags
+mono_btls_x509_verify_param_get_mono_flags (MonoBtlsX509VerifyParam *param)
+{
+ MonoBtlsX509VerifyFlags current;
+ uint64_t flags;
+
+ if (!param->owns)
+ return -1;
+
+ current = 0;
+ flags = X509_VERIFY_PARAM_get_flags (param->param);
+
+ if (flags & X509_V_FLAG_CRL_CHECK)
+ current |= MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK;
+ if (flags & X509_V_FLAG_CRL_CHECK_ALL)
+ current |= MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK_ALL;
+ if (flags & X509_V_FLAG_X509_STRICT)
+ current |= MONO_BTLS_X509_VERIFY_FLAGS_X509_STRICT;
+
+ return current;
+}
+
+MONO_API int
+mono_btls_x509_verify_param_set_mono_flags (MonoBtlsX509VerifyParam *param, MonoBtlsX509VerifyFlags flags)
+{
+ uint64_t current;
+
+ if (!param->owns)
+ return -1;
+
+ current = X509_VERIFY_PARAM_get_flags (param->param);
+ if (flags & MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK)
+ current |= X509_V_FLAG_CRL_CHECK;
+ if (flags & MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK_ALL)
+ current |= X509_V_FLAG_CRL_CHECK_ALL;
+ if (flags & MONO_BTLS_X509_VERIFY_FLAGS_X509_STRICT)
+ current |= X509_V_FLAG_X509_STRICT;
+
+ return X509_VERIFY_PARAM_set_flags (param->param, current);
+}
+
+MONO_API int
+mono_btls_x509_verify_param_set_purpose (MonoBtlsX509VerifyParam *param, MonoBtlsX509Purpose purpose)
+{
+ if (!param->owns)
+ return -1;
+ return X509_VERIFY_PARAM_set_purpose (param->param, purpose);
+}
+
+MONO_API int
+mono_btls_x509_verify_param_get_depth (MonoBtlsX509VerifyParam *param)
+{
+ return X509_VERIFY_PARAM_get_depth (param->param);
+}
+
+MONO_API int
+mono_btls_x509_verify_param_set_depth (MonoBtlsX509VerifyParam *param, int depth)
+{
+ if (!param->owns)
+ return -1;
+ X509_VERIFY_PARAM_set_depth (param->param, depth);
+ return 1;
+}
+
+MONO_API int
+mono_btls_x509_verify_param_set_time (MonoBtlsX509VerifyParam *param, int64_t time)
+{
+ if (!param->owns)
+ return -1;
+ X509_VERIFY_PARAM_set_time (param->param, time);
+ return 1;
+}
+
+MONO_API char *
+mono_btls_x509_verify_param_get_peername (MonoBtlsX509VerifyParam *param)
+{
+ char *peer = X509_VERIFY_PARAM_get0_peername (param->param);
+ return peer;
+}
diff --git a/mono/btls/btls-x509-verify-param.h b/mono/btls/btls-x509-verify-param.h
new file mode 100644
index 0000000000..e85d547fb3
--- /dev/null
+++ b/mono/btls/btls-x509-verify-param.h
@@ -0,0 +1,81 @@
+//
+// btls-x509-verify-param.h
+// MonoBtls
+//
+// Created by Martin Baulig on 3/3/16.
+// Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_verify_param__
+#define __btls__btls_x509_verify_param__
+
+#include
+#include
+#include
+
+typedef enum {
+ MONO_BTLS_X509_VERIFY_FLAGS_DEFAULT = 0,
+ MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK = 1,
+ MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK_ALL = 2,
+ MONO_BTLS_X509_VERIFY_FLAGS_X509_STRICT = 4
+} MonoBtlsX509VerifyFlags;
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_new (void);
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_from_store_ctx (MonoBtlsX509StoreCtx *ctx, X509_VERIFY_PARAM *param);
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_copy (const MonoBtlsX509VerifyParam *from);
+
+void
+mono_btls_x509_verify_param_free (MonoBtlsX509VerifyParam *param);
+
+const X509_VERIFY_PARAM *
+mono_btls_x509_verify_param_peek_param (const MonoBtlsX509VerifyParam *param);
+
+int
+mono_btls_x509_verify_param_can_modify (MonoBtlsX509VerifyParam *param);
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_lookup (const char *name);
+
+int
+mono_btls_x509_verify_param_set_name (MonoBtlsX509VerifyParam *param, const char *name);
+
+int
+mono_btls_x509_verify_param_set_host (MonoBtlsX509VerifyParam *param, const char *host, int namelen);
+
+int
+mono_btls_x509_verify_param_add_host (MonoBtlsX509VerifyParam *param, const char *host, int namelen);
+
+uint64_t
+mono_btls_x509_verify_param_get_flags (MonoBtlsX509VerifyParam *param);
+
+int
+mono_btls_x509_verify_param_set_flags (MonoBtlsX509VerifyParam *param, uint64_t flags);
+
+MonoBtlsX509VerifyFlags
+mono_btls_x509_verify_param_get_mono_flags (MonoBtlsX509VerifyParam *param);
+
+int
+mono_btls_x509_verify_param_set_mono_flags (MonoBtlsX509VerifyParam *param, MonoBtlsX509VerifyFlags flags);
+
+int
+mono_btls_x509_verify_param_set_purpose (MonoBtlsX509VerifyParam *param, MonoBtlsX509Purpose purpose);
+
+int
+mono_btls_x509_verify_param_get_depth (MonoBtlsX509VerifyParam *param);
+
+int
+mono_btls_x509_verify_param_set_depth (MonoBtlsX509VerifyParam *param, int depth);
+
+int
+mono_btls_x509_verify_param_set_time (MonoBtlsX509VerifyParam *param, int64_t time);
+
+char *
+mono_btls_x509_verify_param_get_peername (MonoBtlsX509VerifyParam *param);
+
+#endif /* defined(__btls__btls_x509_verify_param__) */
+
diff --git a/mono/btls/btls-x509.c b/mono/btls/btls-x509.c
new file mode 100644
index 0000000000..473d94fbaf
--- /dev/null
+++ b/mono/btls/btls-x509.c
@@ -0,0 +1,441 @@
+//
+// btls-x509.c
+// MonoBtls
+//
+// Created by Martin Baulig on 14/11/15.
+// Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#include
+#include
+#include
+
+MONO_API X509 *
+mono_btls_x509_from_data (const void *buf, int len, MonoBtlsX509Format format)
+{
+ BIO *bio;
+ X509 *cert = NULL;
+
+ bio = BIO_new_mem_buf ((void *)buf, len);
+ switch (format) {
+ case MONO_BTLS_X509_FORMAT_DER:
+ cert = d2i_X509_bio (bio, NULL);
+ break;
+ case MONO_BTLS_X509_FORMAT_PEM:
+ cert = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
+ break;
+ }
+ BIO_free (bio);
+ return cert;
+}
+
+MONO_API X509 *
+mono_btls_x509_up_ref (X509 *x509)
+{
+ X509_up_ref (x509);
+ return x509;
+}
+
+MONO_API void
+mono_btls_x509_free (X509 *x509)
+{
+ X509_free (x509);
+}
+
+MONO_API X509 *
+mono_btls_x509_dup (X509 *x509)
+{
+ return X509_dup (x509);
+}
+
+MONO_API MonoBtlsX509Name *
+mono_btls_x509_get_subject_name (X509 *x509)
+{
+ return mono_btls_x509_name_copy (X509_get_subject_name (x509));
+}
+
+MONO_API MonoBtlsX509Name *
+mono_btls_x509_get_issuer_name (X509 *x509)
+{
+ return mono_btls_x509_name_copy (X509_get_issuer_name (x509));
+}
+
+MONO_API int
+mono_btls_x509_get_subject_name_string (X509 *name, char *buffer, int size)
+{
+ *buffer = 0;
+ return X509_NAME_oneline (X509_get_subject_name (name), buffer, size) != NULL;
+}
+
+MONO_API int
+mono_btls_x509_get_issuer_name_string (X509 *name, char *buffer, int size)
+{
+ *buffer = 0;
+ return X509_NAME_oneline (X509_get_issuer_name (name), buffer, size) != NULL;
+}
+
+MONO_API int
+mono_btls_x509_get_raw_data (X509 *x509, BIO *bio, MonoBtlsX509Format format)
+{
+ switch (format) {
+ case MONO_BTLS_X509_FORMAT_DER:
+ return i2d_X509_bio (bio, x509);
+ case MONO_BTLS_X509_FORMAT_PEM:
+ return PEM_write_bio_X509 (bio, x509);
+ default:
+ return 0;
+ }
+}
+
+MONO_API int
+mono_btls_x509_cmp (const X509 *a, const X509 *b)
+{
+ return X509_cmp (a, b);
+}
+
+MONO_API int
+mono_btls_x509_get_hash (X509 *x509, const void **data)
+{
+ X509_check_purpose (x509, -1, 0);
+ *data = x509->sha1_hash;
+ return SHA_DIGEST_LENGTH;
+}
+
+MONO_API int64_t
+mono_btls_x509_get_not_before (X509 *x509)
+{
+ return mono_btls_util_asn1_time_to_ticks (X509_get_notBefore (x509));
+}
+
+MONO_API int64_t
+mono_btls_x509_get_not_after (X509 *x509)
+{
+ return mono_btls_util_asn1_time_to_ticks (X509_get_notAfter (x509));
+}
+
+MONO_API int
+mono_btls_x509_get_public_key (X509 *x509, BIO *bio)
+{
+ EVP_PKEY *pkey;
+ uint8_t *data = NULL;
+ int ret;
+
+ pkey = X509_get_pubkey (x509);
+ if (!pkey)
+ return -1;
+
+ ret = i2d_PublicKey (pkey, &data);
+
+ if (ret > 0 && data) {
+ ret = BIO_write (bio, data, ret);
+ OPENSSL_free (data);
+ }
+
+ EVP_PKEY_free (pkey);
+ return ret;
+}
+
+MONO_API int
+mono_btls_x509_get_serial_number (X509 *x509, char *buffer, int size, int mono_style)
+{
+ ASN1_INTEGER *serial;
+ unsigned char *temp, *p;
+ int len, idx;
+
+ serial = X509_get_serialNumber (x509);
+ if (serial->length == 0 || serial->length+1 > size)
+ return 0;
+
+ if (!mono_style) {
+ memcpy (buffer, serial->data, serial->length);
+ return serial->length;
+ }
+
+ temp = OPENSSL_malloc (serial->length + 1);
+ if (!temp)
+ return 0;
+
+ p = temp;
+ len = i2c_ASN1_INTEGER (serial, &p);
+
+ if (!len) {
+ OPENSSL_free (temp);
+ return 0;
+ }
+
+ for (idx = 0; idx < len; idx++) {
+ buffer [idx] = *(--p);
+ }
+ buffer [len] = 0;
+
+ OPENSSL_free (temp);
+ return len;
+}
+
+MONO_API int
+mono_btls_x509_get_public_key_algorithm (X509 *x509, char *buffer, int size)
+{
+ X509_PUBKEY *pkey;
+ ASN1_OBJECT *ppkalg;
+ int ret;
+
+ *buffer = 0;
+ pkey = X509_get_X509_PUBKEY (x509);
+ if (!pkey)
+ return 0;
+
+ ret = X509_PUBKEY_get0_param (&ppkalg, NULL, NULL, NULL, pkey);
+ if (!ret || !ppkalg)
+ return ret;
+
+ return OBJ_obj2txt (buffer, size, ppkalg, 1);
+}
+
+MONO_API int
+mono_btls_x509_get_version (X509 *x509)
+{
+ return (int)X509_get_version (x509) + 1;
+}
+
+MONO_API int
+mono_btls_x509_get_signature_algorithm (X509 *x509, char *buffer, int size)
+{
+ const ASN1_OBJECT *obj;
+ int nid;
+
+ *buffer = 0;
+
+ nid = X509_get_signature_nid (x509);
+
+ obj = OBJ_nid2obj (nid);
+ if (!obj)
+ return 0;
+
+ return OBJ_obj2txt (buffer, size, obj, 1);
+}
+
+MONO_API int
+mono_btls_x509_get_public_key_asn1 (X509 *x509, char *out_oid, int oid_len, uint8_t **buffer, int *size)
+{
+ X509_PUBKEY *pkey;
+ ASN1_OBJECT *ppkalg;
+ const unsigned char *pk;
+ int pk_len;
+ int ret;
+
+ if (out_oid)
+ *out_oid = 0;
+
+ pkey = X509_get_X509_PUBKEY (x509);
+ if (!pkey || !pkey->public_key)
+ return 0;
+
+ ret = X509_PUBKEY_get0_param (&ppkalg, &pk, &pk_len, NULL, pkey);
+ if (ret != 1 || !ppkalg || !pk)
+ return 0;
+
+ if (out_oid) {
+ OBJ_obj2txt (out_oid, oid_len, ppkalg, 1);
+ }
+
+ if (buffer) {
+ *size = pk_len;
+ *buffer = OPENSSL_malloc (pk_len);
+ if (!*buffer)
+ return 0;
+
+ memcpy (*buffer, pk, pk_len);
+ }
+
+ return 1;
+
+}
+
+MONO_API int
+mono_btls_x509_get_public_key_parameters (X509 *x509, char *out_oid, int oid_len, uint8_t **buffer, int *size)
+{
+ X509_PUBKEY *pkey;
+ X509_ALGOR *algor;
+ ASN1_OBJECT *paobj;
+ int ptype;
+ void *pval;
+ int ret;
+
+ if (out_oid)
+ *out_oid = 0;
+
+ pkey = X509_get_X509_PUBKEY (x509);
+
+ ret = X509_PUBKEY_get0_param (NULL, NULL, NULL, &algor, pkey);
+ if (ret != 1 || !algor)
+ return 0;
+
+ X509_ALGOR_get0 (&paobj, &ptype, &pval, algor);
+
+ if (ptype != V_ASN1_NULL && ptype != V_ASN1_SEQUENCE)
+ return 0;
+
+ if (ptype == V_ASN1_NULL) {
+ uint8_t *ptr;
+
+ *size = 2;
+ *buffer = OPENSSL_malloc (2);
+ if (!*buffer)
+ return 0;
+
+ ptr = *buffer;
+ *ptr++ = 0x05;
+ *ptr++ = 0x00;
+
+ if (out_oid)
+ OBJ_obj2txt (out_oid, oid_len, paobj, 1);
+
+ return 1;
+ } else if (ptype == V_ASN1_SEQUENCE) {
+ ASN1_STRING *pstr = pval;
+
+ *size = pstr->length;
+ *buffer = OPENSSL_malloc (pstr->length);
+ if (!*buffer)
+ return 0;
+
+ memcpy (*buffer, pstr->data, pstr->length);
+
+ if (out_oid)
+ OBJ_obj2txt (out_oid, oid_len, paobj, 1);
+
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+MONO_API EVP_PKEY *
+mono_btls_x509_get_pubkey (X509 *x509)
+{
+ return X509_get_pubkey (x509);
+}
+
+MONO_API int
+mono_btls_x509_get_subject_key_identifier (X509 *x509, uint8_t **buffer, int *size)
+{
+ ASN1_OCTET_STRING *skid;
+
+ *size = 0;
+ *buffer = NULL;
+
+ if (X509_get_version (x509) != 2)
+ return 0;
+
+ skid = X509_get_ext_d2i (x509, NID_subject_key_identifier, NULL, NULL);
+ if (!skid)
+ return 0;
+
+ *size = skid->length;
+ *buffer = OPENSSL_malloc (*size);
+ if (!*buffer)
+ return 0;
+
+ memcpy (*buffer, skid->data, *size);
+ return 1;
+}
+
+MONO_API int
+mono_btls_x509_print (X509 *x509, BIO *bio)
+{
+ return X509_print_ex (bio, x509, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
+}
+
+static int
+get_trust_nid (MonoBtlsX509Purpose purpose)
+{
+ switch (purpose) {
+ case MONO_BTLS_X509_PURPOSE_SSL_CLIENT:
+ return NID_client_auth;
+ case MONO_BTLS_X509_PURPOSE_SSL_SERVER:
+ return NID_server_auth;
+ default:
+ return 0;
+ }
+}
+
+MONO_API int
+mono_btls_x509_add_trust_object (X509 *x509, MonoBtlsX509Purpose purpose)
+{
+ ASN1_OBJECT *trust;
+ int nid;
+
+ nid = get_trust_nid (purpose);
+ if (!nid)
+ return 0;
+
+ trust = ASN1_OBJECT_new ();
+ if (!trust)
+ return 0;
+
+ trust->nid = nid;
+ return X509_add1_trust_object (x509, trust);
+}
+
+MONO_API int
+mono_btls_x509_add_reject_object (X509 *x509, MonoBtlsX509Purpose purpose)
+{
+ ASN1_OBJECT *reject;
+ int nid;
+
+ nid = get_trust_nid (purpose);
+ if (!nid)
+ return 0;
+
+ reject = ASN1_OBJECT_new ();
+ if (!reject)
+ return 0;
+
+ reject->nid = nid;
+ return X509_add1_reject_object (x509, reject);
+}
+
+MONO_API int
+mono_btls_x509_add_explicit_trust (X509 *x509, MonoBtlsX509TrustKind kind)
+{
+ int ret = 0;
+
+ if ((kind & MONO_BTLS_X509_TRUST_KIND_REJECT_ALL) != 0)
+ kind |= MONO_BTLS_X509_TRUST_KIND_REJECT_CLIENT | MONO_BTLS_X509_TRUST_KIND_REJECT_SERVER;
+
+ if ((kind & MONO_BTLS_X509_TRUST_KIND_TRUST_ALL) != 0)
+ kind |= MONO_BTLS_X509_TRUST_KIND_TRUST_CLIENT | MONO_BTLS_X509_TRUST_KIND_TRUST_SERVER;
+
+
+ if ((kind & MONO_BTLS_X509_TRUST_KIND_REJECT_CLIENT) != 0) {
+ ret = mono_btls_x509_add_reject_object (x509, MONO_BTLS_X509_PURPOSE_SSL_CLIENT);
+ if (!ret)
+ return ret;
+ }
+
+ if ((kind & MONO_BTLS_X509_TRUST_KIND_REJECT_SERVER) != 0) {
+ ret = mono_btls_x509_add_reject_object (x509, MONO_BTLS_X509_PURPOSE_SSL_SERVER);
+ if (!ret)
+ return ret;
+ }
+
+ if (ret) {
+ // Ignore any MONO_BTLS_X509_TRUST_KIND_TRUST_* settings if we added
+ // any kind of MONO_BTLS_X509_TRUST_KIND_REJECT_* before.
+ return ret;
+ }
+
+ if ((kind & MONO_BTLS_X509_TRUST_KIND_TRUST_CLIENT) != 0) {
+ ret = mono_btls_x509_add_trust_object (x509, MONO_BTLS_X509_PURPOSE_SSL_CLIENT);
+ if (!ret)
+ return ret;
+ }
+
+ if ((kind & MONO_BTLS_X509_TRUST_KIND_TRUST_SERVER) != 0) {
+ ret = mono_btls_x509_add_trust_object (x509, MONO_BTLS_X509_PURPOSE_SSL_SERVER);
+ if (!ret)
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/mono/btls/btls-x509.h b/mono/btls/btls-x509.h
new file mode 100644
index 0000000000..d913743133
--- /dev/null
+++ b/mono/btls/btls-x509.h
@@ -0,0 +1,127 @@
+//
+// btls-x509.h
+// MonoBtls
+//
+// Created by Martin Baulig on 14/11/15.
+// Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509__
+#define __btls__btls_x509__
+
+#include
+#include
+#include
+
+typedef enum {
+ MONO_BTLS_X509_FORMAT_DER = 1,
+ MONO_BTLS_X509_FORMAT_PEM = 2
+} MonoBtlsX509Format;
+
+typedef enum {
+ MONO_BTLS_x509_FILE_TYPE_PEM = 1, // X509_FILETYPE_PEM
+ MONO_BTLS_x509_FILE_TYPE_ASN1 = 2, // X509_FILETYPE_ASN1
+ MONO_BTLS_x509_FILE_TYPE_DEFAULT = 3, // X509_FILETYPE_DEFAULT
+} MonoBtlsX509FileType;
+
+typedef enum {
+ MONO_BTLS_X509_PURPOSE_SSL_CLIENT = 1,
+ MONO_BTLS_X509_PURPOSE_SSL_SERVER = 2,
+ MONO_BTLS_X509_PURPOSE_NS_SSL_SERVER = 3,
+ MONO_BTLS_X509_PURPOSE_SMIME_SIGN = 4,
+ MONO_BTLS_X509_PURPOSE_SMIME_ENCRYPT = 5,
+ MONO_BTLS_X509_PURPOSE_CRL_SIGN = 6,
+ MONO_BTLS_X509_PURPOSE_ANY = 7,
+ MONO_BTLS_X509_PURPOSE_OCSP_HELPER = 8,
+ MONO_BTLS_X509_PURPOSE_TIMESTAMP_SIGN = 9,
+} MonoBtlsX509Purpose;
+
+typedef enum {
+ MONO_BTLS_X509_TRUST_KIND_DEFAULT = 0,
+ MONO_BTLS_X509_TRUST_KIND_TRUST_CLIENT = 1,
+ MONO_BTLS_X509_TRUST_KIND_TRUST_SERVER = 2,
+ MONO_BTLS_X509_TRUST_KIND_TRUST_ALL = 4,
+ MONO_BTLS_X509_TRUST_KIND_REJECT_CLIENT = 32,
+ MONO_BTLS_X509_TRUST_KIND_REJECT_SERVER = 64,
+ MONO_BTLS_X509_TRUST_KIND_REJECT_ALL = 128
+} MonoBtlsX509TrustKind;
+
+X509 *
+mono_btls_x509_from_data (const void *buf, int len, MonoBtlsX509Format format);
+
+X509 *
+mono_btls_x509_up_ref (X509 *x509);
+
+void
+mono_btls_x509_free (X509 *x509);
+
+X509 *
+mono_btls_x509_dup (X509 *x509);
+
+MonoBtlsX509Name *
+mono_btls_x509_get_subject_name (X509 *x509);
+
+MonoBtlsX509Name *
+mono_btls_x509_get_issuer_name (X509 *x509);
+
+int
+mono_btls_x509_get_subject_name_string (X509 *name, char *buffer, int size);
+
+int
+mono_btls_x509_get_issuer_name_string (X509 *name, char *buffer, int size);
+
+int
+mono_btls_x509_get_raw_data (X509 *x509, BIO *bio, MonoBtlsX509Format format);
+
+int
+mono_btls_x509_cmp (const X509 *a, const X509 *b);
+
+int
+mono_btls_x509_get_hash (X509 *x509, const void **data);
+
+int64_t
+mono_btls_x509_get_not_before (X509 *x509);
+
+int64_t
+mono_btls_x509_get_not_after (X509 *x509);
+
+int
+mono_btls_x509_get_public_key (X509 *x509, BIO *bio);
+
+int
+mono_btls_x509_get_public_key_parameters (X509 *x509, char *out_oid, int oid_len, uint8_t **buffer, int *size);
+
+int
+mono_btls_x509_get_serial_number (X509 *x509, char *buffer, int size, int mono_style);
+
+int
+mono_btls_x509_get_public_key_algorithm (X509 *x509, char *buffer, int size);
+
+int
+mono_btls_x509_get_version (X509 *x509);
+
+int
+mono_btls_x509_get_signature_algorithm (X509 *x509, char *buffer, int size);
+
+int
+mono_btls_x509_get_public_key_asn1 (X509 *x509, char *out_oid, int oid_len, uint8_t **buffer, int *size);
+
+EVP_PKEY *
+mono_btls_x509_get_pubkey (X509 *x509);
+
+int
+mono_btls_x509_get_subject_key_identifier (X509 *x509, uint8_t **buffer, int *size);
+
+int
+mono_btls_x509_print (X509 *x509, BIO *bio);
+
+int
+mono_btls_x509_add_trust_object (X509 *x509, MonoBtlsX509Purpose purpose);
+
+int
+mono_btls_x509_add_reject_object (X509 *x509, MonoBtlsX509Purpose purpose);
+
+int
+mono_btls_x509_add_explicit_trust (X509 *x509, MonoBtlsX509TrustKind kind);
+
+#endif /* defined(__btls__btls_x509__) */
diff --git a/mono/btls/create-object-library.sh b/mono/btls/create-object-library.sh
new file mode 100755
index 0000000000..8ceda08a77
--- /dev/null
+++ b/mono/btls/create-object-library.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+DIR=$1; shift
+FILELIST=$1; shift
+LOFILELIST=$1 ; shift
+TARGET=$1; shift
+STATIC=$1; shift
+AR=$1; shift
+RANLIB=$1; shift
+
+HEADER="# Generated by Martin's tool $0, not libtool"
+
+test -f $TARGET && exit 0
+
+rm -f $FILELIST
+rm -f $LOFILELIST
+
+while [ "$1" != "--" ]; do
+ file=$1; shift
+ filename=`basename $file`
+ LOFILE=$file.lo
+ echo "$HEADER" > $LOFILE
+ if [ "$STATIC" = "static" ]; then
+ echo "non_pic_object='$filename'" >> $LOFILE
+ else
+ echo "pic_object='$filename'" >> $LOFILE
+ fi
+ echo "$DIR/$file " >> $FILELIST
+ echo "$DIR/$LOFILE " >> $LOFILELIST
+done
+
+(cd $DIR && $AR cr $TARGET `cat $FILELIST` && $RANLIB $TARGET)
+
diff --git a/mono/metadata/icall-def.h b/mono/metadata/icall-def.h
index 92cb607993..5fae5ea933 100644
--- a/mono/metadata/icall-def.h
+++ b/mono/metadata/icall-def.h
@@ -953,9 +953,7 @@ ICALL(MARSHAL_13, "Prelink", ves_icall_System_Runtime_InteropServices_Marshal_Pr
ICALL(MARSHAL_14, "PrelinkAll", ves_icall_System_Runtime_InteropServices_Marshal_PrelinkAll)
ICALL(MARSHAL_15, "PtrToStringAnsi(intptr)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi)
ICALL(MARSHAL_16, "PtrToStringAnsi(intptr,int)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len)
-#ifndef DISABLE_COM
ICALL(MARSHAL_17, "PtrToStringBSTR", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringBSTR)
-#endif
ICALL(MARSHAL_18, "PtrToStringUni(intptr)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni)
ICALL(MARSHAL_19, "PtrToStringUni(intptr,int)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len)
ICALL(MARSHAL_20, "PtrToStructure(intptr,System.Type)", ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type)
diff --git a/mono/metadata/metadata.c.REMOVED.git-id b/mono/metadata/metadata.c.REMOVED.git-id
index a248df3cd0..e2def32057 100644
--- a/mono/metadata/metadata.c.REMOVED.git-id
+++ b/mono/metadata/metadata.c.REMOVED.git-id
@@ -1 +1 @@
-27115ccc9c1b1e384c9245ff8e976882159a9ed1
\ No newline at end of file
+a5c505495191bdcc23d959d1c02162890e68ac9c
\ No newline at end of file
diff --git a/mono/metadata/object-offsets.h b/mono/metadata/object-offsets.h
index e4965a512a..5c78288ec8 100644
--- a/mono/metadata/object-offsets.h
+++ b/mono/metadata/object-offsets.h
@@ -238,6 +238,8 @@ DECL_OFFSET(GSharedVtCallInfo, gsharedvt_in)
#endif
#if defined(TARGET_ARM64)
+DECL_OFFSET (MonoContext, has_fregs)
+
DECL_OFFSET(GSharedVtCallInfo, stack_usage)
DECL_OFFSET(GSharedVtCallInfo, gsharedvt_in)
DECL_OFFSET(GSharedVtCallInfo, ret_marshal)
diff --git a/mono/metadata/reflection.c b/mono/metadata/reflection.c
index 0a5ea615a0..6f5d1f82fb 100644
--- a/mono/metadata/reflection.c
+++ b/mono/metadata/reflection.c
@@ -2259,10 +2259,17 @@ mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc
if (klass->wastypebuilder) {
tb = (MonoReflectionTypeBuilder *) mono_class_get_ref_info (klass);
-
is_dynamic = TRUE;
}
+ guint gtd_type_argc = mono_class_get_generic_container (klass)->type_argc;
+ if (gtd_type_argc != type_argc) {
+ mono_loader_unlock ();
+ mono_error_set_argument (error, "types", "The generic type definition needs %d type arguments, but was instantiated with %d ", gtd_type_argc, type_argc);
+ return NULL;
+ }
+
+
mono_loader_unlock ();
geninst = mono_class_bind_generic_parameters (klass, type_argc, types, is_dynamic);
diff --git a/mono/metadata/threadpool-ms.c b/mono/metadata/threadpool-ms.c
index 3eaa48dc51..666e373936 100644
--- a/mono/metadata/threadpool-ms.c
+++ b/mono/metadata/threadpool-ms.c
@@ -423,18 +423,20 @@ domain_remove (ThreadPoolDomain *tpdomain)
static ThreadPoolDomain *
domain_get (MonoDomain *domain, gboolean create)
{
- ThreadPoolDomain *tpdomain = NULL;
guint i;
g_assert (domain);
for (i = 0; i < threadpool->domains->len; ++i) {
+ ThreadPoolDomain *tpdomain;
+
tpdomain = (ThreadPoolDomain *)g_ptr_array_index (threadpool->domains, i);
if (tpdomain->domain == domain)
return tpdomain;
}
if (create) {
+ ThreadPoolDomain *tpdomain;
ThreadPoolDomainCleanupSemaphore *cleanup_semaphore;
cleanup_semaphore = g_new0 (ThreadPoolDomainCleanupSemaphore, 1);
cleanup_semaphore->ref = 2;
@@ -446,9 +448,11 @@ domain_get (MonoDomain *domain, gboolean create)
tpdomain = g_new0 (ThreadPoolDomain, 1);
tpdomain->domain = domain;
domain_add (tpdomain);
+
+ return tpdomain;
}
- return tpdomain;
+ return NULL;
}
static void
diff --git a/mono/mini/Makefile.am b/mono/mini/Makefile.am
index d745bb5dd4..a30b00dd80 100644
--- a/mono/mini/Makefile.am
+++ b/mono/mini/Makefile.am
@@ -860,7 +860,7 @@ EXTRA_DIST = TestDriver.cs \
Makefile.am.in
version.h: Makefile
- echo "#define FULL_VERSION \"Stable 4.8.0.309/dea12ad\"" > version.h
+ echo "#define FULL_VERSION \"Stable 4.8.0.344/f5fbc32\"" > version.h
# Utility target for patching libtool to speed up linking
patch-libtool:
diff --git a/mono/mini/Makefile.am.in b/mono/mini/Makefile.am.in
index d745bb5dd4..a30b00dd80 100755
--- a/mono/mini/Makefile.am.in
+++ b/mono/mini/Makefile.am.in
@@ -860,7 +860,7 @@ EXTRA_DIST = TestDriver.cs \
Makefile.am.in
version.h: Makefile
- echo "#define FULL_VERSION \"Stable 4.8.0.309/dea12ad\"" > version.h
+ echo "#define FULL_VERSION \"Stable 4.8.0.344/f5fbc32\"" > version.h
# Utility target for patching libtool to speed up linking
patch-libtool:
diff --git a/mono/mini/Makefile.in.REMOVED.git-id b/mono/mini/Makefile.in.REMOVED.git-id
index 00e2abd56e..d75b1d9af7 100644
--- a/mono/mini/Makefile.in.REMOVED.git-id
+++ b/mono/mini/Makefile.in.REMOVED.git-id
@@ -1 +1 @@
-758b7a9eb4e4abb105aa5381c4c9a16a34e8b4d6
\ No newline at end of file
+d1e6363311745351e05c4bd7f744e07b7ea2f128
\ No newline at end of file
diff --git a/mono/mini/debugger-agent.c.REMOVED.git-id b/mono/mini/debugger-agent.c.REMOVED.git-id
index f71b8e489a..e8aabfddbd 100644
--- a/mono/mini/debugger-agent.c.REMOVED.git-id
+++ b/mono/mini/debugger-agent.c.REMOVED.git-id
@@ -1 +1 @@
-0a708d482293b4d8f1e47e5e967134b8878d3882
\ No newline at end of file
+747cc484fae7811f7e3041ef630f393f4e180cc3
\ No newline at end of file
diff --git a/mono/mini/exceptions-arm64.c b/mono/mini/exceptions-arm64.c
index fe210faa3a..9b7f762e99 100644
--- a/mono/mini/exceptions-arm64.c
+++ b/mono/mini/exceptions-arm64.c
@@ -29,15 +29,21 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
MonoJumpInfo *ji = NULL;
GSList *unwind_ops = NULL;
int i, ctx_reg, size;
+ guint8 *labels [16];
size = 256;
code = start = mono_global_codeman_reserve (size);
arm_movx (code, ARMREG_IP0, ARMREG_R0);
ctx_reg = ARMREG_IP0;
+
/* Restore fregs */
+ arm_ldrx (code, ARMREG_IP1, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, has_fregs));
+ labels [0] = code;
+ arm_cbzx (code, ARMREG_IP1, 0);
for (i = 0; i < 32; ++i)
arm_ldrfpx (code, i, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * 8));
+ mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ);
/* Restore gregs */
// FIXME: Restore less registers
// FIXME: fp should be restored later
@@ -69,9 +75,10 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
{
guint8 *code;
guint8* start;
- int size, offset, gregs_offset, fregs_offset, ctx_offset, num_fregs, frame_size;
+ int i, size, offset, gregs_offset, fregs_offset, ctx_offset, num_fregs, frame_size;
MonoJumpInfo *ji = NULL;
GSList *unwind_ops = NULL;
+ guint8 *labels [16];
size = 512;
start = code = mono_global_codeman_reserve (size);
@@ -105,10 +112,19 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
arm_strx (code, ARMREG_R0, ARMREG_FP, ctx_offset);
/* Save gregs */
code = mono_arm_emit_store_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS | (1 << ARMREG_FP), ARMREG_FP, gregs_offset);
- /* No need to save/restore fregs, since we don't currently use them */
+ /* Save fregs */
+ for (i = 0; i < num_fregs; ++i)
+ arm_strfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8));
/* Load regs from ctx */
code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs));
+ /* Load fregs */
+ arm_ldrx (code, ARMREG_IP0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, has_fregs));
+ labels [0] = code;
+ arm_cbzx (code, ARMREG_IP0, 0);
+ for (i = 0; i < num_fregs; ++i)
+ arm_ldrfpx (code, ARMREG_D8 + i, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * 8));
+ mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ);
/* Load fp */
arm_ldrx (code, ARMREG_FP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_FP * 8));
@@ -126,6 +142,9 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
/* Restore regs */
code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_FP, gregs_offset);
+ /* Restore fregs */
+ for (i = 0; i < num_fregs; ++i)
+ arm_ldrfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8));
/* Destroy frame */
code = mono_arm_emit_destroy_frame (code, frame_size, (1 << ARMREG_IP0));
arm_retx (code, ARMREG_LR);
@@ -374,6 +393,7 @@ mono_arm_throw_exception (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble *
memset (&ctx, 0, sizeof (MonoContext));
memcpy (&(ctx.regs [0]), int_regs, sizeof (mgreg_t) * 32);
memcpy (&(ctx.fregs [ARMREG_D8]), fp_regs, sizeof (double) * 8);
+ ctx.has_fregs = 1;
ctx.pc = pc;
if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
@@ -402,6 +422,7 @@ mono_arm_resume_unwind (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble *fp
memset (&ctx, 0, sizeof (MonoContext));
memcpy (&(ctx.regs [0]), int_regs, sizeof (mgreg_t) * 32);
memcpy (&(ctx.fregs [ARMREG_D8]), fp_regs, sizeof (double) * 8);
+ ctx.has_fregs = 1;
ctx.pc = pc;
mono_resume_unwind (&ctx);
diff --git a/mono/mini/main.c b/mono/mini/main.c
index 80044897a8..77f8bc9578 100644
--- a/mono/mini/main.c
+++ b/mono/mini/main.c
@@ -151,7 +151,7 @@ bundle_save_library_initialize ()
bundle_save_library_initialized = 1;
char *path = g_build_filename (g_get_tmp_dir (), "mono-bundle-XXXXXX", NULL);
bundled_dylibrary_directory = g_mkdtemp (path);
- g_free (path);
+ /* don't free path - mkdtemp modifies it in place, and bundled_dylibrary_directory is an alias of it */
if (bundled_dylibrary_directory == NULL)
return;
atexit (delete_bundled_libraries);
diff --git a/mono/mini/mini-arm64.c.REMOVED.git-id b/mono/mini/mini-arm64.c.REMOVED.git-id
index 6623c313a7..dc87bb7c47 100644
--- a/mono/mini/mini-arm64.c.REMOVED.git-id
+++ b/mono/mini/mini-arm64.c.REMOVED.git-id
@@ -1 +1 @@
-b7652c94f218e0d67ed6ef9ae1bf0c0e4ff1493a
\ No newline at end of file
+b4871f36b910f3efc6be8a41a65c6d80a1e7d70b
\ No newline at end of file
diff --git a/mono/mini/version.h b/mono/mini/version.h
index 43fb80b19e..6fc571709d 100644
--- a/mono/mini/version.h
+++ b/mono/mini/version.h
@@ -1 +1 @@
-#define FULL_VERSION "Stable 4.8.0.309/dea12ad"
+#define FULL_VERSION "Stable 4.8.0.344/f5fbc32"
diff --git a/mono/tests/Makefile.am b/mono/tests/Makefile.am
index 41e4a9b9a4..51ceefca2e 100644
--- a/mono/tests/Makefile.am
+++ b/mono/tests/Makefile.am
@@ -140,7 +140,8 @@ BASE_TEST_MOBILE_STATIC_NOT_SUPPORTED= \
threadpool-exceptions7.cs # Needs AppDomains \
cross-domain.cs # Needs AppDomains \
generic-unloading.2.cs # Needs AppDomains \
- thread6.cs # On MOBILE, ThreadAbortException doesn't have necessary field for this test
+ thread6.cs # On MOBILE, ThreadAbortException doesn't have necessary field for this test \
+ appdomain-threadpool-unload.cs
# Disabled until ?mcs is fixed
# bug-331958.cs
diff --git a/mono/tests/Makefile.in b/mono/tests/Makefile.in
index cb3b5164d0..59dd848612 100644
--- a/mono/tests/Makefile.in
+++ b/mono/tests/Makefile.in
@@ -544,7 +544,8 @@ BASE_TEST_MOBILE_STATIC_NOT_SUPPORTED = \
threadpool-exceptions7.cs # Needs AppDomains \
cross-domain.cs # Needs AppDomains \
generic-unloading.2.cs # Needs AppDomains \
- thread6.cs # On MOBILE, ThreadAbortException doesn't have necessary field for this test
+ thread6.cs # On MOBILE, ThreadAbortException doesn't have necessary field for this test \
+ appdomain-threadpool-unload.cs
# Disabled until ?mcs is fixed
diff --git a/mono/utils/mono-context.h b/mono/utils/mono-context.h
index 907c62ee2e..c5769237e7 100644
--- a/mono/utils/mono-context.h
+++ b/mono/utils/mono-context.h
@@ -294,6 +294,11 @@ typedef struct {
mgreg_t regs [32];
double fregs [32];
mgreg_t pc;
+ /*
+ * fregs might not be initialized if this context was created from a
+ * ucontext.
+ */
+ mgreg_t has_fregs;
} MonoContext;
#define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->pc = (mgreg_t)ip; } while (0)
diff --git a/mono/utils/mono-threads-posix.c b/mono/utils/mono-threads-posix.c
index ce2f58ad13..de38adf137 100644
--- a/mono/utils/mono-threads-posix.c
+++ b/mono/utils/mono-threads-posix.c
@@ -456,8 +456,13 @@ This begins async resume. This function must do the following:
gboolean
mono_threads_suspend_begin_async_resume (MonoThreadInfo *info)
{
- mono_threads_add_to_pending_operation_set (info);
- return mono_threads_pthread_kill (info, mono_threads_posix_get_restart_signal ()) == 0;
+ int sig = mono_threads_posix_get_restart_signal ();
+
+ if (!mono_threads_pthread_kill (info, sig)) {
+ mono_threads_add_to_pending_operation_set (info);
+ return TRUE;
+ }
+ return FALSE;
}
void
diff --git a/mono/utils/mono-threads.c b/mono/utils/mono-threads.c
index d0eedf683e..a33bbf1d01 100644
--- a/mono/utils/mono-threads.c
+++ b/mono/utils/mono-threads.c
@@ -916,7 +916,7 @@ suspend_sync (MonoNativeThreadId tid, gboolean interrupt_kernel)
}
break;
case AsyncSuspendBlocking:
- if (interrupt_kernel)
+ if (interrupt_kernel && mono_threads_suspend_needs_abort_syscall ())
mono_threads_suspend_abort_syscall (info);
break;
diff --git a/po/mcs/de.gmo b/po/mcs/de.gmo
index 6a8e12f4cf..bca6d0c6c4 100644
Binary files a/po/mcs/de.gmo and b/po/mcs/de.gmo differ
diff --git a/po/mcs/de.po.REMOVED.git-id b/po/mcs/de.po.REMOVED.git-id
index 49000b636c..244e9695b5 100644
--- a/po/mcs/de.po.REMOVED.git-id
+++ b/po/mcs/de.po.REMOVED.git-id
@@ -1 +1 @@
-4b4c8c95c1fb9efeb02fa1c5f3c296ffc26f263e
\ No newline at end of file
+57fd3fa17feba29a807193571faff35ba24382a7
\ No newline at end of file
diff --git a/po/mcs/es.gmo b/po/mcs/es.gmo
index fb569f29bd..0b1ab412c3 100644
Binary files a/po/mcs/es.gmo and b/po/mcs/es.gmo differ
diff --git a/po/mcs/es.po.REMOVED.git-id b/po/mcs/es.po.REMOVED.git-id
index 4e0148bc65..bff2d5bf02 100644
--- a/po/mcs/es.po.REMOVED.git-id
+++ b/po/mcs/es.po.REMOVED.git-id
@@ -1 +1 @@
-fbacc0386bed56cd426fa6d1519d7238d83e1658
\ No newline at end of file
+25ed8e9ca5aea8f09cbeab179abb3f686343b9d4
\ No newline at end of file
diff --git a/po/mcs/ja.gmo b/po/mcs/ja.gmo
index a3f815606a..d9d04ba929 100644
Binary files a/po/mcs/ja.gmo and b/po/mcs/ja.gmo differ
diff --git a/po/mcs/ja.po.REMOVED.git-id b/po/mcs/ja.po.REMOVED.git-id
index b25801e01f..fbb803a64b 100644
--- a/po/mcs/ja.po.REMOVED.git-id
+++ b/po/mcs/ja.po.REMOVED.git-id
@@ -1 +1 @@
-40c5ac34c575e1d103e7012e5e11b3dabe35f4ca
\ No newline at end of file
+887acfaf4483d20c897f95097cf4b45032f87c00
\ No newline at end of file
diff --git a/po/mcs/mcs.pot b/po/mcs/mcs.pot
index 1f91fb62fc..5477836962 100644
--- a/po/mcs/mcs.pot
+++ b/po/mcs/mcs.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: mono 4.8.0\n"
"Report-Msgid-Bugs-To: http://www.mono-project.com/Bugs\n"
-"POT-Creation-Date: 2016-11-10 12:38+0000\n"
+"POT-Creation-Date: 2016-11-16 13:09+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
diff --git a/po/mcs/pt_BR.gmo b/po/mcs/pt_BR.gmo
index 08e3a30f36..a980ace30d 100644
Binary files a/po/mcs/pt_BR.gmo and b/po/mcs/pt_BR.gmo differ
diff --git a/po/mcs/pt_BR.po.REMOVED.git-id b/po/mcs/pt_BR.po.REMOVED.git-id
index 7e01505895..b9b2f59725 100644
--- a/po/mcs/pt_BR.po.REMOVED.git-id
+++ b/po/mcs/pt_BR.po.REMOVED.git-id
@@ -1 +1 @@
-7925e43a8725e46f8222cc890cff7acfbe7b709b
\ No newline at end of file
+71cec70833a5f9d22261d7bf02c81682266a7506
\ No newline at end of file
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 3174ec4c3f..39595455da 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -158,6 +158,7 @@ EXTRA_DIST = \
update_submodules \
mcs.in \
dmcs.in \
+ mono-package-runtime \
mono-test-install \
mono-heapviz \
$(MDOC_COMPAT) \
diff --git a/scripts/Makefile.in b/scripts/Makefile.in
index a2c3120079..a5f782cae6 100644
--- a/scripts/Makefile.in
+++ b/scripts/Makefile.in
@@ -500,6 +500,7 @@ EXTRA_DIST = \
update_submodules \
mcs.in \
dmcs.in \
+ mono-package-runtime \
mono-test-install \
mono-heapviz \
$(MDOC_COMPAT) \
diff --git a/scripts/mono-package-runtime b/scripts/mono-package-runtime
new file mode 100644
index 0000000000..d71942ba0c
--- /dev/null
+++ b/scripts/mono-package-runtime
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+if test x$2 = x; then
+ echo usage is: mono-package-runtime MONO_INSTALL_PREFIX LABEL
+ echo The file will be created in the current directory
+ exit 1
+fi
+
+prefix=$1
+output=$2
+if test ! -d $prefix; then
+ echo the specified path is not a directory: $prefix
+ exit 1
+fi
+
+if test -e $output.zip; then
+ echo The output file already exists, refusing to overwrite: $output.zip
+ exit 1
+fi
+
+if test ! -e $prefix/bin/mono; then
+ echo The $prefix does not contains a bin/mono
+ exit 1
+fi
+
+if test ! -d $prefix/lib/mono/4.5; then
+ echo The $prefix does not contains a lib/mono/4.5
+ exit 1
+fi
+
+o=`pwd`/$output
+
+cd $prefix
+(zip -u $o.zip bin/mono lib/mono/4.5/mscorlib.dll lib/mono/4.5/System*dll lib/mono/4.5/Mono.CSharp.dll lib/mono/4.5/Microsoft*dll lib/mono/4.5/FSharp*.dll lib/mono/4.5/I18N*dll lib/mono/4.5/Accessibility.dll lib/mono/4.5/RabbitMQ.Client.dll lib/mono/4.5/ICSharpCode.SharpZipLib.dll lib/mono/4.5/CustomMarshalers.dll etc/mono/config etc/mono/4.5/machine.config etc/mono/4.5/web.config lib/mono/4.5/Mono.Cairo.dll lib/mono/4.5/Mono.Data.Sqlite.dll lib/mono/4.5/Mono.Posix.dll lib/mono/4.5/Mono.Security.*dll lib/mono/4.5/Mono.Simd.dll)
+echo Created file $o.zip
+