//
// KeyAttributesExtension.cs: Handles X.509 *DEPRECATED* KeyAttributes extensions.
//
// Author:
//	Sebastien Pouliot  <sebastien@ximian.com>
//
// (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.Globalization;
using System.Text;

using Mono.Security;
using Mono.Security.X509;

namespace Mono.Security.X509.Extensions {	
	public class KeyAttributesExtension : X509Extension {

		private byte[] keyId;
		private int kubits;
		private DateTime notBefore;
		private DateTime notAfter;

		public KeyAttributesExtension () : base () 
		{
			extnOid = "2.5.29.2";
		}

		public KeyAttributesExtension (ASN1 asn1) : base (asn1)
		{
		}

		public KeyAttributesExtension (X509Extension extension) : base (extension)
		{
		}

		protected override void Decode () 
		{
			ASN1 seq = new ASN1 (extnValue.Value);
			if (seq.Tag != 0x30)
				throw new ArgumentException ("Invalid KeyAttributesExtension extension");
			int n = 0;
			// check for KeyIdentifier
			if (n < seq.Count) {
				ASN1 item = seq [n];
				if (item.Tag == 0x04) {
					n++;
					keyId = item.Value;
				}
			}
			// check for KeyUsage
			if (n < seq.Count) {
				ASN1 item = seq [n];
				if (item.Tag == 0x03) {
					n++;
					int i = 1; // byte zero has the number of unused bits (ASN1's BITSTRING)
					while (i < item.Value.Length)
						kubits = (kubits << 8) + item.Value [i++];
				}
			}
			// check for PrivateKeyValidity
			if (n < seq.Count) {
				ASN1 item = seq [n];
				if (item.Tag == 0x30) {
					int i = 0;
					if (i < item.Count) {
						ASN1 dt = item [i];
						if (dt.Tag == 0x81) {
							i++;
							notBefore = ASN1Convert.ToDateTime (dt);
						}
					}
					if (i < item.Count) {
						ASN1 dt = item [i];
						if (dt.Tag == 0x82)
							notAfter = ASN1Convert.ToDateTime (dt);
					}
				}
			}
		}

		public byte[] KeyIdentifier {
			get { 
				if (keyId == null)
					return null;
				return (byte[]) keyId.Clone ();
			}
		}

		public override string Name {
			get { return "Key Attributes"; }
		}

		public DateTime NotAfter {
			get { return notAfter; }
		}

		public DateTime NotBefore {
			get { return notBefore; }
		}

		public bool Support (KeyUsages usage) 
		{
			int x = Convert.ToInt32 (usage, CultureInfo.InvariantCulture);
			return ((x & kubits) == x);
		}

		public override string ToString () 
		{
			StringBuilder sb = new StringBuilder ();
			if (keyId != null) {
				sb.Append ("KeyID=");
				int x = 0;
				while (x < keyId.Length) {
					sb.Append (keyId [x].ToString ("X2", CultureInfo.InvariantCulture));
					if (x % 2 == 1)
						sb.Append (" ");
					x++;
				}
				sb.Append (Environment.NewLine);
			}

			if (kubits != 0) {
				sb.Append ("Key Usage=");
				const string separator = " , ";
				if (Support (KeyUsages.digitalSignature))
					sb.Append ("Digital Signature");
				if (Support (KeyUsages.nonRepudiation)) {
					if (sb.Length > 0)
						sb.Append (separator);
					sb.Append ("Non-Repudiation");
				}
				if (Support (KeyUsages.keyEncipherment)) {
					if (sb.Length > 0)
						sb.Append (separator);
					sb.Append ("Key Encipherment");
				}
				if (Support (KeyUsages.dataEncipherment)) {
					if (sb.Length > 0)
						sb.Append (separator);
					sb.Append ("Data Encipherment");
				}
				if (Support (KeyUsages.keyAgreement)) {
					if (sb.Length > 0)
						sb.Append (separator);
					sb.Append ("Key Agreement");		
				}
				if (Support (KeyUsages.keyCertSign)) {
					if (sb.Length > 0)
						sb.Append (separator);
					sb.Append ("Certificate Signing");
				}
				if (Support (KeyUsages.cRLSign)) {
					if (sb.Length > 0)
						sb.Append (separator);
					sb.Append ("CRL Signing");
				}
				if (Support (KeyUsages.encipherOnly)) {
					if (sb.Length > 0)
						sb.Append (separator);
					sb.Append ("Encipher Only ");	// ???
				}
				if (Support (KeyUsages.decipherOnly)) {
					if (sb.Length > 0)
						sb.Append (separator);
					sb.Append ("Decipher Only");	// ???
				}
				sb.Append ("(");
				sb.Append (kubits.ToString ("X2", CultureInfo.InvariantCulture));
				sb.Append (")");
				sb.Append (Environment.NewLine);
			}

			if (notBefore != DateTime.MinValue) {
				sb.Append ("Not Before=");
				sb.Append (notBefore.ToString (CultureInfo.CurrentUICulture));
				sb.Append (Environment.NewLine);
			}
			if (notAfter != DateTime.MinValue) {
				sb.Append ("Not After=");
				sb.Append (notAfter.ToString (CultureInfo.CurrentUICulture));
				sb.Append (Environment.NewLine);
			}
			return sb.ToString ();
		}
	}
}