Create self signed cert if one does not exist
This commit is contained in:
parent
de76156391
commit
f6d6d57983
|
@ -2,6 +2,7 @@ using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Net;
|
using MediaBrowser.Model.Net;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Net
|
namespace MediaBrowser.Common.Net
|
||||||
{
|
{
|
||||||
|
@ -51,5 +52,12 @@ namespace MediaBrowser.Common.Net
|
||||||
/// <param name="endpoint">The endpoint.</param>
|
/// <param name="endpoint">The endpoint.</param>
|
||||||
/// <returns><c>true</c> if [is in local network] [the specified endpoint]; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if [is in local network] [the specified endpoint]; otherwise, <c>false</c>.</returns>
|
||||||
bool IsInLocalNetwork(string endpoint);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -57,6 +57,11 @@
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\Mono.Posix.4.0.0.0\lib\net40\Mono.Posix.dll</HintPath>
|
<HintPath>..\packages\Mono.Posix.4.0.0.0\lib\net40\Mono.Posix.dll</HintPath>
|
||||||
</Reference>
|
</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="System" />
|
||||||
<Reference Include="ServiceStack.Interfaces">
|
<Reference Include="ServiceStack.Interfaces">
|
||||||
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
|
<HintPath>..\ThirdParty\ServiceStack\ServiceStack.Interfaces.dll</HintPath>
|
||||||
|
@ -70,6 +75,7 @@
|
||||||
<Link>Properties\SharedVersion.cs</Link>
|
<Link>Properties\SharedVersion.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Native\BaseMonoApp.cs" />
|
<Compile Include="Native\BaseMonoApp.cs" />
|
||||||
|
<Compile Include="Networking\CertificateGenerator.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Native\NativeApp.cs" />
|
<Compile Include="Native\NativeApp.cs" />
|
||||||
|
|
88
MediaBrowser.Server.Mono/Networking/CertificateGenerator.cs
Normal file
88
MediaBrowser.Server.Mono/Networking/CertificateGenerator.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,5 +35,15 @@ namespace MediaBrowser.Server.Mono.Networking
|
||||||
{
|
{
|
||||||
return new List<FileSystemEntryInfo> ();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -779,6 +779,13 @@ namespace MediaBrowser.Server.Startup.Common
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (ServerConfigurationManager.Configuration.EnableHttps)
|
||||||
|
{
|
||||||
|
NetworkManager.GenerateSelfSignedSslCertificate(
|
||||||
|
ServerConfigurationManager.Configuration.CertificatePath,
|
||||||
|
GetHostnameFromExternalDns(ServerConfigurationManager.Configuration.WanDdns));
|
||||||
|
}
|
||||||
|
|
||||||
ServerManager.Start(GetUrlPrefixes(), ServerConfigurationManager.Configuration.CertificatePath);
|
ServerManager.Start(GetUrlPrefixes(), ServerConfigurationManager.Configuration.CertificatePath);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -1183,5 +1190,29 @@ namespace MediaBrowser.Server.Startup.Common
|
||||||
NativeApp.ConfigureAutoRun(autorun);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,6 +109,7 @@
|
||||||
<Compile Include="Native\Standby.cs" />
|
<Compile Include="Native\Standby.cs" />
|
||||||
<Compile Include="Native\ServerAuthorization.cs" />
|
<Compile Include="Native\ServerAuthorization.cs" />
|
||||||
<Compile Include="Native\WindowsApp.cs" />
|
<Compile Include="Native\WindowsApp.cs" />
|
||||||
|
<Compile Include="Networking\CertificateGenerator.cs" />
|
||||||
<Compile Include="Networking\NativeMethods.cs" />
|
<Compile Include="Networking\NativeMethods.cs" />
|
||||||
<Compile Include="Networking\NetworkManager.cs" />
|
<Compile Include="Networking\NetworkManager.cs" />
|
||||||
<Compile Include="Networking\NetworkShares.cs" />
|
<Compile Include="Networking\NetworkShares.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,9 +47,108 @@ namespace MediaBrowser.ServerApplication.Networking
|
||||||
/// <returns>System.Int32.</returns>
|
/// <returns>System.Int32.</returns>
|
||||||
[DllImport("Netapi32", SetLastError = true),
|
[DllImport("Netapi32", SetLastError = true),
|
||||||
SuppressUnmanagedCodeSecurity]
|
SuppressUnmanagedCodeSecurity]
|
||||||
|
|
||||||
public static extern int NetApiBufferFree(
|
public static extern int NetApiBufferFree(
|
||||||
IntPtr pBuf);
|
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
|
//create a _SERVER_INFO_100 STRUCTURE
|
||||||
|
@ -69,4 +168,59 @@ namespace MediaBrowser.ServerApplication.Networking
|
||||||
[MarshalAs(UnmanagedType.LPWStr)]
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
internal string sv100_name;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,6 +155,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>
|
/// <summary>
|
||||||
/// Gets the network prefix.
|
/// Gets the network prefix.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user