| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- package gssapi
- import (
- "encoding/binary"
- "encoding/hex"
- "fmt"
- "github.com/jcmturner/asn1"
- "gopkg.in/jcmturner/gokrb5.v2/asn1tools"
- "gopkg.in/jcmturner/gokrb5.v2/credentials"
- "gopkg.in/jcmturner/gokrb5.v2/crypto"
- "gopkg.in/jcmturner/gokrb5.v2/iana/chksumtype"
- "gopkg.in/jcmturner/gokrb5.v2/krberror"
- "gopkg.in/jcmturner/gokrb5.v2/messages"
- "gopkg.in/jcmturner/gokrb5.v2/types"
- )
- // GSSAPI MechToken IDs and flags.
- const (
- TOK_ID_KRB_AP_REQ = "0100"
- TOK_ID_KRB_AP_REP = "0200"
- TOK_ID_KRB_ERROR = "0300"
- GSS_C_DELEG_FLAG = 1
- GSS_C_MUTUAL_FLAG = 2
- GSS_C_REPLAY_FLAG = 4
- GSS_C_SEQUENCE_FLAG = 8
- GSS_C_CONF_FLAG = 16
- GSS_C_INTEG_FLAG = 32
- )
- // MechToken implementation for GSSAPI
- type MechToken struct {
- OID asn1.ObjectIdentifier
- TokID []byte
- APReq messages.APReq
- APRep messages.APRep
- KRBError messages.KRBError
- }
- // Unmarshal a MechToken
- func (m *MechToken) Unmarshal(b []byte) error {
- var oid asn1.ObjectIdentifier
- r, err := asn1.UnmarshalWithParams(b, &oid, fmt.Sprintf("application,explicit,tag:%v", 0))
- if err != nil {
- return fmt.Errorf("Error unmarshalling MechToken OID: %v", err)
- }
- m.OID = oid
- m.TokID = r[0:2]
- switch hex.EncodeToString(m.TokID) {
- case TOK_ID_KRB_AP_REQ:
- var a messages.APReq
- err = a.Unmarshal(r[2:])
- if err != nil {
- return fmt.Errorf("Error unmarshalling MechToken AP_REQ: %v", err)
- }
- m.APReq = a
- case TOK_ID_KRB_AP_REP:
- var a messages.APRep
- err = a.Unmarshal(r[2:])
- if err != nil {
- return fmt.Errorf("Error unmarshalling MechToken AP_REP: %v", err)
- }
- m.APRep = a
- case TOK_ID_KRB_ERROR:
- var a messages.KRBError
- err = a.Unmarshal(r[2:])
- if err != nil {
- return fmt.Errorf("Error unmarshalling MechToken KRBError: %v", err)
- }
- m.KRBError = a
- }
- return nil
- }
- // IsAPReq tests if the MechToken contains an AP_REQ
- func (m *MechToken) IsAPReq() bool {
- if hex.EncodeToString(m.TokID) == TOK_ID_KRB_AP_REQ {
- return true
- }
- return false
- }
- // IsAPRep tests if the MechToken contains an AP_REP
- func (m *MechToken) IsAPRep() bool {
- if hex.EncodeToString(m.TokID) == TOK_ID_KRB_AP_REP {
- return true
- }
- return false
- }
- // IsKRBError tests if the MechToken contains an KRB_ERROR
- func (m *MechToken) IsKRBError() bool {
- if hex.EncodeToString(m.TokID) == TOK_ID_KRB_ERROR {
- return true
- }
- return false
- }
- // NewKRB5APREQMechToken creates new kerberos AP_REQ MechToken
- func NewKRB5APREQMechToken(creds credentials.Credentials, tkt messages.Ticket, sessionKey types.EncryptionKey) ([]byte, error) {
- // Create the header
- b, _ := asn1.Marshal(MechTypeOIDKRB5)
- tb, _ := hex.DecodeString(TOK_ID_KRB_AP_REQ)
- b = append(b, tb...)
- // Add the token
- auth, err := newAuthenticator(creds, sessionKey.KeyType)
- if err != nil {
- return []byte{}, err
- }
- APReq, err := messages.NewAPReq(
- tkt,
- sessionKey,
- auth,
- )
- if err != nil {
- return []byte{}, err
- }
- tb, err = APReq.Marshal()
- if err != nil {
- return []byte{}, fmt.Errorf("Could not marshal AP_REQ: %v", err)
- }
- b = append(b, tb...)
- return asn1tools.AddASNAppTag(b, 0), nil
- }
- // Create new kerberos authenticator for kerberos MechToken
- func newAuthenticator(creds credentials.Credentials, keyType int) (types.Authenticator, error) {
- //RFC 4121 Section 4.1.1
- auth, err := types.NewAuthenticator(creds.Realm, creds.CName)
- if err != nil {
- return auth, krberror.Errorf(err, krberror.KRBMsgError, "Error generating new authenticator")
- }
- etype, err := crypto.GetEtype(keyType)
- if err != nil {
- return auth, krberror.Errorf(err, krberror.KRBMsgError, "Error generating new authenticator")
- }
- auth.GenerateSeqNumberAndSubKey(keyType, etype.GetKeyByteSize())
- auth.Cksum = types.Checksum{
- CksumType: chksumtype.GSSAPI,
- Checksum: newAuthenticatorChksum([]int{GSS_C_INTEG_FLAG, GSS_C_CONF_FLAG}),
- }
- return auth, nil
- }
- // Create new authenticator checksum for kerberos MechToken
- func newAuthenticatorChksum(flags []int) []byte {
- a := make([]byte, 24)
- binary.LittleEndian.PutUint32(a[:4], 16)
- for _, i := range flags {
- if i == GSS_C_DELEG_FLAG {
- x := make([]byte, 28-len(a))
- a = append(a, x...)
- }
- f := binary.LittleEndian.Uint32(a[20:24])
- f |= uint32(i)
- binary.LittleEndian.PutUint32(a[20:24], f)
- }
- return a
- }
- /*
- The authenticator checksum field SHALL have the following format:
- Octet Name Description
- -----------------------------------------------------------------
- 0..3 Lgth Number of octets in Bnd field; Represented
- in little-endian order; Currently contains
- hex value 10 00 00 00 (16).
- 4..19 Bnd Channel binding information, as described in
- section 4.1.1.2.
- 20..23 Flags Four-octet context-establishment flags in
- little-endian order as described in section
- 4.1.1.1.
- 24..25 DlgOpt The delegation option identifier (=1) in
- little-endian order [optional]. This field
- and the next two fields are present if and
- only if GSS_C_DELEG_FLAG is set as described
- in section 4.1.1.1.
- 26..27 Dlgth The length of the Deleg field in little-endian order [optional].
- 28..(n-1) Deleg A KRB_CRED message (n = Dlgth + 28) [optional].
- n..last Exts Extensions [optional].
- */
|