Merge branch 'master' of github.com:tgiphil/mono
[mono.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap.Security.jvm / Krb5Helper.cs
1 // 
2 // Novell.Directory.Ldap.Security.Krb5Helper.cs
3 //
4 // Authors:
5 //  Boris Kirzner <borsk@mainsoft.com>
6 //      Konstantin Triger <kostat@mainsoft.com>
7 //      
8 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
9 //
10
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 //\r
31 \r
32 using System;\r
33 using vmw.common;\r
34 \r
35 using java.security;\r
36 using javax.security.auth;\r
37 using org.ietf.jgss;\r
38 \r
39 \r
40 namespace Novell.Directory.Ldap.Security\r
41 {\r
42         internal class Krb5Helper : IDisposable\r
43         {\r
44                 enum QOP {\r
45                         NO_PROTECTION = 1,
46                         INTEGRITY_ONLY_PROTECTION = 2,
47                         PRIVACY_PROTECTION = 4\r
48                 }\r
49 \r
50                 #region Fields\r
51 \r
52                 internal static readonly sbyte [] EmptyToken = new sbyte [0];\r
53                      \r
54                 private readonly bool _encryption;\r
55                 private readonly bool _signing;\r
56                 private readonly bool _delegation;\r
57 \r
58                 private readonly GSSContext _context;\r
59 \r
60                 #endregion // Fields\r
61 \r
62                 #region Constructors\r
63 \r
64                 public Krb5Helper(string name, string clientName, Subject subject, AuthenticationTypes authenticationTypes, string mech)\r
65                 {\r
66                         _encryption = (authenticationTypes & AuthenticationTypes.Sealing) != 0;\r
67                         _signing = (authenticationTypes & AuthenticationTypes.Signing) != 0;\r
68                         _delegation = (authenticationTypes & AuthenticationTypes.Delegation) != 0;\r
69 \r
70                         CreateContextPrivilegedAction action = new CreateContextPrivilegedAction (name, clientName, mech,_encryption,_signing,_delegation);\r
71                         try {\r
72                                 _context = (GSSContext) Subject.doAs (subject,action);\r
73                         }\r
74                         catch (PrivilegedActionException e) {\r
75                                 throw new LdapException ("Problem performing token exchange with the server",LdapException.OTHER,"",e.getCause()); \r
76                         }\r
77                 }\r
78 \r
79                 #endregion // Constructors\r
80 \r
81                 #region Properties\r
82 \r
83                 internal GSSContext Context\r
84                 {\r
85                         get { return _context; }\r
86                 }\r
87 \r
88                 #endregion // Properties\r
89 \r
90                 #region Methods\r
91 \r
92                 public sbyte [] ExchangeTokens(sbyte [] clientToken)\r
93                 {\r
94                         if (Context.isEstablished ()) {\r
95                                 if (clientToken == null || clientToken.Length == 0)\r
96                                         return Krb5Helper.EmptyToken;\r
97 \r
98                                 //final handshake\r
99                                 byte [] challengeData = (byte []) TypeUtils.ToByteArray (clientToken);\r
100                                 byte [] gssOutToken = Unwrap (challengeData, 0, challengeData.Length, new MessageProp (false));\r
101 \r
102                                 QOP myCop = QOP.NO_PROTECTION;\r
103 \r
104                                 if (_encryption)\r
105                                         myCop = QOP.PRIVACY_PROTECTION;\r
106                                 else if (_signing || (((QOP)gssOutToken [0] & QOP.INTEGRITY_ONLY_PROTECTION) != 0))\r
107                                         myCop = QOP.INTEGRITY_ONLY_PROTECTION;\r
108 \r
109                                 if ((myCop & (QOP)gssOutToken [0]) == 0)\r
110                                         throw new LdapException ("Server does not support the requested security level", 80, "");\r
111 \r
112                                 int srvMaxBufSize = SecureStream.NetworkByteOrderToInt (gssOutToken, 1, 3);\r
113 \r
114                                 //int rawSendSize = Context.getWrapSizeLimit(0, _encryption, srvMaxBufSize);\r
115 \r
116                                 byte [] gssInToken = new byte [4];
117                                 gssInToken [0] = (byte) myCop;\r
118 \r
119                                 SecureStream.IntToNetworkByteOrder (srvMaxBufSize, gssInToken, 1, 3);\r
120 \r
121                                 gssOutToken = Wrap (gssInToken, 0, gssInToken.Length, new MessageProp (true));\r
122 \r
123                                 return TypeUtils.ToSByteArray (gssOutToken);\r
124                         }\r
125 \r
126                         sbyte [] token = Context.initSecContext (clientToken, 0, clientToken.Length);\r
127 \r
128                         if (Context.isEstablished ()) {\r
129                                 \r
130                                 if (Context.getConfState () != _encryption)\r
131                                         throw new LdapException ("Encryption protocol was not established layer between client and server", 80, "");\r
132                                         \r
133                                 if (Context.getCredDelegState () != _delegation) \r
134                                         throw new LdapException ("Credential delegation was not established layer between client and server", 80, "");\r
135                                         \r
136                                 if (_signing && (Context.getIntegState () != _signing))\r
137                                         throw new LdapException ("Signing protocol was not established layer between client and server", 80, "");\r
138                                         \r
139                                 if (token == null) \r
140                                         return EmptyToken;\r
141                         }\r
142                         return token;\r
143                 }\r
144 \r
145                 public byte [] Wrap(byte [] outgoing, int start, int len) \r
146                 {\r
147                         return Wrap (outgoing, start, len, new MessageProp(true));\r
148                 }\r
149 \r
150                 public byte [] Wrap(byte [] outgoing, int start, int len, MessageProp messageProp)\r
151                 {\r
152                         if (!Context.isEstablished ())\r
153                                 throw new LdapException ("GSSAPI authentication not completed",LdapException.OTHER,"");\r
154 \r
155                         if (!(Context.getConfState () || Context.getIntegState ())) {\r
156                                 // in the case no encryption and no integrity required - return the original data\r
157                                 byte [] buff = new byte [len];\r
158                                 Array.Copy (outgoing, start, buff, 0, len);\r
159                                 return buff;\r
160                         }\r
161 \r
162                         sbyte [] result = Context.wrap (TypeUtils.ToSByteArray (outgoing), start, len, messageProp);\r
163                         return (byte []) TypeUtils.ToByteArray (result);\r
164                 }\r
165 \r
166                 public byte [] Unwrap(byte [] incoming, int start, int len) \r
167                 {\r
168                         return Unwrap (incoming, start, len, new MessageProp(true));\r
169                 }\r
170 \r
171                 public byte [] Unwrap(byte [] incoming, int start, int len, MessageProp messageProp)\r
172                 {\r
173                         if (!Context.isEstablished ())\r
174                                 throw new LdapException ("GSSAPI authentication not completed",LdapException.OTHER,"");\r
175 \r
176                         if (!(Context.getConfState () || Context.getIntegState ())) {\r
177                                 // in the case no encryption and no integrity required - return the original data\r
178                                 byte [] buff = new byte [len];\r
179                                 Array.Copy (incoming, start, buff, 0, len);\r
180                                 return buff;\r
181                         }\r
182 \r
183                         sbyte [] result = Context.unwrap (TypeUtils.ToSByteArray (incoming), start, len, messageProp);\r
184                         return (byte []) TypeUtils.ToByteArray (result);\r
185                 }\r
186 \r
187                 #endregion // Methods\r
188 \r
189                 #region IDisposable Members\r
190 \r
191                 public void Dispose() {\r
192                         Context.dispose();\r
193                 }\r
194 \r
195                 #endregion\r
196         }\r
197 }\r