krb5Token.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package gssapi
  2. import (
  3. "encoding/binary"
  4. "encoding/hex"
  5. "fmt"
  6. "github.com/jcmturner/asn1"
  7. "gopkg.in/jcmturner/gokrb5.v2/asn1tools"
  8. "gopkg.in/jcmturner/gokrb5.v2/credentials"
  9. "gopkg.in/jcmturner/gokrb5.v2/crypto"
  10. "gopkg.in/jcmturner/gokrb5.v2/iana/chksumtype"
  11. "gopkg.in/jcmturner/gokrb5.v2/krberror"
  12. "gopkg.in/jcmturner/gokrb5.v2/messages"
  13. "gopkg.in/jcmturner/gokrb5.v2/types"
  14. )
  15. // GSSAPI MechToken IDs and flags.
  16. const (
  17. TOK_ID_KRB_AP_REQ = "0100"
  18. TOK_ID_KRB_AP_REP = "0200"
  19. TOK_ID_KRB_ERROR = "0300"
  20. GSS_C_DELEG_FLAG = 1
  21. GSS_C_MUTUAL_FLAG = 2
  22. GSS_C_REPLAY_FLAG = 4
  23. GSS_C_SEQUENCE_FLAG = 8
  24. GSS_C_CONF_FLAG = 16
  25. GSS_C_INTEG_FLAG = 32
  26. )
  27. // MechToken implementation for GSSAPI
  28. type MechToken struct {
  29. OID asn1.ObjectIdentifier
  30. TokID []byte
  31. APReq messages.APReq
  32. APRep messages.APRep
  33. KRBError messages.KRBError
  34. }
  35. // Unmarshal a MechToken
  36. func (m *MechToken) Unmarshal(b []byte) error {
  37. var oid asn1.ObjectIdentifier
  38. r, err := asn1.UnmarshalWithParams(b, &oid, fmt.Sprintf("application,explicit,tag:%v", 0))
  39. if err != nil {
  40. return fmt.Errorf("Error unmarshalling MechToken OID: %v", err)
  41. }
  42. m.OID = oid
  43. m.TokID = r[0:2]
  44. switch hex.EncodeToString(m.TokID) {
  45. case TOK_ID_KRB_AP_REQ:
  46. var a messages.APReq
  47. err = a.Unmarshal(r[2:])
  48. if err != nil {
  49. return fmt.Errorf("Error unmarshalling MechToken AP_REQ: %v", err)
  50. }
  51. m.APReq = a
  52. case TOK_ID_KRB_AP_REP:
  53. var a messages.APRep
  54. err = a.Unmarshal(r[2:])
  55. if err != nil {
  56. return fmt.Errorf("Error unmarshalling MechToken AP_REP: %v", err)
  57. }
  58. m.APRep = a
  59. case TOK_ID_KRB_ERROR:
  60. var a messages.KRBError
  61. err = a.Unmarshal(r[2:])
  62. if err != nil {
  63. return fmt.Errorf("Error unmarshalling MechToken KRBError: %v", err)
  64. }
  65. m.KRBError = a
  66. }
  67. return nil
  68. }
  69. // IsAPReq tests if the MechToken contains an AP_REQ
  70. func (m *MechToken) IsAPReq() bool {
  71. if hex.EncodeToString(m.TokID) == TOK_ID_KRB_AP_REQ {
  72. return true
  73. }
  74. return false
  75. }
  76. // IsAPRep tests if the MechToken contains an AP_REP
  77. func (m *MechToken) IsAPRep() bool {
  78. if hex.EncodeToString(m.TokID) == TOK_ID_KRB_AP_REP {
  79. return true
  80. }
  81. return false
  82. }
  83. // IsKRBError tests if the MechToken contains an KRB_ERROR
  84. func (m *MechToken) IsKRBError() bool {
  85. if hex.EncodeToString(m.TokID) == TOK_ID_KRB_ERROR {
  86. return true
  87. }
  88. return false
  89. }
  90. // NewKRB5APREQMechToken creates new kerberos AP_REQ MechToken
  91. func NewKRB5APREQMechToken(creds credentials.Credentials, tkt messages.Ticket, sessionKey types.EncryptionKey) ([]byte, error) {
  92. // Create the header
  93. b, _ := asn1.Marshal(MechTypeOIDKRB5)
  94. tb, _ := hex.DecodeString(TOK_ID_KRB_AP_REQ)
  95. b = append(b, tb...)
  96. // Add the token
  97. auth, err := newAuthenticator(creds, sessionKey.KeyType)
  98. if err != nil {
  99. return []byte{}, err
  100. }
  101. APReq, err := messages.NewAPReq(
  102. tkt,
  103. sessionKey,
  104. auth,
  105. )
  106. if err != nil {
  107. return []byte{}, err
  108. }
  109. tb, err = APReq.Marshal()
  110. if err != nil {
  111. return []byte{}, fmt.Errorf("Could not marshal AP_REQ: %v", err)
  112. }
  113. b = append(b, tb...)
  114. return asn1tools.AddASNAppTag(b, 0), nil
  115. }
  116. // Create new kerberos authenticator for kerberos MechToken
  117. func newAuthenticator(creds credentials.Credentials, keyType int) (types.Authenticator, error) {
  118. //RFC 4121 Section 4.1.1
  119. auth, err := types.NewAuthenticator(creds.Realm, creds.CName)
  120. if err != nil {
  121. return auth, krberror.Errorf(err, krberror.KRBMsgError, "Error generating new authenticator")
  122. }
  123. etype, err := crypto.GetEtype(keyType)
  124. if err != nil {
  125. return auth, krberror.Errorf(err, krberror.KRBMsgError, "Error generating new authenticator")
  126. }
  127. auth.GenerateSeqNumberAndSubKey(keyType, etype.GetKeyByteSize())
  128. auth.Cksum = types.Checksum{
  129. CksumType: chksumtype.GSSAPI,
  130. Checksum: newAuthenticatorChksum([]int{GSS_C_INTEG_FLAG, GSS_C_CONF_FLAG}),
  131. }
  132. return auth, nil
  133. }
  134. // Create new authenticator checksum for kerberos MechToken
  135. func newAuthenticatorChksum(flags []int) []byte {
  136. a := make([]byte, 24)
  137. binary.LittleEndian.PutUint32(a[:4], 16)
  138. for _, i := range flags {
  139. if i == GSS_C_DELEG_FLAG {
  140. x := make([]byte, 28-len(a))
  141. a = append(a, x...)
  142. }
  143. f := binary.LittleEndian.Uint32(a[20:24])
  144. f |= uint32(i)
  145. binary.LittleEndian.PutUint32(a[20:24], f)
  146. }
  147. return a
  148. }
  149. /*
  150. The authenticator checksum field SHALL have the following format:
  151. Octet Name Description
  152. -----------------------------------------------------------------
  153. 0..3 Lgth Number of octets in Bnd field; Represented
  154. in little-endian order; Currently contains
  155. hex value 10 00 00 00 (16).
  156. 4..19 Bnd Channel binding information, as described in
  157. section 4.1.1.2.
  158. 20..23 Flags Four-octet context-establishment flags in
  159. little-endian order as described in section
  160. 4.1.1.1.
  161. 24..25 DlgOpt The delegation option identifier (=1) in
  162. little-endian order [optional]. This field
  163. and the next two fields are present if and
  164. only if GSS_C_DELEG_FLAG is set as described
  165. in section 4.1.1.1.
  166. 26..27 Dlgth The length of the Deleg field in little-endian order [optional].
  167. 28..(n-1) Deleg A KRB_CRED message (n = Dlgth + 28) [optional].
  168. n..last Exts Extensions [optional].
  169. */