From 0b73c25aa4fd61d278e46c33050b42d1c48e5e1d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 28 Sep 2017 13:00:50 -0400 Subject: [PATCH 1/6] update lg dlna profile --- Emby.Dlna/Profiles/LgTvProfile.cs | 6 +++--- Emby.Dlna/Profiles/Xml/LG Smart TV.xml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Emby.Dlna/Profiles/LgTvProfile.cs b/Emby.Dlna/Profiles/LgTvProfile.cs index f81fb1ee7..33185365c 100644 --- a/Emby.Dlna/Profiles/LgTvProfile.cs +++ b/Emby.Dlna/Profiles/LgTvProfile.cs @@ -55,14 +55,14 @@ namespace Emby.Dlna.Profiles { Container = "ts,mpegts,avi,mkv", VideoCodec = "h264", - AudioCodec = "aac,ac3,mp3,dca,dts", + AudioCodec = "aac,ac3,eac3,mp3,dca,dts", Type = DlnaProfileType.Video }, new DirectPlayProfile { Container = "mp4,m4v", VideoCodec = "h264,mpeg4", - AudioCodec = "aac,ac3,mp3,dca,dts", + AudioCodec = "aac,ac3,eac3,mp3,dca,dts", Type = DlnaProfileType.Video }, new DirectPlayProfile @@ -168,7 +168,7 @@ namespace Emby.Dlna.Profiles new CodecProfile { Type = CodecType.VideoAudio, - Codec = "ac3,aac,mp3", + Codec = "ac3,eac3,aac,mp3", Conditions = new[] { diff --git a/Emby.Dlna/Profiles/Xml/LG Smart TV.xml b/Emby.Dlna/Profiles/Xml/LG Smart TV.xml index 92e02799e..ac8c8194c 100644 --- a/Emby.Dlna/Profiles/Xml/LG Smart TV.xml +++ b/Emby.Dlna/Profiles/Xml/LG Smart TV.xml @@ -35,8 +35,8 @@ false - - + + @@ -71,7 +71,7 @@ - + From 2300026e84dcdbcb8b0edcc1315df3e524321909 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 28 Sep 2017 13:01:43 -0400 Subject: [PATCH 2/6] support nef with skia --- Emby.Drawing.Skia/SkiaEncoder.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Emby.Drawing.Skia/SkiaEncoder.cs b/Emby.Drawing.Skia/SkiaEncoder.cs index e8cdd441a..7469d167e 100644 --- a/Emby.Drawing.Skia/SkiaEncoder.cs +++ b/Emby.Drawing.Skia/SkiaEncoder.cs @@ -53,7 +53,8 @@ namespace Emby.Drawing.Skia "wbmp", // working on windows at least - "cr2" + "cr2", + "nef" }; } } From 2e0e1697a8d8ed93669ffdda8e01c0c370e4c6c6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 28 Sep 2017 13:02:49 -0400 Subject: [PATCH 3/6] rework live stream creation --- .../ApplicationHost.cs | 33 +- .../Cryptography/ASN1.cs | 340 --- .../Cryptography/ASN1Convert.cs | 207 -- .../Cryptography/BitConverterLE.cs | 239 -- .../Cryptography/CertificateGenerator.cs | 109 - .../Cryptography/CryptoConvert.cs | 745 ------- .../Cryptography/PKCS1.cs | 491 ----- .../Cryptography/PKCS12.cs | 1934 ----------------- .../Cryptography/PKCS7.cs | 1012 --------- .../Cryptography/PKCS8.cs | 495 ----- .../Cryptography/PfxGenerator.cs | 75 - .../Cryptography/X501Name.cs | 393 ---- .../Cryptography/X509Builder.cs | 153 -- .../Cryptography/X509Certificate.cs | 563 ----- .../Cryptography/X509CertificateBuilder.cs | 245 --- .../Cryptography/X509CertificateCollection.cs | 201 -- .../Cryptography/X509Extension.cs | 208 -- .../Cryptography/X509Extensions.cs | 195 -- .../Cryptography/X520Attributes.cs | 346 --- .../Emby.Server.Implementations.csproj | 19 +- .../LiveTv/EmbyTV/EmbyTV.cs | 10 +- .../LiveTv/LiveTvManager.cs | 2 +- .../LiveTv/TunerHosts/BaseTunerHost.cs | 4 +- .../TunerHosts/HdHomerun/HdHomerunHost.cs | 2 +- .../HdHomerun/HdHomerunHttpStream.cs | 58 +- .../HdHomerun/HdHomerunUdpStream.cs | 82 +- .../LiveTv/TunerHosts/LiveStream.cs | 153 ++ .../LiveTv/TunerHosts/M3UTunerHost.cs | 4 +- 28 files changed, 202 insertions(+), 8116 deletions(-) delete mode 100644 Emby.Server.Implementations/Cryptography/ASN1.cs delete mode 100644 Emby.Server.Implementations/Cryptography/ASN1Convert.cs delete mode 100644 Emby.Server.Implementations/Cryptography/BitConverterLE.cs delete mode 100644 Emby.Server.Implementations/Cryptography/CertificateGenerator.cs delete mode 100644 Emby.Server.Implementations/Cryptography/CryptoConvert.cs delete mode 100644 Emby.Server.Implementations/Cryptography/PKCS1.cs delete mode 100644 Emby.Server.Implementations/Cryptography/PKCS12.cs delete mode 100644 Emby.Server.Implementations/Cryptography/PKCS7.cs delete mode 100644 Emby.Server.Implementations/Cryptography/PKCS8.cs delete mode 100644 Emby.Server.Implementations/Cryptography/PfxGenerator.cs delete mode 100644 Emby.Server.Implementations/Cryptography/X501Name.cs delete mode 100644 Emby.Server.Implementations/Cryptography/X509Builder.cs delete mode 100644 Emby.Server.Implementations/Cryptography/X509Certificate.cs delete mode 100644 Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs delete mode 100644 Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs delete mode 100644 Emby.Server.Implementations/Cryptography/X509Extension.cs delete mode 100644 Emby.Server.Implementations/Cryptography/X509Extensions.cs delete mode 100644 Emby.Server.Implementations/Cryptography/X520Attributes.cs create mode 100644 Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 894d91f71..699621043 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -7,7 +7,6 @@ using Emby.Dlna.MediaReceiverRegistrar; using Emby.Dlna.Ssdp; using Emby.Drawing; using Emby.Photos; -using Emby.Server.Core.Cryptography; using Emby.Server.Implementations.Activity; using Emby.Server.Implementations.Archiving; using Emby.Server.Implementations.Channels; @@ -1640,23 +1639,23 @@ namespace Emby.Server.Implementations var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + (certHost + "2").GetMD5().ToString("N") + ".pfx"); var password = "embycert"; - if (generateCertificate) - { - if (!FileSystemManager.FileExists(certPath)) - { - FileSystemManager.CreateDirectory(FileSystemManager.GetDirectoryName(certPath)); + //if (generateCertificate) + //{ + // if (!FileSystemManager.FileExists(certPath)) + // { + // FileSystemManager.CreateDirectory(FileSystemManager.GetDirectoryName(certPath)); - try - { - CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, password, Logger); - } - catch (Exception ex) - { - Logger.ErrorException("Error creating ssl cert", ex); - return null; - } - } - } + // try + // { + // CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, password, Logger); + // } + // catch (Exception ex) + // { + // Logger.ErrorException("Error creating ssl cert", ex); + // return null; + // } + // } + //} return new CertificateInfo { diff --git a/Emby.Server.Implementations/Cryptography/ASN1.cs b/Emby.Server.Implementations/Cryptography/ASN1.cs deleted file mode 100644 index f5c826436..000000000 --- a/Emby.Server.Implementations/Cryptography/ASN1.cs +++ /dev/null @@ -1,340 +0,0 @@ -// -// ASN1.cs: Abstract Syntax Notation 1 - micro-parser and generator -// -// Authors: -// Sebastien Pouliot -// Jesper Pedersen -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004 Novell, Inc (http://www.novell.com) -// (C) 2004 IT+ A/S (http://www.itplus.dk) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Collections; -using System.IO; -using System.Text; - -namespace Emby.Server.Core.Cryptography -{ - - // References: - // a. ITU ASN.1 standards (free download) - // http://www.itu.int/ITU-T/studygroups/com17/languages/ - - public class ASN1 { - - private byte m_nTag; - private byte[] m_aValue; - private ArrayList elist; - - public ASN1 () : this (0x00, null) {} - - public ASN1 (byte tag) : this (tag, null) {} - - public ASN1 (byte tag, byte[] data) - { - m_nTag = tag; - m_aValue = data; - } - - public ASN1 (byte[] data) - { - m_nTag = data [0]; - - int nLenLength = 0; - int nLength = data [1]; - - if (nLength > 0x80) { - // composed length - nLenLength = nLength - 0x80; - nLength = 0; - for (int i = 0; i < nLenLength; i++) { - nLength *= 256; - nLength += data [i + 2]; - } - } - else if (nLength == 0x80) { - // undefined length encoding - throw new NotSupportedException ("Undefined length encoding."); - } - - m_aValue = new byte [nLength]; - Buffer.BlockCopy (data, (2 + nLenLength), m_aValue, 0, nLength); - - if ((m_nTag & 0x20) == 0x20) { - int nStart = (2 + nLenLength); - Decode (data, ref nStart, data.Length); - } - } - - public int Count { - get { - if (elist == null) - return 0; - return elist.Count; - } - } - - public byte Tag { - get { return m_nTag; } - } - - public int Length { - get { - if (m_aValue != null) - return m_aValue.Length; - else - return 0; - } - } - - public byte[] Value { - get { - if (m_aValue == null) - GetBytes (); - return (byte[]) m_aValue.Clone (); - } - set { - if (value != null) - m_aValue = (byte[]) value.Clone (); - } - } - - private bool CompareArray (byte[] array1, byte[] array2) - { - bool bResult = (array1.Length == array2.Length); - if (bResult) { - for (int i = 0; i < array1.Length; i++) { - if (array1[i] != array2[i]) - return false; - } - } - return bResult; - } - - public bool Equals (byte[] asn1) - { - return CompareArray (this.GetBytes (), asn1); - } - - public bool CompareValue (byte[] value) - { - return CompareArray (m_aValue, value); - } - - public ASN1 Add (ASN1 asn1) - { - if (asn1 != null) { - if (elist == null) - elist = new ArrayList (); - elist.Add (asn1); - } - return asn1; - } - - public virtual byte[] GetBytes () - { - byte[] val = null; - - if (Count > 0) { - int esize = 0; - ArrayList al = new ArrayList (); - foreach (ASN1 a in elist) { - byte[] item = a.GetBytes (); - al.Add (item); - esize += item.Length; - } - val = new byte [esize]; - int pos = 0; - for (int i=0; i < elist.Count; i++) { - byte[] item = (byte[]) al[i]; - Buffer.BlockCopy (item, 0, val, pos, item.Length); - pos += item.Length; - } - } else if (m_aValue != null) { - val = m_aValue; - } - - byte[] der; - int nLengthLen = 0; - - if (val != null) { - int nLength = val.Length; - // special for length > 127 - if (nLength > 127) { - if (nLength <= Byte.MaxValue) { - der = new byte [3 + nLength]; - Buffer.BlockCopy (val, 0, der, 3, nLength); - nLengthLen = 0x81; - der[2] = (byte)(nLength); - } - else if (nLength <= UInt16.MaxValue) { - der = new byte [4 + nLength]; - Buffer.BlockCopy (val, 0, der, 4, nLength); - nLengthLen = 0x82; - der[2] = (byte)(nLength >> 8); - der[3] = (byte)(nLength); - } - else if (nLength <= 0xFFFFFF) { - // 24 bits - der = new byte [5 + nLength]; - Buffer.BlockCopy (val, 0, der, 5, nLength); - nLengthLen = 0x83; - der [2] = (byte)(nLength >> 16); - der [3] = (byte)(nLength >> 8); - der [4] = (byte)(nLength); - } - else { - // max (Length is an integer) 32 bits - der = new byte [6 + nLength]; - Buffer.BlockCopy (val, 0, der, 6, nLength); - nLengthLen = 0x84; - der [2] = (byte)(nLength >> 24); - der [3] = (byte)(nLength >> 16); - der [4] = (byte)(nLength >> 8); - der [5] = (byte)(nLength); - } - } - else { - // basic case (no encoding) - der = new byte [2 + nLength]; - Buffer.BlockCopy (val, 0, der, 2, nLength); - nLengthLen = nLength; - } - if (m_aValue == null) - m_aValue = val; - } - else - der = new byte[2]; - - der[0] = m_nTag; - der[1] = (byte)nLengthLen; - - return der; - } - - // Note: Recursive - protected void Decode (byte[] asn1, ref int anPos, int anLength) - { - byte nTag; - int nLength; - byte[] aValue; - - // minimum is 2 bytes (tag + length of 0) - while (anPos < anLength - 1) { - DecodeTLV (asn1, ref anPos, out nTag, out nLength, out aValue); - // sometimes we get trailing 0 - if (nTag == 0) - continue; - - ASN1 elm = Add (new ASN1 (nTag, aValue)); - - if ((nTag & 0x20) == 0x20) { - int nConstructedPos = anPos; - elm.Decode (asn1, ref nConstructedPos, nConstructedPos + nLength); - } - anPos += nLength; // value length - } - } - - // TLV : Tag - Length - Value - protected void DecodeTLV (byte[] asn1, ref int pos, out byte tag, out int length, out byte[] content) - { - tag = asn1 [pos++]; - length = asn1 [pos++]; - - // special case where L contains the Length of the Length + 0x80 - if ((length & 0x80) == 0x80) { - int nLengthLen = length & 0x7F; - length = 0; - for (int i = 0; i < nLengthLen; i++) - length = length * 256 + asn1 [pos++]; - } - - content = new byte [length]; - Buffer.BlockCopy (asn1, pos, content, 0, length); - } - - public ASN1 this [int index] { - get { - try { - if ((elist == null) || (index >= elist.Count)) - return null; - return (ASN1) elist [index]; - } - catch (ArgumentOutOfRangeException) { - return null; - } - } - } - - public ASN1 Element (int index, byte anTag) - { - try { - if ((elist == null) || (index >= elist.Count)) - return null; - - ASN1 elm = (ASN1) elist [index]; - if (elm.Tag == anTag) - return elm; - else - return null; - } - catch (ArgumentOutOfRangeException) { - return null; - } - } - - public override string ToString() - { - StringBuilder hexLine = new StringBuilder (); - - // Add tag - hexLine.AppendFormat ("Tag: {0} {1}", m_nTag.ToString ("X2"), Environment.NewLine); - - // Add length - hexLine.AppendFormat ("Length: {0} {1}", Value.Length, Environment.NewLine); - - // Add value - hexLine.Append ("Value: "); - hexLine.Append (Environment.NewLine); - for (int i = 0; i < Value.Length; i++) { - hexLine.AppendFormat ("{0} ", Value [i].ToString ("X2")); - if ((i+1) % 16 == 0) - hexLine.AppendFormat (Environment.NewLine); - } - return hexLine.ToString (); - } - - public void SaveToFile (string filename) - { - if (filename == null) - throw new ArgumentNullException ("filename"); - - using (FileStream fs = File.Create (filename)) { - byte[] data = GetBytes (); - fs.Write (data, 0, data.Length); - } - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/ASN1Convert.cs b/Emby.Server.Implementations/Cryptography/ASN1Convert.cs deleted file mode 100644 index 851d36dc7..000000000 --- a/Emby.Server.Implementations/Cryptography/ASN1Convert.cs +++ /dev/null @@ -1,207 +0,0 @@ -// -// ASN1Convert.cs: Abstract Syntax Notation 1 convertion routines -// -// Authors: -// Sebastien Pouliot -// Jesper Pedersen -// -// (C) 2003 Motus Technologies Inc. (http://www.motus.com) -// (C) 2004 IT+ A/S (http://www.itplus.dk) -// Copyright (C) 2004-2007 Novell, Inc (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Globalization; -using System.Security.Cryptography; -using System.Text; - -namespace Emby.Server.Core.Cryptography -{ - - // References: - // a. ITU ASN.1 standards (free download) - // http://www.itu.int/ITU-T/studygroups/com17/languages/ - - public static class ASN1Convert { - // RFC3280, section 4.2.1.5 - // CAs conforming to this profile MUST always encode certificate - // validity dates through the year 2049 as UTCTime; certificate validity - // dates in 2050 or later MUST be encoded as GeneralizedTime. - - // Under 1.x this API requires a Local datetime to be provided - // Under 2.0 it will also accept a Utc datetime - static public ASN1 FromDateTime (DateTime dt) - { - if (dt.Year < 2050) { - // UTCTIME - return new ASN1 (0x17, Encoding.ASCII.GetBytes ( - dt.ToUniversalTime ().ToString ("yyMMddHHmmss", - CultureInfo.InvariantCulture) + "Z")); - } - else { - // GENERALIZEDTIME - return new ASN1 (0x18, Encoding.ASCII.GetBytes ( - dt.ToUniversalTime ().ToString ("yyyyMMddHHmmss", - CultureInfo.InvariantCulture) + "Z")); - } - } - - static public ASN1 FromInt32 (Int32 value) - { - byte[] integer = BitConverterLE.GetBytes (value); - Array.Reverse (integer); - int x = 0; - while ((x < integer.Length) && (integer [x] == 0x00)) - x++; - ASN1 asn1 = new ASN1 (0x02); - switch (x) { - case 0: - asn1.Value = integer; - break; - case 4: - asn1.Value = new byte [1]; - break; - default: - byte[] smallerInt = new byte [4 - x]; - Buffer.BlockCopy (integer, x, smallerInt, 0, smallerInt.Length); - asn1.Value = smallerInt; - break; - } - return asn1; - } - - static public ASN1 FromOid (string oid) - { - if (oid == null) - throw new ArgumentNullException ("oid"); - - return new ASN1 (CryptoConfig.EncodeOID (oid)); - } - - static public ASN1 FromUnsignedBigInteger (byte[] big) - { - if (big == null) - throw new ArgumentNullException ("big"); - - // check for numbers that could be interpreted as negative (first bit) - if (big [0] >= 0x80) { - // in thie cas we add a new, empty, byte (position 0) so we're - // sure this will always be interpreted an unsigned integer. - // However we can't feed it into RSAParameters or DSAParameters - int length = big.Length + 1; - byte[] uinteger = new byte [length]; - Buffer.BlockCopy (big, 0, uinteger, 1, length - 1); - big = uinteger; - } - return new ASN1 (0x02, big); - } - - static public int ToInt32 (ASN1 asn1) - { - if (asn1 == null) - throw new ArgumentNullException ("asn1"); - if (asn1.Tag != 0x02) - throw new FormatException ("Only integer can be converted"); - - int x = 0; - for (int i=0; i < asn1.Value.Length; i++) - x = (x << 8) + asn1.Value [i]; - return x; - } - - // Convert a binary encoded OID to human readable string representation of - // an OID (IETF style). Based on DUMPASN1.C from Peter Gutmann. - static public string ToOid (ASN1 asn1) - { - if (asn1 == null) - throw new ArgumentNullException ("asn1"); - - byte[] aOID = asn1.Value; - StringBuilder sb = new StringBuilder (); - // Pick apart the OID - byte x = (byte) (aOID[0] / 40); - byte y = (byte) (aOID[0] % 40); - if (x > 2) { - // Handle special case for large y if x = 2 - y += (byte) ((x - 2) * 40); - x = 2; - } - sb.Append (x.ToString (CultureInfo.InvariantCulture)); - sb.Append ("."); - sb.Append (y.ToString (CultureInfo.InvariantCulture)); - ulong val = 0; - for (x = 1; x < aOID.Length; x++) { - val = ((val << 7) | ((byte) (aOID [x] & 0x7F))); - if ( !((aOID [x] & 0x80) == 0x80)) { - sb.Append ("."); - sb.Append (val.ToString (CultureInfo.InvariantCulture)); - val = 0; - } - } - return sb.ToString (); - } - - static public DateTime ToDateTime (ASN1 time) - { - if (time == null) - throw new ArgumentNullException ("time"); - - string t = Encoding.ASCII.GetString (time.Value); - // to support both UTCTime and GeneralizedTime (and not so common format) - string mask = null; - int year; - switch (t.Length) { - case 11: - // illegal format, still it's supported for compatibility - mask = "yyMMddHHmmZ"; - break; - case 13: - // RFC3280: 4.1.2.5.1 UTCTime - year = Convert.ToInt16 (t.Substring (0, 2), CultureInfo.InvariantCulture); - // Where YY is greater than or equal to 50, the - // year SHALL be interpreted as 19YY; and - // Where YY is less than 50, the year SHALL be - // interpreted as 20YY. - if (year >= 50) - t = "19" + t; - else - t = "20" + t; - mask = "yyyyMMddHHmmssZ"; - break; - case 15: - mask = "yyyyMMddHHmmssZ"; // GeneralizedTime - break; - case 17: - // another illegal format (990630000000+1000), again supported for compatibility - year = Convert.ToInt16 (t.Substring (0, 2), CultureInfo.InvariantCulture); - string century = (year >= 50) ? "19" : "20"; - // ASN.1 (see ITU X.680 section 43.3) deals with offset differently than .NET - char sign = (t[12] == '+') ? '-' : '+'; - t = String.Format ("{0}{1}{2}{3}{4}:{5}{6}", century, t.Substring (0, 12), sign, - t[13], t[14], t[15], t[16]); - mask = "yyyyMMddHHmmsszzz"; - break; - } - return DateTime.ParseExact (t, mask, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal); - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/BitConverterLE.cs b/Emby.Server.Implementations/Cryptography/BitConverterLE.cs deleted file mode 100644 index 34e6bf6dc..000000000 --- a/Emby.Server.Implementations/Cryptography/BitConverterLE.cs +++ /dev/null @@ -1,239 +0,0 @@ -// -// Mono.Security.BitConverterLE.cs -// Like System.BitConverter but always little endian -// -// Author: -// Bernie Solomon -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; - -namespace Emby.Server.Core.Cryptography -{ - internal sealed class BitConverterLE - { - private BitConverterLE () - { - } - - unsafe private static byte[] GetUShortBytes (byte *bytes) - { - if (BitConverter.IsLittleEndian) - return new byte [] { bytes [0], bytes [1] }; - else - return new byte [] { bytes [1], bytes [0] }; - } - - unsafe private static byte[] GetUIntBytes (byte *bytes) - { - if (BitConverter.IsLittleEndian) - return new byte [] { bytes [0], bytes [1], bytes [2], bytes [3] }; - else - return new byte [] { bytes [3], bytes [2], bytes [1], bytes [0] }; - } - - unsafe private static byte[] GetULongBytes (byte *bytes) - { - if (BitConverter.IsLittleEndian) - return new byte [] { bytes [0], bytes [1], bytes [2], bytes [3], - bytes [4], bytes [5], bytes [6], bytes [7] }; - else - return new byte [] { bytes [7], bytes [6], bytes [5], bytes [4], - bytes [3], bytes [2], bytes [1], bytes [0] }; - } - - unsafe internal static byte[] GetBytes (bool value) - { - return new byte [] { value ? (byte)1 : (byte)0 }; - } - - unsafe internal static byte[] GetBytes (char value) - { - return GetUShortBytes ((byte *) &value); - } - - unsafe internal static byte[] GetBytes (short value) - { - return GetUShortBytes ((byte *) &value); - } - - unsafe internal static byte[] GetBytes (int value) - { - return GetUIntBytes ((byte *) &value); - } - - unsafe internal static byte[] GetBytes (long value) - { - return GetULongBytes ((byte *) &value); - } - - unsafe internal static byte[] GetBytes (ushort value) - { - return GetUShortBytes ((byte *) &value); - } - - unsafe internal static byte[] GetBytes (uint value) - { - return GetUIntBytes ((byte *) &value); - } - - unsafe internal static byte[] GetBytes (ulong value) - { - return GetULongBytes ((byte *) &value); - } - - unsafe internal static byte[] GetBytes (float value) - { - return GetUIntBytes ((byte *) &value); - } - - unsafe internal static byte[] GetBytes (double value) - { - return GetULongBytes ((byte *) &value); - } - - unsafe private static void UShortFromBytes (byte *dst, byte[] src, int startIndex) - { - if (BitConverter.IsLittleEndian) { - dst [0] = src [startIndex]; - dst [1] = src [startIndex + 1]; - } else { - dst [0] = src [startIndex + 1]; - dst [1] = src [startIndex]; - } - } - - unsafe private static void UIntFromBytes (byte *dst, byte[] src, int startIndex) - { - if (BitConverter.IsLittleEndian) { - dst [0] = src [startIndex]; - dst [1] = src [startIndex + 1]; - dst [2] = src [startIndex + 2]; - dst [3] = src [startIndex + 3]; - } else { - dst [0] = src [startIndex + 3]; - dst [1] = src [startIndex + 2]; - dst [2] = src [startIndex + 1]; - dst [3] = src [startIndex]; - } - } - - unsafe private static void ULongFromBytes (byte *dst, byte[] src, int startIndex) - { - if (BitConverter.IsLittleEndian) { - for (int i = 0; i < 8; ++i) - dst [i] = src [startIndex + i]; - } else { - for (int i = 0; i < 8; ++i) - dst [i] = src [startIndex + (7 - i)]; - } - } - - unsafe internal static bool ToBoolean (byte[] value, int startIndex) - { - return value [startIndex] != 0; - } - - unsafe internal static char ToChar (byte[] value, int startIndex) - { - char ret; - - UShortFromBytes ((byte *) &ret, value, startIndex); - - return ret; - } - - unsafe internal static short ToInt16 (byte[] value, int startIndex) - { - short ret; - - UShortFromBytes ((byte *) &ret, value, startIndex); - - return ret; - } - - unsafe internal static int ToInt32 (byte[] value, int startIndex) - { - int ret; - - UIntFromBytes ((byte *) &ret, value, startIndex); - - return ret; - } - - unsafe internal static long ToInt64 (byte[] value, int startIndex) - { - long ret; - - ULongFromBytes ((byte *) &ret, value, startIndex); - - return ret; - } - - unsafe internal static ushort ToUInt16 (byte[] value, int startIndex) - { - ushort ret; - - UShortFromBytes ((byte *) &ret, value, startIndex); - - return ret; - } - - unsafe internal static uint ToUInt32 (byte[] value, int startIndex) - { - uint ret; - - UIntFromBytes ((byte *) &ret, value, startIndex); - - return ret; - } - - unsafe internal static ulong ToUInt64 (byte[] value, int startIndex) - { - ulong ret; - - ULongFromBytes ((byte *) &ret, value, startIndex); - - return ret; - } - - unsafe internal static float ToSingle (byte[] value, int startIndex) - { - float ret; - - UIntFromBytes ((byte *) &ret, value, startIndex); - - return ret; - } - - unsafe internal static double ToDouble (byte[] value, int startIndex) - { - double ret; - - ULongFromBytes ((byte *) &ret, value, startIndex); - - return ret; - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs b/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs deleted file mode 100644 index b4c84a600..000000000 --- a/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs +++ /dev/null @@ -1,109 +0,0 @@ -using MediaBrowser.Model.Logging; -using System; -using System.Collections; -using System.Security.Cryptography; -using System.Xml; - -namespace Emby.Server.Core.Cryptography -{ - public class CertificateGenerator - { - private const string MonoTestRootAgency = "v/4nALBxCE+9JgEC0LnDUvKh6e96PwTpN4Rj+vWnqKT7IAp1iK/JjuqvAg6DQ2vTfv0dTlqffmHH51OyioprcT5nzxcSTsZb/9jcHScG0s3/FRIWnXeLk/fgm7mSYhjUaHNI0m1/NTTktipicjKxo71hGIg9qucCWnDum+Krh/k=AQAB

9jbKxMXEruW2CfZrzhxtull4O8P47+mNsEL+9gf9QsRO1jJ77C+jmzfU6zbzjf8+ViK+q62tCMdC1ZzulwdpXQ==

x5+p198l1PkK0Ga2mRh0SIYSykENpY2aLXoyZD/iUpKYAvATm0/wvKNrE4dKJyPCA+y3hfTdgVag+SP9avvDTQ==ISSjCvXsUfbOGG05eddN1gXxL2pj+jegQRfjpk7RAsnWKvNExzhqd5x+ZuNQyc6QH5wxun54inP4RTUI0P/IaQ==R815VQmR3RIbPqzDXzv5j6CSH6fYlcTiQRtkBsUnzhWmkd/y3XmamO+a8zJFjOCCx9CcjpVuGziivBqi65lVPQ==iYiu0KwMWI/dyqN3RJYUzuuLj02/oTD1pYpwo2rvNCXU1Q5VscOeu2DpNg1gWqI+1RrRCsEoaTNzXB1xtKNlSw==nIfh1LYF8fjRBgMdAH/zt9UKHWiaCnc+jXzq5tkR8HVSKTVdzitD8bl1JgAfFQD8VjSXiCJqluexy/B5SGrCXQ49c78NIQj0hD+J13Y8/E0fUbW1QYbhj6Ff7oHyhaYe1WOQfkp2t/h+llHOdt1HRf7bt7dUknYp7m8bQKGxoYE=
"; - - public static void CreateSelfSignCertificatePfx( - string fileName, - string hostname, - string password, - ILogger logger) - { - if (string.IsNullOrWhiteSpace(fileName)) - { - throw new ArgumentNullException("fileName"); - } - - 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(); -#if NET46 - issuerKey.FromXmlString(MonoTestRootAgency); -#else - RSACryptoServiceProviderExtensions.FromXmlString(issuerKey, MonoTestRootAgency); -#endif - 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.Password = password; - - p12.AddPkcs8ShroudedKeyBag(subjectKey, attributes); - p12.SaveToFile(fileName); - } - } - - 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); - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/CryptoConvert.cs b/Emby.Server.Implementations/Cryptography/CryptoConvert.cs deleted file mode 100644 index 70a91bfff..000000000 --- a/Emby.Server.Implementations/Cryptography/CryptoConvert.cs +++ /dev/null @@ -1,745 +0,0 @@ -// -// CryptoConvert.cs - Crypto Convertion Routines -// -// Author: -// Sebastien Pouliot -// -// (C) 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Globalization; -using System.Security.Cryptography; -using System.Text; - -namespace Emby.Server.Core.Cryptography -{ - - public sealed class CryptoConvert { - - private CryptoConvert () - { - } - - static private int ToInt32LE (byte [] bytes, int offset) - { - return (bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]; - } - - static private uint ToUInt32LE (byte [] bytes, int offset) - { - return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]); - } - - static private byte [] GetBytesLE (int val) - { - return new byte [] { - (byte) (val & 0xff), - (byte) ((val >> 8) & 0xff), - (byte) ((val >> 16) & 0xff), - (byte) ((val >> 24) & 0xff) - }; - } - - static private byte[] Trim (byte[] array) - { - for (int i=0; i < array.Length; i++) { - if (array [i] != 0x00) { - byte[] result = new byte [array.Length - i]; - Buffer.BlockCopy (array, i, result, 0, result.Length); - return result; - } - } - return null; - } - - // convert the key from PRIVATEKEYBLOB to RSA - // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/private_key_blobs.asp - // e.g. SNK files, PVK files - static public RSA FromCapiPrivateKeyBlob (byte[] blob) - { - return FromCapiPrivateKeyBlob (blob, 0); - } - - static public RSA FromCapiPrivateKeyBlob (byte[] blob, int offset) - { - if (blob == null) - throw new ArgumentNullException ("blob"); - if (offset >= blob.Length) - throw new ArgumentException ("blob is too small."); - - RSAParameters rsap = new RSAParameters (); - try { - if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07) - (blob [offset+1] != 0x02) || // Version (0x02) - (blob [offset+2] != 0x00) || // Reserved (word) - (blob [offset+3] != 0x00) || - (ToUInt32LE (blob, offset+8) != 0x32415352)) // DWORD magic = RSA2 - throw new CryptographicException ("Invalid blob header"); - - // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...) - // int algId = ToInt32LE (blob, offset+4); - - // DWORD bitlen - int bitLen = ToInt32LE (blob, offset+12); - - // DWORD public exponent - byte[] exp = new byte [4]; - Buffer.BlockCopy (blob, offset+16, exp, 0, 4); - Array.Reverse (exp); - rsap.Exponent = Trim (exp); - - int pos = offset+20; - // BYTE modulus[rsapubkey.bitlen/8]; - int byteLen = (bitLen >> 3); - rsap.Modulus = new byte [byteLen]; - Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen); - Array.Reverse (rsap.Modulus); - pos += byteLen; - - // BYTE prime1[rsapubkey.bitlen/16]; - int byteHalfLen = (byteLen >> 1); - rsap.P = new byte [byteHalfLen]; - Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen); - Array.Reverse (rsap.P); - pos += byteHalfLen; - - // BYTE prime2[rsapubkey.bitlen/16]; - rsap.Q = new byte [byteHalfLen]; - Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen); - Array.Reverse (rsap.Q); - pos += byteHalfLen; - - // BYTE exponent1[rsapubkey.bitlen/16]; - rsap.DP = new byte [byteHalfLen]; - Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen); - Array.Reverse (rsap.DP); - pos += byteHalfLen; - - // BYTE exponent2[rsapubkey.bitlen/16]; - rsap.DQ = new byte [byteHalfLen]; - Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen); - Array.Reverse (rsap.DQ); - pos += byteHalfLen; - - // BYTE coefficient[rsapubkey.bitlen/16]; - rsap.InverseQ = new byte [byteHalfLen]; - Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen); - Array.Reverse (rsap.InverseQ); - pos += byteHalfLen; - - // ok, this is hackish but CryptoAPI support it so... - // note: only works because CRT is used by default - // http://bugzilla.ximian.com/show_bug.cgi?id=57941 - rsap.D = new byte [byteLen]; // must be allocated - if (pos + byteLen + offset <= blob.Length) { - // BYTE privateExponent[rsapubkey.bitlen/8]; - Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen); - Array.Reverse (rsap.D); - } - } - catch (Exception e) { - throw new CryptographicException ("Invalid blob.", e); - } - - RSA rsa = null; - try - { - rsa = RSA.Create(); - rsa.ImportParameters(rsap); - } - catch (CryptographicException ce) - { - // this may cause problem when this code is run under - // the SYSTEM identity on Windows (e.g. ASP.NET). See - // http://bugzilla.ximian.com/show_bug.cgi?id=77559 - try - { - CspParameters csp = new CspParameters(); - csp.Flags = CspProviderFlags.UseMachineKeyStore; - rsa = new RSACryptoServiceProvider(csp); - rsa.ImportParameters(rsap); - } - catch - { - // rethrow original, not the later, exception if this fails - throw ce; - } - } - return rsa; - } - - static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob) - { - return FromCapiPrivateKeyBlobDSA (blob, 0); - } - - static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob, int offset) - { - if (blob == null) - throw new ArgumentNullException ("blob"); - if (offset >= blob.Length) - throw new ArgumentException ("blob is too small."); - - DSAParameters dsap = new DSAParameters (); - try { - if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07) - (blob [offset + 1] != 0x02) || // Version (0x02) - (blob [offset + 2] != 0x00) || // Reserved (word) - (blob [offset + 3] != 0x00) || - (ToUInt32LE (blob, offset + 8) != 0x32535344)) // DWORD magic - throw new CryptographicException ("Invalid blob header"); - - int bitlen = ToInt32LE (blob, offset + 12); - int bytelen = bitlen >> 3; - int pos = offset + 16; - - dsap.P = new byte [bytelen]; - Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen); - Array.Reverse (dsap.P); - pos += bytelen; - - dsap.Q = new byte [20]; - Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20); - Array.Reverse (dsap.Q); - pos += 20; - - dsap.G = new byte [bytelen]; - Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen); - Array.Reverse (dsap.G); - pos += bytelen; - - dsap.X = new byte [20]; - Buffer.BlockCopy (blob, pos, dsap.X, 0, 20); - Array.Reverse (dsap.X); - pos += 20; - - dsap.Counter = ToInt32LE (blob, pos); - pos += 4; - - dsap.Seed = new byte [20]; - Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20); - Array.Reverse (dsap.Seed); - pos += 20; - } - catch (Exception e) { - throw new CryptographicException ("Invalid blob.", e); - } - - DSA dsa = null; - try - { - dsa = (DSA)DSA.Create(); - dsa.ImportParameters(dsap); - } - catch (CryptographicException ce) - { - // this may cause problem when this code is run under - // the SYSTEM identity on Windows (e.g. ASP.NET). See - // http://bugzilla.ximian.com/show_bug.cgi?id=77559 - try - { - CspParameters csp = new CspParameters(); - csp.Flags = CspProviderFlags.UseMachineKeyStore; - dsa = new DSACryptoServiceProvider(csp); - dsa.ImportParameters(dsap); - } - catch - { - // rethrow original, not the later, exception if this fails - throw ce; - } - } - return dsa; - } - - static public byte[] ToCapiPrivateKeyBlob (RSA rsa) - { - RSAParameters p = rsa.ExportParameters (true); - int keyLength = p.Modulus.Length; // in bytes - byte[] blob = new byte [20 + (keyLength << 2) + (keyLength >> 1)]; - - blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07) - blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02) - // [2], [3] // RESERVED - Always 0 - blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN) - blob [8] = 0x52; // Magic - RSA2 (ASCII in hex) - blob [9] = 0x53; - blob [10] = 0x41; - blob [11] = 0x32; - - byte[] bitlen = GetBytesLE (keyLength << 3); - blob [12] = bitlen [0]; // bitlen - blob [13] = bitlen [1]; - blob [14] = bitlen [2]; - blob [15] = bitlen [3]; - - // public exponent (DWORD) - int pos = 16; - int n = p.Exponent.Length; - while (n > 0) - blob [pos++] = p.Exponent [--n]; - // modulus - pos = 20; - byte[] part = p.Modulus; - int len = part.Length; - Array.Reverse (part, 0, len); - Buffer.BlockCopy (part, 0, blob, pos, len); - pos += len; - // private key - part = p.P; - len = part.Length; - Array.Reverse (part, 0, len); - Buffer.BlockCopy (part, 0, blob, pos, len); - pos += len; - - part = p.Q; - len = part.Length; - Array.Reverse (part, 0, len); - Buffer.BlockCopy (part, 0, blob, pos, len); - pos += len; - - part = p.DP; - len = part.Length; - Array.Reverse (part, 0, len); - Buffer.BlockCopy (part, 0, blob, pos, len); - pos += len; - - part = p.DQ; - len = part.Length; - Array.Reverse (part, 0, len); - Buffer.BlockCopy (part, 0, blob, pos, len); - pos += len; - - part = p.InverseQ; - len = part.Length; - Array.Reverse (part, 0, len); - Buffer.BlockCopy (part, 0, blob, pos, len); - pos += len; - - part = p.D; - len = part.Length; - Array.Reverse (part, 0, len); - Buffer.BlockCopy (part, 0, blob, pos, len); - - return blob; - } - - static public byte[] ToCapiPrivateKeyBlob (DSA dsa) - { - DSAParameters p = dsa.ExportParameters (true); - int keyLength = p.P.Length; // in bytes - - // header + P + Q + G + X + count + seed - byte[] blob = new byte [16 + keyLength + 20 + keyLength + 20 + 4 + 20]; - - blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07) - blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02) - // [2], [3] // RESERVED - Always 0 - blob [5] = 0x22; // ALGID - blob [8] = 0x44; // Magic - blob [9] = 0x53; - blob [10] = 0x53; - blob [11] = 0x32; - - byte[] bitlen = GetBytesLE (keyLength << 3); - blob [12] = bitlen [0]; - blob [13] = bitlen [1]; - blob [14] = bitlen [2]; - blob [15] = bitlen [3]; - - int pos = 16; - byte[] part = p.P; - Array.Reverse (part); - Buffer.BlockCopy (part, 0, blob, pos, keyLength); - pos += keyLength; - - part = p.Q; - Array.Reverse (part); - Buffer.BlockCopy (part, 0, blob, pos, 20); - pos += 20; - - part = p.G; - Array.Reverse (part); - Buffer.BlockCopy (part, 0, blob, pos, keyLength); - pos += keyLength; - - part = p.X; - Array.Reverse (part); - Buffer.BlockCopy (part, 0, blob, pos, 20); - pos += 20; - - Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4); - pos += 4; - - part = p.Seed; - Array.Reverse (part); - Buffer.BlockCopy (part, 0, blob, pos, 20); - - return blob; - } - - static public RSA FromCapiPublicKeyBlob (byte[] blob) - { - return FromCapiPublicKeyBlob (blob, 0); - } - - static public RSA FromCapiPublicKeyBlob (byte[] blob, int offset) - { - if (blob == null) - throw new ArgumentNullException ("blob"); - if (offset >= blob.Length) - throw new ArgumentException ("blob is too small."); - - try { - if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06) - (blob [offset+1] != 0x02) || // Version (0x02) - (blob [offset+2] != 0x00) || // Reserved (word) - (blob [offset+3] != 0x00) || - (ToUInt32LE (blob, offset+8) != 0x31415352)) // DWORD magic = RSA1 - throw new CryptographicException ("Invalid blob header"); - - // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...) - // int algId = ToInt32LE (blob, offset+4); - - // DWORD bitlen - int bitLen = ToInt32LE (blob, offset+12); - - // DWORD public exponent - RSAParameters rsap = new RSAParameters (); - rsap.Exponent = new byte [3]; - rsap.Exponent [0] = blob [offset+18]; - rsap.Exponent [1] = blob [offset+17]; - rsap.Exponent [2] = blob [offset+16]; - - int pos = offset+20; - // BYTE modulus[rsapubkey.bitlen/8]; - int byteLen = (bitLen >> 3); - rsap.Modulus = new byte [byteLen]; - Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen); - Array.Reverse (rsap.Modulus); - RSA rsa = null; - try - { - rsa = RSA.Create(); - rsa.ImportParameters(rsap); - } - catch (CryptographicException) - { - // this may cause problem when this code is run under - // the SYSTEM identity on Windows (e.g. ASP.NET). See - // http://bugzilla.ximian.com/show_bug.cgi?id=77559 - CspParameters csp = new CspParameters(); - csp.Flags = CspProviderFlags.UseMachineKeyStore; - rsa = new RSACryptoServiceProvider(csp); - rsa.ImportParameters(rsap); - } - return rsa; - } - catch (Exception e) { - throw new CryptographicException ("Invalid blob.", e); - } - } - - static public DSA FromCapiPublicKeyBlobDSA (byte[] blob) - { - return FromCapiPublicKeyBlobDSA (blob, 0); - } - - static public DSA FromCapiPublicKeyBlobDSA (byte[] blob, int offset) - { - if (blob == null) - throw new ArgumentNullException ("blob"); - if (offset >= blob.Length) - throw new ArgumentException ("blob is too small."); - - try { - if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06) - (blob [offset + 1] != 0x02) || // Version (0x02) - (blob [offset + 2] != 0x00) || // Reserved (word) - (blob [offset + 3] != 0x00) || - (ToUInt32LE (blob, offset + 8) != 0x31535344)) // DWORD magic - throw new CryptographicException ("Invalid blob header"); - - int bitlen = ToInt32LE (blob, offset + 12); - DSAParameters dsap = new DSAParameters (); - int bytelen = bitlen >> 3; - int pos = offset + 16; - - dsap.P = new byte [bytelen]; - Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen); - Array.Reverse (dsap.P); - pos += bytelen; - - dsap.Q = new byte [20]; - Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20); - Array.Reverse (dsap.Q); - pos += 20; - - dsap.G = new byte [bytelen]; - Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen); - Array.Reverse (dsap.G); - pos += bytelen; - - dsap.Y = new byte [bytelen]; - Buffer.BlockCopy (blob, pos, dsap.Y, 0, bytelen); - Array.Reverse (dsap.Y); - pos += bytelen; - - dsap.Counter = ToInt32LE (blob, pos); - pos += 4; - - dsap.Seed = new byte [20]; - Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20); - Array.Reverse (dsap.Seed); - pos += 20; - - DSA dsa = (DSA)DSA.Create (); - dsa.ImportParameters (dsap); - return dsa; - } - catch (Exception e) { - throw new CryptographicException ("Invalid blob.", e); - } - } - - static public byte[] ToCapiPublicKeyBlob (RSA rsa) - { - RSAParameters p = rsa.ExportParameters (false); - int keyLength = p.Modulus.Length; // in bytes - byte[] blob = new byte [20 + keyLength]; - - blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06) - blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02) - // [2], [3] // RESERVED - Always 0 - blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN) - blob [8] = 0x52; // Magic - RSA1 (ASCII in hex) - blob [9] = 0x53; - blob [10] = 0x41; - blob [11] = 0x31; - - byte[] bitlen = GetBytesLE (keyLength << 3); - blob [12] = bitlen [0]; // bitlen - blob [13] = bitlen [1]; - blob [14] = bitlen [2]; - blob [15] = bitlen [3]; - - // public exponent (DWORD) - int pos = 16; - int n = p.Exponent.Length; - while (n > 0) - blob [pos++] = p.Exponent [--n]; - // modulus - pos = 20; - byte[] part = p.Modulus; - int len = part.Length; - Array.Reverse (part, 0, len); - Buffer.BlockCopy (part, 0, blob, pos, len); - pos += len; - return blob; - } - - static public byte[] ToCapiPublicKeyBlob (DSA dsa) - { - DSAParameters p = dsa.ExportParameters (false); - int keyLength = p.P.Length; // in bytes - - // header + P + Q + G + Y + count + seed - byte[] blob = new byte [16 + keyLength + 20 + keyLength + keyLength + 4 + 20]; - - blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06) - blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02) - // [2], [3] // RESERVED - Always 0 - blob [5] = 0x22; // ALGID - blob [8] = 0x44; // Magic - blob [9] = 0x53; - blob [10] = 0x53; - blob [11] = 0x31; - - byte[] bitlen = GetBytesLE (keyLength << 3); - blob [12] = bitlen [0]; - blob [13] = bitlen [1]; - blob [14] = bitlen [2]; - blob [15] = bitlen [3]; - - int pos = 16; - byte[] part; - - part = p.P; - Array.Reverse (part); - Buffer.BlockCopy (part, 0, blob, pos, keyLength); - pos += keyLength; - - part = p.Q; - Array.Reverse (part); - Buffer.BlockCopy (part, 0, blob, pos, 20); - pos += 20; - - part = p.G; - Array.Reverse (part); - Buffer.BlockCopy (part, 0, blob, pos, keyLength); - pos += keyLength; - - part = p.Y; - Array.Reverse (part); - Buffer.BlockCopy (part, 0, blob, pos, keyLength); - pos += keyLength; - - Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4); - pos += 4; - - part = p.Seed; - Array.Reverse (part); - Buffer.BlockCopy (part, 0, blob, pos, 20); - - return blob; - } - - // PRIVATEKEYBLOB - // PUBLICKEYBLOB - static public RSA FromCapiKeyBlob (byte[] blob) - { - return FromCapiKeyBlob (blob, 0); - } - - static public RSA FromCapiKeyBlob (byte[] blob, int offset) - { - if (blob == null) - throw new ArgumentNullException ("blob"); - if (offset >= blob.Length) - throw new ArgumentException ("blob is too small."); - - switch (blob [offset]) { - case 0x00: - // this could be a public key inside an header - // like "sn -e" would produce - if (blob [offset + 12] == 0x06) { - return FromCapiPublicKeyBlob (blob, offset + 12); - } - break; - case 0x06: - return FromCapiPublicKeyBlob (blob, offset); - case 0x07: - return FromCapiPrivateKeyBlob (blob, offset); - } - throw new CryptographicException ("Unknown blob format."); - } - - static public DSA FromCapiKeyBlobDSA (byte[] blob) - { - return FromCapiKeyBlobDSA (blob, 0); - } - - static public DSA FromCapiKeyBlobDSA (byte[] blob, int offset) - { - if (blob == null) - throw new ArgumentNullException ("blob"); - if (offset >= blob.Length) - throw new ArgumentException ("blob is too small."); - - switch (blob [offset]) { - case 0x06: - return FromCapiPublicKeyBlobDSA (blob, offset); - case 0x07: - return FromCapiPrivateKeyBlobDSA (blob, offset); - } - throw new CryptographicException ("Unknown blob format."); - } - - static public byte[] ToCapiKeyBlob (AsymmetricAlgorithm keypair, bool includePrivateKey) - { - if (keypair == null) - throw new ArgumentNullException ("keypair"); - - // check between RSA and DSA (and potentially others like DH) - if (keypair is RSA) - return ToCapiKeyBlob ((RSA)keypair, includePrivateKey); - else if (keypair is DSA) - return ToCapiKeyBlob ((DSA)keypair, includePrivateKey); - else - return null; // TODO - } - - static public byte[] ToCapiKeyBlob (RSA rsa, bool includePrivateKey) - { - if (rsa == null) - throw new ArgumentNullException ("rsa"); - - if (includePrivateKey) - return ToCapiPrivateKeyBlob (rsa); - else - return ToCapiPublicKeyBlob (rsa); - } - - static public byte[] ToCapiKeyBlob (DSA dsa, bool includePrivateKey) - { - if (dsa == null) - throw new ArgumentNullException ("dsa"); - - if (includePrivateKey) - return ToCapiPrivateKeyBlob (dsa); - else - return ToCapiPublicKeyBlob (dsa); - } - - static public string ToHex (byte[] input) - { - if (input == null) - return null; - - StringBuilder sb = new StringBuilder (input.Length * 2); - foreach (byte b in input) { - sb.Append (b.ToString ("X2", CultureInfo.InvariantCulture)); - } - return sb.ToString (); - } - - static private byte FromHexChar (char c) - { - if ((c >= 'a') && (c <= 'f')) - return (byte) (c - 'a' + 10); - if ((c >= 'A') && (c <= 'F')) - return (byte) (c - 'A' + 10); - if ((c >= '0') && (c <= '9')) - return (byte) (c - '0'); - throw new ArgumentException ("invalid hex char"); - } - - static public byte[] FromHex (string hex) - { - if (hex == null) - return null; - if ((hex.Length & 0x1) == 0x1) - throw new ArgumentException ("Length must be a multiple of 2"); - - byte[] result = new byte [hex.Length >> 1]; - int n = 0; - int i = 0; - while (n < result.Length) { - result [n] = (byte) (FromHexChar (hex [i++]) << 4); - result [n++] += FromHexChar (hex [i++]); - } - return result; - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/PKCS1.cs b/Emby.Server.Implementations/Cryptography/PKCS1.cs deleted file mode 100644 index 24c0708c5..000000000 --- a/Emby.Server.Implementations/Cryptography/PKCS1.cs +++ /dev/null @@ -1,491 +0,0 @@ -// -// PKCS1.cs - Implements PKCS#1 primitives. -// -// Author: -// Sebastien Pouliot -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004 Novell, Inc (http://www.novell.com) -// Copyright 2013 Xamarin Inc. (http://www.xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Security.Cryptography; - -namespace Emby.Server.Core.Cryptography -{ - - // References: - // a. PKCS#1: RSA Cryptography Standard - // http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/index.html - - public sealed class PKCS1 { - - private PKCS1 () - { - } - - private static bool Compare (byte[] array1, byte[] array2) - { - bool result = (array1.Length == array2.Length); - if (result) { - for (int i=0; i < array1.Length; i++) - if (array1[i] != array2[i]) - return false; - } - return result; - } - - private static byte[] xor (byte[] array1, byte[] array2) - { - byte[] result = new byte [array1.Length]; - for (int i=0; i < result.Length; i++) - result[i] = (byte) (array1[i] ^ array2[i]); - return result; - } - - private static byte[] emptySHA1 = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 }; - private static byte[] emptySHA256 = { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }; - private static byte[] emptySHA384 = { 0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, 0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda, 0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b }; - private static byte[] emptySHA512 = { 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e }; - - private static byte[] GetEmptyHash (HashAlgorithm hash) - { - if (hash is SHA1) - return emptySHA1; - else if (hash is SHA256) - return emptySHA256; - else if (hash is SHA384) - return emptySHA384; - else if (hash is SHA512) - return emptySHA512; - else - return hash.ComputeHash ((byte[])null); - } - - // PKCS #1 v.2.1, Section 4.1 - // I2OSP converts a non-negative integer to an octet string of a specified length. - public static byte[] I2OSP (int x, int size) - { - byte[] array = BitConverterLE.GetBytes (x); - Array.Reverse (array, 0, array.Length); - return I2OSP (array, size); - } - - public static byte[] I2OSP (byte[] x, int size) - { - byte[] result = new byte [size]; - Buffer.BlockCopy (x, 0, result, (result.Length - x.Length), x.Length); - return result; - } - - // PKCS #1 v.2.1, Section 4.2 - // OS2IP converts an octet string to a nonnegative integer. - public static byte[] OS2IP (byte[] x) - { - int i = 0; - while ((x [i++] == 0x00) && (i < x.Length)) { - // confuse compiler into reporting a warning with {} - } - i--; - if (i > 0) { - byte[] result = new byte [x.Length - i]; - Buffer.BlockCopy (x, i, result, 0, result.Length); - return result; - } - else - return x; - } - - // PKCS #1 v.2.1, Section 5.1.1 - public static byte[] RSAEP (RSA rsa, byte[] m) - { - // c = m^e mod n - return rsa.EncryptValue (m); - } - - // PKCS #1 v.2.1, Section 5.1.2 - public static byte[] RSADP (RSA rsa, byte[] c) - { - // m = c^d mod n - // Decrypt value may apply CRT optimizations - return rsa.DecryptValue (c); - } - - // PKCS #1 v.2.1, Section 5.2.1 - public static byte[] RSASP1 (RSA rsa, byte[] m) - { - // first form: s = m^d mod n - // Decrypt value may apply CRT optimizations - return rsa.DecryptValue (m); - } - - // PKCS #1 v.2.1, Section 5.2.2 - public static byte[] RSAVP1 (RSA rsa, byte[] s) - { - // m = s^e mod n - return rsa.EncryptValue (s); - } - - // PKCS #1 v.2.1, Section 7.1.1 - // RSAES-OAEP-ENCRYPT ((n, e), M, L) - public static byte[] Encrypt_OAEP (RSA rsa, HashAlgorithm hash, RandomNumberGenerator rng, byte[] M) - { - int size = rsa.KeySize / 8; - int hLen = hash.HashSize / 8; - if (M.Length > size - 2 * hLen - 2) - throw new CryptographicException ("message too long"); - // empty label L SHA1 hash - byte[] lHash = GetEmptyHash (hash); - int PSLength = (size - M.Length - 2 * hLen - 2); - // DB = lHash || PS || 0x01 || M - byte[] DB = new byte [lHash.Length + PSLength + 1 + M.Length]; - Buffer.BlockCopy (lHash, 0, DB, 0, lHash.Length); - DB [(lHash.Length + PSLength)] = 0x01; - Buffer.BlockCopy (M, 0, DB, (DB.Length - M.Length), M.Length); - - byte[] seed = new byte [hLen]; - rng.GetBytes (seed); - - byte[] dbMask = MGF1 (hash, seed, size - hLen - 1); - byte[] maskedDB = xor (DB, dbMask); - byte[] seedMask = MGF1 (hash, maskedDB, hLen); - byte[] maskedSeed = xor (seed, seedMask); - // EM = 0x00 || maskedSeed || maskedDB - byte[] EM = new byte [maskedSeed.Length + maskedDB.Length + 1]; - Buffer.BlockCopy (maskedSeed, 0, EM, 1, maskedSeed.Length); - Buffer.BlockCopy (maskedDB, 0, EM, maskedSeed.Length + 1, maskedDB.Length); - - byte[] m = OS2IP (EM); - byte[] c = RSAEP (rsa, m); - return I2OSP (c, size); - } - - // PKCS #1 v.2.1, Section 7.1.2 - // RSAES-OAEP-DECRYPT (K, C, L) - public static byte[] Decrypt_OAEP (RSA rsa, HashAlgorithm hash, byte[] C) - { - int size = rsa.KeySize / 8; - int hLen = hash.HashSize / 8; - if ((size < (2 * hLen + 2)) || (C.Length != size)) - throw new CryptographicException ("decryption error"); - - byte[] c = OS2IP (C); - byte[] m = RSADP (rsa, c); - byte[] EM = I2OSP (m, size); - - // split EM = Y || maskedSeed || maskedDB - byte[] maskedSeed = new byte [hLen]; - Buffer.BlockCopy (EM, 1, maskedSeed, 0, maskedSeed.Length); - byte[] maskedDB = new byte [size - hLen - 1]; - Buffer.BlockCopy (EM, (EM.Length - maskedDB.Length), maskedDB, 0, maskedDB.Length); - - byte[] seedMask = MGF1 (hash, maskedDB, hLen); - byte[] seed = xor (maskedSeed, seedMask); - byte[] dbMask = MGF1 (hash, seed, size - hLen - 1); - byte[] DB = xor (maskedDB, dbMask); - - byte[] lHash = GetEmptyHash (hash); - // split DB = lHash' || PS || 0x01 || M - byte[] dbHash = new byte [lHash.Length]; - Buffer.BlockCopy (DB, 0, dbHash, 0, dbHash.Length); - bool h = Compare (lHash, dbHash); - - // find separator 0x01 - int nPos = lHash.Length; - while (DB[nPos] == 0) - nPos++; - - int Msize = DB.Length - nPos - 1; - byte[] M = new byte [Msize]; - Buffer.BlockCopy (DB, (nPos + 1), M, 0, Msize); - - // we could have returned EM[0] sooner but would be helping a timing attack - if ((EM[0] != 0) || (!h) || (DB[nPos] != 0x01)) - return null; - return M; - } - - // PKCS #1 v.2.1, Section 7.2.1 - // RSAES-PKCS1-V1_5-ENCRYPT ((n, e), M) - public static byte[] Encrypt_v15 (RSA rsa, RandomNumberGenerator rng, byte[] M) - { - int size = rsa.KeySize / 8; - if (M.Length > size - 11) - throw new CryptographicException ("message too long"); - int PSLength = System.Math.Max (8, (size - M.Length - 3)); - byte[] PS = new byte [PSLength]; - rng.GetNonZeroBytes (PS); - byte[] EM = new byte [size]; - EM [1] = 0x02; - Buffer.BlockCopy (PS, 0, EM, 2, PSLength); - Buffer.BlockCopy (M, 0, EM, (size - M.Length), M.Length); - - byte[] m = OS2IP (EM); - byte[] c = RSAEP (rsa, m); - byte[] C = I2OSP (c, size); - return C; - } - - // PKCS #1 v.2.1, Section 7.2.2 - // RSAES-PKCS1-V1_5-DECRYPT (K, C) - public static byte[] Decrypt_v15 (RSA rsa, byte[] C) - { - int size = rsa.KeySize >> 3; // div by 8 - if ((size < 11) || (C.Length > size)) - throw new CryptographicException ("decryption error"); - byte[] c = OS2IP (C); - byte[] m = RSADP (rsa, c); - byte[] EM = I2OSP (m, size); - - if ((EM [0] != 0x00) || (EM [1] != 0x02)) - return null; - - int mPos = 10; - // PS is a minimum of 8 bytes + 2 bytes for header - while ((EM [mPos] != 0x00) && (mPos < EM.Length)) - mPos++; - if (EM [mPos] != 0x00) - return null; - mPos++; - byte[] M = new byte [EM.Length - mPos]; - Buffer.BlockCopy (EM, mPos, M, 0, M.Length); - return M; - } - - // PKCS #1 v.2.1, Section 8.2.1 - // RSASSA-PKCS1-V1_5-SIGN (K, M) - public static byte[] Sign_v15 (RSA rsa, HashAlgorithm hash, byte[] hashValue) - { - int size = (rsa.KeySize >> 3); // div 8 - byte[] EM = Encode_v15 (hash, hashValue, size); - byte[] m = OS2IP (EM); - byte[] s = RSASP1 (rsa, m); - byte[] S = I2OSP (s, size); - return S; - } - - internal static byte[] Sign_v15 (RSA rsa, string hashName, byte[] hashValue) - { - using (var hash = CreateFromName (hashName)) - return Sign_v15 (rsa, hash, hashValue); - } - - // PKCS #1 v.2.1, Section 8.2.2 - // RSASSA-PKCS1-V1_5-VERIFY ((n, e), M, S) - public static bool Verify_v15 (RSA rsa, HashAlgorithm hash, byte[] hashValue, byte[] signature) - { - return Verify_v15 (rsa, hash, hashValue, signature, false); - } - - internal static bool Verify_v15 (RSA rsa, string hashName, byte[] hashValue, byte[] signature) - { - using (var hash = CreateFromName (hashName)) - return Verify_v15 (rsa, hash, hashValue, signature, false); - } - - // DO NOT USE WITHOUT A VERY GOOD REASON - public static bool Verify_v15 (RSA rsa, HashAlgorithm hash, byte [] hashValue, byte [] signature, bool tryNonStandardEncoding) - { - int size = (rsa.KeySize >> 3); // div 8 - byte[] s = OS2IP (signature); - byte[] m = RSAVP1 (rsa, s); - byte[] EM2 = I2OSP (m, size); - byte[] EM = Encode_v15 (hash, hashValue, size); - bool result = Compare (EM, EM2); - if (result || !tryNonStandardEncoding) - return result; - - // NOTE: some signatures don't include the hash OID (pretty lame but real) - // and compatible with MS implementation. E.g. Verisign Authenticode Timestamps - - // we're making this "as safe as possible" - if ((EM2 [0] != 0x00) || (EM2 [1] != 0x01)) - return false; - int i; - for (i = 2; i < EM2.Length - hashValue.Length - 1; i++) { - if (EM2 [i] != 0xFF) - return false; - } - if (EM2 [i++] != 0x00) - return false; - - byte [] decryptedHash = new byte [hashValue.Length]; - Buffer.BlockCopy (EM2, i, decryptedHash, 0, decryptedHash.Length); - return Compare (decryptedHash, hashValue); - } - - // PKCS #1 v.2.1, Section 9.2 - // EMSA-PKCS1-v1_5-Encode - public static byte[] Encode_v15 (HashAlgorithm hash, byte[] hashValue, int emLength) - { - if (hashValue.Length != (hash.HashSize >> 3)) - throw new CryptographicException ("bad hash length for " + hash.ToString ()); - - // DigestInfo ::= SEQUENCE { - // digestAlgorithm AlgorithmIdentifier, - // digest OCTET STRING - // } - - byte[] t = null; - - string oid = CryptoConfig.MapNameToOID (hash.ToString ()); - if (oid != null) - { - ASN1 digestAlgorithm = new ASN1 (0x30); - digestAlgorithm.Add (new ASN1 (CryptoConfig.EncodeOID (oid))); - digestAlgorithm.Add (new ASN1 (0x05)); // NULL - ASN1 digest = new ASN1 (0x04, hashValue); - ASN1 digestInfo = new ASN1 (0x30); - digestInfo.Add (digestAlgorithm); - digestInfo.Add (digest); - - t = digestInfo.GetBytes (); - } - else - { - // There are no valid OID, in this case t = hashValue - // This is the case of the MD5SHA hash algorithm - t = hashValue; - } - - Buffer.BlockCopy (hashValue, 0, t, t.Length - hashValue.Length, hashValue.Length); - - int PSLength = System.Math.Max (8, emLength - t.Length - 3); - // PS = PSLength of 0xff - - // EM = 0x00 | 0x01 | PS | 0x00 | T - byte[] EM = new byte [PSLength + t.Length + 3]; - EM [1] = 0x01; - for (int i=2; i < PSLength + 2; i++) - EM[i] = 0xff; - Buffer.BlockCopy (t, 0, EM, PSLength + 3, t.Length); - - return EM; - } - - // PKCS #1 v.2.1, Section B.2.1 - public static byte[] MGF1 (HashAlgorithm hash, byte[] mgfSeed, int maskLen) - { - // 1. If maskLen > 2^32 hLen, output "mask too long" and stop. - // easy - this is impossible by using a int (31bits) as parameter ;-) - // BUT with a signed int we do have to check for negative values! - if (maskLen < 0) - throw new OverflowException(); - - int mgfSeedLength = mgfSeed.Length; - int hLen = (hash.HashSize >> 3); // from bits to bytes - int iterations = (maskLen / hLen); - if (maskLen % hLen != 0) - iterations++; - // 2. Let T be the empty octet string. - byte[] T = new byte [iterations * hLen]; - - byte[] toBeHashed = new byte [mgfSeedLength + 4]; - int pos = 0; - // 3. For counter from 0 to \ceil (maskLen / hLen) - 1, do the following: - for (int counter = 0; counter < iterations; counter++) { - // a. Convert counter to an octet string C of length 4 octets - byte[] C = I2OSP (counter, 4); - - // b. Concatenate the hash of the seed mgfSeed and C to the octet string T: - // T = T || Hash (mgfSeed || C) - Buffer.BlockCopy (mgfSeed, 0, toBeHashed, 0, mgfSeedLength); - Buffer.BlockCopy (C, 0, toBeHashed, mgfSeedLength, 4); - byte[] output = hash.ComputeHash (toBeHashed); - Buffer.BlockCopy (output, 0, T, pos, hLen); - pos += hLen; - } - - // 4. Output the leading maskLen octets of T as the octet string mask. - byte[] mask = new byte [maskLen]; - Buffer.BlockCopy (T, 0, mask, 0, maskLen); - return mask; - } - - static internal string HashNameFromOid (string oid, bool throwOnError = true) - { - switch (oid) { - case "1.2.840.113549.1.1.2": // MD2 with RSA encryption - return "MD2"; - case "1.2.840.113549.1.1.3": // MD4 with RSA encryption - return "MD4"; - case "1.2.840.113549.1.1.4": // MD5 with RSA encryption - return "MD5"; - case "1.2.840.113549.1.1.5": // SHA-1 with RSA Encryption - case "1.3.14.3.2.29": // SHA1 with RSA signature - case "1.2.840.10040.4.3": // SHA1-1 with DSA - return "SHA1"; - case "1.2.840.113549.1.1.11": // SHA-256 with RSA Encryption - return "SHA256"; - case "1.2.840.113549.1.1.12": // SHA-384 with RSA Encryption - return "SHA384"; - case "1.2.840.113549.1.1.13": // SHA-512 with RSA Encryption - return "SHA512"; - case "1.3.36.3.3.1.2": - return "RIPEMD160"; - default: - if (throwOnError) - throw new CryptographicException ("Unsupported hash algorithm: " + oid); - return null; - } - } - - static internal HashAlgorithm CreateFromOid (string oid) - { - return CreateFromName (HashNameFromOid (oid)); - } - - static internal HashAlgorithm CreateFromName (string name) - { -#if FULL_AOT_RUNTIME - switch (name) { - case "MD2": - return MD2.Create (); - case "MD4": - return MD4.Create (); - case "MD5": - return MD5.Create (); - case "SHA1": - return SHA1.Create (); - case "SHA256": - return SHA256.Create (); - case "SHA384": - return SHA384.Create (); - case "SHA512": - return SHA512.Create (); - case "RIPEMD160": - return RIPEMD160.Create (); - default: - try { - return (HashAlgorithm) Activator.CreateInstance (Type.GetType (name)); - } - catch { - throw new CryptographicException ("Unsupported hash algorithm: " + name); - } - } -#else - return HashAlgorithm.Create (name); -#endif - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/PKCS12.cs b/Emby.Server.Implementations/Cryptography/PKCS12.cs deleted file mode 100644 index 50f3776d9..000000000 --- a/Emby.Server.Implementations/Cryptography/PKCS12.cs +++ /dev/null @@ -1,1934 +0,0 @@ -// -// PKCS12.cs: PKCS 12 - Personal Information Exchange Syntax -// -// Author: -// Sebastien Pouliot -// -// (C) 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004,2005,2006 Novell Inc. (http://www.novell.com) -// Copyright 2013 Xamarin Inc. (http://www.xamarin.com) -// -// Key derivation translated from Bouncy Castle JCE (http://www.bouncycastle.org/) -// See bouncycastle.txt for 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. -// - -using System; -using System.Collections; -using System.IO; -using System.Security.Cryptography; -using System.Text; - -namespace Emby.Server.Core.Cryptography -{ - - public class PKCS5 { - - public const string pbeWithMD2AndDESCBC = "1.2.840.113549.1.5.1"; - public const string pbeWithMD5AndDESCBC = "1.2.840.113549.1.5.3"; - public const string pbeWithMD2AndRC2CBC = "1.2.840.113549.1.5.4"; - public const string pbeWithMD5AndRC2CBC = "1.2.840.113549.1.5.6"; - public const string pbeWithSHA1AndDESCBC = "1.2.840.113549.1.5.10"; - public const string pbeWithSHA1AndRC2CBC = "1.2.840.113549.1.5.11"; - - public PKCS5 () {} - } - - public class PKCS9 { - - public const string friendlyName = "1.2.840.113549.1.9.20"; - public const string localKeyId = "1.2.840.113549.1.9.21"; - - public PKCS9 () {} - } - - - internal class SafeBag { - private string _bagOID; - private ASN1 _asn1; - - public SafeBag(string bagOID, ASN1 asn1) { - _bagOID = bagOID; - _asn1 = asn1; - } - - public string BagOID { - get { return _bagOID; } - } - - public ASN1 ASN1 { - get { return _asn1; } - } - } - - - public class PKCS12 : ICloneable { - - public const string pbeWithSHAAnd128BitRC4 = "1.2.840.113549.1.12.1.1"; - public const string pbeWithSHAAnd40BitRC4 = "1.2.840.113549.1.12.1.2"; - public const string pbeWithSHAAnd3KeyTripleDESCBC = "1.2.840.113549.1.12.1.3"; - public const string pbeWithSHAAnd2KeyTripleDESCBC = "1.2.840.113549.1.12.1.4"; - public const string pbeWithSHAAnd128BitRC2CBC = "1.2.840.113549.1.12.1.5"; - public const string pbeWithSHAAnd40BitRC2CBC = "1.2.840.113549.1.12.1.6"; - - // bags - public const string keyBag = "1.2.840.113549.1.12.10.1.1"; - public const string pkcs8ShroudedKeyBag = "1.2.840.113549.1.12.10.1.2"; - public const string certBag = "1.2.840.113549.1.12.10.1.3"; - public const string crlBag = "1.2.840.113549.1.12.10.1.4"; - public const string secretBag = "1.2.840.113549.1.12.10.1.5"; - public const string safeContentsBag = "1.2.840.113549.1.12.10.1.6"; - - // types - public const string x509Certificate = "1.2.840.113549.1.9.22.1"; - public const string sdsiCertificate = "1.2.840.113549.1.9.22.2"; - public const string x509Crl = "1.2.840.113549.1.9.23.1"; - - // Adapted from BouncyCastle PKCS12ParametersGenerator.java - public class DeriveBytes { - - public enum Purpose { - Key, - IV, - MAC - } - - static private byte[] keyDiversifier = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }; - static private byte[] ivDiversifier = { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }; - static private byte[] macDiversifier = { 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3 }; - - private string _hashName; - private int _iterations; - private byte[] _password; - private byte[] _salt; - - public DeriveBytes () {} - - public string HashName { - get { return _hashName; } - set { _hashName = value; } - } - - public int IterationCount { - get { return _iterations; } - set { _iterations = value; } - } - - public byte[] Password { - get { return (byte[]) _password.Clone (); } - set { - if (value == null) - _password = new byte [0]; - else - _password = (byte[]) value.Clone (); - } - } - - public byte[] Salt { - get { return (byte[]) _salt.Clone (); } - set { - if (value != null) - _salt = (byte[]) value.Clone (); - else - _salt = null; - } - } - - private void Adjust (byte[] a, int aOff, byte[] b) - { - int x = (b[b.Length - 1] & 0xff) + (a [aOff + b.Length - 1] & 0xff) + 1; - - a [aOff + b.Length - 1] = (byte) x; - x >>= 8; - - for (int i = b.Length - 2; i >= 0; i--) { - x += (b [i] & 0xff) + (a [aOff + i] & 0xff); - a [aOff + i] = (byte) x; - x >>= 8; - } - } - - private byte[] Derive (byte[] diversifier, int n) - { - HashAlgorithm digest = PKCS1.CreateFromName (_hashName); - int u = (digest.HashSize >> 3); // div 8 - int v = 64; - byte[] dKey = new byte [n]; - - byte[] S; - if ((_salt != null) && (_salt.Length != 0)) { - S = new byte[v * ((_salt.Length + v - 1) / v)]; - - for (int i = 0; i != S.Length; i++) { - S[i] = _salt[i % _salt.Length]; - } - } - else { - S = new byte[0]; - } - - byte[] P; - if ((_password != null) && (_password.Length != 0)) { - P = new byte[v * ((_password.Length + v - 1) / v)]; - - for (int i = 0; i != P.Length; i++) { - P[i] = _password[i % _password.Length]; - } - } - else { - P = new byte[0]; - } - - byte[] I = new byte [S.Length + P.Length]; - - Buffer.BlockCopy (S, 0, I, 0, S.Length); - Buffer.BlockCopy (P, 0, I, S.Length, P.Length); - - byte[] B = new byte[v]; - int c = (n + u - 1) / u; - - for (int i = 1; i <= c; i++) { - digest.TransformBlock (diversifier, 0, diversifier.Length, diversifier, 0); - digest.TransformFinalBlock (I, 0, I.Length); - byte[] A = digest.Hash; - digest.Initialize (); - for (int j = 1; j != _iterations; j++) { - A = digest.ComputeHash (A, 0, A.Length); - } - - for (int j = 0; j != B.Length; j++) { - B [j] = A [j % A.Length]; - } - - for (int j = 0; j != I.Length / v; j++) { - Adjust (I, j * v, B); - } - - if (i == c) { - Buffer.BlockCopy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u)); - } - else { - Buffer.BlockCopy(A, 0, dKey, (i - 1) * u, A.Length); - } - } - - return dKey; - } - - public byte[] DeriveKey (int size) - { - return Derive (keyDiversifier, size); - } - - public byte[] DeriveIV (int size) - { - return Derive (ivDiversifier, size); - } - - public byte[] DeriveMAC (int size) - { - return Derive (macDiversifier, size); - } - } - - const int recommendedIterationCount = 2000; - - //private int _version; - private byte[] _password; - private ArrayList _keyBags; - private ArrayList _secretBags; - private X509CertificateCollection _certs; - private bool _keyBagsChanged; - private bool _secretBagsChanged; - private bool _certsChanged; - private int _iterations; - private ArrayList _safeBags; - private RandomNumberGenerator _rng; - - // constructors - - public PKCS12 () - { - _iterations = recommendedIterationCount; - _keyBags = new ArrayList (); - _secretBags = new ArrayList (); - _certs = new X509CertificateCollection (); - _keyBagsChanged = false; - _secretBagsChanged = false; - _certsChanged = false; - _safeBags = new ArrayList (); - } - - public PKCS12 (byte[] data) - : this () - { - Password = null; - Decode (data); - } - - /* - * PFX ::= SEQUENCE { - * version INTEGER {v3(3)}(v3,...), - * authSafe ContentInfo, - * macData MacData OPTIONAL - * } - * - * MacData ::= SEQUENCE { - * mac DigestInfo, - * macSalt OCTET STRING, - * iterations INTEGER DEFAULT 1 - * -- Note: The default is for historical reasons and its use is deprecated. A higher - * -- value, like 1024 is recommended. - * } - * - * SafeContents ::= SEQUENCE OF SafeBag - * - * SafeBag ::= SEQUENCE { - * bagId BAG-TYPE.&id ({PKCS12BagSet}), - * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}), - * bagAttributes SET OF PKCS12Attribute OPTIONAL - * } - */ - public PKCS12 (byte[] data, string password) - : this () - { - Password = password; - Decode (data); - } - - public PKCS12 (byte[] data, byte[] password) - : this () - { - _password = password; - Decode (data); - } - - private void Decode (byte[] data) - { - ASN1 pfx = new ASN1 (data); - if (pfx.Tag != 0x30) - throw new ArgumentException ("invalid data"); - - ASN1 version = pfx [0]; - if (version.Tag != 0x02) - throw new ArgumentException ("invalid PFX version"); - //_version = version.Value [0]; - - PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (pfx [1]); - if (authSafe.ContentType != PKCS7.Oid.data) - throw new ArgumentException ("invalid authenticated safe"); - - // now that we know it's a PKCS#12 file, check the (optional) MAC - // before decoding anything else in the file - if (pfx.Count > 2) { - ASN1 macData = pfx [2]; - if (macData.Tag != 0x30) - throw new ArgumentException ("invalid MAC"); - - ASN1 mac = macData [0]; - if (mac.Tag != 0x30) - throw new ArgumentException ("invalid MAC"); - ASN1 macAlgorithm = mac [0]; - string macOid = ASN1Convert.ToOid (macAlgorithm [0]); - if (macOid != "1.3.14.3.2.26") - throw new ArgumentException ("unsupported HMAC"); - byte[] macValue = mac [1].Value; - - ASN1 macSalt = macData [1]; - if (macSalt.Tag != 0x04) - throw new ArgumentException ("missing MAC salt"); - - _iterations = 1; // default value - if (macData.Count > 2) { - ASN1 iters = macData [2]; - if (iters.Tag != 0x02) - throw new ArgumentException ("invalid MAC iteration"); - _iterations = ASN1Convert.ToInt32 (iters); - } - - byte[] authSafeData = authSafe.Content [0].Value; - byte[] calculatedMac = MAC (_password, macSalt.Value, _iterations, authSafeData); - if (!Compare (macValue, calculatedMac)) { - byte[] nullPassword = {0, 0}; - calculatedMac = MAC(nullPassword, macSalt.Value, _iterations, authSafeData); - if (!Compare (macValue, calculatedMac)) - throw new CryptographicException ("Invalid MAC - file may have been tampe red!"); - _password = nullPassword; - } - } - - // we now returns to our original presentation - PFX - ASN1 authenticatedSafe = new ASN1 (authSafe.Content [0].Value); - for (int i=0; i < authenticatedSafe.Count; i++) { - PKCS7.ContentInfo ci = new PKCS7.ContentInfo (authenticatedSafe [i]); - switch (ci.ContentType) { - case PKCS7.Oid.data: - // unencrypted (by PKCS#12) - ASN1 safeContents = new ASN1 (ci.Content [0].Value); - for (int j=0; j < safeContents.Count; j++) { - ASN1 safeBag = safeContents [j]; - ReadSafeBag (safeBag); - } - break; - case PKCS7.Oid.encryptedData: - // password encrypted - PKCS7.EncryptedData ed = new PKCS7.EncryptedData (ci.Content [0]); - ASN1 decrypted = new ASN1 (Decrypt (ed)); - for (int j=0; j < decrypted.Count; j++) { - ASN1 safeBag = decrypted [j]; - ReadSafeBag (safeBag); - } - break; - case PKCS7.Oid.envelopedData: - // public key encrypted - throw new NotImplementedException ("public key encrypted"); - default: - throw new ArgumentException ("unknown authenticatedSafe"); - } - } - } - - ~PKCS12 () - { - if (_password != null) { - Array.Clear (_password, 0, _password.Length); - } - _password = null; - } - - // properties - - public string Password { - set { - // Clear old password. - if (_password != null) - Array.Clear (_password, 0, _password.Length); - _password = null; - if (value != null) { - if (value.Length > 0) { - int size = value.Length; - int nul = 0; - if (size < MaximumPasswordLength) { - // if not present, add space for a NULL (0x00) character - if (value[size - 1] != 0x00) - nul = 1; - } else { - size = MaximumPasswordLength; - } - _password = new byte[(size + nul) << 1]; // double for unicode - Encoding.BigEndianUnicode.GetBytes (value, 0, size, _password, 0); - } else { - // double-byte (Unicode) NULL (0x00) - see bug #79617 - _password = new byte[2]; - } - } - } - } - - public int IterationCount { - get { return _iterations; } - set { _iterations = value; } - } - - public ArrayList Keys { - get { - if (_keyBagsChanged) { - _keyBags.Clear (); - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (keyBag)) { - ASN1 safeBag = sb.ASN1; - ASN1 bagValue = safeBag [1]; - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value); - byte[] privateKey = pki.PrivateKey; - switch (privateKey [0]) { - case 0x02: - DSAParameters p = new DSAParameters (); // FIXME - _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p)); - break; - case 0x30: - _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey)); - break; - default: - break; - } - Array.Clear (privateKey, 0, privateKey.Length); - - } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) { - ASN1 safeBag = sb.ASN1; - ASN1 bagValue = safeBag [1]; - PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value); - byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData); - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted); - byte[] privateKey = pki.PrivateKey; - switch (privateKey [0]) { - case 0x02: - DSAParameters p = new DSAParameters (); // FIXME - _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p)); - break; - case 0x30: - _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey)); - break; - default: - break; - } - Array.Clear (privateKey, 0, privateKey.Length); - Array.Clear (decrypted, 0, decrypted.Length); - } - } - _keyBagsChanged = false; - } - return ArrayList.ReadOnly(_keyBags); - } - } - - public ArrayList Secrets { - get { - if (_secretBagsChanged) { - _secretBags.Clear (); - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (secretBag)) { - ASN1 safeBag = sb.ASN1; - ASN1 bagValue = safeBag [1]; - byte[] secret = bagValue.Value; - _secretBags.Add(secret); - } - } - _secretBagsChanged = false; - } - return ArrayList.ReadOnly(_secretBags); - } - } - - public X509CertificateCollection Certificates { - get { - if (_certsChanged) { - _certs.Clear (); - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (certBag)) { - ASN1 safeBag = sb.ASN1; - ASN1 bagValue = safeBag [1]; - PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value); - _certs.Add (new X509Certificate (cert.Content [0].Value)); - } - } - _certsChanged = false; - } - return _certs; - } - } - - internal RandomNumberGenerator RNG { - get { - if (_rng == null) - _rng = RandomNumberGenerator.Create (); - return _rng; - } - } - - // private methods - - private bool Compare (byte[] expected, byte[] actual) - { - bool compare = false; - if (expected.Length == actual.Length) { - for (int i=0; i < expected.Length; i++) { - if (expected [i] != actual [i]) - return false; - } - compare = true; - } - return compare; - } - - private SymmetricAlgorithm GetSymmetricAlgorithm (string algorithmOid, byte[] salt, int iterationCount) - { - string algorithm = null; - int keyLength = 8; // 64 bits (default) - int ivLength = 8; // 64 bits (default) - - PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes (); - pd.Password = _password; - pd.Salt = salt; - pd.IterationCount = iterationCount; - - switch (algorithmOid) { - case PKCS5.pbeWithMD2AndDESCBC: // no unit test available - pd.HashName = "MD2"; - algorithm = "DES"; - break; - case PKCS5.pbeWithMD5AndDESCBC: // no unit test available - pd.HashName = "MD5"; - algorithm = "DES"; - break; - case PKCS5.pbeWithMD2AndRC2CBC: // no unit test available - // TODO - RC2-CBC-Parameter (PKCS5) - // if missing default to 32 bits !!! - pd.HashName = "MD2"; - algorithm = "RC2"; - keyLength = 4; // default - break; - case PKCS5.pbeWithMD5AndRC2CBC: // no unit test available - // TODO - RC2-CBC-Parameter (PKCS5) - // if missing default to 32 bits !!! - pd.HashName = "MD5"; - algorithm = "RC2"; - keyLength = 4; // default - break; - case PKCS5.pbeWithSHA1AndDESCBC: // no unit test available - pd.HashName = "SHA1"; - algorithm = "DES"; - break; - case PKCS5.pbeWithSHA1AndRC2CBC: // no unit test available - // TODO - RC2-CBC-Parameter (PKCS5) - // if missing default to 32 bits !!! - pd.HashName = "SHA1"; - algorithm = "RC2"; - keyLength = 4; // default - break; - case PKCS12.pbeWithSHAAnd128BitRC4: // no unit test available - pd.HashName = "SHA1"; - algorithm = "RC4"; - keyLength = 16; - ivLength = 0; // N/A - break; - case PKCS12.pbeWithSHAAnd40BitRC4: // no unit test available - pd.HashName = "SHA1"; - algorithm = "RC4"; - keyLength = 5; - ivLength = 0; // N/A - break; - case PKCS12.pbeWithSHAAnd3KeyTripleDESCBC: - pd.HashName = "SHA1"; - algorithm = "TripleDES"; - keyLength = 24; - break; - case PKCS12.pbeWithSHAAnd2KeyTripleDESCBC: // no unit test available - pd.HashName = "SHA1"; - algorithm = "TripleDES"; - keyLength = 16; - break; - case PKCS12.pbeWithSHAAnd128BitRC2CBC: // no unit test available - pd.HashName = "SHA1"; - algorithm = "RC2"; - keyLength = 16; - break; - case PKCS12.pbeWithSHAAnd40BitRC2CBC: - pd.HashName = "SHA1"; - algorithm = "RC2"; - keyLength = 5; - break; - default: - throw new NotSupportedException ("unknown oid " + algorithm); - } - - SymmetricAlgorithm sa = null; - sa = SymmetricAlgorithm.Create(algorithm); - sa.Key = pd.DeriveKey (keyLength); - // IV required only for block ciphers (not stream ciphers) - if (ivLength > 0) { - sa.IV = pd.DeriveIV (ivLength); - sa.Mode = CipherMode.CBC; - } - return sa; - } - - public byte[] Decrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] encryptedData) - { - SymmetricAlgorithm sa = null; - byte[] result = null; - try { - sa = GetSymmetricAlgorithm (algorithmOid, salt, iterationCount); - ICryptoTransform ct = sa.CreateDecryptor (); - result = ct.TransformFinalBlock (encryptedData, 0, encryptedData.Length); - } - finally { - if (sa != null) - sa.Clear (); - } - return result; - } - - public byte[] Decrypt (PKCS7.EncryptedData ed) - { - return Decrypt (ed.EncryptionAlgorithm.ContentType, - ed.EncryptionAlgorithm.Content [0].Value, - ASN1Convert.ToInt32 (ed.EncryptionAlgorithm.Content [1]), - ed.EncryptedContent); - } - - public byte[] Encrypt (string algorithmOid, byte[] salt, int iterationCount, byte[] data) - { - byte[] result = null; - using (SymmetricAlgorithm sa = GetSymmetricAlgorithm (algorithmOid, salt, iterationCount)) { - ICryptoTransform ct = sa.CreateEncryptor (); - result = ct.TransformFinalBlock (data, 0, data.Length); - } - return result; - } - - private DSAParameters GetExistingParameters (out bool found) - { - foreach (X509Certificate cert in Certificates) { - // FIXME: that won't work if parts of the parameters are missing - if (cert.KeyAlgorithmParameters != null) { - DSA dsa = cert.DSA; - if (dsa != null) { - found = true; - return dsa.ExportParameters (false); - } - } - } - found = false; - return new DSAParameters (); - } - - private void AddPrivateKey (PKCS8.PrivateKeyInfo pki) - { - byte[] privateKey = pki.PrivateKey; - switch (privateKey [0]) { - case 0x02: - bool found; - DSAParameters p = GetExistingParameters (out found); - if (found) { - _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p)); - } - break; - case 0x30: - _keyBags.Add (PKCS8.PrivateKeyInfo.DecodeRSA (privateKey)); - break; - default: - Array.Clear (privateKey, 0, privateKey.Length); - throw new CryptographicException ("Unknown private key format"); - } - Array.Clear (privateKey, 0, privateKey.Length); - } - - private void ReadSafeBag (ASN1 safeBag) - { - if (safeBag.Tag != 0x30) - throw new ArgumentException ("invalid safeBag"); - - ASN1 bagId = safeBag [0]; - if (bagId.Tag != 0x06) - throw new ArgumentException ("invalid safeBag id"); - - ASN1 bagValue = safeBag [1]; - string oid = ASN1Convert.ToOid (bagId); - switch (oid) { - case keyBag: - // NEED UNIT TEST - AddPrivateKey (new PKCS8.PrivateKeyInfo (bagValue.Value)); - break; - case pkcs8ShroudedKeyBag: - PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value); - byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData); - AddPrivateKey (new PKCS8.PrivateKeyInfo (decrypted)); - Array.Clear (decrypted, 0, decrypted.Length); - break; - case certBag: - PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value); - if (cert.ContentType != x509Certificate) - throw new NotSupportedException ("unsupport certificate type"); - X509Certificate x509 = new X509Certificate (cert.Content [0].Value); - _certs.Add (x509); - break; - case crlBag: - // TODO - break; - case secretBag: - byte[] secret = bagValue.Value; - _secretBags.Add(secret); - break; - case safeContentsBag: - // TODO - ? recurse ? - break; - default: - throw new ArgumentException ("unknown safeBag oid"); - } - - if (safeBag.Count > 2) { - ASN1 bagAttributes = safeBag [2]; - if (bagAttributes.Tag != 0x31) - throw new ArgumentException ("invalid safeBag attributes id"); - - for (int i = 0; i < bagAttributes.Count; i++) { - ASN1 pkcs12Attribute = bagAttributes[i]; - - if (pkcs12Attribute.Tag != 0x30) - throw new ArgumentException ("invalid PKCS12 attributes id"); - - ASN1 attrId = pkcs12Attribute [0]; - if (attrId.Tag != 0x06) - throw new ArgumentException ("invalid attribute id"); - - string attrOid = ASN1Convert.ToOid (attrId); - - ASN1 attrValues = pkcs12Attribute[1]; - for (int j = 0; j < attrValues.Count; j++) { - ASN1 attrValue = attrValues[j]; - - switch (attrOid) { - case PKCS9.friendlyName: - if (attrValue.Tag != 0x1e) - throw new ArgumentException ("invalid attribute value id"); - break; - case PKCS9.localKeyId: - if (attrValue.Tag != 0x04) - throw new ArgumentException ("invalid attribute value id"); - break; - default: - // Unknown OID -- don't check Tag - break; - } - } - } - } - - _safeBags.Add (new SafeBag(oid, safeBag)); - } - - private ASN1 Pkcs8ShroudedKeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes) - { - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (); - if (aa is RSA) { - pki.Algorithm = "1.2.840.113549.1.1.1"; - pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa); - } - else if (aa is DSA) { - pki.Algorithm = null; - pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa); - } - else - throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ()); - - PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (); - epki.Algorithm = pbeWithSHAAnd3KeyTripleDESCBC; - epki.IterationCount = _iterations; - epki.EncryptedData = Encrypt (pbeWithSHAAnd3KeyTripleDESCBC, epki.Salt, _iterations, pki.GetBytes ()); - - ASN1 safeBag = new ASN1 (0x30); - safeBag.Add (ASN1Convert.FromOid (pkcs8ShroudedKeyBag)); - ASN1 bagValue = new ASN1 (0xA0); - bagValue.Add (new ASN1 (epki.GetBytes ())); - safeBag.Add (bagValue); - - if (attributes != null) { - ASN1 bagAttributes = new ASN1 (0x31); - IDictionaryEnumerator de = attributes.GetEnumerator (); - - while (de.MoveNext ()) { - string oid = (string)de.Key; - switch (oid) { - case PKCS9.friendlyName: - ArrayList names = (ArrayList)de.Value; - if (names.Count > 0) { - ASN1 pkcs12Attribute = new ASN1 (0x30); - pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName)); - ASN1 attrValues = new ASN1 (0x31); - foreach (byte[] name in names) { - ASN1 attrValue = new ASN1 (0x1e); - attrValue.Value = name; - attrValues.Add (attrValue); - } - pkcs12Attribute.Add (attrValues); - bagAttributes.Add (pkcs12Attribute); - } - break; - case PKCS9.localKeyId: - ArrayList keys = (ArrayList)de.Value; - if (keys.Count > 0) { - ASN1 pkcs12Attribute = new ASN1 (0x30); - pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId)); - ASN1 attrValues = new ASN1 (0x31); - foreach (byte[] key in keys) { - ASN1 attrValue = new ASN1 (0x04); - attrValue.Value = key; - attrValues.Add (attrValue); - } - pkcs12Attribute.Add (attrValues); - bagAttributes.Add (pkcs12Attribute); - } - break; - default: - break; - } - } - - if (bagAttributes.Count > 0) { - safeBag.Add (bagAttributes); - } - } - - return safeBag; - } - - private ASN1 KeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes) - { - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (); - if (aa is RSA) { - pki.Algorithm = "1.2.840.113549.1.1.1"; - pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa); - } - else if (aa is DSA) { - pki.Algorithm = null; - pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa); - } - else - throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ()); - - ASN1 safeBag = new ASN1 (0x30); - safeBag.Add (ASN1Convert.FromOid (keyBag)); - ASN1 bagValue = new ASN1 (0xA0); - bagValue.Add (new ASN1 (pki.GetBytes ())); - safeBag.Add (bagValue); - - if (attributes != null) { - ASN1 bagAttributes = new ASN1 (0x31); - IDictionaryEnumerator de = attributes.GetEnumerator (); - - while (de.MoveNext ()) { - string oid = (string)de.Key; - switch (oid) { - case PKCS9.friendlyName: - ArrayList names = (ArrayList)de.Value; - if (names.Count > 0) { - ASN1 pkcs12Attribute = new ASN1 (0x30); - pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName)); - ASN1 attrValues = new ASN1 (0x31); - foreach (byte[] name in names) { - ASN1 attrValue = new ASN1 (0x1e); - attrValue.Value = name; - attrValues.Add (attrValue); - } - pkcs12Attribute.Add (attrValues); - bagAttributes.Add (pkcs12Attribute); - } - break; - case PKCS9.localKeyId: - ArrayList keys = (ArrayList)de.Value; - if (keys.Count > 0) { - ASN1 pkcs12Attribute = new ASN1 (0x30); - pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId)); - ASN1 attrValues = new ASN1 (0x31); - foreach (byte[] key in keys) { - ASN1 attrValue = new ASN1 (0x04); - attrValue.Value = key; - attrValues.Add (attrValue); - } - pkcs12Attribute.Add (attrValues); - bagAttributes.Add (pkcs12Attribute); - } - break; - default: - break; - } - } - - if (bagAttributes.Count > 0) { - safeBag.Add (bagAttributes); - } - } - - return safeBag; - } - - private ASN1 SecretBagSafeBag (byte[] secret, IDictionary attributes) - { - ASN1 safeBag = new ASN1 (0x30); - safeBag.Add (ASN1Convert.FromOid (secretBag)); - ASN1 bagValue = new ASN1 (0x80, secret); - safeBag.Add (bagValue); - - if (attributes != null) { - ASN1 bagAttributes = new ASN1 (0x31); - IDictionaryEnumerator de = attributes.GetEnumerator (); - - while (de.MoveNext ()) { - string oid = (string)de.Key; - switch (oid) { - case PKCS9.friendlyName: - ArrayList names = (ArrayList)de.Value; - if (names.Count > 0) { - ASN1 pkcs12Attribute = new ASN1 (0x30); - pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName)); - ASN1 attrValues = new ASN1 (0x31); - foreach (byte[] name in names) { - ASN1 attrValue = new ASN1 (0x1e); - attrValue.Value = name; - attrValues.Add (attrValue); - } - pkcs12Attribute.Add (attrValues); - bagAttributes.Add (pkcs12Attribute); - } - break; - case PKCS9.localKeyId: - ArrayList keys = (ArrayList)de.Value; - if (keys.Count > 0) { - ASN1 pkcs12Attribute = new ASN1 (0x30); - pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId)); - ASN1 attrValues = new ASN1 (0x31); - foreach (byte[] key in keys) { - ASN1 attrValue = new ASN1 (0x04); - attrValue.Value = key; - attrValues.Add (attrValue); - } - pkcs12Attribute.Add (attrValues); - bagAttributes.Add (pkcs12Attribute); - } - break; - default: - break; - } - } - - if (bagAttributes.Count > 0) { - safeBag.Add (bagAttributes); - } - } - - return safeBag; - } - - private ASN1 CertificateSafeBag (X509Certificate x509, IDictionary attributes) - { - ASN1 encapsulatedCertificate = new ASN1 (0x04, x509.RawData); - - PKCS7.ContentInfo ci = new PKCS7.ContentInfo (); - ci.ContentType = x509Certificate; - ci.Content.Add (encapsulatedCertificate); - - ASN1 bagValue = new ASN1 (0xA0); - bagValue.Add (ci.ASN1); - - ASN1 safeBag = new ASN1 (0x30); - safeBag.Add (ASN1Convert.FromOid (certBag)); - safeBag.Add (bagValue); - - if (attributes != null) { - ASN1 bagAttributes = new ASN1 (0x31); - IDictionaryEnumerator de = attributes.GetEnumerator (); - - while (de.MoveNext ()) { - string oid = (string)de.Key; - switch (oid) { - case PKCS9.friendlyName: - ArrayList names = (ArrayList)de.Value; - if (names.Count > 0) { - ASN1 pkcs12Attribute = new ASN1 (0x30); - pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName)); - ASN1 attrValues = new ASN1 (0x31); - foreach (byte[] name in names) { - ASN1 attrValue = new ASN1 (0x1e); - attrValue.Value = name; - attrValues.Add (attrValue); - } - pkcs12Attribute.Add (attrValues); - bagAttributes.Add (pkcs12Attribute); - } - break; - case PKCS9.localKeyId: - ArrayList keys = (ArrayList)de.Value; - if (keys.Count > 0) { - ASN1 pkcs12Attribute = new ASN1 (0x30); - pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId)); - ASN1 attrValues = new ASN1 (0x31); - foreach (byte[] key in keys) { - ASN1 attrValue = new ASN1 (0x04); - attrValue.Value = key; - attrValues.Add (attrValue); - } - pkcs12Attribute.Add (attrValues); - bagAttributes.Add (pkcs12Attribute); - } - break; - default: - break; - } - } - - if (bagAttributes.Count > 0) { - safeBag.Add (bagAttributes); - } - } - - return safeBag; - } - - private byte[] MAC (byte[] password, byte[] salt, int iterations, byte[] data) - { - PKCS12.DeriveBytes pd = new PKCS12.DeriveBytes (); - pd.HashName = "SHA1"; - pd.Password = password; - pd.Salt = salt; - pd.IterationCount = iterations; - - HMACSHA1 hmac = (HMACSHA1) HMACSHA1.Create (); - hmac.Key = pd.DeriveMAC (20); - return hmac.ComputeHash (data, 0, data.Length); - } - - /* - * SafeContents ::= SEQUENCE OF SafeBag - * - * SafeBag ::= SEQUENCE { - * bagId BAG-TYPE.&id ({PKCS12BagSet}), - * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}), - * bagAttributes SET OF PKCS12Attribute OPTIONAL - * } - */ - public byte[] GetBytes () - { - // TODO (incomplete) - ASN1 safeBagSequence = new ASN1 (0x30); - - // Sync Safe Bag list since X509CertificateCollection may be updated - ArrayList scs = new ArrayList (); - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (certBag)) { - ASN1 safeBag = sb.ASN1; - ASN1 bagValue = safeBag [1]; - PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value); - scs.Add (new X509Certificate (cert.Content [0].Value)); - } - } - - ArrayList addcerts = new ArrayList (); - ArrayList removecerts = new ArrayList (); - - foreach (X509Certificate c in Certificates) { - bool found = false; - - foreach (X509Certificate lc in scs) { - if (Compare (c.RawData, lc.RawData)) { - found = true; - } - } - - if (!found) { - addcerts.Add (c); - } - } - foreach (X509Certificate c in scs) { - bool found = false; - - foreach (X509Certificate lc in Certificates) { - if (Compare (c.RawData, lc.RawData)) { - found = true; - } - } - - if (!found) { - removecerts.Add (c); - } - } - - foreach (X509Certificate c in removecerts) { - RemoveCertificate (c); - } - - foreach (X509Certificate c in addcerts) { - AddCertificate (c); - } - // Sync done - - if (_safeBags.Count > 0) { - ASN1 certsSafeBag = new ASN1 (0x30); - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (certBag)) { - certsSafeBag.Add (sb.ASN1); - } - } - - if (certsSafeBag.Count > 0) { - PKCS7.ContentInfo contentInfo = EncryptedContentInfo (certsSafeBag, pbeWithSHAAnd3KeyTripleDESCBC); - safeBagSequence.Add (contentInfo.ASN1); - } - } - - if (_safeBags.Count > 0) { - ASN1 safeContents = new ASN1 (0x30); - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (keyBag) || - sb.BagOID.Equals (pkcs8ShroudedKeyBag)) { - safeContents.Add (sb.ASN1); - } - } - if (safeContents.Count > 0) { - ASN1 content = new ASN1 (0xA0); - content.Add (new ASN1 (0x04, safeContents.GetBytes ())); - - PKCS7.ContentInfo keyBag = new PKCS7.ContentInfo (PKCS7.Oid.data); - keyBag.Content = content; - safeBagSequence.Add (keyBag.ASN1); - } - } - - // Doing SecretBags separately in case we want to change their encryption independently. - if (_safeBags.Count > 0) { - ASN1 secretsSafeBag = new ASN1 (0x30); - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (secretBag)) { - secretsSafeBag.Add (sb.ASN1); - } - } - - if (secretsSafeBag.Count > 0) { - PKCS7.ContentInfo contentInfo = EncryptedContentInfo (secretsSafeBag, pbeWithSHAAnd3KeyTripleDESCBC); - safeBagSequence.Add (contentInfo.ASN1); - } - } - - - ASN1 encapsulates = new ASN1 (0x04, safeBagSequence.GetBytes ()); - ASN1 ci = new ASN1 (0xA0); - ci.Add (encapsulates); - PKCS7.ContentInfo authSafe = new PKCS7.ContentInfo (PKCS7.Oid.data); - authSafe.Content = ci; - - ASN1 macData = new ASN1 (0x30); - if (_password != null) { - // only for password based encryption - byte[] salt = new byte [20]; - RNG.GetBytes (salt); - byte[] macValue = MAC (_password, salt, _iterations, authSafe.Content [0].Value); - ASN1 oidSeq = new ASN1 (0x30); - oidSeq.Add (ASN1Convert.FromOid ("1.3.14.3.2.26")); // SHA1 - oidSeq.Add (new ASN1 (0x05)); - - ASN1 mac = new ASN1 (0x30); - mac.Add (oidSeq); - mac.Add (new ASN1 (0x04, macValue)); - - macData.Add (mac); - macData.Add (new ASN1 (0x04, salt)); - macData.Add (ASN1Convert.FromInt32 (_iterations)); - } - - ASN1 version = new ASN1 (0x02, new byte [1] { 0x03 }); - - ASN1 pfx = new ASN1 (0x30); - pfx.Add (version); - pfx.Add (authSafe.ASN1); - if (macData.Count > 0) { - // only for password based encryption - pfx.Add (macData); - } - - return pfx.GetBytes (); - } - - // Creates an encrypted PKCS#7 ContentInfo with safeBags as its SafeContents. Used in GetBytes(), above. - private PKCS7.ContentInfo EncryptedContentInfo(ASN1 safeBags, string algorithmOid) - { - byte[] salt = new byte [8]; - RNG.GetBytes (salt); - - ASN1 seqParams = new ASN1 (0x30); - seqParams.Add (new ASN1 (0x04, salt)); - seqParams.Add (ASN1Convert.FromInt32 (_iterations)); - - ASN1 seqPbe = new ASN1 (0x30); - seqPbe.Add (ASN1Convert.FromOid (algorithmOid)); - seqPbe.Add (seqParams); - - byte[] encrypted = Encrypt (algorithmOid, salt, _iterations, safeBags.GetBytes ()); - ASN1 encryptedContent = new ASN1 (0x80, encrypted); - - ASN1 seq = new ASN1 (0x30); - seq.Add (ASN1Convert.FromOid (PKCS7.Oid.data)); - seq.Add (seqPbe); - seq.Add (encryptedContent); - - ASN1 version = new ASN1 (0x02, new byte [1] { 0x00 }); - ASN1 encData = new ASN1 (0x30); - encData.Add (version); - encData.Add (seq); - - ASN1 finalContent = new ASN1 (0xA0); - finalContent.Add (encData); - - PKCS7.ContentInfo bag = new PKCS7.ContentInfo (PKCS7.Oid.encryptedData); - bag.Content = finalContent; - return bag; - } - - public void AddCertificate (X509Certificate cert) - { - AddCertificate (cert, null); - } - - public void AddCertificate (X509Certificate cert, IDictionary attributes) - { - bool found = false; - - for (int i = 0; !found && i < _safeBags.Count; i++) { - SafeBag sb = (SafeBag)_safeBags [i]; - - if (sb.BagOID.Equals (certBag)) { - ASN1 safeBag = sb.ASN1; - ASN1 bagValue = safeBag [1]; - PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value); - X509Certificate c = new X509Certificate (crt.Content [0].Value); - if (Compare (cert.RawData, c.RawData)) { - found = true; - } - } - } - - if (!found) { - _safeBags.Add (new SafeBag (certBag, CertificateSafeBag (cert, attributes))); - _certsChanged = true; - } - } - - public void RemoveCertificate (X509Certificate cert) - { - RemoveCertificate (cert, null); - } - - public void RemoveCertificate (X509Certificate cert, IDictionary attrs) - { - int certIndex = -1; - - for (int i = 0; certIndex == -1 && i < _safeBags.Count; i++) { - SafeBag sb = (SafeBag)_safeBags [i]; - - if (sb.BagOID.Equals (certBag)) { - ASN1 safeBag = sb.ASN1; - ASN1 bagValue = safeBag [1]; - PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value); - X509Certificate c = new X509Certificate (crt.Content [0].Value); - if (Compare (cert.RawData, c.RawData)) { - if (attrs != null) { - if (safeBag.Count == 3) { - ASN1 bagAttributes = safeBag [2]; - int bagAttributesFound = 0; - for (int j = 0; j < bagAttributes.Count; j++) { - ASN1 pkcs12Attribute = bagAttributes [j]; - ASN1 attrId = pkcs12Attribute [0]; - string ao = ASN1Convert.ToOid (attrId); - ArrayList dattrValues = (ArrayList)attrs [ao]; - - if (dattrValues != null) { - ASN1 attrValues = pkcs12Attribute [1]; - - if (dattrValues.Count == attrValues.Count) { - int attrValuesFound = 0; - for (int k = 0; k < attrValues.Count; k++) { - ASN1 attrValue = attrValues [k]; - byte[] value = (byte[])dattrValues [k]; - - if (Compare (value, attrValue.Value)) { - attrValuesFound += 1; - } - } - if (attrValuesFound == attrValues.Count) { - bagAttributesFound += 1; - } - } - } - } - if (bagAttributesFound == bagAttributes.Count) { - certIndex = i; - } - } - } else { - certIndex = i; - } - } - } - } - - if (certIndex != -1) { - _safeBags.RemoveAt (certIndex); - _certsChanged = true; - } - } - - private bool CompareAsymmetricAlgorithm (AsymmetricAlgorithm a1, AsymmetricAlgorithm a2) - { - // fast path - if (a1.KeySize != a2.KeySize) - return false; - // compare public keys - if they match we can assume the private match too - return (a1.ToXmlString (false) == a2.ToXmlString (false)); - } - - public void AddPkcs8ShroudedKeyBag (AsymmetricAlgorithm aa) - { - AddPkcs8ShroudedKeyBag (aa, null); - } - - public void AddPkcs8ShroudedKeyBag (AsymmetricAlgorithm aa, IDictionary attributes) - { - bool found = false; - - for (int i = 0; !found && i < _safeBags.Count; i++) { - SafeBag sb = (SafeBag)_safeBags [i]; - - if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) { - ASN1 bagValue = sb.ASN1 [1]; - PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value); - byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData); - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted); - byte[] privateKey = pki.PrivateKey; - - AsymmetricAlgorithm saa = null; - switch (privateKey [0]) { - case 0x02: - DSAParameters p = new DSAParameters (); // FIXME - saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p); - break; - case 0x30: - saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey); - break; - default: - Array.Clear (decrypted, 0, decrypted.Length); - Array.Clear (privateKey, 0, privateKey.Length); - throw new CryptographicException ("Unknown private key format"); - } - - Array.Clear (decrypted, 0, decrypted.Length); - Array.Clear (privateKey, 0, privateKey.Length); - - if (CompareAsymmetricAlgorithm (aa , saa)) { - found = true; - } - } - } - - if (!found) { - _safeBags.Add (new SafeBag (pkcs8ShroudedKeyBag, Pkcs8ShroudedKeyBagSafeBag (aa, attributes))); - _keyBagsChanged = true; - } - } - - public void RemovePkcs8ShroudedKeyBag (AsymmetricAlgorithm aa) - { - int aaIndex = -1; - - for (int i = 0; aaIndex == -1 && i < _safeBags.Count; i++) { - SafeBag sb = (SafeBag)_safeBags [i]; - - if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) { - ASN1 bagValue = sb.ASN1 [1]; - PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value); - byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData); - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted); - byte[] privateKey = pki.PrivateKey; - - AsymmetricAlgorithm saa = null; - switch (privateKey [0]) { - case 0x02: - DSAParameters p = new DSAParameters (); // FIXME - saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p); - break; - case 0x30: - saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey); - break; - default: - Array.Clear (decrypted, 0, decrypted.Length); - Array.Clear (privateKey, 0, privateKey.Length); - throw new CryptographicException ("Unknown private key format"); - } - - Array.Clear (decrypted, 0, decrypted.Length); - Array.Clear (privateKey, 0, privateKey.Length); - - if (CompareAsymmetricAlgorithm (aa, saa)) { - aaIndex = i; - } - } - } - - if (aaIndex != -1) { - _safeBags.RemoveAt (aaIndex); - _keyBagsChanged = true; - } - } - - public void AddKeyBag (AsymmetricAlgorithm aa) - { - AddKeyBag (aa, null); - } - - public void AddKeyBag (AsymmetricAlgorithm aa, IDictionary attributes) - { - bool found = false; - - for (int i = 0; !found && i < _safeBags.Count; i++) { - SafeBag sb = (SafeBag)_safeBags [i]; - - if (sb.BagOID.Equals (keyBag)) { - ASN1 bagValue = sb.ASN1 [1]; - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value); - byte[] privateKey = pki.PrivateKey; - - AsymmetricAlgorithm saa = null; - switch (privateKey [0]) { - case 0x02: - DSAParameters p = new DSAParameters (); // FIXME - saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p); - break; - case 0x30: - saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey); - break; - default: - Array.Clear (privateKey, 0, privateKey.Length); - throw new CryptographicException ("Unknown private key format"); - } - - Array.Clear (privateKey, 0, privateKey.Length); - - if (CompareAsymmetricAlgorithm (aa, saa)) { - found = true; - } - } - } - - if (!found) { - _safeBags.Add (new SafeBag (keyBag, KeyBagSafeBag (aa, attributes))); - _keyBagsChanged = true; - } - } - - public void RemoveKeyBag (AsymmetricAlgorithm aa) - { - int aaIndex = -1; - - for (int i = 0; aaIndex == -1 && i < _safeBags.Count; i++) { - SafeBag sb = (SafeBag)_safeBags [i]; - - if (sb.BagOID.Equals (keyBag)) { - ASN1 bagValue = sb.ASN1 [1]; - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value); - byte[] privateKey = pki.PrivateKey; - - AsymmetricAlgorithm saa = null; - switch (privateKey [0]) { - case 0x02: - DSAParameters p = new DSAParameters (); // FIXME - saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p); - break; - case 0x30: - saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey); - break; - default: - Array.Clear (privateKey, 0, privateKey.Length); - throw new CryptographicException ("Unknown private key format"); - } - - Array.Clear (privateKey, 0, privateKey.Length); - - if (CompareAsymmetricAlgorithm (aa, saa)) { - aaIndex = i; - } - } - } - - if (aaIndex != -1) { - _safeBags.RemoveAt (aaIndex); - _keyBagsChanged = true; - } - } - - public void AddSecretBag (byte[] secret) - { - AddSecretBag (secret, null); - } - - public void AddSecretBag (byte[] secret, IDictionary attributes) - { - bool found = false; - - for (int i = 0; !found && i < _safeBags.Count; i++) { - SafeBag sb = (SafeBag)_safeBags [i]; - - if (sb.BagOID.Equals (secretBag)) { - ASN1 bagValue = sb.ASN1 [1]; - byte[] ssecret = bagValue.Value; - - if (Compare (secret, ssecret)) { - found = true; - } - } - } - - if (!found) { - _safeBags.Add (new SafeBag (secretBag, SecretBagSafeBag (secret, attributes))); - _secretBagsChanged = true; - } - } - - public void RemoveSecretBag (byte[] secret) - { - int sIndex = -1; - - for (int i = 0; sIndex == -1 && i < _safeBags.Count; i++) { - SafeBag sb = (SafeBag)_safeBags [i]; - - if (sb.BagOID.Equals (secretBag)) { - ASN1 bagValue = sb.ASN1 [1]; - byte[] ssecret = bagValue.Value; - - if (Compare (secret, ssecret)) { - sIndex = i; - } - } - } - - if (sIndex != -1) { - _safeBags.RemoveAt (sIndex); - _secretBagsChanged = true; - } - } - - public AsymmetricAlgorithm GetAsymmetricAlgorithm (IDictionary attrs) - { - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (keyBag) || sb.BagOID.Equals (pkcs8ShroudedKeyBag)) { - ASN1 safeBag = sb.ASN1; - - if (safeBag.Count == 3) { - ASN1 bagAttributes = safeBag [2]; - - int bagAttributesFound = 0; - for (int i = 0; i < bagAttributes.Count; i++) { - ASN1 pkcs12Attribute = bagAttributes [i]; - ASN1 attrId = pkcs12Attribute [0]; - string ao = ASN1Convert.ToOid (attrId); - ArrayList dattrValues = (ArrayList)attrs [ao]; - - if (dattrValues != null) { - ASN1 attrValues = pkcs12Attribute [1]; - - if (dattrValues.Count == attrValues.Count) { - int attrValuesFound = 0; - for (int j = 0; j < attrValues.Count; j++) { - ASN1 attrValue = attrValues [j]; - byte[] value = (byte[])dattrValues [j]; - - if (Compare (value, attrValue.Value)) { - attrValuesFound += 1; - } - } - if (attrValuesFound == attrValues.Count) { - bagAttributesFound += 1; - } - } - } - } - if (bagAttributesFound == bagAttributes.Count) { - ASN1 bagValue = safeBag [1]; - AsymmetricAlgorithm aa = null; - if (sb.BagOID.Equals (keyBag)) { - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value); - byte[] privateKey = pki.PrivateKey; - switch (privateKey [0]) { - case 0x02: - DSAParameters p = new DSAParameters (); // FIXME - aa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p); - break; - case 0x30: - aa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey); - break; - default: - break; - } - Array.Clear (privateKey, 0, privateKey.Length); - } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) { - PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value); - byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData); - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted); - byte[] privateKey = pki.PrivateKey; - switch (privateKey [0]) { - case 0x02: - DSAParameters p = new DSAParameters (); // FIXME - aa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p); - break; - case 0x30: - aa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey); - break; - default: - break; - } - Array.Clear (privateKey, 0, privateKey.Length); - Array.Clear (decrypted, 0, decrypted.Length); - } - return aa; - } - } - } - } - - return null; - } - - public byte[] GetSecret (IDictionary attrs) - { - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (secretBag)) { - ASN1 safeBag = sb.ASN1; - - if (safeBag.Count == 3) { - ASN1 bagAttributes = safeBag [2]; - - int bagAttributesFound = 0; - for (int i = 0; i < bagAttributes.Count; i++) { - ASN1 pkcs12Attribute = bagAttributes [i]; - ASN1 attrId = pkcs12Attribute [0]; - string ao = ASN1Convert.ToOid (attrId); - ArrayList dattrValues = (ArrayList)attrs [ao]; - - if (dattrValues != null) { - ASN1 attrValues = pkcs12Attribute [1]; - - if (dattrValues.Count == attrValues.Count) { - int attrValuesFound = 0; - for (int j = 0; j < attrValues.Count; j++) { - ASN1 attrValue = attrValues [j]; - byte[] value = (byte[])dattrValues [j]; - - if (Compare (value, attrValue.Value)) { - attrValuesFound += 1; - } - } - if (attrValuesFound == attrValues.Count) { - bagAttributesFound += 1; - } - } - } - } - if (bagAttributesFound == bagAttributes.Count) { - ASN1 bagValue = safeBag [1]; - return bagValue.Value; - } - } - } - } - - return null; - } - - public X509Certificate GetCertificate (IDictionary attrs) - { - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (certBag)) { - ASN1 safeBag = sb.ASN1; - - if (safeBag.Count == 3) { - ASN1 bagAttributes = safeBag [2]; - - int bagAttributesFound = 0; - for (int i = 0; i < bagAttributes.Count; i++) { - ASN1 pkcs12Attribute = bagAttributes [i]; - ASN1 attrId = pkcs12Attribute [0]; - string ao = ASN1Convert.ToOid (attrId); - ArrayList dattrValues = (ArrayList)attrs [ao]; - - if (dattrValues != null) { - ASN1 attrValues = pkcs12Attribute [1]; - - if (dattrValues.Count == attrValues.Count) { - int attrValuesFound = 0; - for (int j = 0; j < attrValues.Count; j++) { - ASN1 attrValue = attrValues [j]; - byte[] value = (byte[])dattrValues [j]; - - if (Compare (value, attrValue.Value)) { - attrValuesFound += 1; - } - } - if (attrValuesFound == attrValues.Count) { - bagAttributesFound += 1; - } - } - } - } - if (bagAttributesFound == bagAttributes.Count) { - ASN1 bagValue = safeBag [1]; - PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value); - return new X509Certificate (crt.Content [0].Value); - } - } - } - } - - return null; - } - - public IDictionary GetAttributes (AsymmetricAlgorithm aa) - { - IDictionary result = new Hashtable (); - - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (keyBag) || sb.BagOID.Equals (pkcs8ShroudedKeyBag)) { - ASN1 safeBag = sb.ASN1; - - ASN1 bagValue = safeBag [1]; - AsymmetricAlgorithm saa = null; - if (sb.BagOID.Equals (keyBag)) { - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (bagValue.Value); - byte[] privateKey = pki.PrivateKey; - switch (privateKey [0]) { - case 0x02: - DSAParameters p = new DSAParameters (); // FIXME - saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p); - break; - case 0x30: - saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey); - break; - default: - break; - } - Array.Clear (privateKey, 0, privateKey.Length); - } else if (sb.BagOID.Equals (pkcs8ShroudedKeyBag)) { - PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value); - byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData); - PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (decrypted); - byte[] privateKey = pki.PrivateKey; - switch (privateKey [0]) { - case 0x02: - DSAParameters p = new DSAParameters (); // FIXME - saa = PKCS8.PrivateKeyInfo.DecodeDSA (privateKey, p); - break; - case 0x30: - saa = PKCS8.PrivateKeyInfo.DecodeRSA (privateKey); - break; - default: - break; - } - Array.Clear (privateKey, 0, privateKey.Length); - Array.Clear (decrypted, 0, decrypted.Length); - } - - if (saa != null && CompareAsymmetricAlgorithm (saa, aa)) { - if (safeBag.Count == 3) { - ASN1 bagAttributes = safeBag [2]; - - for (int i = 0; i < bagAttributes.Count; i++) { - ASN1 pkcs12Attribute = bagAttributes [i]; - ASN1 attrId = pkcs12Attribute [0]; - string aOid = ASN1Convert.ToOid (attrId); - ArrayList aValues = new ArrayList (); - - ASN1 attrValues = pkcs12Attribute [1]; - - for (int j = 0; j < attrValues.Count; j++) { - ASN1 attrValue = attrValues [j]; - aValues.Add (attrValue.Value); - } - result.Add (aOid, aValues); - } - } - } - } - } - - return result; - } - - public IDictionary GetAttributes (X509Certificate cert) - { - IDictionary result = new Hashtable (); - - foreach (SafeBag sb in _safeBags) { - if (sb.BagOID.Equals (certBag)) { - ASN1 safeBag = sb.ASN1; - ASN1 bagValue = safeBag [1]; - PKCS7.ContentInfo crt = new PKCS7.ContentInfo (bagValue.Value); - X509Certificate xc = new X509Certificate (crt.Content [0].Value); - - if (Compare (cert.RawData, xc.RawData)) { - if (safeBag.Count == 3) { - ASN1 bagAttributes = safeBag [2]; - - for (int i = 0; i < bagAttributes.Count; i++) { - ASN1 pkcs12Attribute = bagAttributes [i]; - ASN1 attrId = pkcs12Attribute [0]; - - string aOid = ASN1Convert.ToOid (attrId); - ArrayList aValues = new ArrayList (); - - ASN1 attrValues = pkcs12Attribute [1]; - - for (int j = 0; j < attrValues.Count; j++) { - ASN1 attrValue = attrValues [j]; - aValues.Add (attrValue.Value); - } - result.Add (aOid, aValues); - } - } - } - } - } - - return result; - } - - public void SaveToFile (string filename) - { - if (filename == null) - throw new ArgumentNullException ("filename"); - - using (FileStream fs = File.Create (filename)) { - byte[] data = GetBytes (); - fs.Write (data, 0, data.Length); - } - } - - public object Clone () - { - PKCS12 clone = null; - if (_password != null) { - clone = new PKCS12 (GetBytes (), Encoding.BigEndianUnicode.GetString (_password)); - } else { - clone = new PKCS12 (GetBytes ()); - } - clone.IterationCount = this.IterationCount; - - return clone; - } - - // static - - public const int CryptoApiPasswordLimit = 32; - - static private int password_max_length = Int32.MaxValue; - - // static properties - - // MS CryptoAPI limits the password to a maximum of 31 characters - // other implementations, like OpenSSL, have no such limitation. - // Setting a maximum value will truncate the password length to - // ensure compatibility with MS's PFXImportCertStore API. - static public int MaximumPasswordLength { - get { return password_max_length; } - set { - if (value < CryptoApiPasswordLimit) { - string msg = string.Format ("Maximum password length cannot be less than {0}.", CryptoApiPasswordLimit); - throw new ArgumentOutOfRangeException (msg); - } - password_max_length = value; - } - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/PKCS7.cs b/Emby.Server.Implementations/Cryptography/PKCS7.cs deleted file mode 100644 index 475854500..000000000 --- a/Emby.Server.Implementations/Cryptography/PKCS7.cs +++ /dev/null @@ -1,1012 +0,0 @@ -// -// PKCS7.cs: PKCS #7 - Cryptographic Message Syntax Standard -// http://www.rsasecurity.com/rsalabs/pkcs/pkcs-7/index.html -// -// Authors: -// Sebastien Pouliot -// Daniel Granath -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Collections; -using System.Security.Cryptography; - -namespace Emby.Server.Core.Cryptography -{ - - public sealed class PKCS7 { - - public class Oid { - // pkcs 1 - public const string rsaEncryption = "1.2.840.113549.1.1.1"; - // pkcs 7 - public const string data = "1.2.840.113549.1.7.1"; - public const string signedData = "1.2.840.113549.1.7.2"; - public const string envelopedData = "1.2.840.113549.1.7.3"; - public const string signedAndEnvelopedData = "1.2.840.113549.1.7.4"; - public const string digestedData = "1.2.840.113549.1.7.5"; - public const string encryptedData = "1.2.840.113549.1.7.6"; - // pkcs 9 - public const string contentType = "1.2.840.113549.1.9.3"; - public const string messageDigest = "1.2.840.113549.1.9.4"; - public const string signingTime = "1.2.840.113549.1.9.5"; - public const string countersignature = "1.2.840.113549.1.9.6"; - - public Oid () - { - } - } - - private PKCS7 () - { - } - - static public ASN1 Attribute (string oid, ASN1 value) - { - ASN1 attr = new ASN1 (0x30); - attr.Add (ASN1Convert.FromOid (oid)); - ASN1 aset = attr.Add (new ASN1 (0x31)); - aset.Add (value); - return attr; - } - - static public ASN1 AlgorithmIdentifier (string oid) - { - ASN1 ai = new ASN1 (0x30); - ai.Add (ASN1Convert.FromOid (oid)); - ai.Add (new ASN1 (0x05)); // NULL - return ai; - } - - static public ASN1 AlgorithmIdentifier (string oid, ASN1 parameters) - { - ASN1 ai = new ASN1 (0x30); - ai.Add (ASN1Convert.FromOid (oid)); - ai.Add (parameters); - return ai; - } - - /* - * IssuerAndSerialNumber ::= SEQUENCE { - * issuer Name, - * serialNumber CertificateSerialNumber - * } - */ - static public ASN1 IssuerAndSerialNumber (X509Certificate x509) - { - ASN1 issuer = null; - ASN1 serial = null; - ASN1 cert = new ASN1 (x509.RawData); - int tbs = 0; - bool flag = false; - while (tbs < cert[0].Count) { - ASN1 e = cert[0][tbs++]; - if (e.Tag == 0x02) - serial = e; - else if (e.Tag == 0x30) { - if (flag) { - issuer = e; - break; - } - flag = true; - } - } - ASN1 iasn = new ASN1 (0x30); - iasn.Add (issuer); - iasn.Add (serial); - return iasn; - } - - /* - * ContentInfo ::= SEQUENCE { - * contentType ContentType, - * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL - * } - * ContentType ::= OBJECT IDENTIFIER - */ - public class ContentInfo { - - private string contentType; - private ASN1 content; - - public ContentInfo () - { - content = new ASN1 (0xA0); - } - - public ContentInfo (string oid) : this () - { - contentType = oid; - } - - public ContentInfo (byte[] data) - : this (new ASN1 (data)) {} - - public ContentInfo (ASN1 asn1) - { - // SEQUENCE with 1 or 2 elements - if ((asn1.Tag != 0x30) || ((asn1.Count < 1) && (asn1.Count > 2))) - throw new ArgumentException ("Invalid ASN1"); - if (asn1[0].Tag != 0x06) - throw new ArgumentException ("Invalid contentType"); - contentType = ASN1Convert.ToOid (asn1[0]); - if (asn1.Count > 1) { - if (asn1[1].Tag != 0xA0) - throw new ArgumentException ("Invalid content"); - content = asn1[1]; - } - } - - public ASN1 ASN1 { - get { return GetASN1(); } - } - - public ASN1 Content { - get { return content; } - set { content = value; } - } - - public string ContentType { - get { return contentType; } - set { contentType = value; } - } - - internal ASN1 GetASN1 () - { - // ContentInfo ::= SEQUENCE { - ASN1 contentInfo = new ASN1 (0x30); - // contentType ContentType, -> ContentType ::= OBJECT IDENTIFIER - contentInfo.Add (ASN1Convert.FromOid (contentType)); - // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL - if ((content != null) && (content.Count > 0)) - contentInfo.Add (content); - return contentInfo; - } - - public byte[] GetBytes () - { - return GetASN1 ().GetBytes (); - } - } - - /* - * EncryptedData ::= SEQUENCE { - * version INTEGER {edVer0(0)} (edVer0), - * encryptedContentInfo EncryptedContentInfo - * } - */ - public class EncryptedData { - private byte _version; - private ContentInfo _content; - private ContentInfo _encryptionAlgorithm; - private byte[] _encrypted; - - public EncryptedData () - { - _version = 0; - } - - public EncryptedData (byte[] data) - : this (new ASN1 (data)) - { - } - - public EncryptedData (ASN1 asn1) : this () - { - if ((asn1.Tag != 0x30) || (asn1.Count < 2)) - throw new ArgumentException ("Invalid EncryptedData"); - - if (asn1 [0].Tag != 0x02) - throw new ArgumentException ("Invalid version"); - _version = asn1 [0].Value [0]; - - ASN1 encryptedContentInfo = asn1 [1]; - if (encryptedContentInfo.Tag != 0x30) - throw new ArgumentException ("missing EncryptedContentInfo"); - - ASN1 contentType = encryptedContentInfo [0]; - if (contentType.Tag != 0x06) - throw new ArgumentException ("missing EncryptedContentInfo.ContentType"); - _content = new ContentInfo (ASN1Convert.ToOid (contentType)); - - ASN1 contentEncryptionAlgorithm = encryptedContentInfo [1]; - if (contentEncryptionAlgorithm.Tag != 0x30) - throw new ArgumentException ("missing EncryptedContentInfo.ContentEncryptionAlgorithmIdentifier"); - _encryptionAlgorithm = new ContentInfo (ASN1Convert.ToOid (contentEncryptionAlgorithm [0])); - _encryptionAlgorithm.Content = contentEncryptionAlgorithm [1]; - - ASN1 encryptedContent = encryptedContentInfo [2]; - if (encryptedContent.Tag != 0x80) - throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent"); - _encrypted = encryptedContent.Value; - } - - public ASN1 ASN1 { - get { return GetASN1(); } - } - - public ContentInfo ContentInfo { - get { return _content; } - } - - public ContentInfo EncryptionAlgorithm { - get { return _encryptionAlgorithm; } - } - - public byte[] EncryptedContent { - get { - if (_encrypted == null) - return null; - return (byte[]) _encrypted.Clone (); - } - } - - public byte Version { - get { return _version; } - set { _version = value; } - } - - // methods - - internal ASN1 GetASN1 () - { - return null; - } - - public byte[] GetBytes () - { - return GetASN1 ().GetBytes (); - } - } - - /* - * EnvelopedData ::= SEQUENCE { - * version Version, - * recipientInfos RecipientInfos, - * encryptedContentInfo EncryptedContentInfo - * } - * - * RecipientInfos ::= SET OF RecipientInfo - * - * EncryptedContentInfo ::= SEQUENCE { - * contentType ContentType, - * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, - * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL - * } - * - * EncryptedContent ::= OCTET STRING - * - */ - public class EnvelopedData { - private byte _version; - private ContentInfo _content; - private ContentInfo _encryptionAlgorithm; - private ArrayList _recipientInfos; - private byte[] _encrypted; - - public EnvelopedData () - { - _version = 0; - _content = new ContentInfo (); - _encryptionAlgorithm = new ContentInfo (); - _recipientInfos = new ArrayList (); - } - - public EnvelopedData (byte[] data) - : this (new ASN1 (data)) - { - } - - public EnvelopedData (ASN1 asn1) : this () - { - if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 3)) - throw new ArgumentException ("Invalid EnvelopedData"); - - if (asn1[0][0].Tag != 0x02) - throw new ArgumentException ("Invalid version"); - _version = asn1[0][0].Value[0]; - - // recipientInfos - - ASN1 recipientInfos = asn1 [0][1]; - if (recipientInfos.Tag != 0x31) - throw new ArgumentException ("missing RecipientInfos"); - for (int i=0; i < recipientInfos.Count; i++) { - ASN1 recipientInfo = recipientInfos [i]; - _recipientInfos.Add (new RecipientInfo (recipientInfo)); - } - - ASN1 encryptedContentInfo = asn1[0][2]; - if (encryptedContentInfo.Tag != 0x30) - throw new ArgumentException ("missing EncryptedContentInfo"); - - ASN1 contentType = encryptedContentInfo [0]; - if (contentType.Tag != 0x06) - throw new ArgumentException ("missing EncryptedContentInfo.ContentType"); - _content = new ContentInfo (ASN1Convert.ToOid (contentType)); - - ASN1 contentEncryptionAlgorithm = encryptedContentInfo [1]; - if (contentEncryptionAlgorithm.Tag != 0x30) - throw new ArgumentException ("missing EncryptedContentInfo.ContentEncryptionAlgorithmIdentifier"); - _encryptionAlgorithm = new ContentInfo (ASN1Convert.ToOid (contentEncryptionAlgorithm [0])); - _encryptionAlgorithm.Content = contentEncryptionAlgorithm [1]; - - ASN1 encryptedContent = encryptedContentInfo [2]; - if (encryptedContent.Tag != 0x80) - throw new ArgumentException ("missing EncryptedContentInfo.EncryptedContent"); - _encrypted = encryptedContent.Value; - } - - public ArrayList RecipientInfos { - get { return _recipientInfos; } - } - - public ASN1 ASN1 { - get { return GetASN1(); } - } - - public ContentInfo ContentInfo { - get { return _content; } - } - - public ContentInfo EncryptionAlgorithm { - get { return _encryptionAlgorithm; } - } - - public byte[] EncryptedContent { - get { - if (_encrypted == null) - return null; - return (byte[]) _encrypted.Clone (); - } - } - - public byte Version { - get { return _version; } - set { _version = value; } - } - - internal ASN1 GetASN1 () - { - // SignedData ::= SEQUENCE { - ASN1 signedData = new ASN1 (0x30); - // version Version -> Version ::= INTEGER -/* byte[] ver = { _version }; - signedData.Add (new ASN1 (0x02, ver)); - // digestAlgorithms DigestAlgorithmIdentifiers -> DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier - ASN1 digestAlgorithms = signedData.Add (new ASN1 (0x31)); - if (hashAlgorithm != null) { - string hashOid = CryptoConfig.MapNameToOid (hashAlgorithm); - digestAlgorithms.Add (AlgorithmIdentifier (hashOid)); - } - - // contentInfo ContentInfo, - ASN1 ci = contentInfo.ASN1; - signedData.Add (ci); - if ((mda == null) && (hashAlgorithm != null)) { - // automatically add the messageDigest authenticated attribute - HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm); - byte[] idcHash = ha.ComputeHash (ci[1][0].Value); - ASN1 md = new ASN1 (0x30); - mda = Attribute (messageDigest, md.Add (new ASN1 (0x04, idcHash))); - signerInfo.AuthenticatedAttributes.Add (mda); - } - - // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL, - if (certs.Count > 0) { - ASN1 a0 = signedData.Add (new ASN1 (0xA0)); - foreach (X509Certificate x in certs) - a0.Add (new ASN1 (x.RawData)); - } - // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, - if (crls.Count > 0) { - ASN1 a1 = signedData.Add (new ASN1 (0xA1)); - foreach (byte[] crl in crls) - a1.Add (new ASN1 (crl)); - } - // signerInfos SignerInfos -> SignerInfos ::= SET OF SignerInfo - ASN1 signerInfos = signedData.Add (new ASN1 (0x31)); - if (signerInfo.Key != null) - signerInfos.Add (signerInfo.ASN1);*/ - return signedData; - } - - public byte[] GetBytes () { - return GetASN1 ().GetBytes (); - } - } - - /* RecipientInfo ::= SEQUENCE { - * version Version, - * issuerAndSerialNumber IssuerAndSerialNumber, - * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, - * encryptedKey EncryptedKey - * } - * - * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier - * - * EncryptedKey ::= OCTET STRING - */ - public class RecipientInfo { - - private int _version; - private string _oid; - private byte[] _key; - private byte[] _ski; - private string _issuer; - private byte[] _serial; - - public RecipientInfo () {} - - public RecipientInfo (ASN1 data) - { - if (data.Tag != 0x30) - throw new ArgumentException ("Invalid RecipientInfo"); - - ASN1 version = data [0]; - if (version.Tag != 0x02) - throw new ArgumentException ("missing Version"); - _version = version.Value [0]; - - // issuerAndSerialNumber IssuerAndSerialNumber - ASN1 subjectIdentifierType = data [1]; - if ((subjectIdentifierType.Tag == 0x80) && (_version == 3)) { - _ski = subjectIdentifierType.Value; - } - else { - _issuer = X501.ToString (subjectIdentifierType [0]); - _serial = subjectIdentifierType [1].Value; - } - - ASN1 keyEncryptionAlgorithm = data [2]; - _oid = ASN1Convert.ToOid (keyEncryptionAlgorithm [0]); - - ASN1 encryptedKey = data [3]; - _key = encryptedKey.Value; - } - - public string Oid { - get { return _oid; } - } - - public byte[] Key { - get { - if (_key == null) - return null; - return (byte[]) _key.Clone (); - } - } - - public byte[] SubjectKeyIdentifier { - get { - if (_ski == null) - return null; - return (byte[]) _ski.Clone (); - } - } - - public string Issuer { - get { return _issuer; } - } - - public byte[] Serial { - get { - if (_serial == null) - return null; - return (byte[]) _serial.Clone (); - } - } - - public int Version { - get { return _version; } - } - } - - /* - * SignedData ::= SEQUENCE { - * version Version, - * digestAlgorithms DigestAlgorithmIdentifiers, - * contentInfo ContentInfo, - * certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL, - * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, - * signerInfos SignerInfos - * } - */ - public class SignedData { - private byte version; - private string hashAlgorithm; - private ContentInfo contentInfo; - private X509CertificateCollection certs; - private ArrayList crls; - private SignerInfo signerInfo; - private bool mda; - private bool signed; - - public SignedData () - { - version = 1; - contentInfo = new ContentInfo (); - certs = new X509CertificateCollection (); - crls = new ArrayList (); - signerInfo = new SignerInfo (); - mda = true; - signed = false; - } - - public SignedData (byte[] data) - : this (new ASN1 (data)) - { - } - - public SignedData (ASN1 asn1) - { - if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 4)) - throw new ArgumentException ("Invalid SignedData"); - - if (asn1[0][0].Tag != 0x02) - throw new ArgumentException ("Invalid version"); - version = asn1[0][0].Value[0]; - - contentInfo = new ContentInfo (asn1[0][2]); - - int n = 3; - certs = new X509CertificateCollection (); - if (asn1[0][n].Tag == 0xA0) { - for (int i=0; i < asn1[0][n].Count; i++) - certs.Add (new X509Certificate (asn1[0][n][i].GetBytes ())); - n++; - } - - crls = new ArrayList (); - if (asn1[0][n].Tag == 0xA1) { - for (int i=0; i < asn1[0][n].Count; i++) - crls.Add (asn1[0][n][i].GetBytes ()); - n++; - } - - if (asn1[0][n].Count > 0) - signerInfo = new SignerInfo (asn1[0][n]); - else - signerInfo = new SignerInfo (); - - // Exchange hash algorithm Oid from SignerInfo - if (signerInfo.HashName != null) { - HashName = OidToName(signerInfo.HashName); - } - - // Check if SignerInfo has authenticated attributes - mda = (signerInfo.AuthenticatedAttributes.Count > 0); - } - - public ASN1 ASN1 { - get { return GetASN1(); } - } - - public X509CertificateCollection Certificates { - get { return certs; } - } - - public ContentInfo ContentInfo { - get { return contentInfo; } - } - - public ArrayList Crls { - get { return crls; } - } - - public string HashName { - get { return hashAlgorithm; } - // todo add validation - set { - hashAlgorithm = value; - signerInfo.HashName = value; - } - } - - public SignerInfo SignerInfo { - get { return signerInfo; } - } - - public byte Version { - get { return version; } - set { version = value; } - } - - public bool UseAuthenticatedAttributes { - get { return mda; } - set { mda = value; } - } - - public bool VerifySignature (AsymmetricAlgorithm aa) - { - if (aa == null) { - return false; - } - - RSAPKCS1SignatureDeformatter r = new RSAPKCS1SignatureDeformatter (aa); - r.SetHashAlgorithm (hashAlgorithm); - HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm); - - byte[] signature = signerInfo.Signature; - byte[] hash = null; - - if (mda) { - ASN1 asn = new ASN1 (0x31); - foreach (ASN1 attr in signerInfo.AuthenticatedAttributes) - asn.Add (attr); - - hash = ha.ComputeHash (asn.GetBytes ()); - } else { - hash = ha.ComputeHash (contentInfo.Content[0].Value); - } - - if (hash != null && signature != null) { - return r.VerifySignature (hash, signature); - } - return false; - } - - internal string OidToName (string oid) - { - switch (oid) { - case "1.3.14.3.2.26" : - return "SHA1"; - case "1.2.840.113549.2.2" : - return "MD2"; - case "1.2.840.113549.2.5" : - return "MD5"; - case "2.16.840.1.101.3.4.1" : - return "SHA256"; - case "2.16.840.1.101.3.4.2" : - return "SHA384"; - case "2.16.840.1.101.3.4.3" : - return "SHA512"; - default : - break; - } - // Unknown Oid - return oid; - } - - internal ASN1 GetASN1 () - { - // SignedData ::= SEQUENCE { - ASN1 signedData = new ASN1 (0x30); - // version Version -> Version ::= INTEGER - byte[] ver = { version }; - signedData.Add (new ASN1 (0x02, ver)); - // digestAlgorithms DigestAlgorithmIdentifiers -> DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier - ASN1 digestAlgorithms = signedData.Add (new ASN1 (0x31)); - if (hashAlgorithm != null) { - string hashOid = CryptoConfig.MapNameToOID (hashAlgorithm); - digestAlgorithms.Add (AlgorithmIdentifier (hashOid)); - } - - // contentInfo ContentInfo, - ASN1 ci = contentInfo.ASN1; - signedData.Add (ci); - if (!signed && (hashAlgorithm != null)) { - if (mda) { - // Use authenticated attributes for signature - - // Automatically add the contentType authenticated attribute - ASN1 ctattr = Attribute (Oid.contentType, ci[0]); - signerInfo.AuthenticatedAttributes.Add (ctattr); - - // Automatically add the messageDigest authenticated attribute - HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm); - byte[] idcHash = ha.ComputeHash (ci[1][0].Value); - ASN1 md = new ASN1 (0x30); - ASN1 mdattr = Attribute (Oid.messageDigest, md.Add (new ASN1 (0x04, idcHash))); - signerInfo.AuthenticatedAttributes.Add (mdattr); - } else { - // Don't use authenticated attributes for signature -- signature is content - RSAPKCS1SignatureFormatter r = new RSAPKCS1SignatureFormatter (signerInfo.Key); - r.SetHashAlgorithm (hashAlgorithm); - HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm); - byte[] sig = ha.ComputeHash (ci[1][0].Value); - signerInfo.Signature = r.CreateSignature (sig); - } - signed = true; - } - - // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL, - if (certs.Count > 0) { - ASN1 a0 = signedData.Add (new ASN1 (0xA0)); - foreach (X509Certificate x in certs) - a0.Add (new ASN1 (x.RawData)); - } - // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, - if (crls.Count > 0) { - ASN1 a1 = signedData.Add (new ASN1 (0xA1)); - foreach (byte[] crl in crls) - a1.Add (new ASN1 (crl)); - } - // signerInfos SignerInfos -> SignerInfos ::= SET OF SignerInfo - ASN1 signerInfos = signedData.Add (new ASN1 (0x31)); - if (signerInfo.Key != null) - signerInfos.Add (signerInfo.ASN1); - return signedData; - } - - public byte[] GetBytes () - { - return GetASN1 ().GetBytes (); - } - } - - /* - * SignerInfo ::= SEQUENCE { - * version Version, - * issuerAndSerialNumber IssuerAndSerialNumber, - * digestAlgorithm DigestAlgorithmIdentifier, - * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, - * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, - * encryptedDigest EncryptedDigest, - * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL - * } - * - * For version == 3 issuerAndSerialNumber may be replaced by ... - */ - public class SignerInfo { - - private byte version; - private X509Certificate x509; - private string hashAlgorithm; - private AsymmetricAlgorithm key; - private ArrayList authenticatedAttributes; - private ArrayList unauthenticatedAttributes; - private byte[] signature; - private string issuer; - private byte[] serial; - private byte[] ski; - - public SignerInfo () - { - version = 1; - authenticatedAttributes = new ArrayList (); - unauthenticatedAttributes = new ArrayList (); - } - - public SignerInfo (byte[] data) - : this (new ASN1 (data)) {} - - // TODO: INCOMPLETE - public SignerInfo (ASN1 asn1) : this () - { - if ((asn1[0].Tag != 0x30) || (asn1[0].Count < 5)) - throw new ArgumentException ("Invalid SignedData"); - - // version Version - if (asn1[0][0].Tag != 0x02) - throw new ArgumentException ("Invalid version"); - version = asn1[0][0].Value[0]; - - // issuerAndSerialNumber IssuerAndSerialNumber - ASN1 subjectIdentifierType = asn1 [0][1]; - if ((subjectIdentifierType.Tag == 0x80) && (version == 3)) { - ski = subjectIdentifierType.Value; - } - else { - issuer = X501.ToString (subjectIdentifierType [0]); - serial = subjectIdentifierType [1].Value; - } - - // digestAlgorithm DigestAlgorithmIdentifier - ASN1 digestAlgorithm = asn1 [0][2]; - hashAlgorithm = ASN1Convert.ToOid (digestAlgorithm [0]); - - // authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL - int n = 3; - ASN1 authAttributes = asn1 [0][n]; - if (authAttributes.Tag == 0xA0) { - n++; - for (int i=0; i < authAttributes.Count; i++) - authenticatedAttributes.Add (authAttributes [i]); - } - - // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier - n++; - // ASN1 digestEncryptionAlgorithm = asn1 [0][n++]; - // string digestEncryptionAlgorithmOid = ASN1Convert.ToOid (digestEncryptionAlgorithm [0]); - - // encryptedDigest EncryptedDigest - ASN1 encryptedDigest = asn1 [0][n++]; - if (encryptedDigest.Tag == 0x04) - signature = encryptedDigest.Value; - - // unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL - ASN1 unauthAttributes = asn1 [0][n]; - if ((unauthAttributes != null) && (unauthAttributes.Tag == 0xA1)) { - for (int i=0; i < unauthAttributes.Count; i++) - unauthenticatedAttributes.Add (unauthAttributes [i]); - } - } - - public string IssuerName { - get { return issuer; } - } - - public byte[] SerialNumber { - get { - if (serial == null) - return null; - return (byte[]) serial.Clone (); - } - } - - public byte[] SubjectKeyIdentifier { - get { - if (ski == null) - return null; - return (byte[]) ski.Clone (); - } - } - - public ASN1 ASN1 { - get { return GetASN1(); } - } - - public ArrayList AuthenticatedAttributes { - get { return authenticatedAttributes; } - } - - public X509Certificate Certificate { - get { return x509; } - set { x509 = value; } - } - - public string HashName { - get { return hashAlgorithm; } - set { hashAlgorithm = value; } - } - - public AsymmetricAlgorithm Key { - get { return key; } - set { key = value; } - } - - public byte[] Signature { - get { - if (signature == null) - return null; - return (byte[]) signature.Clone (); - } - - set { - if (value != null) { - signature = (byte[]) value.Clone (); - } - } - } - - public ArrayList UnauthenticatedAttributes { - get { return unauthenticatedAttributes; } - } - - public byte Version { - get { return version; } - set { version = value; } - } - - internal ASN1 GetASN1 () - { - if ((key == null) || (hashAlgorithm == null)) - return null; - byte[] ver = { version }; - ASN1 signerInfo = new ASN1 (0x30); - // version Version -> Version ::= INTEGER - signerInfo.Add (new ASN1 (0x02, ver)); - // issuerAndSerialNumber IssuerAndSerialNumber, - signerInfo.Add (PKCS7.IssuerAndSerialNumber (x509)); - // digestAlgorithm DigestAlgorithmIdentifier, - string hashOid = CryptoConfig.MapNameToOID (hashAlgorithm); - signerInfo.Add (AlgorithmIdentifier (hashOid)); - // authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL, - ASN1 aa = null; - if (authenticatedAttributes.Count > 0) { - aa = signerInfo.Add (new ASN1 (0xA0)); - authenticatedAttributes.Sort(new SortedSet ()); - foreach (ASN1 attr in authenticatedAttributes) - aa.Add (attr); - } - // digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, - if (key is RSA) { - signerInfo.Add (AlgorithmIdentifier (PKCS7.Oid.rsaEncryption)); - - if (aa != null) { - // Calculate the signature here; otherwise it must be set from SignedData - RSAPKCS1SignatureFormatter r = new RSAPKCS1SignatureFormatter (key); - r.SetHashAlgorithm (hashAlgorithm); - byte[] tbs = aa.GetBytes (); - tbs [0] = 0x31; // not 0xA0 for signature - HashAlgorithm ha = HashAlgorithm.Create (hashAlgorithm); - byte[] tbsHash = ha.ComputeHash (tbs); - signature = r.CreateSignature (tbsHash); - } - } - else if (key is DSA) { - throw new NotImplementedException ("not yet"); - } - else - throw new CryptographicException ("Unknown assymetric algorithm"); - // encryptedDigest EncryptedDigest, - signerInfo.Add (new ASN1 (0x04, signature)); - // unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL - if (unauthenticatedAttributes.Count > 0) { - ASN1 ua = signerInfo.Add (new ASN1 (0xA1)); - unauthenticatedAttributes.Sort(new SortedSet ()); - foreach (ASN1 attr in unauthenticatedAttributes) - ua.Add (attr); - } - return signerInfo; - } - - public byte[] GetBytes () - { - return GetASN1 ().GetBytes (); - } - } - - internal class SortedSet : IComparer { - - public int Compare (object x, object y) - { - if (x == null) - return (y == null) ? 0 : -1; - else if (y == null) - return 1; - - ASN1 xx = x as ASN1; - ASN1 yy = y as ASN1; - - if ((xx == null) || (yy == null)) { - throw new ArgumentException (("Invalid objects.")); - } - - byte[] xb = xx.GetBytes (); - byte[] yb = yy.GetBytes (); - - for (int i = 0; i < xb.Length; i++) { - if (i == yb.Length) - break; - - if (xb[i] == yb[i]) - continue; - - return (xb[i] < yb[i]) ? -1 : 1; - } - - // The arrays are equal up to the shortest of them. - if (xb.Length > yb.Length) - return 1; - else if (xb.Length < yb.Length) - return -1; - - return 0; - } - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/PKCS8.cs b/Emby.Server.Implementations/Cryptography/PKCS8.cs deleted file mode 100644 index 7e9a27298..000000000 --- a/Emby.Server.Implementations/Cryptography/PKCS8.cs +++ /dev/null @@ -1,495 +0,0 @@ -// -// PKCS8.cs: PKCS #8 - Private-Key Information Syntax Standard -// ftp://ftp.rsasecurity.com/pub/pkcs/doc/pkcs-8.doc -// -// Author: -// Sebastien Pouliot -// -// (C) 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com) -// Copyright 2013 Xamarin Inc. (http://www.xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Collections; -using System.Security.Cryptography; - -namespace Emby.Server.Core.Cryptography -{ - - public sealed class PKCS8 { - - public enum KeyInfo { - PrivateKey, - EncryptedPrivateKey, - Unknown - } - - private PKCS8 () - { - } - - static public KeyInfo GetType (byte[] data) - { - if (data == null) - throw new ArgumentNullException ("data"); - - KeyInfo ki = KeyInfo.Unknown; - try { - ASN1 top = new ASN1 (data); - if ((top.Tag == 0x30) && (top.Count > 0)) { - ASN1 firstLevel = top [0]; - switch (firstLevel.Tag) { - case 0x02: - ki = KeyInfo.PrivateKey; - break; - case 0x30: - ki = KeyInfo.EncryptedPrivateKey; - break; - } - } - } - catch { - throw new CryptographicException ("invalid ASN.1 data"); - } - return ki; - } - - /* - * PrivateKeyInfo ::= SEQUENCE { - * version Version, - * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, - * privateKey PrivateKey, - * attributes [0] IMPLICIT Attributes OPTIONAL - * } - * - * Version ::= INTEGER - * - * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier - * - * PrivateKey ::= OCTET STRING - * - * Attributes ::= SET OF Attribute - */ - public class PrivateKeyInfo { - - private int _version; - private string _algorithm; - private byte[] _key; - private ArrayList _list; - - public PrivateKeyInfo () - { - _version = 0; - _list = new ArrayList (); - } - - public PrivateKeyInfo (byte[] data) : this () - { - Decode (data); - } - - // properties - - public string Algorithm { - get { return _algorithm; } - set { _algorithm = value; } - } - - public ArrayList Attributes { - get { return _list; } - } - - public byte[] PrivateKey { - get { - if (_key == null) - return null; - return (byte[]) _key.Clone (); - } - set { - if (value == null) - throw new ArgumentNullException ("PrivateKey"); - _key = (byte[]) value.Clone (); - } - } - - public int Version { - get { return _version; } - set { - if (value < 0) - throw new ArgumentOutOfRangeException ("negative version"); - _version = value; - } - } - - // methods - - private void Decode (byte[] data) - { - ASN1 privateKeyInfo = new ASN1 (data); - if (privateKeyInfo.Tag != 0x30) - throw new CryptographicException ("invalid PrivateKeyInfo"); - - ASN1 version = privateKeyInfo [0]; - if (version.Tag != 0x02) - throw new CryptographicException ("invalid version"); - _version = version.Value [0]; - - ASN1 privateKeyAlgorithm = privateKeyInfo [1]; - if (privateKeyAlgorithm.Tag != 0x30) - throw new CryptographicException ("invalid algorithm"); - - ASN1 algorithm = privateKeyAlgorithm [0]; - if (algorithm.Tag != 0x06) - throw new CryptographicException ("missing algorithm OID"); - _algorithm = ASN1Convert.ToOid (algorithm); - - ASN1 privateKey = privateKeyInfo [2]; - _key = privateKey.Value; - - // attributes [0] IMPLICIT Attributes OPTIONAL - if (privateKeyInfo.Count > 3) { - ASN1 attributes = privateKeyInfo [3]; - for (int i=0; i < attributes.Count; i++) { - _list.Add (attributes [i]); - } - } - } - - public byte[] GetBytes () - { - ASN1 privateKeyAlgorithm = new ASN1 (0x30); - privateKeyAlgorithm.Add (ASN1Convert.FromOid (_algorithm)); - privateKeyAlgorithm.Add (new ASN1 (0x05)); // ASN.1 NULL - - ASN1 pki = new ASN1 (0x30); - pki.Add (new ASN1 (0x02, new byte [1] { (byte) _version })); - pki.Add (privateKeyAlgorithm); - pki.Add (new ASN1 (0x04, _key)); - - if (_list.Count > 0) { - ASN1 attributes = new ASN1 (0xA0); - foreach (ASN1 attribute in _list) { - attributes.Add (attribute); - } - pki.Add (attributes); - } - - return pki.GetBytes (); - } - - // static methods - - static private byte[] RemoveLeadingZero (byte[] bigInt) - { - int start = 0; - int length = bigInt.Length; - if (bigInt [0] == 0x00) { - start = 1; - length--; - } - byte[] bi = new byte [length]; - Buffer.BlockCopy (bigInt, start, bi, 0, length); - return bi; - } - - static private byte[] Normalize (byte[] bigInt, int length) - { - if (bigInt.Length == length) - return bigInt; - else if (bigInt.Length > length) - return RemoveLeadingZero (bigInt); - else { - // pad with 0 - byte[] bi = new byte [length]; - Buffer.BlockCopy (bigInt, 0, bi, (length - bigInt.Length), bigInt.Length); - return bi; - } - } - - /* - * RSAPrivateKey ::= SEQUENCE { - * version Version, - * modulus INTEGER, -- n - * publicExponent INTEGER, -- e - * privateExponent INTEGER, -- d - * prime1 INTEGER, -- p - * prime2 INTEGER, -- q - * exponent1 INTEGER, -- d mod (p-1) - * exponent2 INTEGER, -- d mod (q-1) - * coefficient INTEGER, -- (inverse of q) mod p - * otherPrimeInfos OtherPrimeInfos OPTIONAL - * } - */ - static public RSA DecodeRSA (byte[] keypair) - { - ASN1 privateKey = new ASN1 (keypair); - if (privateKey.Tag != 0x30) - throw new CryptographicException ("invalid private key format"); - - ASN1 version = privateKey [0]; - if (version.Tag != 0x02) - throw new CryptographicException ("missing version"); - - if (privateKey.Count < 9) - throw new CryptographicException ("not enough key parameters"); - - RSAParameters param = new RSAParameters (); - // note: MUST remove leading 0 - else MS wont import the key - param.Modulus = RemoveLeadingZero (privateKey [1].Value); - int keysize = param.Modulus.Length; - int keysize2 = (keysize >> 1); // half-size - // size must be normalized - else MS wont import the key - param.D = Normalize (privateKey [3].Value, keysize); - param.DP = Normalize (privateKey [6].Value, keysize2); - param.DQ = Normalize (privateKey [7].Value, keysize2); - param.Exponent = RemoveLeadingZero (privateKey [2].Value); - param.InverseQ = Normalize (privateKey [8].Value, keysize2); - param.P = Normalize (privateKey [4].Value, keysize2); - param.Q = Normalize (privateKey [5].Value, keysize2); - - RSA rsa = null; - try { - rsa = RSA.Create (); - rsa.ImportParameters (param); - } - catch (CryptographicException) { - // this may cause problem when this code is run under - // the SYSTEM identity on Windows (e.g. ASP.NET). See - // http://bugzilla.ximian.com/show_bug.cgi?id=77559 - CspParameters csp = new CspParameters(); - csp.Flags = CspProviderFlags.UseMachineKeyStore; - rsa = new RSACryptoServiceProvider(csp); - rsa.ImportParameters(param); - } - return rsa; - } - - /* - * RSAPrivateKey ::= SEQUENCE { - * version Version, - * modulus INTEGER, -- n - * publicExponent INTEGER, -- e - * privateExponent INTEGER, -- d - * prime1 INTEGER, -- p - * prime2 INTEGER, -- q - * exponent1 INTEGER, -- d mod (p-1) - * exponent2 INTEGER, -- d mod (q-1) - * coefficient INTEGER, -- (inverse of q) mod p - * otherPrimeInfos OtherPrimeInfos OPTIONAL - * } - */ - static public byte[] Encode (RSA rsa) - { - RSAParameters param = rsa.ExportParameters (true); - - ASN1 rsaPrivateKey = new ASN1 (0x30); - rsaPrivateKey.Add (new ASN1 (0x02, new byte [1] { 0x00 })); - rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.Modulus)); - rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.Exponent)); - rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.D)); - rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.P)); - rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.Q)); - rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.DP)); - rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.DQ)); - rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.InverseQ)); - - return rsaPrivateKey.GetBytes (); - } - - // DSA only encode it's X private key inside an ASN.1 INTEGER (Hint: Tag == 0x02) - // which isn't enough for rebuilding the keypair. The other parameters - // can be found (98% of the time) in the X.509 certificate associated - // with the private key or (2% of the time) the parameters are in it's - // issuer X.509 certificate (not supported in the .NET framework). - static public DSA DecodeDSA (byte[] privateKey, DSAParameters dsaParameters) - { - ASN1 pvk = new ASN1 (privateKey); - if (pvk.Tag != 0x02) - throw new CryptographicException ("invalid private key format"); - - // X is ALWAYS 20 bytes (no matter if the key length is 512 or 1024 bits) - dsaParameters.X = Normalize (pvk.Value, 20); - DSA dsa = DSA.Create (); - dsa.ImportParameters (dsaParameters); - return dsa; - } - - static public byte[] Encode (DSA dsa) - { - DSAParameters param = dsa.ExportParameters (true); - return ASN1Convert.FromUnsignedBigInteger (param.X).GetBytes (); - } - - static public byte[] Encode (AsymmetricAlgorithm aa) - { - if (aa is RSA) - return Encode ((RSA)aa); - else if (aa is DSA) - return Encode ((DSA)aa); - else - throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ()); - } - } - - /* - * EncryptedPrivateKeyInfo ::= SEQUENCE { - * encryptionAlgorithm EncryptionAlgorithmIdentifier, - * encryptedData EncryptedData - * } - * - * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier - * - * EncryptedData ::= OCTET STRING - * - * -- - * AlgorithmIdentifier ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL - * } - * - * -- from PKCS#5 - * PBEParameter ::= SEQUENCE { - * salt OCTET STRING SIZE(8), - * iterationCount INTEGER - * } - */ - public class EncryptedPrivateKeyInfo { - - private string _algorithm; - private byte[] _salt; - private int _iterations; - private byte[] _data; - - public EncryptedPrivateKeyInfo () {} - - public EncryptedPrivateKeyInfo (byte[] data) : this () - { - Decode (data); - } - - // properties - - public string Algorithm { - get { return _algorithm; } - set { _algorithm = value; } - } - - public byte[] EncryptedData { - get { return (_data == null) ? null : (byte[]) _data.Clone (); } - set { _data = (value == null) ? null : (byte[]) value.Clone (); } - } - - public byte[] Salt { - get { - if (_salt == null) { - RandomNumberGenerator rng = RandomNumberGenerator.Create (); - _salt = new byte [8]; - rng.GetBytes (_salt); - } - return (byte[]) _salt.Clone (); - } - set { _salt = (byte[]) value.Clone (); } - } - - public int IterationCount { - get { return _iterations; } - set { - if (value < 0) - throw new ArgumentOutOfRangeException ("IterationCount", "Negative"); - _iterations = value; - } - } - - // methods - - private void Decode (byte[] data) - { - ASN1 encryptedPrivateKeyInfo = new ASN1 (data); - if (encryptedPrivateKeyInfo.Tag != 0x30) - throw new CryptographicException ("invalid EncryptedPrivateKeyInfo"); - - ASN1 encryptionAlgorithm = encryptedPrivateKeyInfo [0]; - if (encryptionAlgorithm.Tag != 0x30) - throw new CryptographicException ("invalid encryptionAlgorithm"); - ASN1 algorithm = encryptionAlgorithm [0]; - if (algorithm.Tag != 0x06) - throw new CryptographicException ("invalid algorithm"); - _algorithm = ASN1Convert.ToOid (algorithm); - // parameters ANY DEFINED BY algorithm OPTIONAL - if (encryptionAlgorithm.Count > 1) { - ASN1 parameters = encryptionAlgorithm [1]; - if (parameters.Tag != 0x30) - throw new CryptographicException ("invalid parameters"); - - ASN1 salt = parameters [0]; - if (salt.Tag != 0x04) - throw new CryptographicException ("invalid salt"); - _salt = salt.Value; - - ASN1 iterationCount = parameters [1]; - if (iterationCount.Tag != 0x02) - throw new CryptographicException ("invalid iterationCount"); - _iterations = ASN1Convert.ToInt32 (iterationCount); - } - - ASN1 encryptedData = encryptedPrivateKeyInfo [1]; - if (encryptedData.Tag != 0x04) - throw new CryptographicException ("invalid EncryptedData"); - _data = encryptedData.Value; - } - - // Note: PKCS#8 doesn't define how to generate the key required for encryption - // so you're on your own. Just don't try to copy the big guys too much ;) - // Netscape: http://www.cs.auckland.ac.nz/~pgut001/pubs/netscape.txt - // Microsoft: http://www.cs.auckland.ac.nz/~pgut001/pubs/breakms.txt - public byte[] GetBytes () - { - if (_algorithm == null) - throw new CryptographicException ("No algorithm OID specified"); - - ASN1 encryptionAlgorithm = new ASN1 (0x30); - encryptionAlgorithm.Add (ASN1Convert.FromOid (_algorithm)); - - // parameters ANY DEFINED BY algorithm OPTIONAL - if ((_iterations > 0) || (_salt != null)) { - ASN1 salt = new ASN1 (0x04, _salt); - ASN1 iterations = ASN1Convert.FromInt32 (_iterations); - - ASN1 parameters = new ASN1 (0x30); - parameters.Add (salt); - parameters.Add (iterations); - encryptionAlgorithm.Add (parameters); - } - - // encapsulates EncryptedData into an OCTET STRING - ASN1 encryptedData = new ASN1 (0x04, _data); - - ASN1 encryptedPrivateKeyInfo = new ASN1 (0x30); - encryptedPrivateKeyInfo.Add (encryptionAlgorithm); - encryptedPrivateKeyInfo.Add (encryptedData); - - return encryptedPrivateKeyInfo.GetBytes (); - } - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/PfxGenerator.cs b/Emby.Server.Implementations/Cryptography/PfxGenerator.cs deleted file mode 100644 index 2d1dd649e..000000000 --- a/Emby.Server.Implementations/Cryptography/PfxGenerator.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Collections; -using System.Security.Cryptography; - -namespace Emby.Server.Core.Cryptography -{ - public class PFXGenerator - { - // http://www.freekpaans.nl/2015/04/creating-self-signed-x-509-certificates-using-mono-security/ - public static byte[] GeneratePfx(string certificateName, string password) - { - byte[] sn = GenerateSerialNumber(); - string subject = string.Format("CN={0}", certificateName); - - DateTime notBefore = DateTime.Now; - DateTime notAfter = DateTime.Now.AddYears(20); - - RSA subjectKey = new RSACryptoServiceProvider(2048); - - - string hashName = "SHA256"; - - X509CertificateBuilder cb = new X509CertificateBuilder(3); - cb.SerialNumber = sn; - cb.IssuerName = subject; - cb.NotBefore = notBefore; - cb.NotAfter = notAfter; - cb.SubjectName = subject; - cb.SubjectPublicKey = subjectKey; - cb.Hash = hashName; - - byte[] rawcert = cb.Sign(subjectKey); - - - PKCS12 p12 = new PKCS12(); - p12.Password = password; - - Hashtable attributes = GetAttributes(); - - p12.AddCertificate(new X509Certificate(rawcert), attributes); - p12.AddPkcs8ShroudedKeyBag(subjectKey, attributes); - - return p12.GetBytes(); - } - - private static Hashtable GetAttributes() - { - 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); - return attributes; - } - - private static byte[] GenerateSerialNumber() - { - byte[] sn = Guid.NewGuid().ToByteArray(); - - //must be positive - if ((sn[0] & 0x80) == 0x80) - sn[0] -= 0x80; - return sn; - } - - public static byte[] GetCertificateForBytes(byte[] pfx, string password) - { - var pkcs = new PKCS12(pfx, password); - var cert = pkcs.GetCertificate(GetAttributes()); - - return cert.RawData; - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/X501Name.cs b/Emby.Server.Implementations/Cryptography/X501Name.cs deleted file mode 100644 index 3318f95e2..000000000 --- a/Emby.Server.Implementations/Cryptography/X501Name.cs +++ /dev/null @@ -1,393 +0,0 @@ -// -// X501Name.cs: X.501 Distinguished Names stuff -// -// Author: -// Sebastien Pouliot -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Globalization; -using System.Text; - -namespace Emby.Server.Core.Cryptography -{ - - // References: - // 1. Information technology - Open Systems Interconnection - The Directory: Models - // http://www.itu.int/rec/recommendation.asp?type=items&lang=e&parent=T-REC-X.501-200102-I - // 2. RFC2253: Lightweight Directory Access Protocol (v3): UTF-8 String Representation of Distinguished Names - // http://www.ietf.org/rfc/rfc2253.txt - - /* - * Name ::= CHOICE { RDNSequence } - * - * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName - * - * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue - */ - public sealed class X501 { - - static byte[] countryName = { 0x55, 0x04, 0x06 }; - static byte[] organizationName = { 0x55, 0x04, 0x0A }; - static byte[] organizationalUnitName = { 0x55, 0x04, 0x0B }; - static byte[] commonName = { 0x55, 0x04, 0x03 }; - static byte[] localityName = { 0x55, 0x04, 0x07 }; - static byte[] stateOrProvinceName = { 0x55, 0x04, 0x08 }; - static byte[] streetAddress = { 0x55, 0x04, 0x09 }; - //static byte[] serialNumber = { 0x55, 0x04, 0x05 }; - static byte[] domainComponent = { 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19 }; - static byte[] userid = { 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x01 }; - static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 }; - static byte[] dnQualifier = { 0x55, 0x04, 0x2E }; - static byte[] title = { 0x55, 0x04, 0x0C }; - static byte[] surname = { 0x55, 0x04, 0x04 }; - static byte[] givenName = { 0x55, 0x04, 0x2A }; - static byte[] initial = { 0x55, 0x04, 0x2B }; - - private X501 () - { - } - - static public string ToString (ASN1 seq) - { - StringBuilder sb = new StringBuilder (); - for (int i = 0; i < seq.Count; i++) { - ASN1 entry = seq [i]; - AppendEntry (sb, entry, true); - - // separator (not on last iteration) - if (i < seq.Count - 1) - sb.Append (", "); - } - return sb.ToString (); - } - - static public string ToString (ASN1 seq, bool reversed, string separator, bool quotes) - { - StringBuilder sb = new StringBuilder (); - - if (reversed) { - for (int i = seq.Count - 1; i >= 0; i--) { - ASN1 entry = seq [i]; - AppendEntry (sb, entry, quotes); - - // separator (not on last iteration) - if (i > 0) - sb.Append (separator); - } - } else { - for (int i = 0; i < seq.Count; i++) { - ASN1 entry = seq [i]; - AppendEntry (sb, entry, quotes); - - // separator (not on last iteration) - if (i < seq.Count - 1) - sb.Append (separator); - } - } - return sb.ToString (); - } - - static private void AppendEntry (StringBuilder sb, ASN1 entry, bool quotes) - { - // multiple entries are valid - for (int k = 0; k < entry.Count; k++) { - ASN1 pair = entry [k]; - ASN1 s = pair [1]; - if (s == null) - continue; - - ASN1 poid = pair [0]; - if (poid == null) - continue; - - if (poid.CompareValue (countryName)) - sb.Append ("C="); - else if (poid.CompareValue (organizationName)) - sb.Append ("O="); - else if (poid.CompareValue (organizationalUnitName)) - sb.Append ("OU="); - else if (poid.CompareValue (commonName)) - sb.Append ("CN="); - else if (poid.CompareValue (localityName)) - sb.Append ("L="); - else if (poid.CompareValue (stateOrProvinceName)) - sb.Append ("S="); // NOTE: RFC2253 uses ST= - else if (poid.CompareValue (streetAddress)) - sb.Append ("STREET="); - else if (poid.CompareValue (domainComponent)) - sb.Append ("DC="); - else if (poid.CompareValue (userid)) - sb.Append ("UID="); - else if (poid.CompareValue (email)) - sb.Append ("E="); // NOTE: Not part of RFC2253 - else if (poid.CompareValue (dnQualifier)) - sb.Append ("dnQualifier="); - else if (poid.CompareValue (title)) - sb.Append ("T="); - else if (poid.CompareValue (surname)) - sb.Append ("SN="); - else if (poid.CompareValue (givenName)) - sb.Append ("G="); - else if (poid.CompareValue (initial)) - sb.Append ("I="); - else { - // unknown OID - sb.Append ("OID."); // NOTE: Not present as RFC2253 - sb.Append (ASN1Convert.ToOid (poid)); - sb.Append ("="); - } - - string sValue = null; - // 16bits or 8bits string ? TODO not complete (+special chars!) - if (s.Tag == 0x1E) { - // BMPSTRING - StringBuilder sb2 = new StringBuilder (); - for (int j = 1; j < s.Value.Length; j += 2) - sb2.Append ((char)s.Value[j]); - sValue = sb2.ToString (); - } else { - if (s.Tag == 0x14) - sValue = Encoding.UTF7.GetString (s.Value); - else - sValue = Encoding.UTF8.GetString (s.Value); - // in some cases we must quote (") the value - // Note: this doesn't seems to conform to RFC2253 - char[] specials = { ',', '+', '"', '\\', '<', '>', ';' }; - if (quotes) { - if ((sValue.IndexOfAny (specials, 0, sValue.Length) > 0) || - sValue.StartsWith (" ") || (sValue.EndsWith (" "))) - sValue = "\"" + sValue + "\""; - } - } - - sb.Append (sValue); - - // separator (not on last iteration) - if (k < entry.Count - 1) - sb.Append (", "); - } - } - - static private X520.AttributeTypeAndValue GetAttributeFromOid (string attributeType) - { - string s = attributeType.ToUpper (CultureInfo.InvariantCulture).Trim (); - switch (s) { - case "C": - return new X520.CountryName (); - case "O": - return new X520.OrganizationName (); - case "OU": - return new X520.OrganizationalUnitName (); - case "CN": - return new X520.CommonName (); - case "L": - return new X520.LocalityName (); - case "S": // Microsoft - case "ST": // RFC2253 - return new X520.StateOrProvinceName (); - case "E": // NOTE: Not part of RFC2253 - return new X520.EmailAddress (); - case "DC": // RFC2247 - return new X520.DomainComponent (); - case "UID": // RFC1274 - return new X520.UserId (); - case "DNQUALIFIER": - return new X520.DnQualifier (); - case "T": - return new X520.Title (); - case "SN": - return new X520.Surname (); - case "G": - return new X520.GivenName (); - case "I": - return new X520.Initial (); - default: - if (s.StartsWith ("OID.")) { - // MUST support it but it OID may be without it - return new X520.Oid (s.Substring (4)); - } else { - if (IsOid (s)) - return new X520.Oid (s); - else - return null; - } - } - } - - static private bool IsOid (string oid) - { - try { - ASN1 asn = ASN1Convert.FromOid (oid); - return (asn.Tag == 0x06); - } - catch { - return false; - } - } - - // no quote processing - static private X520.AttributeTypeAndValue ReadAttribute (string value, ref int pos) - { - while ((value[pos] == ' ') && (pos < value.Length)) - pos++; - - // get '=' position in substring - int equal = value.IndexOf ('=', pos); - if (equal == -1) { - string msg = ("No attribute found."); - throw new FormatException (msg); - } - - string s = value.Substring (pos, equal - pos); - X520.AttributeTypeAndValue atv = GetAttributeFromOid (s); - if (atv == null) { - string msg = ("Unknown attribute '{0}'."); - throw new FormatException (String.Format (msg, s)); - } - pos = equal + 1; // skip the '=' - return atv; - } - - static private bool IsHex (char c) - { - if (Char.IsDigit (c)) - return true; - char up = Char.ToUpper (c, CultureInfo.InvariantCulture); - return ((up >= 'A') && (up <= 'F')); - } - - static string ReadHex (string value, ref int pos) - { - StringBuilder sb = new StringBuilder (); - // it is (at least an) 8 bits char - sb.Append (value[pos++]); - sb.Append (value[pos]); - // look ahead for a 16 bits char - if ((pos < value.Length - 4) && (value[pos+1] == '\\') && IsHex (value[pos+2])) { - pos += 2; // pass last char and skip \ - sb.Append (value[pos++]); - sb.Append (value[pos]); - } - byte[] data = CryptoConvert.FromHex (sb.ToString ()); - return Encoding.UTF8.GetString (data); - } - - static private int ReadEscaped (StringBuilder sb, string value, int pos) - { - switch (value[pos]) { - case '\\': - case '"': - case '=': - case ';': - case '<': - case '>': - case '+': - case '#': - case ',': - sb.Append (value[pos]); - return pos; - default: - if (pos >= value.Length - 2) { - string msg = ("Malformed escaped value '{0}'."); - throw new FormatException (string.Format (msg, value.Substring (pos))); - } - // it's either a 8 bits or 16 bits char - sb.Append (ReadHex (value, ref pos)); - return pos; - } - } - - static private int ReadQuoted (StringBuilder sb, string value, int pos) - { - int original = pos; - while (pos <= value.Length) { - switch (value[pos]) { - case '"': - return pos; - case '\\': - return ReadEscaped (sb, value, pos); - default: - sb.Append (value[pos]); - pos++; - break; - } - } - string msg = ("Malformed quoted value '{0}'."); - throw new FormatException (string.Format (msg, value.Substring (original))); - } - - static private string ReadValue (string value, ref int pos) - { - int original = pos; - StringBuilder sb = new StringBuilder (); - while (pos < value.Length) { - switch (value [pos]) { - case '\\': - pos = ReadEscaped (sb, value, ++pos); - break; - case '"': - pos = ReadQuoted (sb, value, ++pos); - break; - case '=': - case ';': - case '<': - case '>': - string msg =("Malformed value '{0}' contains '{1}' outside quotes."); - throw new FormatException (string.Format (msg, value.Substring (original), value[pos])); - case '+': - case '#': - throw new NotImplementedException (); - case ',': - pos++; - return sb.ToString (); - default: - sb.Append (value[pos]); - break; - } - pos++; - } - return sb.ToString (); - } - - static public ASN1 FromString (string rdn) - { - if (rdn == null) - throw new ArgumentNullException ("rdn"); - - int pos = 0; - ASN1 asn1 = new ASN1 (0x30); - while (pos < rdn.Length) { - X520.AttributeTypeAndValue atv = ReadAttribute (rdn, ref pos); - atv.Value = ReadValue (rdn, ref pos); - - ASN1 sequence = new ASN1 (0x31); - sequence.Add (atv.GetASN1 ()); - asn1.Add (sequence); - } - return asn1; - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/X509Builder.cs b/Emby.Server.Implementations/Cryptography/X509Builder.cs deleted file mode 100644 index a2e292350..000000000 --- a/Emby.Server.Implementations/Cryptography/X509Builder.cs +++ /dev/null @@ -1,153 +0,0 @@ -// -// X509Builder.cs: Abstract builder class for X509 objects -// -// Author: -// Sebastien Pouliot -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// (C) 2004 Novell (http://www.novell.com) -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Globalization; -using System.Security.Cryptography; - -namespace Emby.Server.Core.Cryptography -{ - - public abstract class X509Builder { - - private const string defaultHash = "SHA1"; - private string hashName; - - protected X509Builder () - { - hashName = defaultHash; - } - - protected abstract ASN1 ToBeSigned (string hashName); - - // move to PKCS1 - protected string GetOid (string hashName) - { - switch (hashName.ToLower (CultureInfo.InvariantCulture)) { - case "md2": - // md2withRSAEncryption (1 2 840 113549 1 1 2) - return "1.2.840.113549.1.1.2"; - case "md4": - // md4withRSAEncryption (1 2 840 113549 1 1 3) - return "1.2.840.113549.1.1.3"; - case "md5": - // md5withRSAEncryption (1 2 840 113549 1 1 4) - return "1.2.840.113549.1.1.4"; - case "sha1": - // sha1withRSAEncryption (1 2 840 113549 1 1 5) - return "1.2.840.113549.1.1.5"; - case "sha256": - // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } - return "1.2.840.113549.1.1.11"; - case "sha384": - // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } - return "1.2.840.113549.1.1.12"; - case "sha512": - // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } - return "1.2.840.113549.1.1.13"; - default: - throw new NotSupportedException ("Unknown hash algorithm " + hashName); - } - } - - public string Hash { - get { return hashName; } - set { - if (hashName == null) - hashName = defaultHash; - else - hashName = value; - } - } - - public virtual byte[] Sign (AsymmetricAlgorithm aa) - { - if (aa is RSA) - return Sign (aa as RSA); - else if (aa is DSA) - return Sign (aa as DSA); - else - throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString()); - } - - private byte[] Build (ASN1 tbs, string hashoid, byte[] signature) - { - ASN1 builder = new ASN1 (0x30); - builder.Add (tbs); - builder.Add (PKCS7.AlgorithmIdentifier (hashoid)); - // first byte of BITSTRING is the number of unused bits in the first byte - byte[] bitstring = new byte [signature.Length + 1]; - Buffer.BlockCopy (signature, 0, bitstring, 1, signature.Length); - builder.Add (new ASN1 (0x03, bitstring)); - return builder.GetBytes (); - } - - public virtual byte[] Sign (RSA key) - { - string oid = GetOid (hashName); - ASN1 tbs = ToBeSigned (oid); - HashAlgorithm ha = HashAlgorithm.Create (hashName); - byte[] hash = ha.ComputeHash (tbs.GetBytes ()); - - RSAPKCS1SignatureFormatter pkcs1 = new RSAPKCS1SignatureFormatter (key); - pkcs1.SetHashAlgorithm (hashName); - byte[] signature = pkcs1.CreateSignature (hash); - - return Build (tbs, oid, signature); - } - - public virtual byte[] Sign (DSA key) - { - string oid = "1.2.840.10040.4.3"; - ASN1 tbs = ToBeSigned (oid); - HashAlgorithm ha = HashAlgorithm.Create (hashName); - if (!(ha is SHA1)) - throw new NotSupportedException ("Only SHA-1 is supported for DSA"); - byte[] hash = ha.ComputeHash (tbs.GetBytes ()); - - DSASignatureFormatter dsa = new DSASignatureFormatter (key); - dsa.SetHashAlgorithm (hashName); - byte[] rs = dsa.CreateSignature (hash); - - // split R and S - byte[] r = new byte [20]; - Buffer.BlockCopy (rs, 0, r, 0, 20); - byte[] s = new byte [20]; - Buffer.BlockCopy (rs, 20, s, 0, 20); - ASN1 signature = new ASN1 (0x30); - signature.Add (new ASN1 (0x02, r)); - signature.Add (new ASN1 (0x02, s)); - - // dsaWithSha1 (1 2 840 10040 4 3) - return Build (tbs, oid, signature.GetBytes ()); - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/X509Certificate.cs b/Emby.Server.Implementations/Cryptography/X509Certificate.cs deleted file mode 100644 index 3de58cfee..000000000 --- a/Emby.Server.Implementations/Cryptography/X509Certificate.cs +++ /dev/null @@ -1,563 +0,0 @@ -// -// X509Certificates.cs: Handles X.509 certificates. -// -// Author: -// Sebastien Pouliot -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com) -// Copyright 2013 Xamarin Inc. (http://www.xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Runtime.Serialization; -using System.Security.Cryptography; -using System.Security.Permissions; -using System.Text; - -namespace Emby.Server.Core.Cryptography -{ - - // References: - // a. Internet X.509 Public Key Infrastructure Certificate and CRL Profile - // http://www.ietf.org/rfc/rfc3280.txt - // b. ITU ASN.1 standards (free download) - // http://www.itu.int/ITU-T/studygroups/com17/languages/ - - public class X509Certificate : ISerializable - { - - private ASN1 decoder; - - private byte[] m_encodedcert; - private DateTime m_from; - private DateTime m_until; - private ASN1 issuer; - private string m_issuername; - private string m_keyalgo; - private byte[] m_keyalgoparams; - private ASN1 subject; - private string m_subject; - private byte[] m_publickey; - private byte[] signature; - private string m_signaturealgo; - private byte[] m_signaturealgoparams; - private byte[] certhash; - private RSA _rsa; - private DSA _dsa; - - // from http://msdn.microsoft.com/en-gb/library/ff635835.aspx - private const string OID_DSA = "1.2.840.10040.4.1"; - private const string OID_RSA = "1.2.840.113549.1.1.1"; - - // from http://www.ietf.org/rfc/rfc2459.txt - // - //Certificate ::= SEQUENCE { - // tbsCertificate TBSCertificate, - // signatureAlgorithm AlgorithmIdentifier, - // signature BIT STRING } - // - //TBSCertificate ::= SEQUENCE { - // version [0] Version DEFAULT v1, - // serialNumber CertificateSerialNumber, - // signature AlgorithmIdentifier, - // issuer Name, - // validity Validity, - // subject Name, - // subjectPublicKeyInfo SubjectPublicKeyInfo, - // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, - // -- If present, version shall be v2 or v3 - // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, - // -- If present, version shall be v2 or v3 - // extensions [3] Extensions OPTIONAL - // -- If present, version shall be v3 -- } - private int version; - private byte[] serialnumber; - - private byte[] issuerUniqueID; - private byte[] subjectUniqueID; - private X509ExtensionCollection extensions; - - private static string encoding_error = ("Input data cannot be coded as a valid certificate."); - - - // that's were the real job is! - private void Parse (byte[] data) - { - try { - decoder = new ASN1 (data); - // Certificate - if (decoder.Tag != 0x30) - throw new CryptographicException (encoding_error); - // Certificate / TBSCertificate - if (decoder [0].Tag != 0x30) - throw new CryptographicException (encoding_error); - - ASN1 tbsCertificate = decoder [0]; - - int tbs = 0; - // Certificate / TBSCertificate / Version - ASN1 v = decoder [0][tbs]; - version = 1; // DEFAULT v1 - if ((v.Tag == 0xA0) && (v.Count > 0)) { - // version (optional) is present only in v2+ certs - version += v [0].Value [0]; // zero based - tbs++; - } - - // Certificate / TBSCertificate / CertificateSerialNumber - ASN1 sn = decoder [0][tbs++]; - if (sn.Tag != 0x02) - throw new CryptographicException (encoding_error); - serialnumber = sn.Value; - Array.Reverse (serialnumber, 0, serialnumber.Length); - - // Certificate / TBSCertificate / AlgorithmIdentifier - tbs++; - // ASN1 signatureAlgo = tbsCertificate.Element (tbs++, 0x30); - - issuer = tbsCertificate.Element (tbs++, 0x30); - m_issuername = X501.ToString (issuer); - - ASN1 validity = tbsCertificate.Element (tbs++, 0x30); - ASN1 notBefore = validity [0]; - m_from = ASN1Convert.ToDateTime (notBefore); - ASN1 notAfter = validity [1]; - m_until = ASN1Convert.ToDateTime (notAfter); - - subject = tbsCertificate.Element (tbs++, 0x30); - m_subject = X501.ToString (subject); - - ASN1 subjectPublicKeyInfo = tbsCertificate.Element (tbs++, 0x30); - - ASN1 algorithm = subjectPublicKeyInfo.Element (0, 0x30); - ASN1 algo = algorithm.Element (0, 0x06); - m_keyalgo = ASN1Convert.ToOid (algo); - // parameters ANY DEFINED BY algorithm OPTIONAL - // so we dont ask for a specific (Element) type and return DER - ASN1 parameters = algorithm [1]; - m_keyalgoparams = ((algorithm.Count > 1) ? parameters.GetBytes () : null); - - ASN1 subjectPublicKey = subjectPublicKeyInfo.Element (1, 0x03); - // we must drop th first byte (which is the number of unused bits - // in the BITSTRING) - int n = subjectPublicKey.Length - 1; - m_publickey = new byte [n]; - Buffer.BlockCopy (subjectPublicKey.Value, 1, m_publickey, 0, n); - - // signature processing - byte[] bitstring = decoder [2].Value; - // first byte contains unused bits in first byte - signature = new byte [bitstring.Length - 1]; - Buffer.BlockCopy (bitstring, 1, signature, 0, signature.Length); - - algorithm = decoder [1]; - algo = algorithm.Element (0, 0x06); - m_signaturealgo = ASN1Convert.ToOid (algo); - parameters = algorithm [1]; - if (parameters != null) - m_signaturealgoparams = parameters.GetBytes (); - else - m_signaturealgoparams = null; - - // Certificate / TBSCertificate / issuerUniqueID - ASN1 issuerUID = tbsCertificate.Element (tbs, 0x81); - if (issuerUID != null) { - tbs++; - issuerUniqueID = issuerUID.Value; - } - - // Certificate / TBSCertificate / subjectUniqueID - ASN1 subjectUID = tbsCertificate.Element (tbs, 0x82); - if (subjectUID != null) { - tbs++; - subjectUniqueID = subjectUID.Value; - } - - // Certificate / TBSCertificate / Extensions - ASN1 extns = tbsCertificate.Element (tbs, 0xA3); - if ((extns != null) && (extns.Count == 1)) - extensions = new X509ExtensionCollection (extns [0]); - else - extensions = new X509ExtensionCollection (null); - - // keep a copy of the original data - m_encodedcert = (byte[]) data.Clone (); - } - catch (Exception ex) { - throw new CryptographicException (encoding_error, ex); - } - } - - // constructors - - public X509Certificate (byte[] data) - { - if (data != null) { - // does it looks like PEM ? - if ((data.Length > 0) && (data [0] != 0x30)) { - try { - data = PEM ("CERTIFICATE", data); - } - catch (Exception ex) { - throw new CryptographicException (encoding_error, ex); - } - } - Parse (data); - } - } - - private byte[] GetUnsignedBigInteger (byte[] integer) - { - if (integer [0] == 0x00) { - // this first byte is added so we're sure it's an unsigned integer - // however we can't feed it into RSAParameters or DSAParameters - int length = integer.Length - 1; - byte[] uinteger = new byte [length]; - Buffer.BlockCopy (integer, 1, uinteger, 0, length); - return uinteger; - } - else - return integer; - } - - // public methods - - public DSA DSA { - get { - if (m_keyalgoparams == null) - throw new CryptographicException ("Missing key algorithm parameters."); - - if (_dsa == null && m_keyalgo == OID_DSA) { - DSAParameters dsaParams = new DSAParameters (); - // for DSA m_publickey contains 1 ASN.1 integer - Y - ASN1 pubkey = new ASN1 (m_publickey); - if ((pubkey == null) || (pubkey.Tag != 0x02)) - return null; - dsaParams.Y = GetUnsignedBigInteger (pubkey.Value); - - ASN1 param = new ASN1 (m_keyalgoparams); - if ((param == null) || (param.Tag != 0x30) || (param.Count < 3)) - return null; - if ((param [0].Tag != 0x02) || (param [1].Tag != 0x02) || (param [2].Tag != 0x02)) - return null; - dsaParams.P = GetUnsignedBigInteger (param [0].Value); - dsaParams.Q = GetUnsignedBigInteger (param [1].Value); - dsaParams.G = GetUnsignedBigInteger (param [2].Value); - - // BUG: MS BCL 1.0 can't import a key which - // isn't the same size as the one present in - // the container. - _dsa = (DSA) new DSACryptoServiceProvider (dsaParams.Y.Length << 3); - _dsa.ImportParameters (dsaParams); - } - return _dsa; - } - - set { - _dsa = value; - if (value != null) - _rsa = null; - } - } - - public X509ExtensionCollection Extensions { - get { return extensions; } - } - - public byte[] Hash { - get { - if (certhash == null) { - if ((decoder == null) || (decoder.Count < 1)) - return null; - string algo = PKCS1.HashNameFromOid (m_signaturealgo, false); - if (algo == null) - return null; - byte[] toBeSigned = decoder [0].GetBytes (); - using (var hash = PKCS1.CreateFromName (algo)) - certhash = hash.ComputeHash (toBeSigned, 0, toBeSigned.Length); - } - return (byte[]) certhash.Clone (); - } - } - - public virtual string IssuerName { - get { return m_issuername; } - } - - public virtual string KeyAlgorithm { - get { return m_keyalgo; } - } - - public virtual byte[] KeyAlgorithmParameters { - get { - if (m_keyalgoparams == null) - return null; - return (byte[]) m_keyalgoparams.Clone (); - } - set { m_keyalgoparams = value; } - } - - public virtual byte[] PublicKey { - get { - if (m_publickey == null) - return null; - return (byte[]) m_publickey.Clone (); - } - } - - public virtual RSA RSA { - get { - if (_rsa == null && m_keyalgo == OID_RSA) { - RSAParameters rsaParams = new RSAParameters (); - // for RSA m_publickey contains 2 ASN.1 integers - // the modulus and the public exponent - ASN1 pubkey = new ASN1 (m_publickey); - ASN1 modulus = pubkey [0]; - if ((modulus == null) || (modulus.Tag != 0x02)) - return null; - ASN1 exponent = pubkey [1]; - if (exponent.Tag != 0x02) - return null; - - rsaParams.Modulus = GetUnsignedBigInteger (modulus.Value); - rsaParams.Exponent = exponent.Value; - - // BUG: MS BCL 1.0 can't import a key which - // isn't the same size as the one present in - // the container. - int keySize = (rsaParams.Modulus.Length << 3); - _rsa = (RSA) new RSACryptoServiceProvider (keySize); - _rsa.ImportParameters (rsaParams); - } - return _rsa; - } - - set { - if (value != null) - _dsa = null; - _rsa = value; - } - } - - public virtual byte[] RawData { - get { - if (m_encodedcert == null) - return null; - return (byte[]) m_encodedcert.Clone (); - } - } - - public virtual byte[] SerialNumber { - get { - if (serialnumber == null) - return null; - return (byte[]) serialnumber.Clone (); - } - } - - public virtual byte[] Signature { - get { - if (signature == null) - return null; - - switch (m_signaturealgo) { - case "1.2.840.113549.1.1.2": // MD2 with RSA encryption - case "1.2.840.113549.1.1.3": // MD4 with RSA encryption - case "1.2.840.113549.1.1.4": // MD5 with RSA encryption - case "1.2.840.113549.1.1.5": // SHA-1 with RSA Encryption - case "1.3.14.3.2.29": // SHA1 with RSA signature - case "1.2.840.113549.1.1.11": // SHA-256 with RSA Encryption - case "1.2.840.113549.1.1.12": // SHA-384 with RSA Encryption - case "1.2.840.113549.1.1.13": // SHA-512 with RSA Encryption - case "1.3.36.3.3.1.2": // RIPEMD160 with RSA Encryption - return (byte[]) signature.Clone (); - - case "1.2.840.10040.4.3": // SHA-1 with DSA - ASN1 sign = new ASN1 (signature); - if ((sign == null) || (sign.Count != 2)) - return null; - byte[] part1 = sign [0].Value; - byte[] part2 = sign [1].Value; - byte[] sig = new byte [40]; - // parts may be less than 20 bytes (i.e. first bytes were 0x00) - // parts may be more than 20 bytes (i.e. first byte > 0x80, negative) - int s1 = System.Math.Max (0, part1.Length - 20); - int e1 = System.Math.Max (0, 20 - part1.Length); - Buffer.BlockCopy (part1, s1, sig, e1, part1.Length - s1); - int s2 = System.Math.Max (0, part2.Length - 20); - int e2 = System.Math.Max (20, 40 - part2.Length); - Buffer.BlockCopy (part2, s2, sig, e2, part2.Length - s2); - return sig; - - default: - throw new CryptographicException ("Unsupported hash algorithm: " + m_signaturealgo); - } - } - } - - public virtual string SignatureAlgorithm { - get { return m_signaturealgo; } - } - - public virtual byte[] SignatureAlgorithmParameters { - get { - if (m_signaturealgoparams == null) - return m_signaturealgoparams; - return (byte[]) m_signaturealgoparams.Clone (); - } - } - - public virtual string SubjectName { - get { return m_subject; } - } - - public virtual DateTime ValidFrom { - get { return m_from; } - } - - public virtual DateTime ValidUntil { - get { return m_until; } - } - - public int Version { - get { return version; } - } - - public bool IsCurrent { - get { return WasCurrent (DateTime.UtcNow); } - } - - public bool WasCurrent (DateTime instant) - { - return ((instant > ValidFrom) && (instant <= ValidUntil)); - } - - // uncommon v2 "extension" - public byte[] IssuerUniqueIdentifier { - get { - if (issuerUniqueID == null) - return null; - return (byte[]) issuerUniqueID.Clone (); - } - } - - // uncommon v2 "extension" - public byte[] SubjectUniqueIdentifier { - get { - if (subjectUniqueID == null) - return null; - return (byte[]) subjectUniqueID.Clone (); - } - } - - internal bool VerifySignature (DSA dsa) - { - // signatureOID is check by both this.Hash and this.Signature - DSASignatureDeformatter v = new DSASignatureDeformatter (dsa); - // only SHA-1 is supported - v.SetHashAlgorithm ("SHA1"); - return v.VerifySignature (this.Hash, this.Signature); - } - - internal bool VerifySignature (RSA rsa) - { - // SHA1-1 with DSA - if (m_signaturealgo == "1.2.840.10040.4.3") - return false; - RSAPKCS1SignatureDeformatter v = new RSAPKCS1SignatureDeformatter (rsa); - v.SetHashAlgorithm (PKCS1.HashNameFromOid (m_signaturealgo)); - return v.VerifySignature (this.Hash, this.Signature); - } - - public bool VerifySignature (AsymmetricAlgorithm aa) - { - if (aa == null) - throw new ArgumentNullException ("aa"); - - if (aa is RSA) - return VerifySignature (aa as RSA); - else if (aa is DSA) - return VerifySignature (aa as DSA); - else - throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString ()); - } - - public bool CheckSignature (byte[] hash, string hashAlgorithm, byte[] signature) - { - RSACryptoServiceProvider r = (RSACryptoServiceProvider) RSA; - return r.VerifyHash (hash, hashAlgorithm, signature); - } - - public bool IsSelfSigned { - get { - if (m_issuername != m_subject) - return false; - - try { - if (RSA != null) - return VerifySignature (RSA); - else if (DSA != null) - return VerifySignature (DSA); - else - return false; // e.g. a certificate with only DSA parameters - } - catch (CryptographicException) { - return false; - } - } - } - - public ASN1 GetIssuerName () - { - return issuer; - } - - public ASN1 GetSubjectName () - { - return subject; - } - - protected X509Certificate (SerializationInfo info, StreamingContext context) - { - Parse ((byte[]) info.GetValue ("raw", typeof (byte[]))); - } - - [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)] - public virtual void GetObjectData (SerializationInfo info, StreamingContext context) - { - info.AddValue ("raw", m_encodedcert); - // note: we NEVER serialize the private key - } - - static byte[] PEM (string type, byte[] data) - { - string pem = Encoding.ASCII.GetString (data); - string header = String.Format ("-----BEGIN {0}-----", type); - string footer = String.Format ("-----END {0}-----", type); - int start = pem.IndexOf (header) + header.Length; - int end = pem.IndexOf (footer, start); - string base64 = pem.Substring (start, (end - start)); - return Convert.FromBase64String (base64); - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs b/Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs deleted file mode 100644 index cecff6578..000000000 --- a/Emby.Server.Implementations/Cryptography/X509CertificateBuilder.cs +++ /dev/null @@ -1,245 +0,0 @@ -// -// X509CertificateBuilder.cs: Handles building of X.509 certificates. -// -// Author: -// Sebastien Pouliot -// -// (C) 2003 Motus Technologies Inc. (http://www.motus.com) -// (C) 2004 Novell (http://www.novell.com) -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Security.Cryptography; - -namespace Emby.Server.Core.Cryptography -{ - // From RFC3280 - /* - * Certificate ::= SEQUENCE { - * tbsCertificate TBSCertificate, - * signatureAlgorithm AlgorithmIdentifier, - * signature BIT STRING - * } - * TBSCertificate ::= SEQUENCE { - * version [0] Version DEFAULT v1, - * serialNumber CertificateSerialNumber, - * signature AlgorithmIdentifier, - * issuer Name, - * validity Validity, - * subject Name, - * subjectPublicKeyInfo SubjectPublicKeyInfo, - * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, - * -- If present, version MUST be v2 or v3 - * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, - * -- If present, version MUST be v2 or v3 - * extensions [3] Extensions OPTIONAL - * -- If present, version MUST be v3 -- - * } - * Version ::= INTEGER { v1(0), v2(1), v3(2) } - * CertificateSerialNumber ::= INTEGER - * Validity ::= SEQUENCE { - * notBefore Time, - * notAfter Time - * } - * Time ::= CHOICE { - * utcTime UTCTime, - * generalTime GeneralizedTime - * } - */ - public class X509CertificateBuilder : X509Builder { - - private byte version; - private byte[] sn; - private string issuer; - private DateTime notBefore; - private DateTime notAfter; - private string subject; - private AsymmetricAlgorithm aa; - private byte[] issuerUniqueID; - private byte[] subjectUniqueID; - private X509ExtensionCollection extensions; - - public X509CertificateBuilder () : this (3) {} - - public X509CertificateBuilder (byte version) - { - if (version > 3) - throw new ArgumentException ("Invalid certificate version"); - this.version = version; - extensions = new X509ExtensionCollection (); - } - - public byte Version { - get { return version; } - set { version = value; } - } - - public byte[] SerialNumber { - get { return sn; } - set { sn = value; } - } - - public string IssuerName { - get { return issuer; } - set { issuer = value; } - } - - public DateTime NotBefore { - get { return notBefore; } - set { notBefore = value; } - } - - public DateTime NotAfter { - get { return notAfter; } - set { notAfter = value; } - } - - public string SubjectName { - get { return subject; } - set { subject = value; } - } - - public AsymmetricAlgorithm SubjectPublicKey { - get { return aa; } - set { aa = value; } - } - - public byte[] IssuerUniqueId { - get { return issuerUniqueID; } - set { issuerUniqueID = value; } - } - - public byte[] SubjectUniqueId { - get { return subjectUniqueID; } - set { subjectUniqueID = value; } - } - - public X509ExtensionCollection Extensions { - get { return extensions; } - } - - - /* SubjectPublicKeyInfo ::= SEQUENCE { - * algorithm AlgorithmIdentifier, - * subjectPublicKey BIT STRING } - */ - private ASN1 SubjectPublicKeyInfo () - { - ASN1 keyInfo = new ASN1 (0x30); - if (aa is RSA) { - keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.113549.1.1.1")); - RSAParameters p = (aa as RSA).ExportParameters (false); - /* RSAPublicKey ::= SEQUENCE { - * modulus INTEGER, -- n - * publicExponent INTEGER } -- e - */ - ASN1 key = new ASN1 (0x30); - key.Add (ASN1Convert.FromUnsignedBigInteger (p.Modulus)); - key.Add (ASN1Convert.FromUnsignedBigInteger (p.Exponent)); - keyInfo.Add (new ASN1 (UniqueIdentifier (key.GetBytes ()))); - } - else if (aa is DSA) { - DSAParameters p = (aa as DSA).ExportParameters (false); - /* Dss-Parms ::= SEQUENCE { - * p INTEGER, - * q INTEGER, - * g INTEGER } - */ - ASN1 param = new ASN1 (0x30); - param.Add (ASN1Convert.FromUnsignedBigInteger (p.P)); - param.Add (ASN1Convert.FromUnsignedBigInteger (p.Q)); - param.Add (ASN1Convert.FromUnsignedBigInteger (p.G)); - keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.10040.4.1", param)); - ASN1 key = keyInfo.Add (new ASN1 (0x03)); - // DSAPublicKey ::= INTEGER -- public key, y - key.Add (ASN1Convert.FromUnsignedBigInteger (p.Y)); - } - else - throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString ()); - return keyInfo; - } - - private byte[] UniqueIdentifier (byte[] id) - { - // UniqueIdentifier ::= BIT STRING - ASN1 uid = new ASN1 (0x03); - // first byte in a BITSTRING is the number of unused bits in the first byte - byte[] v = new byte [id.Length + 1]; - Buffer.BlockCopy (id, 0, v, 1, id.Length); - uid.Value = v; - return uid.GetBytes (); - } - - protected override ASN1 ToBeSigned (string oid) - { - // TBSCertificate - ASN1 tbsCert = new ASN1 (0x30); - - if (version > 1) { - // TBSCertificate / [0] Version DEFAULT v1, - byte[] ver = { (byte)(version - 1) }; - ASN1 v = tbsCert.Add (new ASN1 (0xA0)); - v.Add (new ASN1 (0x02, ver)); - } - - // TBSCertificate / CertificateSerialNumber, - tbsCert.Add (new ASN1 (0x02, sn)); - - // TBSCertificate / AlgorithmIdentifier, - tbsCert.Add (PKCS7.AlgorithmIdentifier (oid)); - - // TBSCertificate / Name - tbsCert.Add (X501.FromString (issuer)); - - // TBSCertificate / Validity - ASN1 validity = tbsCert.Add (new ASN1 (0x30)); - // TBSCertificate / Validity / Time - validity.Add (ASN1Convert.FromDateTime (notBefore)); - // TBSCertificate / Validity / Time - validity.Add (ASN1Convert.FromDateTime (notAfter)); - - // TBSCertificate / Name - tbsCert.Add (X501.FromString (subject)); - - // TBSCertificate / SubjectPublicKeyInfo - tbsCert.Add (SubjectPublicKeyInfo ()); - - if (version > 1) { - // TBSCertificate / [1] IMPLICIT UniqueIdentifier OPTIONAL - if (issuerUniqueID != null) - tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (issuerUniqueID))); - - // TBSCertificate / [2] IMPLICIT UniqueIdentifier OPTIONAL - if (subjectUniqueID != null) - tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (subjectUniqueID))); - - // TBSCertificate / [3] Extensions OPTIONAL - if ((version > 2) && (extensions.Count > 0)) - tbsCert.Add (new ASN1 (0xA3, extensions.GetBytes ())); - } - - return tbsCert; - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs b/Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs deleted file mode 100644 index a129bfc1a..000000000 --- a/Emby.Server.Implementations/Cryptography/X509CertificateCollection.cs +++ /dev/null @@ -1,201 +0,0 @@ -// -// Based on System.Security.Cryptography.X509Certificates.X509CertificateCollection -// in System assembly -// -// Authors: -// Lawrence Pit (loz@cable.a2000.nl) -// Sebastien Pouliot -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Collections; - -namespace Emby.Server.Core.Cryptography -{ - - [Serializable] - public class X509CertificateCollection : CollectionBase, IEnumerable { - - public X509CertificateCollection () - { - } - - public X509CertificateCollection (X509Certificate [] value) - { - AddRange (value); - } - - public X509CertificateCollection (X509CertificateCollection value) - { - AddRange (value); - } - - // Properties - - public X509Certificate this [int index] { - get { return (X509Certificate) InnerList [index]; } - set { InnerList [index] = value; } - } - - // Methods - - public int Add (X509Certificate value) - { - if (value == null) - throw new ArgumentNullException ("value"); - - return InnerList.Add (value); - } - - public void AddRange (X509Certificate [] value) - { - if (value == null) - throw new ArgumentNullException ("value"); - - for (int i = 0; i < value.Length; i++) - InnerList.Add (value [i]); - } - - public void AddRange (X509CertificateCollection value) - { - if (value == null) - throw new ArgumentNullException ("value"); - - for (int i = 0; i < value.InnerList.Count; i++) - InnerList.Add (value [i]); - } - - public bool Contains (X509Certificate value) - { - return (IndexOf (value) != -1); - } - - public void CopyTo (X509Certificate[] array, int index) - { - InnerList.CopyTo (array, index); - } - - public new X509CertificateEnumerator GetEnumerator () - { - return new X509CertificateEnumerator (this); - } - - IEnumerator IEnumerable.GetEnumerator () - { - return InnerList.GetEnumerator (); - } - - public override int GetHashCode () - { - return InnerList.GetHashCode (); - } - - public int IndexOf (X509Certificate value) - { - if (value == null) - throw new ArgumentNullException ("value"); - - byte[] hash = value.Hash; - for (int i=0; i < InnerList.Count; i++) { - X509Certificate x509 = (X509Certificate) InnerList [i]; - if (Compare (x509.Hash, hash)) - return i; - } - return -1; - } - - public void Insert (int index, X509Certificate value) - { - InnerList.Insert (index, value); - } - - public void Remove (X509Certificate value) - { - InnerList.Remove (value); - } - - // private stuff - - private bool Compare (byte[] array1, byte[] array2) - { - if ((array1 == null) && (array2 == null)) - return true; - if ((array1 == null) || (array2 == null)) - return false; - if (array1.Length != array2.Length) - return false; - for (int i=0; i < array1.Length; i++) { - if (array1 [i] != array2 [i]) - return false; - } - return true; - } - - // Inner Class - - public class X509CertificateEnumerator : IEnumerator { - - private IEnumerator enumerator; - - // Constructors - - public X509CertificateEnumerator (X509CertificateCollection mappings) - { - enumerator = ((IEnumerable) mappings).GetEnumerator (); - } - - // Properties - - public X509Certificate Current { - get { return (X509Certificate) enumerator.Current; } - } - - object IEnumerator.Current { - get { return enumerator.Current; } - } - - // Methods - - bool IEnumerator.MoveNext () - { - return enumerator.MoveNext (); - } - - void IEnumerator.Reset () - { - enumerator.Reset (); - } - - public bool MoveNext () - { - return enumerator.MoveNext (); - } - - public void Reset () - { - enumerator.Reset (); - } - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/X509Extension.cs b/Emby.Server.Implementations/Cryptography/X509Extension.cs deleted file mode 100644 index 36b17deba..000000000 --- a/Emby.Server.Implementations/Cryptography/X509Extension.cs +++ /dev/null @@ -1,208 +0,0 @@ -// -// X509Extension.cs: Base class for all X.509 extensions. -// -// Author: -// Sebastien Pouliot -// -// (C) 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Globalization; -using System.Text; - -namespace Emby.Server.Core.Cryptography -{ - /* - * Extension ::= SEQUENCE { - * extnID OBJECT IDENTIFIER, - * critical BOOLEAN DEFAULT FALSE, - * extnValue OCTET STRING - * } - */ - public class X509Extension { - - protected string extnOid; - protected bool extnCritical; - protected ASN1 extnValue; - - protected X509Extension () - { - extnCritical = false; - } - - public X509Extension (ASN1 asn1) - { - if ((asn1.Tag != 0x30) || (asn1.Count < 2)) - throw new ArgumentException (("Invalid X.509 extension.")); - if (asn1[0].Tag != 0x06) - throw new ArgumentException (("Invalid X.509 extension.")); - - extnOid = ASN1Convert.ToOid (asn1[0]); - extnCritical = ((asn1[1].Tag == 0x01) && (asn1[1].Value[0] == 0xFF)); - // last element is an octet string which may need to be decoded - extnValue = asn1 [asn1.Count - 1]; - if ((extnValue.Tag == 0x04) && (extnValue.Length > 0) && (extnValue.Count == 0)) { - try { - ASN1 encapsulated = new ASN1 (extnValue.Value); - extnValue.Value = null; - extnValue.Add (encapsulated); - } - catch { - // data isn't ASN.1 - } - } - Decode (); - } - - public X509Extension (X509Extension extension) - { - if (extension == null) - throw new ArgumentNullException ("extension"); - if ((extension.Value == null) || (extension.Value.Tag != 0x04) || (extension.Value.Count != 1)) - throw new ArgumentException (("Invalid X.509 extension.")); - - extnOid = extension.Oid; - extnCritical = extension.Critical; - extnValue = extension.Value; - Decode (); - } - - // encode the extension *into* an OCTET STRING - protected virtual void Decode () - { - } - - // decode the extension from *inside* an OCTET STRING - protected virtual void Encode () - { - } - - public ASN1 ASN1 { - get { - ASN1 extension = new ASN1 (0x30); - extension.Add (ASN1Convert.FromOid (extnOid)); - if (extnCritical) - extension.Add (new ASN1 (0x01, new byte [1] { 0xFF })); - Encode (); - extension.Add (extnValue); - return extension; - } - } - - public string Oid { - get { return extnOid; } - } - - public bool Critical { - get { return extnCritical; } - set { extnCritical = value; } - } - - // this gets overrided with more meaningful names - public virtual string Name { - get { return extnOid; } - } - - public ASN1 Value { - get { - if (extnValue == null) { - Encode (); - } - return extnValue; - } - } - - public override bool Equals (object obj) - { - if (obj == null) - return false; - - X509Extension ex = (obj as X509Extension); - if (ex == null) - return false; - - if (extnCritical != ex.extnCritical) - return false; - if (extnOid != ex.extnOid) - return false; - if (extnValue.Length != ex.extnValue.Length) - return false; - - for (int i=0; i < extnValue.Length; i++) { - if (extnValue [i] != ex.extnValue [i]) - return false; - } - return true; - } - - public byte[] GetBytes () - { - return ASN1.GetBytes (); - } - - public override int GetHashCode () - { - // OID should be unique in a collection of extensions - return extnOid.GetHashCode (); - } - - private void WriteLine (StringBuilder sb, int n, int pos) - { - byte[] value = extnValue.Value; - int p = pos; - for (int j=0; j < 8; j++) { - if (j < n) { - sb.Append (value [p++].ToString ("X2", CultureInfo.InvariantCulture)); - sb.Append (" "); - } - else - sb.Append (" "); - } - sb.Append (" "); - p = pos; - for (int j=0; j < n; j++) { - byte b = value [p++]; - if (b < 0x20) - sb.Append ("."); - else - sb.Append (Convert.ToChar (b)); - } - sb.Append (Environment.NewLine); - } - - public override string ToString () - { - StringBuilder sb = new StringBuilder (); - int div = (extnValue.Length >> 3); - int rem = (extnValue.Length - (div << 3)); - int x = 0; - for (int i=0; i < div; i++) { - WriteLine (sb, 8, x); - x += 8; - } - WriteLine (sb, rem, x); - return sb.ToString (); - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/X509Extensions.cs b/Emby.Server.Implementations/Cryptography/X509Extensions.cs deleted file mode 100644 index 018a04d79..000000000 --- a/Emby.Server.Implementations/Cryptography/X509Extensions.cs +++ /dev/null @@ -1,195 +0,0 @@ -// -// X509Extensions.cs: Handles X.509 extensions. -// -// Author: -// Sebastien Pouliot -// -// (C) 2003 Motus Technologies Inc. (http://www.motus.com) -// (C) 2004 Novell (http://www.novell.com) -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Collections; - -namespace Emby.Server.Core.Cryptography -{ - /* - * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension - * - * Note: 1..MAX -> There shouldn't be 0 Extensions in the ASN1 structure - */ - public sealed class X509ExtensionCollection : CollectionBase, IEnumerable { - - private bool readOnly; - - public X509ExtensionCollection () : base () - { - } - - public X509ExtensionCollection (ASN1 asn1) : this () - { - readOnly = true; - if (asn1 == null) - return; - if (asn1.Tag != 0x30) - throw new Exception ("Invalid extensions format"); - for (int i=0; i < asn1.Count; i++) { - X509Extension extension = new X509Extension (asn1 [i]); - InnerList.Add (extension); - } - } - - public int Add (X509Extension extension) - { - if (extension == null) - throw new ArgumentNullException ("extension"); - if (readOnly) - throw new NotSupportedException ("Extensions are read only"); - - return InnerList.Add (extension); - } - - public void AddRange (X509Extension[] extension) - { - if (extension == null) - throw new ArgumentNullException ("extension"); - if (readOnly) - throw new NotSupportedException ("Extensions are read only"); - - for (int i = 0; i < extension.Length; i++) - InnerList.Add (extension [i]); - } - - public void AddRange (X509ExtensionCollection collection) - { - if (collection == null) - throw new ArgumentNullException ("collection"); - if (readOnly) - throw new NotSupportedException ("Extensions are read only"); - - for (int i = 0; i < collection.InnerList.Count; i++) - InnerList.Add (collection [i]); - } - - public bool Contains (X509Extension extension) - { - return (IndexOf (extension) != -1); - } - - public bool Contains (string oid) - { - return (IndexOf (oid) != -1); - } - - public void CopyTo (X509Extension[] extensions, int index) - { - if (extensions == null) - throw new ArgumentNullException ("extensions"); - - InnerList.CopyTo (extensions, index); - } - - public int IndexOf (X509Extension extension) - { - if (extension == null) - throw new ArgumentNullException ("extension"); - - for (int i=0; i < InnerList.Count; i++) { - X509Extension ex = (X509Extension) InnerList [i]; - if (ex.Equals (extension)) - return i; - } - return -1; - } - - public int IndexOf (string oid) - { - if (oid == null) - throw new ArgumentNullException ("oid"); - - for (int i=0; i < InnerList.Count; i++) { - X509Extension ex = (X509Extension) InnerList [i]; - if (ex.Oid == oid) - return i; - } - return -1; - } - - public void Insert (int index, X509Extension extension) - { - if (extension == null) - throw new ArgumentNullException ("extension"); - - InnerList.Insert (index, extension); - } - - public void Remove (X509Extension extension) - { - if (extension == null) - throw new ArgumentNullException ("extension"); - - InnerList.Remove (extension); - } - - public void Remove (string oid) - { - if (oid == null) - throw new ArgumentNullException ("oid"); - - int index = IndexOf (oid); - if (index != -1) - InnerList.RemoveAt (index); - } - - IEnumerator IEnumerable.GetEnumerator () - { - return InnerList.GetEnumerator (); - } - - public X509Extension this [int index] { - get { return (X509Extension) InnerList [index]; } - } - - public X509Extension this [string oid] { - get { - int index = IndexOf (oid); - if (index == -1) - return null; - return (X509Extension) InnerList [index]; - } - } - - public byte[] GetBytes () - { - if (InnerList.Count < 1) - return null; - ASN1 sequence = new ASN1 (0x30); - for (int i=0; i < InnerList.Count; i++) { - X509Extension x = (X509Extension) InnerList [i]; - sequence.Add (x.ASN1); - } - return sequence.GetBytes (); - } - } -} diff --git a/Emby.Server.Implementations/Cryptography/X520Attributes.cs b/Emby.Server.Implementations/Cryptography/X520Attributes.cs deleted file mode 100644 index da7fd2b82..000000000 --- a/Emby.Server.Implementations/Cryptography/X520Attributes.cs +++ /dev/null @@ -1,346 +0,0 @@ -// -// X520.cs: X.520 related stuff (attributes, RDN) -// -// Author: -// Sebastien Pouliot -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Text; - -namespace Emby.Server.Core.Cryptography -{ - - // References: - // 1. Information technology - Open Systems Interconnection - The Directory: Selected attribute types - // http://www.itu.int/rec/recommendation.asp?type=folders&lang=e&parent=T-REC-X.520 - // 2. Internet X.509 Public Key Infrastructure Certificate and CRL Profile - // http://www.ietf.org/rfc/rfc3280.txt - // 3. A Summary of the X.500(96) User Schema for use with LDAPv3 - // http://www.faqs.org/rfcs/rfc2256.html - // 4. RFC 2247 - Using Domains in LDAP/X.500 Distinguished Names - // http://www.faqs.org/rfcs/rfc2247.html - - /* - * AttributeTypeAndValue ::= SEQUENCE { - * type AttributeType, - * value AttributeValue - * } - * - * AttributeType ::= OBJECT IDENTIFIER - * - * AttributeValue ::= ANY DEFINED BY AttributeType - */ - public class X520 { - - public abstract class AttributeTypeAndValue { - private string oid; - private string attrValue; - private int upperBound; - private byte encoding; - - protected AttributeTypeAndValue (string oid, int upperBound) - { - this.oid = oid; - this.upperBound = upperBound; - this.encoding = 0xFF; - } - - protected AttributeTypeAndValue (string oid, int upperBound, byte encoding) - { - this.oid = oid; - this.upperBound = upperBound; - this.encoding = encoding; - } - - public string Value { - get { return attrValue; } - set { - if ((attrValue != null) && (attrValue.Length > upperBound)) { - string msg = ("Value length bigger than upperbound ({0})."); - throw new FormatException (String.Format (msg, upperBound)); - } - attrValue = value; - } - } - - public ASN1 ASN1 { - get { return GetASN1 (); } - } - - internal ASN1 GetASN1 (byte encoding) - { - byte encode = encoding; - if (encode == 0xFF) - encode = SelectBestEncoding (); - - ASN1 asn1 = new ASN1 (0x30); - asn1.Add (ASN1Convert.FromOid (oid)); - switch (encode) { - case 0x13: - // PRINTABLESTRING - asn1.Add (new ASN1 (0x13, Encoding.ASCII.GetBytes (attrValue))); - break; - case 0x16: - // IA5STRING - asn1.Add (new ASN1 (0x16, Encoding.ASCII.GetBytes (attrValue))); - break; - case 0x1E: - // BMPSTRING - asn1.Add (new ASN1 (0x1E, Encoding.BigEndianUnicode.GetBytes (attrValue))); - break; - } - return asn1; - } - - internal ASN1 GetASN1 () - { - return GetASN1 (encoding); - } - - public byte[] GetBytes (byte encoding) - { - return GetASN1 (encoding) .GetBytes (); - } - - public byte[] GetBytes () - { - return GetASN1 () .GetBytes (); - } - - private byte SelectBestEncoding () - { - foreach (char c in attrValue) { - switch (c) { - case '@': - case '_': - return 0x1E; // BMPSTRING - default: - if (c > 127) - return 0x1E; // BMPSTRING - break; - } - } - return 0x13; // PRINTABLESTRING - } - } - - public class Name : AttributeTypeAndValue { - - public Name () : base ("2.5.4.41", 32768) - { - } - } - - public class CommonName : AttributeTypeAndValue { - - public CommonName () : base ("2.5.4.3", 64) - { - } - } - - // RFC2256, Section 5.6 - public class SerialNumber : AttributeTypeAndValue { - - // max length 64 bytes, Printable String only - public SerialNumber () - : base ("2.5.4.5", 64, 0x13) - { - } - } - - public class LocalityName : AttributeTypeAndValue { - - public LocalityName () : base ("2.5.4.7", 128) - { - } - } - - public class StateOrProvinceName : AttributeTypeAndValue { - - public StateOrProvinceName () : base ("2.5.4.8", 128) - { - } - } - - public class OrganizationName : AttributeTypeAndValue { - - public OrganizationName () : base ("2.5.4.10", 64) - { - } - } - - public class OrganizationalUnitName : AttributeTypeAndValue { - - public OrganizationalUnitName () : base ("2.5.4.11", 64) - { - } - } - - // NOTE: Not part of RFC2253 - public class EmailAddress : AttributeTypeAndValue { - - public EmailAddress () : base ("1.2.840.113549.1.9.1", 128, 0x16) - { - } - } - - // RFC2247, Section 4 - public class DomainComponent : AttributeTypeAndValue { - - // no maximum length defined - public DomainComponent () - : base ("0.9.2342.19200300.100.1.25", Int32.MaxValue, 0x16) - { - } - } - - // RFC1274, Section 9.3.1 - public class UserId : AttributeTypeAndValue { - - public UserId () - : base ("0.9.2342.19200300.100.1.1", 256) - { - } - } - - public class Oid : AttributeTypeAndValue { - - public Oid (string oid) - : base (oid, Int32.MaxValue) - { - } - } - - /* -- Naming attributes of type X520Title - * id-at-title AttributeType ::= { id-at 12 } - * - * X520Title ::= CHOICE { - * teletexString TeletexString (SIZE (1..ub-title)), - * printableString PrintableString (SIZE (1..ub-title)), - * universalString UniversalString (SIZE (1..ub-title)), - * utf8String UTF8String (SIZE (1..ub-title)), - * bmpString BMPString (SIZE (1..ub-title)) - * } - */ - public class Title : AttributeTypeAndValue { - - public Title () : base ("2.5.4.12", 64) - { - } - } - - public class CountryName : AttributeTypeAndValue { - - // (0x13) PRINTABLESTRING - public CountryName () : base ("2.5.4.6", 2, 0x13) - { - } - } - - public class DnQualifier : AttributeTypeAndValue { - - // (0x13) PRINTABLESTRING - public DnQualifier () : base ("2.5.4.46", 2, 0x13) - { - } - } - - public class Surname : AttributeTypeAndValue { - - public Surname () : base ("2.5.4.4", 32768) - { - } - } - - public class GivenName : AttributeTypeAndValue { - - public GivenName () : base ("2.5.4.42", 16) - { - } - } - - public class Initial : AttributeTypeAndValue { - - public Initial () : base ("2.5.4.43", 5) - { - } - } - - } - - /* From RFC3280 - * -- specifications of Upper Bounds MUST be regarded as mandatory - * -- from Annex B of ITU-T X.411 Reference Definition of MTS Parameter - * - * -- Upper Bounds - * - * ub-name INTEGER ::= 32768 - * ub-common-name INTEGER ::= 64 - * ub-locality-name INTEGER ::= 128 - * ub-state-name INTEGER ::= 128 - * ub-organization-name INTEGER ::= 64 - * ub-organizational-unit-name INTEGER ::= 64 - * ub-title INTEGER ::= 64 - * ub-serial-number INTEGER ::= 64 - * ub-match INTEGER ::= 128 - * ub-emailaddress-length INTEGER ::= 128 - * ub-common-name-length INTEGER ::= 64 - * ub-country-name-alpha-length INTEGER ::= 2 - * ub-country-name-numeric-length INTEGER ::= 3 - * ub-domain-defined-attributes INTEGER ::= 4 - * ub-domain-defined-attribute-type-length INTEGER ::= 8 - * ub-domain-defined-attribute-value-length INTEGER ::= 128 - * ub-domain-name-length INTEGER ::= 16 - * ub-extension-attributes INTEGER ::= 256 - * ub-e163-4-number-length INTEGER ::= 15 - * ub-e163-4-sub-address-length INTEGER ::= 40 - * ub-generation-qualifier-length INTEGER ::= 3 - * ub-given-name-length INTEGER ::= 16 - * ub-initials-length INTEGER ::= 5 - * ub-integer-options INTEGER ::= 256 - * ub-numeric-user-id-length INTEGER ::= 32 - * ub-organization-name-length INTEGER ::= 64 - * ub-organizational-unit-name-length INTEGER ::= 32 - * ub-organizational-units INTEGER ::= 4 - * ub-pds-name-length INTEGER ::= 16 - * ub-pds-parameter-length INTEGER ::= 30 - * ub-pds-physical-address-lines INTEGER ::= 6 - * ub-postal-code-length INTEGER ::= 16 - * ub-pseudonym INTEGER ::= 128 - * ub-surname-length INTEGER ::= 40 - * ub-terminal-id-length INTEGER ::= 24 - * ub-unformatted-address-length INTEGER ::= 180 - * ub-x121-address-length INTEGER ::= 16 - * - * -- Note - upper bounds on string types, such as TeletexString, are - * -- measured in characters. Excepting PrintableString or IA5String, a - * -- significantly greater number of octets will be required to hold - * -- such a value. As a minimum, 16 octets, or twice the specified - * -- upper bound, whichever is the larger, should be allowed for - * -- TeletexString. For UTF8String or UniversalString at least four - * -- times the upper bound should be allowed. - */ -} diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 2a74817c2..518fa0d38 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -56,25 +56,7 @@ - - - - - - - - - - - - - - - - - - @@ -425,6 +407,7 @@ + diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 1975a6b01..9ad99c242 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -1006,7 +1006,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } private readonly SemaphoreSlim _liveStreamsSemaphore = new SemaphoreSlim(1, 1); - private readonly List _liveStreams = new List(); + private readonly List _liveStreams = new List(); public async Task GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) { @@ -1039,7 +1039,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return mediaSource; } - public async Task GetLiveStream(string uniqueId) + public async Task GetLiveStream(string uniqueId) { await _liveStreamsSemaphore.WaitAsync().ConfigureAwait(false); @@ -1055,7 +1055,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } - private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken) + private async Task> GetChannelStreamInternal(string channelId, string streamId, CancellationToken cancellationToken) { _logger.Info("Streaming Channel " + channelId); @@ -1072,7 +1072,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _logger.Info("Live stream {0} consumer count is now {1}", streamId, result.ConsumerCount); - return new Tuple(result, openedMediaSource, result.TunerHost); + return new Tuple(result, openedMediaSource, result.TunerHost); } foreach (var hostInstance in _liveTvManager.TunerHosts) @@ -1092,7 +1092,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _logger.Info("Returning mediasource streamId {0}, mediaSource.Id {1}, mediaSource.LiveStreamId {2}", streamId, openedMediaSource.Id, openedMediaSource.LiveStreamId); - return new Tuple(result, openedMediaSource, hostInstance); + return new Tuple(result, openedMediaSource, hostInstance); } catch (FileNotFoundException) { diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 38d2fd3c6..857afa378 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -78,7 +78,7 @@ namespace Emby.Server.Implementations.LiveTv return EmbyTV.EmbyTV.Current.GetActiveRecordingPath(id); } - public Task GetEmbyTvLiveStream(string id) + public Task GetEmbyTvLiveStream(string id) { return EmbyTV.EmbyTV.Current.GetLiveStream(id); } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index 787dcb5d3..e0fd32aee 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -193,9 +193,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return new List(); } - protected abstract Task GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken); + protected abstract Task GetChannelStream(TunerHostInfo tuner, string channelId, string streamId, CancellationToken cancellationToken); - public async Task GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) + public async Task GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(channelId)) { diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index b9a58a011..bb11dac5f 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -500,7 +500,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return list; } - protected override async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) + protected override async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) { var profile = streamId.Split('_')[0]; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs index 0ae7098b1..604aa74f0 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHttpStream.cs @@ -19,24 +19,18 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { public class HdHomerunHttpStream : LiveStream, IDirectStreamProvider { - private readonly ILogger _logger; private readonly IHttpClient _httpClient; private readonly IServerApplicationHost _appHost; private readonly CancellationTokenSource _liveStreamCancellationTokenSource = new CancellationTokenSource(); private readonly TaskCompletionSource _liveStreamTaskCompletionSource = new TaskCompletionSource(); - private readonly string _tempFilePath; - public HdHomerunHttpStream(MediaSourceInfo mediaSource, string originalStreamId, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, IEnvironmentInfo environment) - : base(mediaSource, environment, fileSystem) + : base(mediaSource, environment, fileSystem, logger, appPaths) { _httpClient = httpClient; - _logger = logger; _appHost = appHost; OriginalStreamId = originalStreamId; - - _tempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts"); } protected override Task OpenInternal(CancellationToken openCancellationToken) @@ -47,7 +41,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun var url = mediaSource.Path; - _logger.Info("Opening HDHR Live stream from {0}", url); + Logger.Info("Opening HDHR Live stream from {0}", url); var taskCompletionSource = new TaskCompletionSource(); @@ -73,7 +67,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun public override Task Close() { - _logger.Info("Closing HDHR live stream"); + Logger.Info("Closing HDHR live stream"); _liveStreamCancellationTokenSource.Cancel(); return _liveStreamTaskCompletionSource.Task; @@ -102,14 +96,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun }, "GET").ConfigureAwait(false)) { - _logger.Info("Opened HDHR stream from {0}", url); + Logger.Info("Opened HDHR stream from {0}", url); if (!cancellationToken.IsCancellationRequested) { - _logger.Info("Beginning multicastStream.CopyUntilCancelled"); + Logger.Info("Beginning multicastStream.CopyUntilCancelled"); - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath)); - using (var fileStream = FileSystem.GetFileStream(_tempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None)) + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(TempFilePath)); + using (var fileStream = FileSystem.GetFileStream(TempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None)) { StreamHelper.CopyTo(response.Content, fileStream, 81920, () => Resolve(openTaskCompletionSource), cancellationToken); } @@ -124,19 +118,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { if (isFirstAttempt) { - _logger.ErrorException("Error opening live stream:", ex); + Logger.ErrorException("Error opening live stream:", ex); openTaskCompletionSource.TrySetException(ex); break; } - _logger.ErrorException("Error copying live stream, will reopen", ex); + Logger.ErrorException("Error copying live stream, will reopen", ex); } isFirstAttempt = false; } _liveStreamTaskCompletionSource.TrySetResult(true); - await DeleteTempFile(_tempFilePath).ConfigureAwait(false); + await DeleteTempFile(TempFilePath).ConfigureAwait(false); }); } @@ -147,37 +141,5 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun openTaskCompletionSource.TrySetResult(true); }); } - - public async Task CopyToAsync(Stream stream, CancellationToken cancellationToken) - { - var allowAsync = false;//Environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; - // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - - using (var inputStream = (FileStream)GetInputStream(_tempFilePath, allowAsync)) - { - TrySeek(inputStream, -20000); - - while (!cancellationToken.IsCancellationRequested) - { - StreamHelper.CopyTo(inputStream, stream, 81920, cancellationToken); - //await inputStream.CopyToAsync(stream, 81920, cancellationToken).ConfigureAwait(false); - - //var position = fs.Position; - //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); - } - } - } - - private void TrySeek(FileStream stream, long offset) - { - try - { - stream.Seek(offset, SeekOrigin.End); - } - catch (Exception ex) - { - _logger.ErrorException("Error seeking stream", ex); - } - } } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index bf3febaf2..ff8fd1bc4 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -23,7 +23,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { public class HdHomerunUdpStream : LiveStream, IDirectStreamProvider { - private readonly ILogger _logger; private readonly IServerApplicationHost _appHost; private readonly ISocketFactory _socketFactory; @@ -33,19 +32,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun private readonly int _numTuners; private readonly INetworkManager _networkManager; - private readonly string _tempFilePath; - public HdHomerunUdpStream(MediaSourceInfo mediaSource, string originalStreamId, IHdHomerunChannelCommands channelCommands, int numTuners, IFileSystem fileSystem, IHttpClient httpClient, ILogger logger, IServerApplicationPaths appPaths, IServerApplicationHost appHost, ISocketFactory socketFactory, INetworkManager networkManager, IEnvironmentInfo environment) - : base(mediaSource, environment, fileSystem) + : base(mediaSource, environment, fileSystem, logger, appPaths) { - _logger = logger; _appHost = appHost; _socketFactory = socketFactory; _networkManager = networkManager; OriginalStreamId = originalStreamId; _channelCommands = channelCommands; _numTuners = numTuners; - _tempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts"); } protected override Task OpenInternal(CancellationToken openCancellationToken) @@ -57,7 +52,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun var uri = new Uri(mediaSource.Path); var localPort = _networkManager.GetRandomUnusedUdpPort(); - _logger.Info("Opening HDHR UDP Live stream from {0}", uri.Host); + Logger.Info("Opening HDHR UDP Live stream from {0}", uri.Host); var taskCompletionSource = new TaskCompletionSource(); @@ -80,7 +75,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun public override Task Close() { - _logger.Info("Closing HDHR UDP live stream"); + Logger.Info("Closing HDHR UDP live stream"); _liveStreamCancellationTokenSource.Cancel(); return _liveStreamTaskCompletionSource.Task; @@ -107,7 +102,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } catch (Exception) { - _logger.Error("Unable to determine local ip address for Legacy HDHomerun stream."); + Logger.Error("Unable to determine local ip address for Legacy HDHomerun stream."); return; } } @@ -119,12 +114,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun // send url to start streaming await hdHomerunManager.StartStreaming(remoteAddress, localAddress, localPort, _channelCommands, _numTuners, cancellationToken).ConfigureAwait(false); - _logger.Info("Opened HDHR UDP stream from {0}", remoteAddress); + Logger.Info("Opened HDHR UDP stream from {0}", remoteAddress); if (!cancellationToken.IsCancellationRequested) { - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(_tempFilePath)); - using (var fileStream = FileSystem.GetFileStream(_tempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None)) + FileSystem.CreateDirectory(FileSystem.GetDirectoryName(TempFilePath)); + using (var fileStream = FileSystem.GetFileStream(TempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None)) { CopyTo(udpClient, fileStream, openTaskCompletionSource, cancellationToken); } @@ -132,7 +127,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } catch (OperationCanceledException ex) { - _logger.Info("HDHR UDP stream cancelled or timed out from {0}", remoteAddress); + Logger.Info("HDHR UDP stream cancelled or timed out from {0}", remoteAddress); openTaskCompletionSource.TrySetException(ex); break; } @@ -140,12 +135,12 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun { if (isFirstAttempt) { - _logger.ErrorException("Error opening live stream:", ex); + Logger.ErrorException("Error opening live stream:", ex); openTaskCompletionSource.TrySetException(ex); break; } - _logger.ErrorException("Error copying live stream, will reopen", ex); + Logger.ErrorException("Error copying live stream, will reopen", ex); } isFirstAttempt = false; @@ -156,7 +151,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun } } - await DeleteTempFile(_tempFilePath).ConfigureAwait(false); + await DeleteTempFile(TempFilePath).ConfigureAwait(false); }); } @@ -168,37 +163,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun }); } - public async Task CopyToAsync(Stream stream, CancellationToken cancellationToken) - { - var allowAsync = false;//Environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; - // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - - using (var inputStream = (FileStream)GetInputStream(_tempFilePath, allowAsync)) - { - TrySeek(inputStream, -20000); - - while (!cancellationToken.IsCancellationRequested) - { - StreamHelper.CopyTo(inputStream, stream, 81920, cancellationToken); - - //var position = fs.Position; - //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); - } - } - } - - private void TrySeek(FileStream stream, long offset) - { - try - { - stream.Seek(offset, SeekOrigin.End); - } - catch (Exception ex) - { - _logger.ErrorException("Error seeking stream", ex); - } - } - private static int RtpHeaderBytes = 12; private void CopyTo(ISocket udpClient, Stream target, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) { @@ -226,30 +190,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun Resolve(openTaskCompletionSource); } } - - //var copier = new AsyncStreamCopier(source, target, 0, cancellationToken, false, bufferSize, bufferCount); - //copier.IndividualReadOffset = RtpHeaderBytes; - - //var taskCompletion = new TaskCompletionSource(); - - //copier.TaskCompletionSource = taskCompletion; - - //var result = copier.BeginCopy(StreamCopyCallback, copier); - - //if (openTaskCompletionSource != null) - //{ - // Resolve(openTaskCompletionSource); - // openTaskCompletionSource = null; - //} - - //if (result.CompletedSynchronously) - //{ - // StreamCopyCallback(result); - //} - - //cancellationToken.Register(() => taskCompletion.TrySetCanceled()); - - //return taskCompletion.Task; } public class UdpClientStream : Stream diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs new file mode 100644 index 000000000..4641a1c91 --- /dev/null +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller; +using MediaBrowser.Controller.IO; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.System; + +namespace Emby.Server.Implementations.LiveTv.TunerHosts +{ + public class LiveStream : ILiveStream + { + public MediaSourceInfo OriginalMediaSource { get; set; } + public MediaSourceInfo OpenedMediaSource { get; set; } + public int ConsumerCount + { + get { return SharedStreamIds.Count; } + } + public ITunerHost TunerHost { get; set; } + public string OriginalStreamId { get; set; } + public bool EnableStreamSharing { get; set; } + public string UniqueId { get; private set; } + + public List SharedStreamIds { get; private set; } + protected readonly IEnvironmentInfo Environment; + protected readonly IFileSystem FileSystem; + + protected readonly string TempFilePath; + protected readonly ILogger Logger; + + public LiveStream(MediaSourceInfo mediaSource, IEnvironmentInfo environment, IFileSystem fileSystem, ILogger logger, IServerApplicationPaths appPaths) + { + OriginalMediaSource = mediaSource; + Environment = environment; + FileSystem = fileSystem; + OpenedMediaSource = mediaSource; + Logger = logger; + EnableStreamSharing = true; + SharedStreamIds = new List(); + UniqueId = Guid.NewGuid().ToString("N"); + TempFilePath = Path.Combine(appPaths.TranscodingTempPath, UniqueId + ".ts"); + } + + public Task Open(CancellationToken cancellationToken) + { + return OpenInternal(cancellationToken); + } + + protected virtual Task OpenInternal(CancellationToken cancellationToken) + { + return Task.FromResult(true); + } + + public virtual Task Close() + { + return Task.FromResult(true); + } + + protected Stream GetInputStream(string path, bool allowAsyncFileRead) + { + var fileOpenOptions = FileOpenOptions.SequentialScan; + + if (allowAsyncFileRead) + { + fileOpenOptions |= FileOpenOptions.Asynchronous; + } + + return FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions); + } + + protected async Task DeleteTempFile(string path, int retryCount = 0) + { + try + { + FileSystem.DeleteFile(path); + return; + } + catch + { + + } + + if (retryCount > 20) + { + return; + } + + await Task.Delay(500).ConfigureAwait(false); + await DeleteTempFile(path, retryCount + 1).ConfigureAwait(false); + } + + public async Task CopyToAsync(Stream stream, CancellationToken cancellationToken) + { + var allowAsync = false;//Environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows; + // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 + + using (var inputStream = (FileStream)GetInputStream(TempFilePath, allowAsync)) + { + TrySeek(inputStream, -20000); + + await CopyTo(inputStream, stream, 81920, null, cancellationToken).ConfigureAwait(false); + } + } + + private static async Task CopyTo(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken) + { + byte[] buffer = new byte[bufferSize]; + while (true) + { + cancellationToken.ThrowIfCancellationRequested(); + + var read = source.Read(buffer, 0, buffer.Length); + + if (read > 0) + { + //await destination.WriteAsync(buffer, 0, read).ConfigureAwait(false); + destination.Write(buffer, 0, read); + + if (onStarted != null) + { + onStarted(); + onStarted = null; + } + } + else + { + await Task.Delay(10).ConfigureAwait(false); + } + } + } + + private void TrySeek(FileStream stream, long offset) + { + try + { + stream.Seek(offset, SeekOrigin.End); + } + catch (ArgumentException) + { + + } + catch (Exception ex) + { + Logger.ErrorException("Error seeking stream", ex); + } + } + } +} diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs index eac845579..8d1854f4b 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs @@ -75,11 +75,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return Task.FromResult(list); } - protected override async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) + protected override async Task GetChannelStream(TunerHostInfo info, string channelId, string streamId, CancellationToken cancellationToken) { var sources = await GetChannelStreamMediaSources(info, channelId, cancellationToken).ConfigureAwait(false); - var liveStream = new LiveStream(sources.First(), _environment, FileSystem); + var liveStream = new LiveStream(sources.First(), _environment, FileSystem, Logger, Config.ApplicationPaths); return liveStream; } From 539fecd08b752a50ebdbcef45b51a998f1390167 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 28 Sep 2017 13:04:06 -0400 Subject: [PATCH 4/6] rework live stream creation --- MediaBrowser.Controller/IO/StreamHelper.cs | 5 -- .../LiveTv/ILiveTvManager.cs | 2 +- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 15 +++- MediaBrowser.Controller/LiveTv/LiveStream.cs | 87 ------------------- .../MediaBrowser.Controller.csproj | 1 - MediaBrowser.Server.Mono/MonoAppHost.cs | 2 +- MediaBrowser.Server.Mono/Program.cs | 2 - MediaBrowser.ServerApplication/MainStartup.cs | 2 - .../WindowsAppHost.cs | 1 - 9 files changed, 16 insertions(+), 101 deletions(-) delete mode 100644 MediaBrowser.Controller/LiveTv/LiveStream.cs diff --git a/MediaBrowser.Controller/IO/StreamHelper.cs b/MediaBrowser.Controller/IO/StreamHelper.cs index af97a0233..106fec41f 100644 --- a/MediaBrowser.Controller/IO/StreamHelper.cs +++ b/MediaBrowser.Controller/IO/StreamHelper.cs @@ -6,11 +6,6 @@ namespace MediaBrowser.Controller.IO { public static class StreamHelper { - public static void CopyTo(Stream source, Stream destination, int bufferSize, CancellationToken cancellationToken) - { - CopyTo(source, destination, bufferSize, null, cancellationToken); - } - public static void CopyTo(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken) { byte[] buffer = new byte[bufferSize]; diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 42c31c629..be85e115c 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -383,7 +383,7 @@ namespace MediaBrowser.Controller.LiveTv event EventHandler> SeriesTimerCreated; string GetEmbyTvActiveRecordingPath(string id); - Task GetEmbyTvLiveStream(string id); + Task GetEmbyTvLiveStream(string id); ActiveRecordingInfo GetActiveRecordingInfo(string path); diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index fc344298b..2019259c5 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Controller.LiveTv /// The stream identifier. /// The cancellation token. /// Task<MediaSourceInfo>. - Task GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken); + Task GetChannelStream(string channelId, string streamId, CancellationToken cancellationToken); /// /// Gets the channel stream media sources. /// @@ -56,4 +56,17 @@ namespace MediaBrowser.Controller.LiveTv /// Task. Task Validate(TunerHostInfo info); } + + public interface ILiveStream + { + Task Open(CancellationToken cancellationToken); + Task Close(); + int ConsumerCount { get; } + string OriginalStreamId { get; set; } + bool EnableStreamSharing { get; set; } + ITunerHost TunerHost { get; set; } + MediaSourceInfo OpenedMediaSource { get; set; } + string UniqueId { get; } + List SharedStreamIds { get; } + } } diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs deleted file mode 100644 index 20947462e..000000000 --- a/MediaBrowser.Controller/LiveTv/LiveStream.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.System; - -namespace MediaBrowser.Controller.LiveTv -{ - public class LiveStream - { - public MediaSourceInfo OriginalMediaSource { get; set; } - public MediaSourceInfo OpenedMediaSource { get; set; } - public int ConsumerCount - { - get { return SharedStreamIds.Count; } - } - public ITunerHost TunerHost { get; set; } - public string OriginalStreamId { get; set; } - public bool EnableStreamSharing { get; set; } - public string UniqueId = Guid.NewGuid().ToString("N"); - - public List SharedStreamIds = new List(); - protected readonly IEnvironmentInfo Environment; - protected readonly IFileSystem FileSystem; - const int StreamCopyToBufferSize = 81920; - - public LiveStream(MediaSourceInfo mediaSource, IEnvironmentInfo environment, IFileSystem fileSystem) - { - OriginalMediaSource = mediaSource; - Environment = environment; - FileSystem = fileSystem; - OpenedMediaSource = mediaSource; - EnableStreamSharing = true; - } - - public Task Open(CancellationToken cancellationToken) - { - return OpenInternal(cancellationToken); - } - - protected virtual Task OpenInternal(CancellationToken cancellationToken) - { - return Task.FromResult(true); - } - - public virtual Task Close() - { - return Task.FromResult(true); - } - - protected Stream GetInputStream(string path, bool allowAsyncFileRead) - { - var fileOpenOptions = FileOpenOptions.SequentialScan; - - if (allowAsyncFileRead) - { - fileOpenOptions |= FileOpenOptions.Asynchronous; - } - - return FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions); - } - - protected async Task DeleteTempFile(string path, int retryCount = 0) - { - try - { - FileSystem.DeleteFile(path); - return; - } - catch - { - - } - - if (retryCount > 20) - { - return; - } - - await Task.Delay(500).ConfigureAwait(false); - await DeleteTempFile(path, retryCount + 1).ConfigureAwait(false); - } - } -} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 5ef763b62..b33993859 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -145,7 +145,6 @@ - diff --git a/MediaBrowser.Server.Mono/MonoAppHost.cs b/MediaBrowser.Server.Mono/MonoAppHost.cs index fe684d928..312f14732 100644 --- a/MediaBrowser.Server.Mono/MonoAppHost.cs +++ b/MediaBrowser.Server.Mono/MonoAppHost.cs @@ -26,7 +26,7 @@ namespace MediaBrowser.Server.Mono get { // A restart script must be provided - return false; + return StartupOptions.ContainsOption("-restartpath") && StartupOptions.ContainsOption("-ffmpeg"); } } diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs index 566a84da2..3267a77b9 100644 --- a/MediaBrowser.Server.Mono/Program.cs +++ b/MediaBrowser.Server.Mono/Program.cs @@ -12,8 +12,6 @@ using System.Reflection; using System.Text.RegularExpressions; using System.Threading.Tasks; using Emby.Drawing; -using Emby.Server.Core.Cryptography; -using Emby.Server.Core; using Emby.Server.Implementations; using Emby.Server.Implementations.EnvironmentInfo; using Emby.Server.Implementations.IO; diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index d17d9ee43..70b03aa44 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -16,9 +16,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; -using Emby.Server.Core.Cryptography; using Emby.Drawing; -using Emby.Server.Core; using Emby.Server.Implementations; using Emby.Server.Implementations.Browser; using Emby.Server.Implementations.EnvironmentInfo; diff --git a/MediaBrowser.ServerApplication/WindowsAppHost.cs b/MediaBrowser.ServerApplication/WindowsAppHost.cs index 19079fbc9..9896b75e3 100644 --- a/MediaBrowser.ServerApplication/WindowsAppHost.cs +++ b/MediaBrowser.ServerApplication/WindowsAppHost.cs @@ -6,7 +6,6 @@ using System.Reflection; using System.Runtime.InteropServices.ComTypes; using Emby.Server.CinemaMode; using Emby.Server.Connect; -using Emby.Server.Core; using Emby.Server.Implementations; using Emby.Server.Implementations.EntryPoints; using Emby.Server.Implementations.FFMpeg; From 8d4602035f48e5d00d3145b3e7b6a7075d627b7f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 28 Sep 2017 13:05:10 -0400 Subject: [PATCH 5/6] fix for missing response headers --- .../HttpServer/HttpResultFactory.cs | 47 +++++++++---------- .../ImageEncoderHelper.cs | 1 - 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index a70aad14e..86deccee1 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -142,8 +142,6 @@ namespace Emby.Server.Implementations.HttpServer throw new ArgumentNullException("result"); } - var optimizedResult = ToOptimizedResult(requestContext, result); - if (responseHeaders == null) { responseHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -154,15 +152,7 @@ namespace Emby.Server.Implementations.HttpServer responseHeaders["Expires"] = "-1"; } - // Apply headers - var hasHeaders = optimizedResult as IHasHeaders; - - if (hasHeaders != null) - { - AddResponseHeaders(hasHeaders, responseHeaders); - } - - return optimizedResult; + return ToOptimizedResultInternal(requestContext, result, responseHeaders); } public static string GetCompressionType(IRequest request) @@ -189,6 +179,11 @@ namespace Emby.Server.Implementations.HttpServer /// /// public object ToOptimizedResult(IRequest request, T dto) + { + return ToOptimizedResultInternal(request, dto, null); + } + + private object ToOptimizedResultInternal(IRequest request, T dto, IDictionary responseHeaders = null) { var contentType = request.ResponseContentType; @@ -197,27 +192,27 @@ namespace Emby.Server.Implementations.HttpServer case "application/xml": case "text/xml": case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml - return SerializeToXmlString(dto); + return GetHttpResult(SerializeToXmlString(dto), contentType, false, responseHeaders); case "application/json": case "text/json": - return _jsonSerializer.SerializeToString(dto); + return GetHttpResult(_jsonSerializer.SerializeToString(dto), contentType, false, responseHeaders); default: + { + var ms = new MemoryStream(); + var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType); + + writerFn(dto, ms); + + ms.Position = 0; + + if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase)) { - var ms = new MemoryStream(); - var writerFn = RequestHelper.GetResponseWriter(HttpListenerHost.Instance, contentType); - - writerFn(dto, ms); - - ms.Position = 0; - - if (string.Equals(request.Verb, "head", StringComparison.OrdinalIgnoreCase)) - { - return GetHttpResult(new byte[] { }, contentType, true); - } - - return GetHttpResult(ms, contentType, true); + return GetHttpResult(new byte[] { }, contentType, true, responseHeaders); } + + return GetHttpResult(ms, contentType, true, responseHeaders); + } } } diff --git a/MediaBrowser.ServerApplication/ImageEncoderHelper.cs b/MediaBrowser.ServerApplication/ImageEncoderHelper.cs index 0e99bbbad..c86e85785 100644 --- a/MediaBrowser.ServerApplication/ImageEncoderHelper.cs +++ b/MediaBrowser.ServerApplication/ImageEncoderHelper.cs @@ -1,7 +1,6 @@ using System; using Emby.Drawing; using Emby.Drawing.Skia; -using Emby.Server.Core; using Emby.Server.Implementations; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; From f2444d97a0d1b2d69e5b73dd82bc4a76e73b00f0 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 28 Sep 2017 13:05:52 -0400 Subject: [PATCH 6/6] 3.2.32.10 --- SharedVersion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharedVersion.cs b/SharedVersion.cs index 9576d512d..e1a18d590 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.32.9")] +[assembly: AssemblyVersion("3.2.32.10")]