Skip to content

Commit

Permalink
Next step of NTLM refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
hierynomus committed May 12, 2023
1 parent 7794355 commit 5c37afa
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 41 deletions.
81 changes: 81 additions & 0 deletions src/main/java/com/hierynomus/ntlm/NtlmConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (C)2016 - SMBJ Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hierynomus.ntlm;

import com.hierynomus.ntlm.messages.WindowsVersion;
import com.hierynomus.ntlm.messages.WindowsVersion.NtlmRevisionCurrent;
import com.hierynomus.ntlm.messages.WindowsVersion.ProductMajorVersion;
import com.hierynomus.ntlm.messages.WindowsVersion.ProductMinorVersion;

public class NtlmConfig {
private WindowsVersion windowsVersion;
private String workstationName;

public static NtlmConfig defaultConfig() {
return builder().build();
}

public static Builder builder() {
return new Builder();
}

private NtlmConfig() {
}

private NtlmConfig(NtlmConfig other) {
this.windowsVersion = other.windowsVersion;
this.workstationName = other.workstationName;
}

public WindowsVersion getWindowsVersion() {
return windowsVersion;
}

public String getWorkstationName() {
return workstationName;
}

public static class Builder {
private NtlmConfig config;

public Builder() {
config = new NtlmConfig();
config.windowsVersion = new WindowsVersion(ProductMajorVersion.WINDOWS_MAJOR_VERSION_6, ProductMinorVersion.WINDOWS_MINOR_VERSION_1, 7600, NtlmRevisionCurrent.NTLMSSP_REVISION_W2K3);
}

public Builder withWindowsVersion(WindowsVersion windowsVersion) {
config.windowsVersion = windowsVersion;
return this;
}

public Builder withWorkstationName(String workstationName) {
config.workstationName = workstationName;
return this;
}

public Builder withIntegrity(boolean integrity) {
return this;
}

public Builder withOmitVersion(boolean omitVersion) {
return this;
}

public NtlmConfig build() {
return new NtlmConfig(config);
}
}
}
17 changes: 2 additions & 15 deletions src/main/java/com/hierynomus/ntlm/messages/NtlmNegotiate.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import com.hierynomus.protocol.commons.Charsets;
import com.hierynomus.protocol.commons.buffer.Buffer;

import java.util.EnumSet;
import java.util.Set;

import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.*;
Expand All @@ -27,21 +26,9 @@
* [MS-NLMP].pdf 2.2.1.1 NEGOTIATE_MESSAGE
*/
public class NtlmNegotiate extends NtlmMessage {
public static final Set<NtlmNegotiateFlag> DEFAULT_FLAGS = EnumSet.of(
NTLMSSP_NEGOTIATE_56,
NTLMSSP_NEGOTIATE_128,
NTLMSSP_NEGOTIATE_TARGET_INFO,
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY,
NTLMSSP_NEGOTIATE_SIGN,
NTLMSSP_NEGOTIATE_ALWAYS_SIGN,
NTLMSSP_NEGOTIATE_KEY_EXCH,
NTLMSSP_NEGOTIATE_NTLM,
NTLMSSP_NEGOTIATE_NTLM,
NTLMSSP_REQUEST_TARGET,
NTLMSSP_NEGOTIATE_UNICODE);

public NtlmNegotiate() {
super(DEFAULT_FLAGS, null);
public NtlmNegotiate(Set<NtlmNegotiateFlag> negotiateFlags) {
super(negotiateFlags, null);
}

public void write(Buffer.PlainBuffer buffer) {
Expand Down
62 changes: 49 additions & 13 deletions src/main/java/com/hierynomus/smbj/SmbConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,31 @@
*/
package com.hierynomus.smbj;

import static com.hierynomus.mssmb2.SMB2Dialect.SMB_2_0_2;
import static com.hierynomus.mssmb2.SMB2Dialect.SMB_2_1;
import static com.hierynomus.mssmb2.SMB2Dialect.SMB_3_0;
import static com.hierynomus.mssmb2.SMB2Dialect.SMB_3_0_2;
import static com.hierynomus.mssmb2.SMB2Dialect.SMB_3_1_1;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import javax.net.SocketFactory;

import com.hierynomus.mssmb2.SMB2Dialect;
import com.hierynomus.mssmb2.SMB2GlobalCapability;
import com.hierynomus.ntlm.NtlmConfig;
import com.hierynomus.protocol.commons.Factory;
import com.hierynomus.protocol.commons.socket.ProxySocketFactory;
import com.hierynomus.security.SecurityProvider;
import com.hierynomus.security.bc.BCSecurityProvider;
import com.hierynomus.security.jce.JceSecurityProvider;
import com.hierynomus.smb.SMBPacket;
import com.hierynomus.smb.SMBPacketData;
import com.hierynomus.smbj.auth.Authenticator;
Expand All @@ -30,13 +48,6 @@
import com.hierynomus.smbj.transport.TransportLayerFactory;
import com.hierynomus.smbj.transport.tcp.direct.DirectTcpTransportFactory;

import javax.net.SocketFactory;
import java.security.SecureRandom;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.hierynomus.mssmb2.SMB2Dialect.*;

public final class SmbConfig {
private static final int DEFAULT_BUFFER_SIZE = 1024 * 1024;

Expand Down Expand Up @@ -78,7 +89,7 @@ public final class SmbConfig {
private long transactTimeout;
private GSSContextConfig clientGSSContextConfig;
private boolean encryptData;
private String workStationName;
private NtlmConfig ntlmConfig;

private int soTimeout;

Expand All @@ -87,7 +98,7 @@ public static SmbConfig createDefaultConfig() {
}

public static Builder builder() {
return new Builder()
Builder b = new Builder()
.withClientGuid(UUID.randomUUID())
.withRandomProvider(new SecureRandom())
.withSecurityProvider(getDefaultSecurityProvider())
Expand All @@ -104,6 +115,8 @@ public static Builder builder() {
.withTimeout(DEFAULT_TIMEOUT, DEFAULT_TIMEOUT_UNIT)
.withClientGSSContextConfig(GSSContextConfig.createDefaultConfig())
.withEncryptData(false);

return b;
}

private static SecurityProvider getDefaultSecurityProvider() {
Expand Down Expand Up @@ -152,7 +165,7 @@ private SmbConfig(SmbConfig other) {
useMultiProtocolNegotiate = other.useMultiProtocolNegotiate;
clientGSSContextConfig = other.clientGSSContextConfig;
encryptData = other.encryptData;
workStationName = other.workStationName;
ntlmConfig = other.ntlmConfig;
}

public Random getRandomProvider() {
Expand Down Expand Up @@ -235,8 +248,17 @@ public boolean isEncryptData() {
return encryptData;
}

/**
* Get the work station name to be used in the NTLM authentication.
*
* @deprecated Moved into getNtlmConfig().getWorkStationName()
*/
public String getWorkStationName() {
return workStationName;
return getNtlmConfig().getWorkstationName();
}

public NtlmConfig getNtlmConfig() {
return ntlmConfig;
}

public Set<SMB2GlobalCapability> getClientCapabilities() {
Expand All @@ -255,9 +277,11 @@ public Set<SMB2GlobalCapability> getClientCapabilities() {

public static class Builder {
private SmbConfig config;
private NtlmConfig.Builder ntlmConfigBuilder;

Builder() {
config = new SmbConfig();
ntlmConfigBuilder = NtlmConfig.builder();
}

public Builder withRandomProvider(Random random) {
Expand Down Expand Up @@ -424,6 +448,8 @@ public SmbConfig build() {
throw new IllegalStateException("If encryption is enabled, at least one dialect should be SMB3.x compatible");
}

config.ntlmConfig = ntlmConfigBuilder.build();

return new SmbConfig(config);
}

Expand All @@ -450,9 +476,19 @@ public Builder withEncryptData(boolean encryptData) {
return this;
}

/**
* Set the workstation name to be used in the NTLM authentication.
*
* @deprecated Moved into
* withNtlmConfig(NtlmConfig.builder().withWorkstationName(..).build())
*/
public Builder withWorkStationName(String workStationName) {
config.workStationName = workStationName;
ntlmConfigBuilder.withWorkstationName(workStationName);
return this;
}

public NtlmConfig.Builder withNtlmConfig() {
return ntlmConfigBuilder;
}
}
}
45 changes: 33 additions & 12 deletions src/main/java/com/hierynomus/smbj/auth/NtlmAuthenticator.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,34 @@
*/
package com.hierynomus.smbj.auth;

import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_56;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_128;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_ANONYMOUS;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_KEY_EXCH;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_NTLM;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_SEAL;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_SIGN;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_TARGET_INFO;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_NEGOTIATE_UNICODE;
import static com.hierynomus.ntlm.messages.NtlmNegotiateFlag.NTLMSSP_REQUEST_TARGET;

import java.io.IOException;
import java.math.BigInteger;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hierynomus.asn1.types.primitive.ASN1ObjectIdentifier;
import com.hierynomus.msdtyp.MsDataTypes;
import com.hierynomus.ntlm.NtlmConfig;
import com.hierynomus.ntlm.av.AvId;
import com.hierynomus.ntlm.av.AvPairFlags;
import com.hierynomus.ntlm.functions.ComputedNtlmV2Response;
Expand All @@ -39,12 +52,7 @@
import com.hierynomus.ntlm.messages.NtlmChallenge;
import com.hierynomus.ntlm.messages.NtlmNegotiate;
import com.hierynomus.ntlm.messages.NtlmNegotiateFlag;
import com.hierynomus.ntlm.messages.WindowsVersion;
import com.hierynomus.ntlm.messages.WindowsVersion.NtlmRevisionCurrent;
import com.hierynomus.ntlm.messages.WindowsVersion.ProductMajorVersion;
import com.hierynomus.ntlm.messages.WindowsVersion.ProductMinorVersion;
import com.hierynomus.protocol.commons.ByteArrayUtils;
import com.hierynomus.protocol.commons.EnumWithValue;
import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.protocol.commons.buffer.Endian;
import com.hierynomus.security.SecurityProvider;
Expand All @@ -64,11 +72,12 @@ enum State { NEGOTIATE, AUTHENTICATE, COMPLETE };
private static final ASN1ObjectIdentifier NTLMSSP = new ASN1ObjectIdentifier("1.3.6.1.4.1.311.2.2.10");
private SecurityProvider securityProvider;
private Random random;
private String workStationName;
private NtlmV2Functions functions;
private NtlmConfig config;

// Context buildup
private State state;
private Set<NtlmNegotiateFlag> negotiateFlags;
private NtlmNegotiate negotiateMessage;

public static class Factory implements com.hierynomus.protocol.commons.Factory.Named<Authenticator> {
Expand Down Expand Up @@ -116,7 +125,20 @@ public AuthenticateResponse authenticate(final AuthenticationContext context, fi

private AuthenticateResponse doNegotiate(AuthenticationContext context, byte[] gssToken) throws SpnegoException {
AuthenticateResponse response = new AuthenticateResponse();
this.negotiateMessage = new NtlmNegotiate();
this.negotiateFlags = EnumSet.of(
NTLMSSP_NEGOTIATE_56,
NTLMSSP_NEGOTIATE_128,
NTLMSSP_NEGOTIATE_TARGET_INFO,
NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY,
NTLMSSP_NEGOTIATE_SIGN,
NTLMSSP_NEGOTIATE_ALWAYS_SIGN,
NTLMSSP_NEGOTIATE_KEY_EXCH,
NTLMSSP_NEGOTIATE_NTLM,
NTLMSSP_NEGOTIATE_NTLM,
NTLMSSP_REQUEST_TARGET,
NTLMSSP_NEGOTIATE_UNICODE);

this.negotiateMessage = new NtlmNegotiate(negotiateFlags);
logger.trace("Sending NTLM negotiate message: {}", this.negotiateMessage);
response.setNegToken(negTokenInit(this.negotiateMessage));
return response;
Expand Down Expand Up @@ -157,8 +179,6 @@ private AuthenticateResponse doAuthenticate(AuthenticationContext context, NtlmC
// If NTLM v2 is used, KeyExchangeKey MUST be set to the given 128-bit
// SessionBaseKey value.

WindowsVersion version = new WindowsVersion(ProductMajorVersion.WINDOWS_MAJOR_VERSION_6,
ProductMinorVersion.WINDOWS_MINOR_VERSION_1, 7600, NtlmRevisionCurrent.NTLMSSP_REVISION_W2K3);
// MIC (16 bytes) provided if in AvPairType is key MsvAvFlags with value &
// 0x00000002 is true
AvPairFlags pair = serverNtlmChallenge.getTargetInfo() != null
Expand All @@ -167,7 +187,7 @@ private AuthenticateResponse doAuthenticate(AuthenticationContext context, NtlmC
if (pair != null && (pair.getValue() & 0x00000002) > 0) {
// MIC should be calculated
NtlmAuthenticate resp = new NtlmAuthenticate(new byte[0], ntlmv2Response,
context.getUsername(), context.getDomain(), workStationName, sessionkey, negotiateFlags, version,
context.getUsername(), context.getDomain(), config.getWorkstationName(), sessionkey, negotiateFlags, config.getWindowsVersion(),
true);

// TODO correct hash should be tested
Expand All @@ -184,7 +204,7 @@ private AuthenticateResponse doAuthenticate(AuthenticationContext context, NtlmC
return response;
} else {
NtlmAuthenticate resp = new NtlmAuthenticate(new byte[0], ntlmv2Response,
context.getUsername(), context.getDomain(), workStationName, sessionkey, negotiateFlags, version,
context.getUsername(), context.getDomain(), config.getWorkstationName(), sessionkey, negotiateFlags, config.getWindowsVersion(),
false);
response.setNegToken(negTokenTarg(resp));
return response;
Expand Down Expand Up @@ -216,8 +236,9 @@ private byte[] negTokenTarg(NtlmAuthenticate resp) throws SpnegoException {
public void init(SmbConfig config) {
this.securityProvider = config.getSecurityProvider();
this.random = config.getRandomProvider();
this.workStationName = config.getWorkStationName();
this.config = config.getNtlmConfig();
this.state = State.NEGOTIATE;
this.negotiateFlags = new HashSet<>();
this.functions = new NtlmV2Functions(random, securityProvider);
}

Expand Down
Loading

0 comments on commit 5c37afa

Please sign in to comment.