aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Common/Net/INetworkManager.cs8
-rw-r--r--MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj6
-rw-r--r--MediaBrowser.Server.Mono/Networking/CertificateGenerator.cs88
-rw-r--r--MediaBrowser.Server.Mono/Networking/NetworkManager.cs10
-rw-r--r--MediaBrowser.Server.Startup.Common/ApplicationHost.cs31
-rw-r--r--MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj1
-rw-r--r--MediaBrowser.ServerApplication/Networking/CertificateGenerator.cs263
-rw-r--r--MediaBrowser.ServerApplication/Networking/NativeMethods.cs156
-rw-r--r--MediaBrowser.ServerApplication/Networking/NetworkManager.cs10
9 files changed, 572 insertions, 1 deletions
diff --git a/MediaBrowser.Common/Net/INetworkManager.cs b/MediaBrowser.Common/Net/INetworkManager.cs
index 979dae49c..6b8136d87 100644
--- a/MediaBrowser.Common/Net/INetworkManager.cs
+++ b/MediaBrowser.Common/Net/INetworkManager.cs
@@ -2,6 +2,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
using System.Collections.Generic;
using System.Net;
+using MediaBrowser.Model.Logging;
namespace MediaBrowser.Common.Net
{
@@ -51,5 +52,12 @@ namespace MediaBrowser.Common.Net
/// <param name="endpoint">The endpoint.</param>
/// <returns><c>true</c> if [is in local network] [the specified endpoint]; otherwise, <c>false</c>.</returns>
bool IsInLocalNetwork(string endpoint);
+
+ /// <summary>
+ /// Generates a self signed certificate at the locatation specified by <paramref name="certificatePath"/>.
+ /// </summary>
+ /// <param name="certificatePath">The path to generate the certificate.</param>
+ /// <param name="hostname">The common name for the certificate.</param>
+ void GenerateSelfSignedSslCertificate(string certificatePath, string hostname);
}
} \ No newline at end of file
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index e780f447f..232caba4f 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -57,6 +57,11 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Mono.Posix.4.0.0.0\lib\net40\Mono.Posix.dll</HintPath>
</Reference>
+ <Reference Include="Mono.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\ThirdParty\Mono.Security\Mono.Security.dll</HintPath>
+ <Private>False</Private>
+ </Reference>
<Reference Include="System" />
<Reference Include="ServiceStack.Interfaces">
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
@@ -70,6 +75,7 @@
<Link>Properties\SharedVersion.cs</Link>
</Compile>
<Compile Include="Native\BaseMonoApp.cs" />
+ <Compile Include="Networking\CertificateGenerator.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Native\NativeApp.cs" />
diff --git a/MediaBrowser.Server.Mono/Networking/CertificateGenerator.cs b/MediaBrowser.Server.Mono/Networking/CertificateGenerator.cs
new file mode 100644
index 000000000..52909a544
--- /dev/null
+++ b/MediaBrowser.Server.Mono/Networking/CertificateGenerator.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+using Mono.Security.X509;
+
+namespace MediaBrowser.Server.Mono.Networking
+{
+ internal class CertificateGenerator
+ {
+ private const string MonoTestRootAgency = "<RSAKeyValue><Modulus>v/4nALBxCE+9JgEC0LnDUvKh6e96PwTpN4Rj+vWnqKT7IAp1iK/JjuqvAg6DQ2vTfv0dTlqffmHH51OyioprcT5nzxcSTsZb/9jcHScG0s3/FRIWnXeLk/fgm7mSYhjUaHNI0m1/NTTktipicjKxo71hGIg9qucCWnDum+Krh/k=</Modulus><Exponent>AQAB</Exponent><P>9jbKxMXEruW2CfZrzhxtull4O8P47+mNsEL+9gf9QsRO1jJ77C+jmzfU6zbzjf8+ViK+q62tCMdC1ZzulwdpXQ==</P><Q>x5+p198l1PkK0Ga2mRh0SIYSykENpY2aLXoyZD/iUpKYAvATm0/wvKNrE4dKJyPCA+y3hfTdgVag+SP9avvDTQ==</Q><DP>ISSjCvXsUfbOGG05eddN1gXxL2pj+jegQRfjpk7RAsnWKvNExzhqd5x+ZuNQyc6QH5wxun54inP4RTUI0P/IaQ==</DP><DQ>R815VQmR3RIbPqzDXzv5j6CSH6fYlcTiQRtkBsUnzhWmkd/y3XmamO+a8zJFjOCCx9CcjpVuGziivBqi65lVPQ==</DQ><InverseQ>iYiu0KwMWI/dyqN3RJYUzuuLj02/oTD1pYpwo2rvNCXU1Q5VscOeu2DpNg1gWqI+1RrRCsEoaTNzXB1xtKNlSw==</InverseQ><D>nIfh1LYF8fjRBgMdAH/zt9UKHWiaCnc+jXzq5tkR8HVSKTVdzitD8bl1JgAfFQD8VjSXiCJqluexy/B5SGrCXQ49c78NIQj0hD+J13Y8/E0fUbW1QYbhj6Ff7oHyhaYe1WOQfkp2t/h+llHOdt1HRf7bt7dUknYp7m8bQKGxoYE=</D></RSAKeyValue>";
+
+ internal static void CreateSelfSignCertificatePfx(
+ string fileName,
+ string hostname,
+ ILogger logger)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(fileName))
+ {
+ logger.Info("No certificate filename specified.");
+ return;
+ }
+
+ if (File.Exists(fileName))
+ {
+ logger.Info("Certificate file already exists. To regenerate, delete {0}", fileName);
+ return;
+ }
+
+ byte[] sn = Guid.NewGuid().ToByteArray();
+ string subject = string.Format("CN={0}", hostname);
+ string issuer = subject;
+ DateTime notBefore = DateTime.Now.AddDays(-2);
+ DateTime notAfter = DateTime.Now.AddYears(10);
+
+ RSA issuerKey = RSA.Create();
+ issuerKey.FromXmlString(MonoTestRootAgency);
+ RSA subjectKey = RSA.Create();
+
+ // serial number MUST be positive
+ if ((sn[0] & 0x80) == 0x80)
+ sn[0] -= 0x80;
+
+ issuer = subject;
+ issuerKey = subjectKey;
+
+ X509CertificateBuilder cb = new X509CertificateBuilder(3);
+ cb.SerialNumber = sn;
+ cb.IssuerName = issuer;
+ cb.NotBefore = notBefore;
+ cb.NotAfter = notAfter;
+ cb.SubjectName = subject;
+ cb.SubjectPublicKey = subjectKey;
+
+ // signature
+ cb.Hash = "SHA256";
+ byte[] rawcert = cb.Sign(issuerKey);
+
+ PKCS12 p12 = new PKCS12();
+
+
+ ArrayList list = new ArrayList();
+ // we use a fixed array to avoid endianess issues
+ // (in case some tools requires the ID to be 1).
+ list.Add(new byte[4] {1, 0, 0, 0});
+ Hashtable attributes = new Hashtable(1);
+ attributes.Add(PKCS9.localKeyId, list);
+
+ p12.AddCertificate(new X509Certificate(rawcert), attributes);
+
+ p12.AddPkcs8ShroudedKeyBag(subjectKey, attributes);
+ p12.SaveToFile(fileName);
+ }
+ catch (Exception e)
+ {
+ logger.ErrorException("Error generating self signed ssl certificate: {0}", e, fileName);
+ }
+
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Mono/Networking/NetworkManager.cs b/MediaBrowser.Server.Mono/Networking/NetworkManager.cs
index 60c250115..b4133f6dd 100644
--- a/MediaBrowser.Server.Mono/Networking/NetworkManager.cs
+++ b/MediaBrowser.Server.Mono/Networking/NetworkManager.cs
@@ -35,5 +35,15 @@ namespace MediaBrowser.Server.Mono.Networking
{
return new List<FileSystemEntryInfo> ();
}
+
+ /// <summary>
+ /// Generates a self signed certificate at the locatation specified by <paramref name="certificatePath"/>.
+ /// </summary>
+ /// <param name="certificatePath">The path to generate the certificate.</param>
+ /// <param name="hostname">The common name for the certificate.</param>
+ public void GenerateSelfSignedSslCertificate(string certificatePath, string hostname)
+ {
+ CertificateGenerator.CreateSelfSignCertificatePfx(certificatePath, hostname, Logger);
+ }
}
}
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index 16cf4258a..4e05bceff 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -779,6 +779,13 @@ namespace MediaBrowser.Server.Startup.Common
{
try
{
+ if (ServerConfigurationManager.Configuration.EnableHttps)
+ {
+ NetworkManager.GenerateSelfSignedSslCertificate(
+ ServerConfigurationManager.Configuration.CertificatePath,
+ GetHostnameFromExternalDns(ServerConfigurationManager.Configuration.WanDdns));
+ }
+
ServerManager.Start(GetUrlPrefixes(), ServerConfigurationManager.Configuration.CertificatePath);
}
catch (Exception ex)
@@ -1183,5 +1190,29 @@ namespace MediaBrowser.Server.Startup.Common
NativeApp.ConfigureAutoRun(autorun);
}
}
+
+ /// <summary>
+ /// This returns localhost in the case of no external dns, and the hostname if the
+ /// dns is prefixed with a valid Uri prefix.
+ /// </summary>
+ /// <param name="externalDns">The external dns prefix to get the hostname of.</param>
+ /// <returns>The hostname in <paramref name="externalDns"/></returns>
+ private static string GetHostnameFromExternalDns(string externalDns)
+ {
+ if (string.IsNullOrWhiteSpace(externalDns))
+ {
+ return "localhost";
+ }
+
+ try
+ {
+ Uri uri = new Uri(externalDns);
+ return uri.Host;
+ }
+ catch (Exception e)
+ {
+ return externalDns;
+ }
+ }
}
}
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index cc0bf3126..8df2d3ab0 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -109,6 +109,7 @@
<Compile Include="Native\Standby.cs" />
<Compile Include="Native\ServerAuthorization.cs" />
<Compile Include="Native\WindowsApp.cs" />
+ <Compile Include="Networking\CertificateGenerator.cs" />
<Compile Include="Networking\NativeMethods.cs" />
<Compile Include="Networking\NetworkManager.cs" />
<Compile Include="Networking\NetworkShares.cs" />
diff --git a/MediaBrowser.ServerApplication/Networking/CertificateGenerator.cs b/MediaBrowser.ServerApplication/Networking/CertificateGenerator.cs
new file mode 100644
index 000000000..a0200ba1d
--- /dev/null
+++ b/MediaBrowser.ServerApplication/Networking/CertificateGenerator.cs
@@ -0,0 +1,263 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+
+namespace MediaBrowser.ServerApplication.Networking
+{
+ // Copied from: http://blogs.msdn.com/b/dcook/archive/2014/05/16/9143036.aspx
+ // In case anybody is interested, source code is attached and is free for use by anybody as long as you don't hold me or Microsoft liable for it --
+ // I have no idea whether this is actually the right or best way to do this. Give it the X500 distinguished name, validity start and end dates,
+ // and an optional password for encrypting the key data, and it will give you the PFX file data. Let me know if you find any bugs or have any suggestions.
+ internal class CertificateGenerator
+ {
+ internal static void CreateSelfSignCertificatePfx(
+ string fileName,
+ string hostname,
+ ILogger logger)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(fileName))
+ {
+ logger.Info("No certificate filename specified.");
+ return;
+ }
+
+ if (File.Exists(fileName))
+ {
+ logger.Info("Certificate file already exists. To regenerate, delete {0}", fileName);
+ return;
+ }
+
+ string x500 = string.Format("CN={0}", hostname);
+
+ DateTime startTime = DateTime.Now.AddDays(-2);
+ DateTime endTime = DateTime.Now.AddYears(10);
+
+ byte[] pfxData = CreateSelfSignCertificatePfx(
+ x500,
+ startTime,
+ endTime);
+
+ File.WriteAllBytes(fileName, pfxData);
+ }
+ catch (Exception e)
+ {
+ logger.ErrorException("Error generating self signed ssl certificate: {0}", e, fileName);
+ }
+ }
+
+ private static byte[] CreateSelfSignCertificatePfx(
+ string x500,
+ DateTime startTime,
+ DateTime endTime)
+ {
+ byte[] pfxData;
+
+ if (x500 == null)
+ {
+ x500 = "";
+ }
+
+ SystemTime startSystemTime = ToSystemTime(startTime);
+ SystemTime endSystemTime = ToSystemTime(endTime);
+ string containerName = Guid.NewGuid().ToString();
+
+ GCHandle dataHandle = new GCHandle();
+ IntPtr providerContext = IntPtr.Zero;
+ IntPtr cryptKey = IntPtr.Zero;
+ IntPtr certContext = IntPtr.Zero;
+ IntPtr certStore = IntPtr.Zero;
+ IntPtr storeCertContext = IntPtr.Zero;
+ IntPtr passwordPtr = IntPtr.Zero;
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
+ {
+ Check(NativeMethods.CryptAcquireContextW(
+ out providerContext,
+ containerName,
+ null,
+ 1, // PROV_RSA_FULL
+ 8)); // CRYPT_NEWKEYSET
+
+ Check(NativeMethods.CryptGenKey(
+ providerContext,
+ 1, // AT_KEYEXCHANGE
+ 1 | 2048 << 16, // CRYPT_EXPORTABLE 2048 bit key
+ out cryptKey));
+
+ IntPtr errorStringPtr;
+ int nameDataLength = 0;
+ byte[] nameData;
+
+ // errorStringPtr gets a pointer into the middle of the x500 string,
+ // so x500 needs to be pinned until after we've copied the value
+ // of errorStringPtr.
+ dataHandle = GCHandle.Alloc(x500, GCHandleType.Pinned);
+
+ if (!NativeMethods.CertStrToNameW(
+ 0x00010001, // X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
+ dataHandle.AddrOfPinnedObject(),
+ 3, // CERT_X500_NAME_STR = 3
+ IntPtr.Zero,
+ null,
+ ref nameDataLength,
+ out errorStringPtr))
+ {
+ string error = Marshal.PtrToStringUni(errorStringPtr);
+ throw new ArgumentException(error);
+ }
+
+ nameData = new byte[nameDataLength];
+
+ if (!NativeMethods.CertStrToNameW(
+ 0x00010001, // X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
+ dataHandle.AddrOfPinnedObject(),
+ 3, // CERT_X500_NAME_STR = 3
+ IntPtr.Zero,
+ nameData,
+ ref nameDataLength,
+ out errorStringPtr))
+ {
+ string error = Marshal.PtrToStringUni(errorStringPtr);
+ throw new ArgumentException(error);
+ }
+
+ dataHandle.Free();
+
+ dataHandle = GCHandle.Alloc(nameData, GCHandleType.Pinned);
+ CryptoApiBlob nameBlob = new CryptoApiBlob(
+ nameData.Length,
+ dataHandle.AddrOfPinnedObject());
+
+ CryptKeyProviderInformation kpi = new CryptKeyProviderInformation();
+ kpi.ContainerName = containerName;
+ kpi.ProviderType = 1; // PROV_RSA_FULL
+ kpi.KeySpec = 1; // AT_KEYEXCHANGE
+
+ CryptAlgorithmIdentifier sha256Identifier = new CryptAlgorithmIdentifier();
+ sha256Identifier.pszObjId = "1.2.840.113549.1.1.11";
+
+ certContext = NativeMethods.CertCreateSelfSignCertificate(
+ providerContext,
+ ref nameBlob,
+ 0,
+ ref kpi,
+ ref sha256Identifier,
+ ref startSystemTime,
+ ref endSystemTime,
+ IntPtr.Zero);
+ Check(certContext != IntPtr.Zero);
+ dataHandle.Free();
+
+ certStore = NativeMethods.CertOpenStore(
+ "Memory", // sz_CERT_STORE_PROV_MEMORY
+ 0,
+ IntPtr.Zero,
+ 0x2000, // CERT_STORE_CREATE_NEW_FLAG
+ IntPtr.Zero);
+ Check(certStore != IntPtr.Zero);
+
+ Check(NativeMethods.CertAddCertificateContextToStore(
+ certStore,
+ certContext,
+ 1, // CERT_STORE_ADD_NEW
+ out storeCertContext));
+
+ NativeMethods.CertSetCertificateContextProperty(
+ storeCertContext,
+ 2, // CERT_KEY_PROV_INFO_PROP_ID
+ 0,
+ ref kpi);
+
+ CryptoApiBlob pfxBlob = new CryptoApiBlob();
+ Check(NativeMethods.PFXExportCertStoreEx(
+ certStore,
+ ref pfxBlob,
+ passwordPtr,
+ IntPtr.Zero,
+ 7)); // EXPORT_PRIVATE_KEYS | REPORT_NO_PRIVATE_KEY | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
+
+ pfxData = new byte[pfxBlob.DataLength];
+ dataHandle = GCHandle.Alloc(pfxData, GCHandleType.Pinned);
+ pfxBlob.Data = dataHandle.AddrOfPinnedObject();
+ Check(NativeMethods.PFXExportCertStoreEx(
+ certStore,
+ ref pfxBlob,
+ passwordPtr,
+ IntPtr.Zero,
+ 7)); // EXPORT_PRIVATE_KEYS | REPORT_NO_PRIVATE_KEY | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY
+ dataHandle.Free();
+ }
+ finally
+ {
+ if (passwordPtr != IntPtr.Zero)
+ {
+ Marshal.ZeroFreeCoTaskMemUnicode(passwordPtr);
+ }
+
+ if (dataHandle.IsAllocated)
+ {
+ dataHandle.Free();
+ }
+
+ if (certContext != IntPtr.Zero)
+ {
+ NativeMethods.CertFreeCertificateContext(certContext);
+ }
+
+ if (storeCertContext != IntPtr.Zero)
+ {
+ NativeMethods.CertFreeCertificateContext(storeCertContext);
+ }
+
+ if (certStore != IntPtr.Zero)
+ {
+ NativeMethods.CertCloseStore(certStore, 0);
+ }
+
+ if (cryptKey != IntPtr.Zero)
+ {
+ NativeMethods.CryptDestroyKey(cryptKey);
+ }
+
+ if (providerContext != IntPtr.Zero)
+ {
+ NativeMethods.CryptReleaseContext(providerContext, 0);
+ NativeMethods.CryptAcquireContextW(
+ out providerContext,
+ containerName,
+ null,
+ 1, // PROV_RSA_FULL
+ 0x10); // CRYPT_DELETEKEYSET
+ }
+ }
+
+ return pfxData;
+ }
+
+ private static SystemTime ToSystemTime(DateTime dateTime)
+ {
+ long fileTime = dateTime.ToFileTime();
+ SystemTime systemTime;
+ Check(NativeMethods.FileTimeToSystemTime(ref fileTime, out systemTime));
+ return systemTime;
+ }
+
+ private static void Check(bool nativeCallSucceeded)
+ {
+ if (!nativeCallSucceeded)
+ {
+ int error = Marshal.GetHRForLastWin32Error();
+ Marshal.ThrowExceptionForHR(error);
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.ServerApplication/Networking/NativeMethods.cs b/MediaBrowser.ServerApplication/Networking/NativeMethods.cs
index 20f7ac23d..037b1f75b 100644
--- a/MediaBrowser.ServerApplication/Networking/NativeMethods.cs
+++ b/MediaBrowser.ServerApplication/Networking/NativeMethods.cs
@@ -47,9 +47,108 @@ namespace MediaBrowser.ServerApplication.Networking
/// <returns>System.Int32.</returns>
[DllImport("Netapi32", SetLastError = true),
SuppressUnmanagedCodeSecurity]
-
public static extern int NetApiBufferFree(
IntPtr pBuf);
+
+ [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool FileTimeToSystemTime(
+ [In] ref long fileTime,
+ out SystemTime systemTime);
+
+ [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CryptAcquireContextW(
+ out IntPtr providerContext,
+ [MarshalAs(UnmanagedType.LPWStr)] string container,
+ [MarshalAs(UnmanagedType.LPWStr)] string provider,
+ int providerType,
+ int flags);
+
+ [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CryptReleaseContext(
+ IntPtr providerContext,
+ int flags);
+
+ [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CryptGenKey(
+ IntPtr providerContext,
+ int algorithmId,
+ int flags,
+ out IntPtr cryptKeyHandle);
+
+ [DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CryptDestroyKey(
+ IntPtr cryptKeyHandle);
+
+ [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CertStrToNameW(
+ int certificateEncodingType,
+ IntPtr x500,
+ int strType,
+ IntPtr reserved,
+ [MarshalAs(UnmanagedType.LPArray)] [Out] byte[] encoded,
+ ref int encodedLength,
+ out IntPtr errorString);
+
+ [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+ public static extern IntPtr CertCreateSelfSignCertificate(
+ IntPtr providerHandle,
+ [In] ref CryptoApiBlob subjectIssuerBlob,
+ int flags,
+ [In] ref CryptKeyProviderInformation keyProviderInformation,
+ [In] ref CryptAlgorithmIdentifier algorithmIdentifier,
+ [In] ref SystemTime startTime,
+ [In] ref SystemTime endTime,
+ IntPtr extensions);
+
+ [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CertFreeCertificateContext(
+ IntPtr certificateContext);
+
+ [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+ public static extern IntPtr CertOpenStore(
+ [MarshalAs(UnmanagedType.LPStr)] string storeProvider,
+ int messageAndCertificateEncodingType,
+ IntPtr cryptProvHandle,
+ int flags,
+ IntPtr parameters);
+
+ [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CertCloseStore(
+ IntPtr certificateStoreHandle,
+ int flags);
+
+ [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CertAddCertificateContextToStore(
+ IntPtr certificateStoreHandle,
+ IntPtr certificateContext,
+ int addDisposition,
+ out IntPtr storeContextPtr);
+
+ [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool CertSetCertificateContextProperty(
+ IntPtr certificateContext,
+ int propertyId,
+ int flags,
+ [In] ref CryptKeyProviderInformation data);
+
+ [DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool PFXExportCertStoreEx(
+ IntPtr certificateStoreHandle,
+ ref CryptoApiBlob pfxBlob,
+ IntPtr password,
+ IntPtr reserved,
+ int flags);
}
//create a _SERVER_INFO_100 STRUCTURE
@@ -69,4 +168,59 @@ namespace MediaBrowser.ServerApplication.Networking
[MarshalAs(UnmanagedType.LPWStr)]
internal string sv100_name;
}
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SystemTime
+ {
+ public short Year;
+ public short Month;
+ public short DayOfWeek;
+ public short Day;
+ public short Hour;
+ public short Minute;
+ public short Second;
+ public short Milliseconds;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CryptObjIdBlob
+ {
+ public uint cbData;
+ public IntPtr pbData;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CryptAlgorithmIdentifier
+ {
+ [MarshalAs(UnmanagedType.LPStr)]
+ public String pszObjId;
+ public CryptObjIdBlob Parameters;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CryptoApiBlob
+ {
+ public int DataLength;
+ public IntPtr Data;
+
+ public CryptoApiBlob(int dataLength, IntPtr data)
+ {
+ this.DataLength = dataLength;
+ this.Data = data;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CryptKeyProviderInformation
+ {
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string ContainerName;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string ProviderName;
+ public int ProviderType;
+ public int Flags;
+ public int ProviderParameterCount;
+ public IntPtr ProviderParameters; // PCRYPT_KEY_PROV_PARAM
+ public int KeySpec;
+ }
}
diff --git a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
index fc4d26363..978a29db0 100644
--- a/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
+++ b/MediaBrowser.ServerApplication/Networking/NetworkManager.cs
@@ -156,6 +156,16 @@ namespace MediaBrowser.ServerApplication.Networking
}
/// <summary>
+ /// Generates a self signed certificate at the locatation specified by <paramref name="certificatePath"/>.
+ /// </summary>
+ /// <param name="certificatePath">The path to generate the certificate.</param>
+ /// <param name="hostname">The common name for the certificate.</param>
+ public void GenerateSelfSignedSslCertificate(string certificatePath, string hostname)
+ {
+ CertificateGenerator.CreateSelfSignCertificatePfx(certificatePath, hostname, Logger);
+ }
+
+ /// <summary>
/// Gets the network prefix.
/// </summary>
/// <value>The network prefix.</value>