2 // PublicKey.cs - System.Security.Cryptography.PublicKey
5 // Sebastien Pouliot <sebastien@ximian.com>
6 // Tim Coleman (tim@timcoleman.com)
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)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
32 #if SECURITY_DEP || MOONLIGHT
35 using Mono.Security.Cryptography;
36 using MSX = Mono.Security.X509;
38 namespace System.Security.Cryptography.X509Certificates {
40 public sealed class PublicKey {
42 private const string rsaOid = "1.2.840.113549.1.1.1";
43 private const string dsaOid = "1.2.840.10040.4.1";
45 private AsymmetricAlgorithm _key;
46 private AsnEncodedData _keyValue;
47 private AsnEncodedData _params;
50 static byte[] Empty = new byte [0];
52 public PublicKey (Oid oid, AsnEncodedData parameters, AsnEncodedData keyValue)
55 throw new ArgumentNullException ("oid");
56 if (parameters == null)
57 throw new ArgumentNullException ("parameters");
59 throw new ArgumentNullException ("keyValue");
62 _params = new AsnEncodedData (parameters);
63 _keyValue = new AsnEncodedData (keyValue);
66 internal PublicKey (MSX.X509Certificate certificate)
68 // note: _key MUSTonly contains the public part of the key
69 bool export_required = true;
71 if (certificate.KeyAlgorithm == rsaOid) {
73 // shortcut export/import in the case the private key isn't available
74 RSACryptoServiceProvider rcsp = (certificate.RSA as RSACryptoServiceProvider);
75 if ((rcsp != null) && rcsp.PublicOnly) {
76 _key = certificate.RSA;
77 export_required = false;
81 RSAManaged rsam = (certificate.RSA as RSAManaged);
82 if ((rsam != null) && rsam.PublicOnly) {
83 _key = certificate.RSA;
84 export_required = false;
88 if (export_required) {
89 RSAParameters rsap = certificate.RSA.ExportParameters (false);
91 (_key as RSA).ImportParameters (rsap);
95 // shortcut export/import in the case the private key isn't available
96 DSACryptoServiceProvider dcsp = (certificate.DSA as DSACryptoServiceProvider);
97 if ((dcsp != null) && dcsp.PublicOnly) {
98 _key = certificate.DSA;
99 export_required = false;
101 // note: DSAManaged isn't available in Mono.Security due to a bug in Fx 1.x
103 if (export_required) {
104 DSAParameters rsap = certificate.DSA.ExportParameters (false);
105 _key = DSA.Create ();
106 (_key as DSA).ImportParameters (rsap);
111 _oid = new Oid (certificate.KeyAlgorithm);
112 _keyValue = new AsnEncodedData (_oid, certificate.PublicKey);
113 _params = new AsnEncodedData (_oid, certificate.KeyAlgorithmParameters ?? Empty);
118 public AsnEncodedData EncodedKeyValue {
119 get { return _keyValue; }
122 public AsnEncodedData EncodedParameters {
123 get { return _params; }
126 public AsymmetricAlgorithm Key {
129 switch (_oid.Value) {
131 _key = DecodeRSA (_keyValue.RawData);
134 _key = DecodeDSA (_keyValue.RawData, _params.RawData);
137 string msg = Locale.GetText ("Cannot decode public key from unknown OID '{0}'.", _oid.Value);
138 throw new NotSupportedException (msg);
151 static private byte[] GetUnsignedBigInteger (byte[] integer)
153 if (integer [0] != 0x00)
156 // this first byte is added so we're sure it's an unsigned integer
157 // however we can't feed it into RSAParameters or DSAParameters
158 int length = integer.Length - 1;
159 byte[] uinteger = new byte [length];
160 Buffer.BlockCopy (integer, 1, uinteger, 0, length);
164 static internal DSA DecodeDSA (byte[] rawPublicKey, byte[] rawParameters)
166 DSAParameters dsaParams = new DSAParameters ();
168 // for DSA rawPublicKey contains 1 ASN.1 integer - Y
169 ASN1 pubkey = new ASN1 (rawPublicKey);
170 if (pubkey.Tag != 0x02)
171 throw new CryptographicException (Locale.GetText ("Missing DSA Y integer."));
172 dsaParams.Y = GetUnsignedBigInteger (pubkey.Value);
174 ASN1 param = new ASN1 (rawParameters);
175 if ((param == null) || (param.Tag != 0x30) || (param.Count < 3))
176 throw new CryptographicException (Locale.GetText ("Missing DSA parameters."));
177 if ((param [0].Tag != 0x02) || (param [1].Tag != 0x02) || (param [2].Tag != 0x02))
178 throw new CryptographicException (Locale.GetText ("Invalid DSA parameters."));
180 dsaParams.P = GetUnsignedBigInteger (param [0].Value);
181 dsaParams.Q = GetUnsignedBigInteger (param [1].Value);
182 dsaParams.G = GetUnsignedBigInteger (param [2].Value);
184 catch (Exception e) {
185 string msg = Locale.GetText ("Error decoding the ASN.1 structure.");
186 throw new CryptographicException (msg, e);
190 DSA dsa = (DSA) new DSAManaged (dsaParams.Y.Length << 3);
192 DSA dsa = (DSA) new DSACryptoServiceProvider (dsaParams.Y.Length << 3);
194 dsa.ImportParameters (dsaParams);
198 static internal RSA DecodeRSA (byte[] rawPublicKey)
200 RSAParameters rsaParams = new RSAParameters ();
202 // for RSA rawPublicKey contains 2 ASN.1 integers
203 // the modulus and the public exponent
204 ASN1 pubkey = new ASN1 (rawPublicKey);
205 if (pubkey.Count == 0)
206 throw new CryptographicException (Locale.GetText ("Missing RSA modulus and exponent."));
207 ASN1 modulus = pubkey [0];
208 if ((modulus == null) || (modulus.Tag != 0x02))
209 throw new CryptographicException (Locale.GetText ("Missing RSA modulus."));
210 ASN1 exponent = pubkey [1];
211 if (exponent.Tag != 0x02)
212 throw new CryptographicException (Locale.GetText ("Missing RSA public exponent."));
214 rsaParams.Modulus = GetUnsignedBigInteger (modulus.Value);
215 rsaParams.Exponent = exponent.Value;
217 catch (Exception e) {
218 string msg = Locale.GetText ("Error decoding the ASN.1 structure.");
219 throw new CryptographicException (msg, e);
222 int keySize = (rsaParams.Modulus.Length << 3);
224 RSA rsa = (RSA) new RSAManaged (keySize);
226 RSA rsa = (RSA) new RSACryptoServiceProvider (keySize);
228 rsa.ImportParameters (rsaParams);