mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-30 22:11:07 +00:00 
			
		
		
		
	* [Vendor] update go-ldap to v3.0.3 * update go-ldap to v3.2.4 Co-authored-by: techknowlogick <techknowlogick@gitea.io>
		
			
				
	
	
		
			183 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			183 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
| package ntlmssp
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"crypto/rand"
 | |
| 	"encoding/binary"
 | |
| 	"encoding/hex"
 | |
| 	"errors"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| type authenicateMessage struct {
 | |
| 	LmChallengeResponse []byte
 | |
| 	NtChallengeResponse []byte
 | |
| 
 | |
| 	TargetName string
 | |
| 	UserName   string
 | |
| 
 | |
| 	// only set if negotiateFlag_NTLMSSP_NEGOTIATE_KEY_EXCH
 | |
| 	EncryptedRandomSessionKey []byte
 | |
| 
 | |
| 	NegotiateFlags negotiateFlags
 | |
| 
 | |
| 	MIC []byte
 | |
| }
 | |
| 
 | |
| type authenticateMessageFields struct {
 | |
| 	messageHeader
 | |
| 	LmChallengeResponse varField
 | |
| 	NtChallengeResponse varField
 | |
| 	TargetName          varField
 | |
| 	UserName            varField
 | |
| 	Workstation         varField
 | |
| 	_                   [8]byte
 | |
| 	NegotiateFlags      negotiateFlags
 | |
| }
 | |
| 
 | |
| func (m authenicateMessage) MarshalBinary() ([]byte, error) {
 | |
| 	if !m.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEUNICODE) {
 | |
| 		return nil, errors.New("Only unicode is supported")
 | |
| 	}
 | |
| 
 | |
| 	target, user := toUnicode(m.TargetName), toUnicode(m.UserName)
 | |
| 	workstation := toUnicode("go-ntlmssp")
 | |
| 
 | |
| 	ptr := binary.Size(&authenticateMessageFields{})
 | |
| 	f := authenticateMessageFields{
 | |
| 		messageHeader:       newMessageHeader(3),
 | |
| 		NegotiateFlags:      m.NegotiateFlags,
 | |
| 		LmChallengeResponse: newVarField(&ptr, len(m.LmChallengeResponse)),
 | |
| 		NtChallengeResponse: newVarField(&ptr, len(m.NtChallengeResponse)),
 | |
| 		TargetName:          newVarField(&ptr, len(target)),
 | |
| 		UserName:            newVarField(&ptr, len(user)),
 | |
| 		Workstation:         newVarField(&ptr, len(workstation)),
 | |
| 	}
 | |
| 
 | |
| 	f.NegotiateFlags.Unset(negotiateFlagNTLMSSPNEGOTIATEVERSION)
 | |
| 
 | |
| 	b := bytes.Buffer{}
 | |
| 	if err := binary.Write(&b, binary.LittleEndian, &f); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if err := binary.Write(&b, binary.LittleEndian, &m.LmChallengeResponse); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if err := binary.Write(&b, binary.LittleEndian, &m.NtChallengeResponse); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if err := binary.Write(&b, binary.LittleEndian, &target); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if err := binary.Write(&b, binary.LittleEndian, &user); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	if err := binary.Write(&b, binary.LittleEndian, &workstation); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	return b.Bytes(), nil
 | |
| }
 | |
| 
 | |
| //ProcessChallenge crafts an AUTHENTICATE message in response to the CHALLENGE message
 | |
| //that was received from the server
 | |
| func ProcessChallenge(challengeMessageData []byte, user, password string) ([]byte, error) {
 | |
| 	if user == "" && password == "" {
 | |
| 		return nil, errors.New("Anonymous authentication not supported")
 | |
| 	}
 | |
| 
 | |
| 	var cm challengeMessage
 | |
| 	if err := cm.UnmarshalBinary(challengeMessageData); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATELMKEY) {
 | |
| 		return nil, errors.New("Only NTLM v2 is supported, but server requested v1 (NTLMSSP_NEGOTIATE_LM_KEY)")
 | |
| 	}
 | |
| 	if cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEKEYEXCH) {
 | |
| 		return nil, errors.New("Key exchange requested but not supported (NTLMSSP_NEGOTIATE_KEY_EXCH)")
 | |
| 	}
 | |
| 
 | |
| 	am := authenicateMessage{
 | |
| 		UserName:       user,
 | |
| 		TargetName:     cm.TargetName,
 | |
| 		NegotiateFlags: cm.NegotiateFlags,
 | |
| 	}
 | |
| 
 | |
| 	timestamp := cm.TargetInfo[avIDMsvAvTimestamp]
 | |
| 	if timestamp == nil { // no time sent, take current time
 | |
| 		ft := uint64(time.Now().UnixNano()) / 100
 | |
| 		ft += 116444736000000000 // add time between unix & windows offset
 | |
| 		timestamp = make([]byte, 8)
 | |
| 		binary.LittleEndian.PutUint64(timestamp, ft)
 | |
| 	}
 | |
| 
 | |
| 	clientChallenge := make([]byte, 8)
 | |
| 	rand.Reader.Read(clientChallenge)
 | |
| 
 | |
| 	ntlmV2Hash := getNtlmV2Hash(password, user, cm.TargetName)
 | |
| 
 | |
| 	am.NtChallengeResponse = computeNtlmV2Response(ntlmV2Hash,
 | |
| 		cm.ServerChallenge[:], clientChallenge, timestamp, cm.TargetInfoRaw)
 | |
| 
 | |
| 	if cm.TargetInfoRaw == nil {
 | |
| 		am.LmChallengeResponse = computeLmV2Response(ntlmV2Hash,
 | |
| 			cm.ServerChallenge[:], clientChallenge)
 | |
| 	}
 | |
| 	return am.MarshalBinary()
 | |
| }
 | |
| 
 | |
| func ProcessChallengeWithHash(challengeMessageData []byte, user, hash string) ([]byte, error) {
 | |
| 	if user == "" && hash == "" {
 | |
| 		return nil, errors.New("Anonymous authentication not supported")
 | |
| 	}
 | |
| 
 | |
| 	var cm challengeMessage
 | |
| 	if err := cm.UnmarshalBinary(challengeMessageData); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	if cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATELMKEY) {
 | |
| 		return nil, errors.New("Only NTLM v2 is supported, but server requested v1 (NTLMSSP_NEGOTIATE_LM_KEY)")
 | |
| 	}
 | |
| 	if cm.NegotiateFlags.Has(negotiateFlagNTLMSSPNEGOTIATEKEYEXCH) {
 | |
| 		return nil, errors.New("Key exchange requested but not supported (NTLMSSP_NEGOTIATE_KEY_EXCH)")
 | |
| 	}
 | |
| 
 | |
| 	am := authenicateMessage{
 | |
| 		UserName:       user,
 | |
| 		TargetName:     cm.TargetName,
 | |
| 		NegotiateFlags: cm.NegotiateFlags,
 | |
| 	}
 | |
| 
 | |
| 	timestamp := cm.TargetInfo[avIDMsvAvTimestamp]
 | |
| 	if timestamp == nil { // no time sent, take current time
 | |
| 		ft := uint64(time.Now().UnixNano()) / 100
 | |
| 		ft += 116444736000000000 // add time between unix & windows offset
 | |
| 		timestamp = make([]byte, 8)
 | |
| 		binary.LittleEndian.PutUint64(timestamp, ft)
 | |
| 	}
 | |
| 
 | |
| 	clientChallenge := make([]byte, 8)
 | |
| 	rand.Reader.Read(clientChallenge)
 | |
| 
 | |
| 	hashParts := strings.Split(hash, ":")
 | |
| 	if len(hashParts) > 1 {
 | |
| 		hash = hashParts[1]
 | |
| 	}
 | |
| 	hashBytes, err := hex.DecodeString(hash)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	ntlmV2Hash := hmacMd5(hashBytes, toUnicode(strings.ToUpper(user)+cm.TargetName))
 | |
| 
 | |
| 	am.NtChallengeResponse = computeNtlmV2Response(ntlmV2Hash,
 | |
| 		cm.ServerChallenge[:], clientChallenge, timestamp, cm.TargetInfoRaw)
 | |
| 
 | |
| 	if cm.TargetInfoRaw == nil {
 | |
| 		am.LmChallengeResponse = computeLmV2Response(ntlmV2Hash,
 | |
| 			cm.ServerChallenge[:], clientChallenge)
 | |
| 	}
 | |
| 	return am.MarshalBinary()
 | |
| }
 |