198 lines
6.4 KiB
C#
198 lines
6.4 KiB
C#
//
|
|
// Novell.Directory.Ldap.Security.Krb5Helper.cs
|
|
//
|
|
// Authors:
|
|
// Boris Kirzner <borsk@mainsoft.com>
|
|
// Konstantin Triger <kostat@mainsoft.com>
|
|
//
|
|
// (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
|
|
//
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using vmw.common;
|
|
|
|
using java.security;
|
|
using javax.security.auth;
|
|
using org.ietf.jgss;
|
|
|
|
|
|
namespace Novell.Directory.Ldap.Security
|
|
{
|
|
internal class Krb5Helper : IDisposable
|
|
{
|
|
enum QOP {
|
|
NO_PROTECTION = 1,
|
|
INTEGRITY_ONLY_PROTECTION = 2,
|
|
PRIVACY_PROTECTION = 4
|
|
}
|
|
|
|
#region Fields
|
|
|
|
internal static readonly sbyte [] EmptyToken = new sbyte [0];
|
|
|
|
private readonly bool _encryption;
|
|
private readonly bool _signing;
|
|
private readonly bool _delegation;
|
|
|
|
private readonly GSSContext _context;
|
|
|
|
#endregion // Fields
|
|
|
|
#region Constructors
|
|
|
|
public Krb5Helper(string name, string clientName, Subject subject, AuthenticationTypes authenticationTypes, string mech)
|
|
{
|
|
_encryption = (authenticationTypes & AuthenticationTypes.Sealing) != 0;
|
|
_signing = (authenticationTypes & AuthenticationTypes.Signing) != 0;
|
|
_delegation = (authenticationTypes & AuthenticationTypes.Delegation) != 0;
|
|
|
|
CreateContextPrivilegedAction action = new CreateContextPrivilegedAction (name, clientName, mech,_encryption,_signing,_delegation);
|
|
try {
|
|
_context = (GSSContext) Subject.doAs (subject,action);
|
|
}
|
|
catch (PrivilegedActionException e) {
|
|
throw new LdapException ("Problem performing token exchange with the server",LdapException.OTHER,"",e.getCause());
|
|
}
|
|
}
|
|
|
|
#endregion // Constructors
|
|
|
|
#region Properties
|
|
|
|
internal GSSContext Context
|
|
{
|
|
get { return _context; }
|
|
}
|
|
|
|
#endregion // Properties
|
|
|
|
#region Methods
|
|
|
|
public sbyte [] ExchangeTokens(sbyte [] clientToken)
|
|
{
|
|
if (Context.isEstablished ()) {
|
|
if (clientToken == null || clientToken.Length == 0)
|
|
return Krb5Helper.EmptyToken;
|
|
|
|
//final handshake
|
|
byte [] challengeData = (byte []) TypeUtils.ToByteArray (clientToken);
|
|
byte [] gssOutToken = Unwrap (challengeData, 0, challengeData.Length, new MessageProp (false));
|
|
|
|
QOP myCop = QOP.NO_PROTECTION;
|
|
|
|
if (_encryption)
|
|
myCop = QOP.PRIVACY_PROTECTION;
|
|
else if (_signing || (((QOP)gssOutToken [0] & QOP.INTEGRITY_ONLY_PROTECTION) != 0))
|
|
myCop = QOP.INTEGRITY_ONLY_PROTECTION;
|
|
|
|
if ((myCop & (QOP)gssOutToken [0]) == 0)
|
|
throw new LdapException ("Server does not support the requested security level", 80, "");
|
|
|
|
int srvMaxBufSize = SecureStream.NetworkByteOrderToInt (gssOutToken, 1, 3);
|
|
|
|
//int rawSendSize = Context.getWrapSizeLimit(0, _encryption, srvMaxBufSize);
|
|
|
|
byte [] gssInToken = new byte [4];
|
|
gssInToken [0] = (byte) myCop;
|
|
|
|
SecureStream.IntToNetworkByteOrder (srvMaxBufSize, gssInToken, 1, 3);
|
|
|
|
gssOutToken = Wrap (gssInToken, 0, gssInToken.Length, new MessageProp (true));
|
|
|
|
return TypeUtils.ToSByteArray (gssOutToken);
|
|
}
|
|
|
|
sbyte [] token = Context.initSecContext (clientToken, 0, clientToken.Length);
|
|
|
|
if (Context.isEstablished ()) {
|
|
|
|
if (Context.getConfState () != _encryption)
|
|
throw new LdapException ("Encryption protocol was not established layer between client and server", 80, "");
|
|
|
|
if (Context.getCredDelegState () != _delegation)
|
|
throw new LdapException ("Credential delegation was not established layer between client and server", 80, "");
|
|
|
|
if (_signing && (Context.getIntegState () != _signing))
|
|
throw new LdapException ("Signing protocol was not established layer between client and server", 80, "");
|
|
|
|
if (token == null)
|
|
return EmptyToken;
|
|
}
|
|
return token;
|
|
}
|
|
|
|
public byte [] Wrap(byte [] outgoing, int start, int len)
|
|
{
|
|
return Wrap (outgoing, start, len, new MessageProp(true));
|
|
}
|
|
|
|
public byte [] Wrap(byte [] outgoing, int start, int len, MessageProp messageProp)
|
|
{
|
|
if (!Context.isEstablished ())
|
|
throw new LdapException ("GSSAPI authentication not completed",LdapException.OTHER,"");
|
|
|
|
if (!(Context.getConfState () || Context.getIntegState ())) {
|
|
// in the case no encryption and no integrity required - return the original data
|
|
byte [] buff = new byte [len];
|
|
Array.Copy (outgoing, start, buff, 0, len);
|
|
return buff;
|
|
}
|
|
|
|
sbyte [] result = Context.wrap (TypeUtils.ToSByteArray (outgoing), start, len, messageProp);
|
|
return (byte []) TypeUtils.ToByteArray (result);
|
|
}
|
|
|
|
public byte [] Unwrap(byte [] incoming, int start, int len)
|
|
{
|
|
return Unwrap (incoming, start, len, new MessageProp(true));
|
|
}
|
|
|
|
public byte [] Unwrap(byte [] incoming, int start, int len, MessageProp messageProp)
|
|
{
|
|
if (!Context.isEstablished ())
|
|
throw new LdapException ("GSSAPI authentication not completed",LdapException.OTHER,"");
|
|
|
|
if (!(Context.getConfState () || Context.getIntegState ())) {
|
|
// in the case no encryption and no integrity required - return the original data
|
|
byte [] buff = new byte [len];
|
|
Array.Copy (incoming, start, buff, 0, len);
|
|
return buff;
|
|
}
|
|
|
|
sbyte [] result = Context.unwrap (TypeUtils.ToSByteArray (incoming), start, len, messageProp);
|
|
return (byte []) TypeUtils.ToByteArray (result);
|
|
}
|
|
|
|
#endregion // Methods
|
|
|
|
#region IDisposable Members
|
|
|
|
public void Dispose() {
|
|
Context.dispose();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|