2015-01-19 06:42:31 +00:00
|
|
|
|
using MediaBrowser.Model.Logging;
|
|
|
|
|
using System;
|
2015-01-18 21:44:35 +00:00
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Security.Cryptography;
|
2017-08-17 20:19:02 +00:00
|
|
|
|
using System.Xml;
|
2015-01-18 21:44:35 +00:00
|
|
|
|
|
2017-05-24 19:12:55 +00:00
|
|
|
|
namespace Emby.Server.Core.Cryptography
|
2015-01-18 21:44:35 +00:00
|
|
|
|
{
|
2016-11-11 07:24:36 +00:00
|
|
|
|
public class CertificateGenerator
|
2015-01-18 21:44:35 +00:00
|
|
|
|
{
|
|
|
|
|
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>";
|
|
|
|
|
|
2016-11-11 19:55:12 +00:00
|
|
|
|
public static void CreateSelfSignCertificatePfx(
|
2015-01-18 21:44:35 +00:00
|
|
|
|
string fileName,
|
|
|
|
|
string hostname,
|
2017-05-01 02:22:13 +00:00
|
|
|
|
string password,
|
2015-01-18 21:44:35 +00:00
|
|
|
|
ILogger logger)
|
|
|
|
|
{
|
2015-01-19 06:42:31 +00:00
|
|
|
|
if (string.IsNullOrWhiteSpace(fileName))
|
2015-01-18 21:44:35 +00:00
|
|
|
|
{
|
2015-01-19 06:42:31 +00:00
|
|
|
|
throw new ArgumentNullException("fileName");
|
|
|
|
|
}
|
2015-01-18 21:44:35 +00:00
|
|
|
|
|
2015-01-19 06:42:31 +00:00
|
|
|
|
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);
|
2015-01-18 21:44:35 +00:00
|
|
|
|
|
2015-01-19 06:42:31 +00:00
|
|
|
|
RSA issuerKey = RSA.Create();
|
2017-08-17 20:19:02 +00:00
|
|
|
|
#if NET46
|
2015-01-19 06:42:31 +00:00
|
|
|
|
issuerKey.FromXmlString(MonoTestRootAgency);
|
2017-08-17 20:19:02 +00:00
|
|
|
|
#else
|
|
|
|
|
RSACryptoServiceProviderExtensions.FromXmlString(issuerKey, MonoTestRootAgency);
|
|
|
|
|
#endif
|
2015-01-19 06:42:31 +00:00
|
|
|
|
RSA subjectKey = RSA.Create();
|
2015-01-18 21:44:35 +00:00
|
|
|
|
|
2015-01-19 06:42:31 +00:00
|
|
|
|
// serial number MUST be positive
|
|
|
|
|
if ((sn[0] & 0x80) == 0x80)
|
|
|
|
|
sn[0] -= 0x80;
|
2015-01-18 21:44:35 +00:00
|
|
|
|
|
2015-01-19 06:42:31 +00:00
|
|
|
|
issuer = subject;
|
|
|
|
|
issuerKey = subjectKey;
|
2015-01-18 21:44:35 +00:00
|
|
|
|
|
2015-01-19 06:42:31 +00:00
|
|
|
|
X509CertificateBuilder cb = new X509CertificateBuilder(3);
|
|
|
|
|
cb.SerialNumber = sn;
|
|
|
|
|
cb.IssuerName = issuer;
|
|
|
|
|
cb.NotBefore = notBefore;
|
|
|
|
|
cb.NotAfter = notAfter;
|
|
|
|
|
cb.SubjectName = subject;
|
|
|
|
|
cb.SubjectPublicKey = subjectKey;
|
2017-08-17 20:19:02 +00:00
|
|
|
|
|
2015-01-19 06:42:31 +00:00
|
|
|
|
// signature
|
|
|
|
|
cb.Hash = "SHA256";
|
|
|
|
|
byte[] rawcert = cb.Sign(issuerKey);
|
2015-01-18 21:44:35 +00:00
|
|
|
|
|
2015-01-19 06:42:31 +00:00
|
|
|
|
PKCS12 p12 = new PKCS12();
|
2015-01-18 21:44:35 +00:00
|
|
|
|
|
|
|
|
|
|
2015-01-19 06:42:31 +00:00
|
|
|
|
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);
|
2015-01-18 21:44:35 +00:00
|
|
|
|
|
2015-01-19 06:42:31 +00:00
|
|
|
|
p12.AddCertificate(new X509Certificate(rawcert), attributes);
|
2017-05-01 20:03:27 +00:00
|
|
|
|
p12.Password = password;
|
2015-01-18 21:44:35 +00:00
|
|
|
|
|
2015-01-19 06:42:31 +00:00
|
|
|
|
p12.AddPkcs8ShroudedKeyBag(subjectKey, attributes);
|
|
|
|
|
p12.SaveToFile(fileName);
|
2015-01-18 21:44:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-17 20:19:02 +00:00
|
|
|
|
|
|
|
|
|
public static class RSACryptoServiceProviderExtensions
|
|
|
|
|
{
|
|
|
|
|
public static void FromXmlString(RSA rsa, string xmlString)
|
|
|
|
|
{
|
|
|
|
|
RSAParameters parameters = new RSAParameters();
|
|
|
|
|
|
|
|
|
|
XmlDocument xmlDoc = new XmlDocument();
|
|
|
|
|
xmlDoc.LoadXml(xmlString);
|
|
|
|
|
|
|
|
|
|
if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
|
|
|
|
|
{
|
|
|
|
|
foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
|
|
|
|
|
{
|
|
|
|
|
switch (node.Name)
|
|
|
|
|
{
|
|
|
|
|
case "Modulus": parameters.Modulus = Convert.FromBase64String(node.InnerText); break;
|
|
|
|
|
case "Exponent": parameters.Exponent = Convert.FromBase64String(node.InnerText); break;
|
|
|
|
|
case "P": parameters.P = Convert.FromBase64String(node.InnerText); break;
|
|
|
|
|
case "Q": parameters.Q = Convert.FromBase64String(node.InnerText); break;
|
|
|
|
|
case "DP": parameters.DP = Convert.FromBase64String(node.InnerText); break;
|
|
|
|
|
case "DQ": parameters.DQ = Convert.FromBase64String(node.InnerText); break;
|
|
|
|
|
case "InverseQ": parameters.InverseQ = Convert.FromBase64String(node.InnerText); break;
|
|
|
|
|
case "D": parameters.D = Convert.FromBase64String(node.InnerText); break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Invalid XML RSA key.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsa.ImportParameters(parameters);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-01-18 21:44:35 +00:00
|
|
|
|
}
|