github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/upstreamproxy/go-ntlm/ntlm/av_pairs.go (about) 1 //Copyright 2013 Thomson Reuters Global Resources. BSD License please see License file for more information 2 3 package ntlm 4 5 import ( 6 "bytes" 7 "encoding/binary" 8 "encoding/hex" 9 "errors" 10 "fmt" 11 ) 12 13 type AvPairType uint16 14 15 // MS-NLMP - 2.2.2.1 AV_PAIR 16 const ( 17 // Indicates that this is the last AV_PAIR in the list. AvLen MUST be 0. This type of information MUST be present in the AV pair list. 18 MsvAvEOL AvPairType = iota 19 // The server's NetBIOS computer name. The name MUST be in Unicode, and is not null-terminated. This type of information MUST be present in the AV_pair list. 20 MsvAvNbComputerName 21 // The server's NetBIOS domain name. The name MUST be in Unicode, and is not null-terminated. This type of information MUST be present in the AV_pair list. 22 MsvAvNbDomainName 23 // The fully qualified domain name (FQDN (1)) of the computer. The name MUST be in Unicode, and is not null-terminated. 24 MsvAvDnsComputerName 25 // The FQDN (2) of the domain. The name MUST be in Unicode, and is not null-terminate. 26 MsvAvDnsDomainName 27 // The FQDN (2) of the forest. The name MUST be in Unicode, and is not null-terminated.<11> 28 MsvAvDnsTreeName 29 // A 32-bit value indicating server or client configuration. 30 // 0x00000001: indicates to the client that the account authentication is constrained. 31 // 0x00000002: indicates that the client is providing message integrity in the MIC field (section 2.2.1.3) in the AUTHENTICATE_MESSAGE.<12> 32 // 0x00000004: indicates that the client is providing a target SPN generated from an untrusted source.<13> 33 MsvAvFlags 34 // A FILETIME structure ([MS-DTYP] section 2.3.1) in little-endian byte order that contains the server local time.<14> 35 MsvAvTimestamp 36 //A Restriction_Encoding (section 2.2.2.2) structure. The Value field contains a structure representing the integrity level of the security principal, as well as a MachineID created at computer startup to identify the calling machine.<15> 37 MsAvRestrictions 38 // The SPN of the target server. The name MUST be in Unicode and is not null-terminated.<16> 39 MsvAvTargetName 40 // annel bindings hash. The Value field contains an MD5 hash ([RFC4121] section 4.1.1.2) of a gss_channel_bindings_struct ([RFC2744] section 3.11). 41 // An all-zero value of the hash is used to indicate absence of channel bindings.<17> 42 MsvChannelBindings 43 ) 44 45 // Helper struct that contains a list of AvPairs with helper methods for running through them 46 type AvPairs struct { 47 List []AvPair 48 } 49 50 func (p *AvPairs) AddAvPair(avId AvPairType, bytes []byte) { 51 a := &AvPair{AvId: avId, AvLen: uint16(len(bytes)), Value: bytes} 52 p.List = append(p.List, *a) 53 } 54 55 func ReadAvPairs(data []byte) (*AvPairs, error) { 56 pairs := new(AvPairs) 57 58 // Get the number of AvPairs and allocate enough AvPair structures to hold them 59 offset := 0 60 for i := 0; len(data) > 0 && i < 11; i++ { 61 pair, err := ReadAvPair(data, offset) 62 if err != nil { 63 return nil, err 64 } 65 offset = offset + 4 + int(pair.AvLen) 66 pairs.List = append(pairs.List, *pair) 67 if pair.AvId == MsvAvEOL { 68 break 69 } 70 } 71 72 return pairs, nil 73 } 74 75 func (p *AvPairs) Bytes() (result []byte) { 76 totalLength := 0 77 for i := range p.List { 78 a := p.List[i] 79 totalLength = totalLength + int(a.AvLen) + 4 80 } 81 82 result = make([]byte, 0, totalLength) 83 for i := range p.List { 84 a := p.List[i] 85 result = append(result, a.Bytes()...) 86 } 87 88 return result 89 } 90 91 func (p *AvPairs) String() string { 92 var buffer bytes.Buffer 93 94 buffer.WriteString(fmt.Sprintf("Av Pairs (Total %d pairs)\n", len(p.List))) 95 96 for i := range p.List { 97 buffer.WriteString(p.List[i].String()) 98 buffer.WriteString("\n") 99 } 100 101 return buffer.String() 102 } 103 104 func (p *AvPairs) Find(avType AvPairType) (result *AvPair) { 105 for i := range p.List { 106 pair := p.List[i] 107 if avType == pair.AvId { 108 result = &pair 109 break 110 } 111 } 112 return 113 } 114 115 func (p *AvPairs) ByteValue(avType AvPairType) (result []byte) { 116 pair := p.Find(avType) 117 if pair != nil { 118 result = pair.Value 119 } 120 return 121 } 122 123 func (p *AvPairs) StringValue(avType AvPairType) (result string) { 124 pair := p.Find(avType) 125 if pair != nil { 126 result = pair.UnicodeStringValue() 127 } 128 return 129 } 130 131 // AvPair as described by MS-NLMP 132 type AvPair struct { 133 AvId AvPairType 134 AvLen uint16 135 Value []byte 136 } 137 138 func ReadAvPair(data []byte, offset int) (*AvPair, error) { 139 140 // [Psiphon] 141 // Don't panic on malformed remote input. 142 if len(data) < offset+4 { 143 return nil, errors.New("invalid AvPair") 144 } 145 146 pair := new(AvPair) 147 pair.AvId = AvPairType(binary.LittleEndian.Uint16(data[offset : offset+2])) 148 pair.AvLen = binary.LittleEndian.Uint16(data[offset+2 : offset+4]) 149 150 // [Psiphon] 151 // Don't panic on malformed remote input. 152 if len(data) < offset+4+int(pair.AvLen) { 153 return nil, errors.New("invalid AvPair") 154 } 155 156 pair.Value = data[offset+4 : offset+4+int(pair.AvLen)] 157 return pair, nil 158 } 159 160 func (a *AvPair) UnicodeStringValue() string { 161 return utf16ToString(a.Value) 162 } 163 164 func (a *AvPair) Bytes() (result []byte) { 165 result = make([]byte, 4, a.AvLen+4) 166 result[0] = byte(a.AvId) 167 result[1] = byte(a.AvId >> 8) 168 result[2] = byte(a.AvLen) 169 result[3] = byte(a.AvLen >> 8) 170 result = append(result, a.Value...) 171 return 172 } 173 174 func (a *AvPair) String() string { 175 var outString string 176 177 switch a.AvId { 178 case MsvAvEOL: 179 outString = "MsvAvEOL" 180 case MsvAvNbComputerName: 181 outString = "MsAvNbComputerName: " + a.UnicodeStringValue() 182 case MsvAvNbDomainName: 183 outString = "MsvAvNbDomainName: " + a.UnicodeStringValue() 184 case MsvAvDnsComputerName: 185 outString = "MsvAvDnsComputerName: " + a.UnicodeStringValue() 186 case MsvAvDnsDomainName: 187 outString = "MsvAvDnsDomainName: " + a.UnicodeStringValue() 188 case MsvAvDnsTreeName: 189 outString = "MsvAvDnsTreeName: " + a.UnicodeStringValue() 190 case MsvAvFlags: 191 outString = "MsvAvFlags: " + hex.EncodeToString(a.Value) 192 case MsvAvTimestamp: 193 outString = "MsvAvTimestamp: " + hex.EncodeToString(a.Value) 194 case MsAvRestrictions: 195 outString = "MsAvRestrictions: " + hex.EncodeToString(a.Value) 196 case MsvAvTargetName: 197 outString = "MsvAvTargetName: " + a.UnicodeStringValue() 198 case MsvChannelBindings: 199 outString = "MsvChannelBindings: " + hex.EncodeToString(a.Value) 200 default: 201 outString = fmt.Sprintf("unknown pair type: '%d'", a.AvId) 202 } 203 204 return outString 205 }