diff options
Diffstat (limited to 'mcs/class/System/System.Security.Cryptography.X509Certificates/X509SubjectKeyIdentifierExtension.cs')
-rw-r--r-- | mcs/class/System/System.Security.Cryptography.X509Certificates/X509SubjectKeyIdentifierExtension.cs | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/mcs/class/System/System.Security.Cryptography.X509Certificates/X509SubjectKeyIdentifierExtension.cs b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509SubjectKeyIdentifierExtension.cs new file mode 100644 index 00000000000..fa212b03c23 --- /dev/null +++ b/mcs/class/System/System.Security.Cryptography.X509Certificates/X509SubjectKeyIdentifierExtension.cs @@ -0,0 +1,242 @@ +// +// System.Security.Cryptography.X509Certificates.X509SubjectKeyIdentifierExtension +// +// Authors: +// Tim Coleman (tim@timcoleman.com) +// Sebastien Pouliot <sebastien@ximian.com> +// +// Copyright (C) Tim Coleman, 2004 +// 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. +// + +#if NET_2_0 + +using System.Text; + +using Mono.Security; +using Mono.Security.Cryptography; + +namespace System.Security.Cryptography.X509Certificates { + + public sealed class X509SubjectKeyIdentifierExtension : X509Extension { + + internal const string oid = "2.5.29.14"; + internal const string friendlyName = "Subject Key Identifier"; + + private byte[] _subjectKeyIdentifier; + private string _ski; + private AsnDecodeStatus _status; + + // constructors + + public X509SubjectKeyIdentifierExtension () + { + _oid = new Oid (oid, friendlyName); + } + + public X509SubjectKeyIdentifierExtension (AsnEncodedData encodedSubjectKeyIdentifier, bool critical) + { + // ignore the Oid provided by encodedKeyUsage (our rules!) + _oid = new Oid (oid, friendlyName); + _raw = encodedSubjectKeyIdentifier.RawData; + base.Critical = critical; + _status = Decode (this.RawData); + } + + public X509SubjectKeyIdentifierExtension (byte[] subjectKeyIdentifier, bool critical) + { + if (subjectKeyIdentifier == null) + throw new ArgumentNullException ("subjectKeyIdentifier"); + if (subjectKeyIdentifier.Length == 0) + throw new ArgumentException ("subjectKeyIdentifier"); + + _oid = new Oid (oid, friendlyName); + base.Critical = critical; + _subjectKeyIdentifier = (byte[])subjectKeyIdentifier.Clone (); + RawData = Encode (); + } + + public X509SubjectKeyIdentifierExtension (string subjectKeyIdentifier, bool critical) + { + if (subjectKeyIdentifier == null) + throw new ArgumentNullException ("subjectKeyIdentifier"); + if (subjectKeyIdentifier.Length < 2) + throw new ArgumentException ("subjectKeyIdentifier"); + + _oid = new Oid (oid, friendlyName); + base.Critical = critical; + _subjectKeyIdentifier = FromHex (subjectKeyIdentifier); + RawData = Encode (); + } + + [MonoTODO] + public X509SubjectKeyIdentifierExtension (PublicKey key, bool critical) + : this (key, X509SubjectKeyIdentifierHashAlgorithm.Sha1, critical) + { + } + + [MonoTODO] + public X509SubjectKeyIdentifierExtension (PublicKey key, X509SubjectKeyIdentifierHashAlgorithm algorithm, bool critical) + { + if (key == null) + throw new ArgumentNullException ("key"); + } + + // properties + + public string SubjectKeyIdentifier { + get { + switch (_status) { + case AsnDecodeStatus.Ok: + case AsnDecodeStatus.InformationNotAvailable: + if (_subjectKeyIdentifier != null) + _ski = CryptoConvert.ToHex (_subjectKeyIdentifier); + return _ski; + default: + throw new CryptographicException ("Badly encoded extension."); + } + } + } + + // methods + + public override void CopyFrom (AsnEncodedData encodedData) + { + if (encodedData == null) + throw new ArgumentNullException ("encodedData"); + + X509Extension ex = (encodedData as X509Extension); + if (ex == null) + throw new ArgumentException (Locale.GetText ("Wrong type."), "encodedData"); + + if (ex._oid == null) + _oid = new Oid (oid, friendlyName); + else + _oid = new Oid (ex._oid); + + RawData = ex.RawData; + base.Critical = ex.Critical; + // and we deal with the rest later + _status = Decode (this.RawData); + } + + // internal + + static internal 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'); + return 255; // F + } + + static internal byte FromHexChars (char c1, char c2) + { + byte result = FromHexChar (c1); + if (result < 255) + result = (byte) ((result << 4) | FromHexChar (c2)); + return result; + } + + static internal byte[] FromHex (string hex) + { + // here we can't use CryptoConvert.FromHex because we + // must convert any *illegal* (non hex) 2 characters + // to 'FF' and ignore last char on odd length + if (hex == null) + return null; + + int length = hex.Length >> 1; + + byte[] result = new byte [length]; // + (odd ? 1 : 0)]; + int n = 0; + int i = 0; + while (n < length) { + result [n++] = FromHexChars (hex [i++], hex [i++]); + } + return result; + } + + internal AsnDecodeStatus Decode (byte[] extension) + { + if ((extension == null) || (extension.Length == 0)) + return AsnDecodeStatus.BadAsn; + _ski = String.Empty; + if (extension [0] != 0x04) + return AsnDecodeStatus.BadTag; + if (extension.Length == 2) + return AsnDecodeStatus.InformationNotAvailable; + if (extension.Length < 3) + return AsnDecodeStatus.BadLength; + + try { + ASN1 ex = new ASN1 (extension); + _subjectKeyIdentifier = ex.Value; + } + catch { + return AsnDecodeStatus.BadAsn; + } + + return AsnDecodeStatus.Ok; + } + + internal byte[] Encode () + { + ASN1 ex = new ASN1 (0x04, _subjectKeyIdentifier); + return ex.GetBytes (); + } + + internal override string ToString (bool multiLine) + { + switch (_status) { + case AsnDecodeStatus.BadAsn: + return String.Empty; + case AsnDecodeStatus.BadTag: + case AsnDecodeStatus.BadLength: + return FormatUnkownData (_raw); + case AsnDecodeStatus.InformationNotAvailable: + return "Information Not Available"; + } + + if (_oid.Value != oid) + return String.Format ("Unknown Key Usage ({0})", _oid.Value); + + StringBuilder sb = new StringBuilder (); + + for (int i=0; i < _subjectKeyIdentifier.Length; i++) { + sb.Append (_subjectKeyIdentifier [i].ToString ("x2")); + if (i != _subjectKeyIdentifier.Length - 1) + sb.Append (" "); + } + + if (multiLine) + sb.Append (Environment.NewLine); + + return sb.ToString (); + } + } +} + +#endif |