credentials_info.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. package pac
  2. import (
  3. "encoding/binary"
  4. "fmt"
  5. "gopkg.in/jcmturner/gokrb5.v2/crypto"
  6. "gopkg.in/jcmturner/gokrb5.v2/iana/keyusage"
  7. "gopkg.in/jcmturner/gokrb5.v2/mstypes"
  8. "gopkg.in/jcmturner/gokrb5.v2/ndr"
  9. "gopkg.in/jcmturner/gokrb5.v2/types"
  10. )
  11. // https://msdn.microsoft.com/en-us/library/cc237931.aspx
  12. // CredentialsInfo implements https://msdn.microsoft.com/en-us/library/cc237953.aspx
  13. type CredentialsInfo struct {
  14. Version uint32 // A 32-bit unsigned integer in little-endian format that defines the version. MUST be 0x00000000.
  15. EType uint32
  16. PACCredentialDataEncrypted []byte // Key usage number for encryption: KERB_NON_KERB_SALT (16)
  17. PACCredentialData CredentialData
  18. }
  19. // Unmarshal bytes into the CredentialsInfo struct
  20. func (c *CredentialsInfo) Unmarshal(b []byte, k types.EncryptionKey) error {
  21. ch, _, p, err := ndr.ReadHeaders(&b)
  22. if err != nil {
  23. return fmt.Errorf("Error parsing byte stream headers: %v", err)
  24. }
  25. e := &ch.Endianness
  26. //The next 4 bytes are an RPC unique pointer referent. We just skip these
  27. p += 4
  28. c.Version = ndr.ReadUint32(&b, &p, e)
  29. c.EType = ndr.ReadUint32(&b, &p, e)
  30. c.PACCredentialDataEncrypted = ndr.ReadBytes(&b, &p, len(b)-p, e)
  31. err = c.DecryptEncPart(k, e)
  32. if err != nil {
  33. return fmt.Errorf("Error decrypting PAC Credentials Data: %v", err)
  34. }
  35. return nil
  36. }
  37. // DecryptEncPart decrypts the encrypted part of the CredentialsInfo.
  38. func (c *CredentialsInfo) DecryptEncPart(k types.EncryptionKey, e *binary.ByteOrder) error {
  39. if k.KeyType != int(c.EType) {
  40. return fmt.Errorf("Key provided is not the correct type. Type needed: %d, type provided: %d", c.EType, k.KeyType)
  41. }
  42. pt, err := crypto.DecryptMessage(c.PACCredentialDataEncrypted, k, keyusage.KERB_NON_KERB_SALT)
  43. if err != nil {
  44. return err
  45. }
  46. var p int
  47. c.PACCredentialData = ReadPACCredentialData(&pt, &p, e)
  48. return nil
  49. }
  50. // CredentialData implements https://msdn.microsoft.com/en-us/library/cc237952.aspx
  51. // This structure is encrypted prior to being encoded in any other structures.
  52. // Encryption is performed by first serializing the data structure via Network Data Representation (NDR) encoding, as specified in [MS-RPCE].
  53. // Once serialized, the data is encrypted using the key and cryptographic system selected through the AS protocol and the KRB_AS_REP message
  54. // Fields (for capturing this information) and cryptographic parameters are specified in PAC_CREDENTIAL_INFO (section 2.6.1).
  55. type CredentialData struct {
  56. CredentialCount uint32
  57. Credentials []SECPKGSupplementalCred // Size is the value of CredentialCount
  58. }
  59. // ReadPACCredentialData reads a CredentialData from the byte slice.
  60. func ReadPACCredentialData(b *[]byte, p *int, e *binary.ByteOrder) CredentialData {
  61. c := ndr.ReadUint32(b, p, e)
  62. cr := make([]SECPKGSupplementalCred, c, c)
  63. for i := range cr {
  64. cr[i] = ReadSECPKGSupplementalCred(b, p, e)
  65. }
  66. return CredentialData{
  67. CredentialCount: c,
  68. Credentials: cr,
  69. }
  70. }
  71. // SECPKGSupplementalCred implements https://msdn.microsoft.com/en-us/library/cc237956.aspx
  72. type SECPKGSupplementalCred struct {
  73. PackageName mstypes.RPCUnicodeString
  74. CredentialSize uint32
  75. Credentials []uint8 // Is a ptr. Size is the value of CredentialSize
  76. }
  77. // ReadSECPKGSupplementalCred reads a SECPKGSupplementalCred from the byte slice.
  78. func ReadSECPKGSupplementalCred(b *[]byte, p *int, e *binary.ByteOrder) SECPKGSupplementalCred {
  79. n, _ := mstypes.ReadRPCUnicodeString(b, p, e)
  80. cs := ndr.ReadUint32(b, p, e)
  81. c := make([]uint8, cs, cs)
  82. for i := range c {
  83. c[i] = ndr.ReadUint8(b, p)
  84. }
  85. return SECPKGSupplementalCred{
  86. PackageName: n,
  87. CredentialSize: cs,
  88. Credentials: c,
  89. }
  90. }
  91. // NTLMSupplementalCred implements https://msdn.microsoft.com/en-us/library/cc237949.aspx
  92. type NTLMSupplementalCred struct {
  93. Version uint32 // A 32-bit unsigned integer that defines the credential version.This field MUST be 0x00000000.
  94. Flags uint32
  95. LMPassword []byte // A 16-element array of unsigned 8-bit integers that define the LM OWF. The LmPassword member MUST be ignored if the L flag is not set in the Flags member.
  96. NTPassword []byte // A 16-element array of unsigned 8-bit integers that define the NT OWF. The LtPassword member MUST be ignored if the N flag is not set in the Flags member.
  97. }
  98. // ReadNTLMSupplementalCred reads a NTLMSupplementalCred from the byte slice.
  99. func ReadNTLMSupplementalCred(b *[]byte, p *int, e *binary.ByteOrder) NTLMSupplementalCred {
  100. v := ndr.ReadUint32(b, p, e)
  101. f := ndr.ReadUint32(b, p, e)
  102. l := ndr.ReadBytes(b, p, 16, e)
  103. n := ndr.ReadBytes(b, p, 16, e)
  104. return NTLMSupplementalCred{
  105. Version: v,
  106. Flags: f,
  107. LMPassword: l,
  108. NTPassword: n,
  109. }
  110. }
  111. const (
  112. // NTLMSupCredLMOWF indicates that the LM OWF member is present and valid.
  113. NTLMSupCredLMOWF = 31
  114. // NTLMSupCredNTOWF indicates that the NT OWF member is present and valid.
  115. NTLMSupCredNTOWF = 30
  116. )