|
@@ -5,6 +5,7 @@ import (
|
|
|
"fmt"
|
|
"fmt"
|
|
|
"github.com/jcmturner/gokrb5/crypto"
|
|
"github.com/jcmturner/gokrb5/crypto"
|
|
|
"github.com/jcmturner/gokrb5/iana/errorcode"
|
|
"github.com/jcmturner/gokrb5/iana/errorcode"
|
|
|
|
|
+ "github.com/jcmturner/gokrb5/iana/keyusage"
|
|
|
"github.com/jcmturner/gokrb5/iana/patype"
|
|
"github.com/jcmturner/gokrb5/iana/patype"
|
|
|
"github.com/jcmturner/gokrb5/messages"
|
|
"github.com/jcmturner/gokrb5/messages"
|
|
|
"github.com/jcmturner/gokrb5/types"
|
|
"github.com/jcmturner/gokrb5/types"
|
|
@@ -16,70 +17,89 @@ func (cl *Client) ASExchange() error {
|
|
|
if !cl.IsConfigured() {
|
|
if !cl.IsConfigured() {
|
|
|
return errors.New("Client is not configured correctly.")
|
|
return errors.New("Client is not configured correctly.")
|
|
|
}
|
|
}
|
|
|
- a := messages.NewASReq(cl.Config, cl.Credentials.CName)
|
|
|
|
|
- b, err := a.Marshal()
|
|
|
|
|
|
|
+ ASReq := messages.NewASReq(cl.Config, cl.Credentials.CName)
|
|
|
|
|
+ err := setPAData(cl, &ASReq)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- return fmt.Errorf("Error marshalling AS_REQ: %v", err)
|
|
|
|
|
|
|
+ return fmt.Errorf("Error setting AS_REQ PAData: %v", err)
|
|
|
}
|
|
}
|
|
|
- rb, err := cl.SendToKDC(b)
|
|
|
|
|
|
|
+ b, err := ASReq.Marshal()
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- return fmt.Errorf("Error sending AS_REQ to KDC: %v", err)
|
|
|
|
|
|
|
+ return fmt.Errorf("Error marshalling AS_REQ: %v", err)
|
|
|
}
|
|
}
|
|
|
- var ar messages.ASRep
|
|
|
|
|
- err = ar.Unmarshal(rb)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ var ASRep messages.ASRep
|
|
|
|
|
+
|
|
|
|
|
+ rb, err := cl.SendToKDC(b)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- //A KRBError may have been returned instead.
|
|
|
|
|
- var krberr messages.KRBError
|
|
|
|
|
- err = krberr.Unmarshal(rb)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return fmt.Errorf("Could not unmarshal data returned from KDC: %v", err)
|
|
|
|
|
- }
|
|
|
|
|
- if krberr.ErrorCode == errorcode.KDC_ERR_PREAUTH_REQUIRED {
|
|
|
|
|
- paTSb, err := types.GetPAEncTSEncAsnMarshalled()
|
|
|
|
|
|
|
+ if e, ok := err.(messages.KRBError); ok && e.ErrorCode == errorcode.KDC_ERR_PREAUTH_REQUIRED {
|
|
|
|
|
+ // From now on assume this client will need to do this pre-auth and set the PAData
|
|
|
|
|
+ cl.GoKrb5Conf.Assume_PA_ENC_TIMESTAMP_Required = true
|
|
|
|
|
+ err = setPAData(cl, &ASReq)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- return fmt.Errorf("Error creating PAEncTSEnc for Pre-Authentication: %v", err)
|
|
|
|
|
|
|
+ return fmt.Errorf("Error setting AS_REQ PAData for pre-authentication required: %v", err)
|
|
|
}
|
|
}
|
|
|
- sort.Sort(sort.Reverse(sort.IntSlice(cl.Config.LibDefaults.Default_tkt_enctype_ids)))
|
|
|
|
|
- etype, err := crypto.GetEtype(cl.Config.LibDefaults.Default_tkt_enctype_ids[0])
|
|
|
|
|
|
|
+ b, err := ASReq.Marshal()
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- return fmt.Errorf("Error creating etype: %v", err)
|
|
|
|
|
|
|
+ return fmt.Errorf("Error marshalling AS_REQ with PAData: %v", err)
|
|
|
}
|
|
}
|
|
|
- //paEncTS, err := crypto.GetEncryptedData(paTSb, etype, cl.Config.LibDefaults.Default_realm, cl.Credentials.Username, cl.Credentials.Keytab, 1)
|
|
|
|
|
- key, err := cl.Credentials.Keytab.GetEncryptionKey(cl.Credentials.CName.NameString, cl.Config.LibDefaults.Default_realm, 1, etype.GetETypeID())
|
|
|
|
|
- paEncTS, err := crypto.GetEncryptedData(paTSb, key, 0, 1)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return fmt.Errorf("Error encrypting pre-authentication timestamp: %v", err)
|
|
|
|
|
- }
|
|
|
|
|
- pa := types.PAData{
|
|
|
|
|
- PADataType: patype.PA_ENC_TIMESTAMP,
|
|
|
|
|
- PADataValue: paEncTS.Cipher,
|
|
|
|
|
- }
|
|
|
|
|
- a.PAData = append(a.PAData, pa)
|
|
|
|
|
- b, err := a.Marshal()
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return fmt.Errorf("Error marshalling AS_REQ: %v", err)
|
|
|
|
|
- }
|
|
|
|
|
- rb, err := cl.SendToKDC(b)
|
|
|
|
|
|
|
+ rb, err = cl.SendToKDC(b)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return fmt.Errorf("Error sending AS_REQ to KDC: %v", err)
|
|
return fmt.Errorf("Error sending AS_REQ to KDC: %v", err)
|
|
|
}
|
|
}
|
|
|
- err = ar.Unmarshal(rb)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return fmt.Errorf("Could not unmarshal data returned from KDC: %v", err)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return fmt.Errorf("Error sending AS_REQ to KDC: %v", err)
|
|
|
}
|
|
}
|
|
|
- return krberr
|
|
|
|
|
}
|
|
}
|
|
|
- if ok, err := ar.IsValid(cl.Config, cl.Credentials, a); !ok {
|
|
|
|
|
|
|
+ err = ASRep.Unmarshal(rb)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("Could not unmarshal AS_REP data returned from KDC: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ if ok, err := ASRep.IsValid(cl.Config, cl.Credentials, ASReq); !ok {
|
|
|
return fmt.Errorf("AS_REP is not valid: %v", err)
|
|
return fmt.Errorf("AS_REP is not valid: %v", err)
|
|
|
}
|
|
}
|
|
|
cl.Session = &Session{
|
|
cl.Session = &Session{
|
|
|
- AuthTime: ar.DecryptedEncPart.AuthTime,
|
|
|
|
|
- EndTime: ar.DecryptedEncPart.EndTime,
|
|
|
|
|
- RenewTill: ar.DecryptedEncPart.RenewTill,
|
|
|
|
|
- TGT: ar.Ticket,
|
|
|
|
|
- SessionKey: ar.DecryptedEncPart.Key,
|
|
|
|
|
- SessionKeyExpiration: ar.DecryptedEncPart.KeyExpiration,
|
|
|
|
|
|
|
+ AuthTime: ASRep.DecryptedEncPart.AuthTime,
|
|
|
|
|
+ EndTime: ASRep.DecryptedEncPart.EndTime,
|
|
|
|
|
+ RenewTill: ASRep.DecryptedEncPart.RenewTill,
|
|
|
|
|
+ TGT: ASRep.Ticket,
|
|
|
|
|
+ SessionKey: ASRep.DecryptedEncPart.Key,
|
|
|
|
|
+ SessionKeyExpiration: ASRep.DecryptedEncPart.KeyExpiration,
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func setPAData(cl *Client, ASReq *messages.ASReq) error {
|
|
|
|
|
+ if !cl.GoKrb5Conf.Disable_PA_FX_FAST {
|
|
|
|
|
+ pa := types.PAData{PADataType: patype.PA_REQ_ENC_PA_REP}
|
|
|
|
|
+ ASReq.PAData = append(ASReq.PAData, pa)
|
|
|
|
|
+ }
|
|
|
|
|
+ if cl.GoKrb5Conf.Assume_PA_ENC_TIMESTAMP_Required {
|
|
|
|
|
+ paTSb, err := types.GetPAEncTSEncAsnMarshalled()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("Error creating PAEncTSEnc for Pre-Authentication: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ sort.Sort(sort.Reverse(sort.IntSlice(cl.Config.LibDefaults.Default_tkt_enctype_ids)))
|
|
|
|
|
+ etype, err := crypto.GetEtype(cl.Config.LibDefaults.Default_tkt_enctype_ids[0])
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("Error creating etype: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ key, err := cl.Credentials.Keytab.GetEncryptionKey(cl.Credentials.CName.NameString, cl.Config.LibDefaults.Default_realm, 1, etype.GetETypeID())
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("Error getting key from keytab in credentials: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ paEncTS, err := crypto.GetEncryptedData(paTSb, key, keyusage.AS_REQ_PA_ENC_TIMESTAMP, 1)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("Error encrypting pre-authentication timestamp: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ pb, err := paEncTS.Marshal()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("Error marshaling the PAEncTSEnc encrypted data: %v", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ pa := types.PAData{
|
|
|
|
|
+ PADataType: patype.PA_ENC_TIMESTAMP,
|
|
|
|
|
+ PADataValue: pb,
|
|
|
|
|
+ }
|
|
|
|
|
+ ASReq.PAData = append(ASReq.PAData, pa)
|
|
|
}
|
|
}
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|