Просмотр исходного кода

get etype ID from krberror for pre-auth

Jonathan Turner 8 лет назад
Родитель
Сommit
d06903dd81
1 измененных файлов с 58 добавлено и 5 удалено
  1. 58 5
      client/ASExchange.go

+ 58 - 5
client/ASExchange.go

@@ -2,13 +2,13 @@ package client
 
 import (
 	"gopkg.in/jcmturner/gokrb5.v2/crypto"
+	"gopkg.in/jcmturner/gokrb5.v2/crypto/etype"
 	"gopkg.in/jcmturner/gokrb5.v2/iana/errorcode"
 	"gopkg.in/jcmturner/gokrb5.v2/iana/keyusage"
 	"gopkg.in/jcmturner/gokrb5.v2/iana/patype"
 	"gopkg.in/jcmturner/gokrb5.v2/krberror"
 	"gopkg.in/jcmturner/gokrb5.v2/messages"
 	"gopkg.in/jcmturner/gokrb5.v2/types"
-	"sort"
 )
 
 // ASExchange performs an AS exchange for the client to retrieve a TGT.
@@ -83,10 +83,19 @@ func setPAData(cl *Client, krberr messages.KRBError, ASReq *messages.ASReq) erro
 		if err != nil {
 			return krberror.Errorf(err, krberror.KRBMsgError, "Error creating PAEncTSEnc for Pre-Authentication")
 		}
-		sort.Sort(sort.Reverse(sort.IntSlice(cl.Config.LibDefaults.DefaultTktEnctypeIDs)))
-		etype, err := crypto.GetEtype(cl.Config.LibDefaults.DefaultTktEnctypeIDs[0])
-		if err != nil {
-			return krberror.Errorf(err, krberror.EncryptingError, "Error creating etype")
+		var etype etype.EType
+		if krberr.ErrorCode == 0 {
+			// This is not in response to an error from the KDC. It is preemptive
+			etype, err = crypto.GetEtype(ASReq.ReqBody.EType[0]) // Take the first as preference
+			if err != nil {
+				return krberror.Errorf(err, krberror.EncryptingError, "error getting etype for pre-auth encryption")
+			}
+		} else {
+			// Get the etype to use from the PA data in the KRBError e-data
+			etype, err = preAuthEType(krberr)
+			if err != nil {
+				return krberror.Errorf(err, krberror.EncryptingError, "error getting etype for pre-auth encryption")
+			}
 		}
 		key, err := cl.Key(etype, krberr)
 		if err != nil {
@@ -108,3 +117,47 @@ func setPAData(cl *Client, krberr messages.KRBError, ASReq *messages.ASReq) erro
 	}
 	return nil
 }
+
+func preAuthEType(krberr messages.KRBError) (etype etype.EType, err error) {
+	//The preferred ordering of the "hint" pre-authentication data that
+	//affect client key selection is: ETYPE-INFO2, followed by ETYPE-INFO,
+	//followed by PW-SALT.
+	//A KDC SHOULD NOT send PA-PW-SALT when issuing a KRB-ERROR message
+	//that requests additional pre-authentication.  Implementation note:
+	//Some KDC implementations issue an erroneous PA-PW-SALT when issuing a
+	//KRB-ERROR message that requests additional pre-authentication.
+	//Therefore, clients SHOULD ignore a PA-PW-SALT accompanying a
+	//KRB-ERROR message that requests additional pre-authentication.
+	var etypeID int
+	var pas types.PADataSequence
+	e := pas.Unmarshal(krberr.EData)
+	if e != nil {
+		err = krberror.Errorf(e, krberror.EncodingError, "error unmashalling KRBError data")
+		return
+	}
+	for _, pa := range pas {
+		switch pa.PADataType {
+		case patype.PA_ETYPE_INFO2:
+			info, e := pa.GetETypeInfo2()
+			if e != nil {
+				err = krberror.Errorf(e, krberror.EncodingError, "error unmashalling ETYPE-INFO2 data")
+				return
+			}
+			etypeID = info[0].EType
+			break
+		case patype.PA_ETYPE_INFO:
+			info, e := pa.GetETypeInfo()
+			if e != nil {
+				err = krberror.Errorf(e, krberror.EncodingError, "error unmashalling ETYPE-INFO data")
+				return
+			}
+			etypeID = info[0].EType
+		}
+	}
+	etype, e = crypto.GetEtype(etypeID)
+	if e != nil {
+		err = krberror.Errorf(e, krberror.EncryptingError, "Error creating etype")
+		return
+	}
+	return etype, nil
+}