Add another dummy type to keep silverlight sdk assemblies happy wrt
[mono.git] / mcs / class / System.ServiceModel / Mono.Security.Protocol.Tls.Handshake.Client / TlsClientCertificateVerify.cs
1 // Transport Security Layer (TLS)
2 // Copyright (c) 2003-2004 Carlos Guzman Alvarez
3
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the
7 // "Software"), to deal in the Software without restriction, including
8 // without limitation the rights to use, copy, modify, merge, publish,
9 // distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so, subject to
11 // the following conditions:
12 // 
13 // The above copyright notice and this permission notice shall be
14 // included in all copies or substantial portions of the Software.
15 // 
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 //
24
25 using System;
26 using System.Security.Cryptography.X509Certificates;
27
28 using System.Security.Cryptography;
29 using Mono.Security.Cryptography;
30
31 namespace Mono.Security.Protocol.Tls.Handshake.Client
32 {
33         internal class TlsClientCertificateVerify : HandshakeMessage
34         {
35                 #region Constructors
36
37                 public TlsClientCertificateVerify(Context context) 
38                         : base(context, HandshakeType.CertificateVerify)
39                 {
40                 }
41
42                 #endregion
43
44                 #region Methods
45
46                 public override void Update()
47                 {
48                         base.Update();
49                         this.Reset();
50                 }
51
52                 #endregion
53
54                 #region Protected Methods
55
56                 protected override void ProcessAsSsl3()
57                 {
58                         AsymmetricAlgorithm privKey = null;
59                         ClientContext           context = (ClientContext)this.Context;
60                         
61                         privKey = context.SslStream.RaisePrivateKeySelection(
62                                 context.ClientSettings.ClientCertificate,
63                                 context.ClientSettings.TargetHost);
64
65                         if (privKey == null)
66                         {
67                                 throw new TlsException(AlertDescription.UserCancelled, "Client certificate Private Key unavailable.");
68                         }
69                         else
70                         {
71                                 SslHandshakeHash hash = new SslHandshakeHash(context.MasterSecret);                     
72                                 hash.TransformFinalBlock(
73                                         context.HandshakeMessages.ToArray(), 
74                                         0, 
75                                         (int)context.HandshakeMessages.Length);
76
77                                 // CreateSignature uses ((RSA)privKey).DecryptValue which is not implemented
78                                 // in RSACryptoServiceProvider. Other implementations likely implement DecryptValue
79                                 // so we will try the CreateSignature method.
80                                 byte[] signature = null;
81 #if !MOONLIGHT
82                                 if (!(privKey is RSACryptoServiceProvider))
83 #endif
84                                 {
85                                         try
86                                         {
87                                                 signature = hash.CreateSignature((RSA)privKey);
88                                         }
89                                         catch (NotImplementedException)
90                                         { }
91                                 }
92                                 // If DecryptValue is not implemented, then try to export the private
93                                 // key and let the RSAManaged class do the DecryptValue
94                                 if (signature == null)
95                                 {
96                                         // RSAManaged of the selected ClientCertificate 
97                                         // (at this moment the first one)
98                                         RSA rsa = this.getClientCertRSA((RSA)privKey);
99
100                                         // Write message
101                                         signature = hash.CreateSignature(rsa);
102                                 }
103                                 this.Write((short)signature.Length);
104                                 this.Write(signature, 0, signature.Length);
105                         }
106                 }
107
108                 protected override void ProcessAsTls1()
109                 {
110                         AsymmetricAlgorithm privKey = null;
111                         ClientContext           context = (ClientContext)this.Context;
112                         
113                         privKey = context.SslStream.RaisePrivateKeySelection(
114                                 context.ClientSettings.ClientCertificate,
115                                 context.ClientSettings.TargetHost);
116
117                         if (privKey == null)
118                         {
119                                 throw new TlsException(AlertDescription.UserCancelled, "Client certificate Private Key unavailable.");
120                         }
121                         else
122                         {
123                                 // Compute handshake messages hash
124                                 MD5SHA1 hash = new MD5SHA1();
125                                 hash.ComputeHash(
126                                         context.HandshakeMessages.ToArray(),
127                                         0,
128                                         (int)context.HandshakeMessages.Length);
129
130                                 // CreateSignature uses ((RSA)privKey).DecryptValue which is not implemented
131                                 // in RSACryptoServiceProvider. Other implementations likely implement DecryptValue
132                                 // so we will try the CreateSignature method.
133                                 byte[] signature = null;
134 #if !MOONLIGHT
135                                 if (!(privKey is RSACryptoServiceProvider))
136 #endif
137                                 {
138                                         try
139                                         {
140                                                 signature = hash.CreateSignature((RSA)privKey);
141                                         }
142                                         catch (NotImplementedException)
143                                         { }
144                                 }
145                                 // If DecryptValue is not implemented, then try to export the private
146                                 // key and let the RSAManaged class do the DecryptValue
147                                 if (signature == null)
148                                 {
149                                         // RSAManaged of the selected ClientCertificate 
150                                         // (at this moment the first one)
151                                         RSA rsa = this.getClientCertRSA((RSA)privKey);
152
153                                         // Write message
154                                         signature = hash.CreateSignature(rsa);
155                                 }
156                                 this.Write((short)signature.Length);
157                                 this.Write(signature, 0, signature.Length);
158                         }
159                 }
160
161                 #endregion
162
163                 #region Private methods
164
165                 private RSA getClientCertRSA(RSA privKey)
166                 {
167                         RSAParameters rsaParams         = new RSAParameters();
168                         RSAParameters privateParams = privKey.ExportParameters(true);
169
170                         // for RSA m_publickey contains 2 ASN.1 integers
171                         // the modulus and the public exponent
172                         ASN1 pubkey = new ASN1 (this.Context.ClientSettings.Certificates[0].GetPublicKey());
173                         ASN1 modulus = pubkey [0];
174                         if ((modulus == null) || (modulus.Tag != 0x02))
175                         {
176                                 return null;
177                         }
178                         ASN1 exponent = pubkey [1];
179                         if (exponent.Tag != 0x02)
180                         {
181                                 return null;
182                         }
183
184                         rsaParams.Modulus = this.getUnsignedBigInteger(modulus.Value);
185                         rsaParams.Exponent = exponent.Value;
186
187                         // Set private key parameters
188                         rsaParams.D                     = privateParams.D;
189                         rsaParams.DP            = privateParams.DP;
190                         rsaParams.DQ            = privateParams.DQ;
191                         rsaParams.InverseQ      = privateParams.InverseQ;
192                         rsaParams.P                     = privateParams.P;
193                         rsaParams.Q                     = privateParams.Q;                      
194
195                         // BUG: MS BCL 1.0 can't import a key which 
196                         // isn't the same size as the one present in
197                         // the container.
198                         int keySize = (rsaParams.Modulus.Length << 3);
199                         RSAManaged rsa = new RSAManaged(keySize);
200                         rsa.ImportParameters (rsaParams);
201
202                         return (RSA)rsa;
203                 }
204
205                 private byte[] getUnsignedBigInteger(byte[] integer) 
206                 {
207                         if (integer [0] == 0x00) 
208                         {
209                                 // this first byte is added so we're sure it's an unsigned integer
210                                 // however we can't feed it into RSAParameters or DSAParameters
211                                 int length = integer.Length - 1;
212                                 byte[] uinteger = new byte [length];
213                                 Buffer.BlockCopy (integer, 1, uinteger, 0, length);
214                                 return uinteger;
215                         }
216                         else
217                         {
218                                 return integer;
219                         }
220                 }
221
222                 #endregion
223         }
224 }