In .:
[mono.git] / mcs / class / System / System.Security.Cryptography.X509Certificates / PublicKey.cs
1 //
2 // PublicKey.cs - System.Security.Cryptography.PublicKey
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //      Tim Coleman (tim@timcoleman.com)
7 //
8 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) Tim Coleman, 2004
10 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 #if NET_2_0 && SECURITY_DEP
33
34 using Mono.Security;
35 using MSX = Mono.Security.X509;
36
37 namespace System.Security.Cryptography.X509Certificates {
38
39         public sealed class PublicKey {
40
41                 private const string rsaOid = "1.2.840.113549.1.1.1";
42                 private const string dsaOid = "1.2.840.10040.4.1";
43
44                 private AsymmetricAlgorithm _key;
45                 private AsnEncodedData _keyValue;
46                 private AsnEncodedData _params;
47                 private Oid _oid;
48
49                 public PublicKey (Oid oid, AsnEncodedData parameters, AsnEncodedData keyValue)
50                 {
51                         if (oid == null)
52                                 throw new ArgumentNullException ("oid");
53                         if (parameters == null)
54                                 throw new ArgumentNullException ("parameters");
55                         if (keyValue == null)
56                                 throw new ArgumentNullException ("keyValue");
57
58                         _oid = new Oid (oid);
59                         _params = new AsnEncodedData (parameters);
60                         _keyValue = new AsnEncodedData (keyValue);
61                 }
62
63                 internal PublicKey (MSX.X509Certificate certificate)
64                 {
65                         if (certificate.KeyAlgorithm == rsaOid) {
66                                 _key = certificate.RSA;
67                         } else {
68                                 _key = certificate.DSA;
69                         }
70
71                         _oid = new Oid (certificate.KeyAlgorithm);
72                         _keyValue = new AsnEncodedData (_oid, certificate.PublicKey);
73                         _params = new AsnEncodedData (_oid, certificate.KeyAlgorithmParameters);
74                 }
75
76                 // properties
77
78                 public AsnEncodedData EncodedKeyValue {
79                         get { return _keyValue; }
80                 }
81
82                 public AsnEncodedData EncodedParameters {
83                         get { return _params; }
84                 }
85
86                 public AsymmetricAlgorithm Key {
87                         get {
88                                 if (_key == null) {
89                                         switch (_oid.Value) {
90                                         case rsaOid:
91                                                 _key = DecodeRSA (_keyValue.RawData);
92                                                 break;
93                                         case dsaOid:
94                                                 _key = DecodeDSA (_keyValue.RawData, _params.RawData);
95                                                 break;
96                                         default:
97                                                 string msg = Locale.GetText ("Cannot decode public key from unknown OID '{0}'.", _oid.Value);
98                                                 throw new NotSupportedException (msg);
99                                         }
100                                 }
101                                 return _key;
102                         }
103                 }
104
105                 public Oid Oid {
106                         get { return _oid; }
107                 }
108
109                 // private stuff
110
111                 static private byte[] GetUnsignedBigInteger (byte[] integer) 
112                 {
113                         if (integer [0] != 0x00)
114                                 return integer;
115
116                         // this first byte is added so we're sure it's an unsigned integer
117                         // however we can't feed it into RSAParameters or DSAParameters
118                         int length = integer.Length - 1;
119                         byte[] uinteger = new byte [length];
120                         Buffer.BlockCopy (integer, 1, uinteger, 0, length);
121                         return uinteger;
122                 }
123
124                 static internal DSA DecodeDSA (byte[] rawPublicKey, byte[] rawParameters)
125                 {
126                         DSAParameters dsaParams = new DSAParameters ();
127                         try {
128                                 // for DSA rawPublicKey contains 1 ASN.1 integer - Y
129                                 ASN1 pubkey = new ASN1 (rawPublicKey);
130                                 if (pubkey.Tag != 0x02)
131                                         throw new CryptographicException (Locale.GetText ("Missing DSA Y integer."));
132                                 dsaParams.Y = GetUnsignedBigInteger (pubkey.Value);
133
134                                 ASN1 param = new ASN1 (rawParameters);
135                                 if ((param == null) || (param.Tag != 0x30) || (param.Count < 3))
136                                         throw new CryptographicException (Locale.GetText ("Missing DSA parameters."));
137                                 if ((param [0].Tag != 0x02) || (param [1].Tag != 0x02) || (param [2].Tag != 0x02))
138                                         throw new CryptographicException (Locale.GetText ("Invalid DSA parameters."));
139
140                                 dsaParams.P = GetUnsignedBigInteger (param [0].Value);
141                                 dsaParams.Q = GetUnsignedBigInteger (param [1].Value);
142                                 dsaParams.G = GetUnsignedBigInteger (param [2].Value);
143                         }
144                         catch (Exception e) {
145                                 string msg = Locale.GetText ("Error decoding the ASN.1 structure.");
146                                 throw new CryptographicException (msg, e);
147                         }
148
149                         DSA dsa = (DSA) new DSACryptoServiceProvider (dsaParams.Y.Length << 3);
150                         dsa.ImportParameters (dsaParams);
151                         return dsa;
152                 }
153
154                 static internal RSA DecodeRSA (byte[] rawPublicKey)
155                 {
156                         RSAParameters rsaParams = new RSAParameters ();
157                         try {
158                                 // for RSA rawPublicKey contains 2 ASN.1 integers
159                                 // the modulus and the public exponent
160                                 ASN1 pubkey = new ASN1 (rawPublicKey);
161                                 if (pubkey.Count == 0)
162                                         throw new CryptographicException (Locale.GetText ("Missing RSA modulus and exponent."));
163                                 ASN1 modulus = pubkey [0];
164                                 if ((modulus == null) || (modulus.Tag != 0x02))
165                                         throw new CryptographicException (Locale.GetText ("Missing RSA modulus."));
166                                 ASN1 exponent = pubkey [1];
167                                 if (exponent.Tag != 0x02)
168                                         throw new CryptographicException (Locale.GetText ("Missing RSA public exponent."));
169
170                                 rsaParams.Modulus = GetUnsignedBigInteger (modulus.Value);
171                                 rsaParams.Exponent = exponent.Value;
172                         }
173                         catch (Exception e) {
174                                 string msg = Locale.GetText ("Error decoding the ASN.1 structure.");
175                                 throw new CryptographicException (msg, e);
176                         }
177
178                         int keySize = (rsaParams.Modulus.Length << 3);
179                         RSA rsa = (RSA) new RSACryptoServiceProvider (keySize);
180                         rsa.ImportParameters (rsaParams);
181                         return rsa;
182                 }
183         }
184 }
185
186 #endif