In .:
[mono.git] / mcs / class / System / System.Security.Cryptography.X509Certificates / PublicKey.cs
index c8108cf776ba9dbba24a3d7641bea0a1b624a0d8..0ad64d445e8b9b67f5b8ae97b2d1b3c66cecf617 100644 (file)
@@ -2,13 +2,12 @@
 // PublicKey.cs - System.Security.Cryptography.PublicKey
 //
 // Author:
-//     Sebastien Pouliot (spouliot@motus.com)
+//     Sebastien Pouliot  <sebastien@ximian.com>
 //     Tim Coleman (tim@timcoleman.com)
 //
 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
 // Copyright (C) Tim Coleman, 2004
-//
-
+// Copyright (C) 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
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-#if NET_2_0
+#if NET_2_0 && SECURITY_DEP
 
-using System;
+using Mono.Security;
+using MSX = Mono.Security.X509;
 
 namespace System.Security.Cryptography.X509Certificates {
 
-       // Note: Match the definition of framework version 1.2.3400.0 on http://longhorn.msdn.microsoft.com
-
        public sealed class PublicKey {
 
+               private const string rsaOid = "1.2.840.113549.1.1.1";
+               private const string dsaOid = "1.2.840.10040.4.1";
+
                private AsymmetricAlgorithm _key;
                private AsnEncodedData _keyValue;
                private AsnEncodedData _params;
                private Oid _oid;
 
-               [MonoTODO]
                public PublicKey (Oid oid, AsnEncodedData parameters, AsnEncodedData keyValue)
                {
-                       _oid = oid;
-                       _params = parameters;
-                       _keyValue = keyValue;
+                       if (oid == null)
+                               throw new ArgumentNullException ("oid");
+                       if (parameters == null)
+                               throw new ArgumentNullException ("parameters");
+                       if (keyValue == null)
+                               throw new ArgumentNullException ("keyValue");
+
+                       _oid = new Oid (oid);
+                       _params = new AsnEncodedData (parameters);
+                       _keyValue = new AsnEncodedData (keyValue);
                }
 
-               internal PublicKey (Mono.Security.X509.X509Certificate certificate)
+               internal PublicKey (MSX.X509Certificate certificate)
                {
-                       if (certificate.KeyAlgorithm == "1.2.840.113549.1.1.1") {
+                       if (certificate.KeyAlgorithm == rsaOid) {
                                _key = certificate.RSA;
-                       }
-                       else {
+                       } else {
                                _key = certificate.DSA;
                        }
 
@@ -78,12 +84,102 @@ namespace System.Security.Cryptography.X509Certificates {
                }
 
                public AsymmetricAlgorithm Key {
-                       get { return _key; }
+                       get {
+                               if (_key == null) {
+                                       switch (_oid.Value) {
+                                       case rsaOid:
+                                               _key = DecodeRSA (_keyValue.RawData);
+                                               break;
+                                       case dsaOid:
+                                               _key = DecodeDSA (_keyValue.RawData, _params.RawData);
+                                               break;
+                                       default:
+                                               string msg = Locale.GetText ("Cannot decode public key from unknown OID '{0}'.", _oid.Value);
+                                               throw new NotSupportedException (msg);
+                                       }
+                               }
+                               return _key;
+                       }
                }
 
                public Oid Oid {
                        get { return _oid; }
                }
+
+               // private stuff
+
+               static private byte[] GetUnsignedBigInteger (byte[] integer) 
+               {
+                       if (integer [0] != 0x00)
+                               return integer;
+
+                       // 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;
+               }
+
+               static internal DSA DecodeDSA (byte[] rawPublicKey, byte[] rawParameters)
+               {
+                       DSAParameters dsaParams = new DSAParameters ();
+                       try {
+                               // for DSA rawPublicKey contains 1 ASN.1 integer - Y
+                               ASN1 pubkey = new ASN1 (rawPublicKey);
+                               if (pubkey.Tag != 0x02)
+                                       throw new CryptographicException (Locale.GetText ("Missing DSA Y integer."));
+                               dsaParams.Y = GetUnsignedBigInteger (pubkey.Value);
+
+                               ASN1 param = new ASN1 (rawParameters);
+                               if ((param == null) || (param.Tag != 0x30) || (param.Count < 3))
+                                       throw new CryptographicException (Locale.GetText ("Missing DSA parameters."));
+                               if ((param [0].Tag != 0x02) || (param [1].Tag != 0x02) || (param [2].Tag != 0x02))
+                                       throw new CryptographicException (Locale.GetText ("Invalid DSA parameters."));
+
+                               dsaParams.P = GetUnsignedBigInteger (param [0].Value);
+                               dsaParams.Q = GetUnsignedBigInteger (param [1].Value);
+                               dsaParams.G = GetUnsignedBigInteger (param [2].Value);
+                       }
+                       catch (Exception e) {
+                               string msg = Locale.GetText ("Error decoding the ASN.1 structure.");
+                               throw new CryptographicException (msg, e);
+                       }
+
+                       DSA dsa = (DSA) new DSACryptoServiceProvider (dsaParams.Y.Length << 3);
+                       dsa.ImportParameters (dsaParams);
+                       return dsa;
+               }
+
+               static internal RSA DecodeRSA (byte[] rawPublicKey)
+               {
+                       RSAParameters rsaParams = new RSAParameters ();
+                       try {
+                               // for RSA rawPublicKey contains 2 ASN.1 integers
+                               // the modulus and the public exponent
+                               ASN1 pubkey = new ASN1 (rawPublicKey);
+                               if (pubkey.Count == 0)
+                                       throw new CryptographicException (Locale.GetText ("Missing RSA modulus and exponent."));
+                               ASN1 modulus = pubkey [0];
+                               if ((modulus == null) || (modulus.Tag != 0x02))
+                                       throw new CryptographicException (Locale.GetText ("Missing RSA modulus."));
+                               ASN1 exponent = pubkey [1];
+                               if (exponent.Tag != 0x02)
+                                       throw new CryptographicException (Locale.GetText ("Missing RSA public exponent."));
+
+                               rsaParams.Modulus = GetUnsignedBigInteger (modulus.Value);
+                               rsaParams.Exponent = exponent.Value;
+                       }
+                       catch (Exception e) {
+                               string msg = Locale.GetText ("Error decoding the ASN.1 structure.");
+                               throw new CryptographicException (msg, e);
+                       }
+
+                       int keySize = (rsaParams.Modulus.Length << 3);
+                       RSA rsa = (RSA) new RSACryptoServiceProvider (keySize);
+                       rsa.ImportParameters (rsaParams);
+                       return rsa;
+               }
        }
 }