github.com/jcmturner/gokrb5/v8@v8.4.4/pac/pac_type.go (about) 1 package pac 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "log" 8 9 "github.com/jcmturner/gokrb5/v8/crypto" 10 "github.com/jcmturner/gokrb5/v8/iana/keyusage" 11 "github.com/jcmturner/gokrb5/v8/types" 12 "github.com/jcmturner/rpc/v2/mstypes" 13 ) 14 15 const ( 16 infoTypeKerbValidationInfo uint32 = 1 17 infoTypeCredentials uint32 = 2 18 infoTypePACServerSignatureData uint32 = 6 19 infoTypePACKDCSignatureData uint32 = 7 20 infoTypePACClientInfo uint32 = 10 21 infoTypeS4UDelegationInfo uint32 = 11 22 infoTypeUPNDNSInfo uint32 = 12 23 infoTypePACClientClaimsInfo uint32 = 13 24 infoTypePACDeviceInfo uint32 = 14 25 infoTypePACDeviceClaimsInfo uint32 = 15 26 ) 27 28 // PACType implements: https://msdn.microsoft.com/en-us/library/cc237950.aspx 29 type PACType struct { 30 CBuffers uint32 31 Version uint32 32 Buffers []InfoBuffer 33 Data []byte 34 KerbValidationInfo *KerbValidationInfo 35 CredentialsInfo *CredentialsInfo 36 ServerChecksum *SignatureData 37 KDCChecksum *SignatureData 38 ClientInfo *ClientInfo 39 S4UDelegationInfo *S4UDelegationInfo 40 UPNDNSInfo *UPNDNSInfo 41 ClientClaimsInfo *ClientClaimsInfo 42 DeviceInfo *DeviceInfo 43 DeviceClaimsInfo *DeviceClaimsInfo 44 ZeroSigData []byte 45 } 46 47 // InfoBuffer implements the PAC Info Buffer: https://msdn.microsoft.com/en-us/library/cc237954.aspx 48 type InfoBuffer struct { 49 ULType uint32 // A 32-bit unsigned integer in little-endian format that describes the type of data present in the buffer contained at Offset. 50 CBBufferSize uint32 // A 32-bit unsigned integer in little-endian format that contains the size, in bytes, of the buffer in the PAC located at Offset. 51 Offset uint64 // A 64-bit unsigned integer in little-endian format that contains the offset to the beginning of the buffer, in bytes, from the beginning of the PACTYPE structure. The data offset MUST be a multiple of eight. The following sections specify the format of each type of element. 52 } 53 54 // Unmarshal bytes into the PACType struct 55 func (pac *PACType) Unmarshal(b []byte) (err error) { 56 pac.Data = b 57 zb := make([]byte, len(b), len(b)) 58 copy(zb, b) 59 pac.ZeroSigData = zb 60 r := mstypes.NewReader(bytes.NewReader(b)) 61 pac.CBuffers, err = r.Uint32() 62 if err != nil { 63 return 64 } 65 pac.Version, err = r.Uint32() 66 if err != nil { 67 return 68 } 69 buf := make([]InfoBuffer, pac.CBuffers, pac.CBuffers) 70 for i := range buf { 71 buf[i].ULType, err = r.Uint32() 72 if err != nil { 73 return 74 } 75 buf[i].CBBufferSize, err = r.Uint32() 76 if err != nil { 77 return 78 } 79 buf[i].Offset, err = r.Uint64() 80 if err != nil { 81 return 82 } 83 } 84 pac.Buffers = buf 85 return nil 86 } 87 88 // ProcessPACInfoBuffers processes the PAC Info Buffers. 89 // https://msdn.microsoft.com/en-us/library/cc237954.aspx 90 func (pac *PACType) ProcessPACInfoBuffers(key types.EncryptionKey, l *log.Logger) error { 91 for _, buf := range pac.Buffers { 92 p := make([]byte, buf.CBBufferSize, buf.CBBufferSize) 93 copy(p, pac.Data[int(buf.Offset):int(buf.Offset)+int(buf.CBBufferSize)]) 94 switch buf.ULType { 95 case infoTypeKerbValidationInfo: 96 if pac.KerbValidationInfo != nil { 97 //Must ignore subsequent buffers of this type 98 continue 99 } 100 var k KerbValidationInfo 101 err := k.Unmarshal(p) 102 if err != nil { 103 return fmt.Errorf("error processing KerbValidationInfo: %v", err) 104 } 105 pac.KerbValidationInfo = &k 106 case infoTypeCredentials: 107 // Currently PAC parsing is only useful on the service side in gokrb5 108 // The CredentialsInfo are only useful when gokrb5 has implemented RFC4556 and only applied on the client side. 109 // Skipping CredentialsInfo - will be revisited under RFC4556 implementation. 110 continue 111 //if pac.CredentialsInfo != nil { 112 // //Must ignore subsequent buffers of this type 113 // continue 114 //} 115 //var k CredentialsInfo 116 //err := k.Unmarshal(p, key) // The encryption key used is the AS reply key only available to the client. 117 //if err != nil { 118 // return fmt.Errorf("error processing CredentialsInfo: %v", err) 119 //} 120 //pac.CredentialsInfo = &k 121 case infoTypePACServerSignatureData: 122 if pac.ServerChecksum != nil { 123 //Must ignore subsequent buffers of this type 124 continue 125 } 126 var k SignatureData 127 zb, err := k.Unmarshal(p) 128 copy(pac.ZeroSigData[int(buf.Offset):int(buf.Offset)+int(buf.CBBufferSize)], zb) 129 if err != nil { 130 return fmt.Errorf("error processing ServerChecksum: %v", err) 131 } 132 pac.ServerChecksum = &k 133 case infoTypePACKDCSignatureData: 134 if pac.KDCChecksum != nil { 135 //Must ignore subsequent buffers of this type 136 continue 137 } 138 var k SignatureData 139 zb, err := k.Unmarshal(p) 140 copy(pac.ZeroSigData[int(buf.Offset):int(buf.Offset)+int(buf.CBBufferSize)], zb) 141 if err != nil { 142 return fmt.Errorf("error processing KDCChecksum: %v", err) 143 } 144 pac.KDCChecksum = &k 145 case infoTypePACClientInfo: 146 if pac.ClientInfo != nil { 147 //Must ignore subsequent buffers of this type 148 continue 149 } 150 var k ClientInfo 151 err := k.Unmarshal(p) 152 if err != nil { 153 return fmt.Errorf("error processing ClientInfo: %v", err) 154 } 155 pac.ClientInfo = &k 156 case infoTypeS4UDelegationInfo: 157 if pac.S4UDelegationInfo != nil { 158 //Must ignore subsequent buffers of this type 159 continue 160 } 161 var k S4UDelegationInfo 162 err := k.Unmarshal(p) 163 if err != nil { 164 l.Printf("could not process S4U_DelegationInfo: %v", err) 165 continue 166 } 167 pac.S4UDelegationInfo = &k 168 case infoTypeUPNDNSInfo: 169 if pac.UPNDNSInfo != nil { 170 //Must ignore subsequent buffers of this type 171 continue 172 } 173 var k UPNDNSInfo 174 err := k.Unmarshal(p) 175 if err != nil { 176 l.Printf("could not process UPN_DNSInfo: %v", err) 177 continue 178 } 179 pac.UPNDNSInfo = &k 180 case infoTypePACClientClaimsInfo: 181 if pac.ClientClaimsInfo != nil || len(p) < 1 { 182 //Must ignore subsequent buffers of this type 183 continue 184 } 185 var k ClientClaimsInfo 186 err := k.Unmarshal(p) 187 if err != nil { 188 l.Printf("could not process ClientClaimsInfo: %v", err) 189 continue 190 } 191 pac.ClientClaimsInfo = &k 192 case infoTypePACDeviceInfo: 193 if pac.DeviceInfo != nil { 194 //Must ignore subsequent buffers of this type 195 continue 196 } 197 var k DeviceInfo 198 err := k.Unmarshal(p) 199 if err != nil { 200 l.Printf("could not process DeviceInfo: %v", err) 201 continue 202 } 203 pac.DeviceInfo = &k 204 case infoTypePACDeviceClaimsInfo: 205 if pac.DeviceClaimsInfo != nil { 206 //Must ignore subsequent buffers of this type 207 continue 208 } 209 var k DeviceClaimsInfo 210 err := k.Unmarshal(p) 211 if err != nil { 212 l.Printf("could not process DeviceClaimsInfo: %v", err) 213 continue 214 } 215 pac.DeviceClaimsInfo = &k 216 } 217 } 218 219 if ok, err := pac.verify(key); !ok { 220 return err 221 } 222 223 return nil 224 } 225 226 func (pac *PACType) verify(key types.EncryptionKey) (bool, error) { 227 if pac.KerbValidationInfo == nil { 228 return false, errors.New("PAC Info Buffers does not contain a KerbValidationInfo") 229 } 230 if pac.ServerChecksum == nil { 231 return false, errors.New("PAC Info Buffers does not contain a ServerChecksum") 232 } 233 if pac.KDCChecksum == nil { 234 return false, errors.New("PAC Info Buffers does not contain a KDCChecksum") 235 } 236 if pac.ClientInfo == nil { 237 return false, errors.New("PAC Info Buffers does not contain a ClientInfo") 238 } 239 etype, err := crypto.GetChksumEtype(int32(pac.ServerChecksum.SignatureType)) 240 if err != nil { 241 return false, err 242 } 243 if ok := etype.VerifyChecksum(key.KeyValue, 244 pac.ZeroSigData, 245 pac.ServerChecksum.Signature, 246 keyusage.KERB_NON_KERB_CKSUM_SALT); !ok { 247 return false, errors.New("PAC service checksum verification failed") 248 } 249 250 return true, nil 251 }