Browse Source

error handling

Jonathan Turner 9 years ago
parent
commit
576d25610f

+ 14 - 14
client/ASExchange.go

@@ -2,11 +2,11 @@ package client
 
 import (
 	"errors"
-	"fmt"
 	"github.com/jcmturner/gokrb5/crypto"
 	"github.com/jcmturner/gokrb5/iana/errorcode"
 	"github.com/jcmturner/gokrb5/iana/keyusage"
 	"github.com/jcmturner/gokrb5/iana/patype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/messages"
 	"github.com/jcmturner/gokrb5/types"
 	"sort"
@@ -20,11 +20,11 @@ func (cl *Client) ASExchange() error {
 	ASReq := messages.NewASReq(cl.Config, cl.Credentials.CName)
 	err := setPAData(cl, &ASReq)
 	if err != nil {
-		return fmt.Errorf("Error setting AS_REQ PAData: %v", err)
+		return krberror.Errorf(err, krberror.KRBMSG_ERROR, "AS Exchange Error: failed setting AS_REQ PAData")
 	}
 	b, err := ASReq.Marshal()
 	if err != nil {
-		return fmt.Errorf("Error marshalling AS_REQ: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "AS Exchange Error: failed marshaling AS_REQ")
 	}
 
 	var ASRep messages.ASRep
@@ -36,26 +36,26 @@ func (cl *Client) ASExchange() error {
 			cl.GoKrb5Conf.Assume_PA_ENC_TIMESTAMP_Required = true
 			err = setPAData(cl, &ASReq)
 			if err != nil {
-				return fmt.Errorf("Error setting AS_REQ PAData for pre-authentication required: %v", err)
+				return krberror.Errorf(err, krberror.KRBMSG_ERROR, "AS Exchange Error: failed setting AS_REQ PAData for pre-authentication required")
 			}
 			b, err := ASReq.Marshal()
 			if err != nil {
-				return fmt.Errorf("Error marshalling AS_REQ with PAData: %v", err)
+				return krberror.Errorf(err, krberror.ENCODING_ERROR, "AS Exchange Error: failed marshaling AS_REQ with PAData")
 			}
 			rb, err = cl.SendToKDC(b)
 			if err != nil {
-				return fmt.Errorf("Error sending AS_REQ to KDC: %v", err)
+				return krberror.Errorf(err, krberror.NETWORKING_ERROR, "AS Exchange Error: failed sending AS_REQ to KDC")
 			}
 		} else {
-			return fmt.Errorf("Error sending AS_REQ to KDC: %v", err)
+			return krberror.Errorf(err, krberror.NETWORKING_ERROR, "AS Exchange Error: failed sending AS_REQ to KDC")
 		}
 	}
 	err = ASRep.Unmarshal(rb)
 	if err != nil {
-		return fmt.Errorf("Could not unmarshal AS_REP data returned from KDC: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "AS Exchange Error: failed to process the AS_REP")
 	}
 	if ok, err := ASRep.IsValid(cl.Config, cl.Credentials, ASReq); !ok {
-		return fmt.Errorf("AS_REP is not valid: %v", err)
+		return krberror.Errorf(err, krberror.KRBMSG_ERROR, "AS Exchange Error: AS_REP is not valid")
 	}
 	cl.Session = &Session{
 		AuthTime:             ASRep.DecryptedEncPart.AuthTime,
@@ -76,24 +76,24 @@ func setPAData(cl *Client, ASReq *messages.ASReq) error {
 	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)
+			return krberror.Errorf(err, krberror.KRBMSG_ERROR, "Error creating PAEncTSEnc for Pre-Authentication")
 		}
 		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)
+			return krberror.Errorf(err, krberror.ENCRYPTING_ERROR, "Error creating etype")
 		}
 		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)
+			return krberror.Errorf(err, krberror.ENCRYPTING_ERROR, "Error getting key from keytab in credentials")
 		}
 		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)
+			return krberror.Errorf(err, krberror.ENCRYPTING_ERROR, "Error encrypting pre-authentication timestamp")
 		}
 		pb, err := paEncTS.Marshal()
 		if err != nil {
-			return fmt.Errorf("Error marshaling the PAEncTSEnc encrypted data: %v", err)
+			return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error marshaling the PAEncTSEnc encrypted data")
 		}
 		pa := types.PAData{
 			PADataType:  patype.PA_ENC_TIMESTAMP,

+ 8 - 8
client/TGSExchange.go

@@ -2,8 +2,8 @@ package client
 
 import (
 	"errors"
-	"fmt"
 	"github.com/jcmturner/gokrb5/iana/nametype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/messages"
 	"github.com/jcmturner/gokrb5/types"
 	"strings"
@@ -14,30 +14,30 @@ import (
 // The ticket retrieved is added to the client's cache.
 func (cl *Client) TGSExchange(spn types.PrincipalName, tkt messages.Ticket, sessionKey types.EncryptionKey, renewal bool) (tgsReq messages.TGSReq, tgsRep messages.TGSRep, err error) {
 	if cl.Session == nil {
-		return tgsReq, tgsRep, errors.New("Error client does not have a session. Client needs to login first")
+		return tgsReq, tgsRep, errors.New("TGS Exchange Error: client does not have a session. Client needs to login first")
 	}
 	tgsReq, err = messages.NewTGSReq(cl.Credentials.CName, cl.Config, tkt, sessionKey, spn, renewal)
 	if err != nil {
-		return tgsReq, tgsRep, fmt.Errorf("Error generating New TGS_REQ: %v", err)
+		return tgsReq, tgsRep, krberror.Errorf(err, krberror.KRBMSG_ERROR, "TGS Exchange Error: failed to generate a new TGS_REQ")
 	}
 	b, err := tgsReq.Marshal()
 	if err != nil {
-		return tgsReq, tgsRep, fmt.Errorf("Error marshalling TGS_REQ: %v", err)
+		return tgsReq, tgsRep, krberror.Errorf(err, krberror.ENCODING_ERROR, "TGS Exchange Error: failed to generate a new TGS_REQ")
 	}
 	r, err := cl.SendToKDC(b)
 	if err != nil {
-		return tgsReq, tgsRep, fmt.Errorf("Error sending TGS_REQ to KDC: %v", err)
+		return tgsReq, tgsRep, krberror.Errorf(err, krberror.NETWORKING_ERROR, "TGS Exchange Error: issue sending TGS_REQ to KDC")
 	}
 	err = tgsRep.Unmarshal(r)
 	if err != nil {
-		return tgsReq, tgsRep, fmt.Errorf("Error unmarshalling TGS_REP: %v", err)
+		return tgsReq, tgsRep, krberror.Errorf(err, krberror.ENCODING_ERROR, "TGS Exchange Error: failed to process the TGS_REP")
 	}
 	err = tgsRep.DecryptEncPart(sessionKey)
 	if err != nil {
-		return tgsReq, tgsRep, fmt.Errorf("Error decrypting EncPart of TGS_REP: %v", err)
+		return tgsReq, tgsRep, krberror.Errorf(err, krberror.ENCODING_ERROR, "TGS Exchange Error: failed to process the TGS_REP")
 	}
 	if ok, err := tgsRep.IsValid(cl.Config, tgsReq); !ok {
-		return tgsReq, tgsRep, fmt.Errorf("TGS_REP is not valid: %v", err)
+		return tgsReq, tgsRep, krberror.Errorf(err, krberror.ENCODING_ERROR, "TGS Exchange Error: TGS_REP is not valid")
 	}
 	return tgsReq, tgsRep, nil
 }

+ 2 - 1
client/http.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"github.com/jcmturner/gokrb5/credentials"
 	"github.com/jcmturner/gokrb5/gssapi"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/messages"
 	"github.com/jcmturner/gokrb5/types"
 	"net/http"
@@ -32,7 +33,7 @@ func SetSPNEGOHeader(creds credentials.Credentials, tkt messages.Ticket, session
 	SPNEGOToken, err := gssapi.GetSPNEGOKrbNegTokenInit(creds, tkt, sessionKey)
 	nb, err := SPNEGOToken.Marshal()
 	if err != nil {
-		return fmt.Errorf("Could marshal SPNEGO: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Could marshal SPNEGO")
 	}
 	hs := "Negotiate " + base64.StdEncoding.EncodeToString(nb)
 	r.Header.Set("Authorization", hs)

+ 2 - 1
client/session.go

@@ -2,6 +2,7 @@ package client
 
 import (
 	"github.com/jcmturner/gokrb5/iana/nametype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/messages"
 	"github.com/jcmturner/gokrb5/types"
 	"time"
@@ -41,7 +42,7 @@ func (cl *Client) RenewTGT() error {
 	}
 	_, tgsRep, err := cl.TGSExchange(spn, cl.Session.TGT, cl.Session.SessionKey, true)
 	if err != nil {
-		return err
+		return krberror.Errorf(err, krberror.KRBMSG_ERROR, "Error renewing TGT")
 	}
 	cl.Session = &Session{
 		AuthTime:             tgsRep.DecryptedEncPart.AuthTime,

+ 2 - 5
crypto/crypto.go

@@ -64,7 +64,7 @@ func GetKeyFromPassword(passwd string, cname types.PrincipalName, realm string,
 			var eti types.ETypeInfo
 			err := eti.Unmarshal(pa.PADataValue)
 			if err != nil {
-				return key, et, fmt.Errorf("Error unmashalling PA Data to PA-ETYPE-INFO2: %v", err)
+				return key, et, fmt.Errorf("Error unmashaling PA Data to PA-ETYPE-INFO2: %v", err)
 			}
 			if etypeID != eti[0].EType {
 				et, err = GetEtype(eti[0].EType)
@@ -181,12 +181,9 @@ func DecryptBytes(ed []byte, key types.EncryptionKey, usage uint32) ([]byte, err
 	}
 	//Verify checksum
 	if !et.VerifyIntegrity(key.KeyValue, ed, b, usage) {
-		return nil, errors.New("Error decrypting encrypted part: integrity verification failed")
+		return nil, errors.New("Error decrypting: integrity verification failed")
 	}
 	//Remove the confounder bytes
 	b = b[et.GetConfounderByteSize():]
-	if err != nil {
-		return nil, fmt.Errorf("Error decrypting encrypted part: %v", err)
-	}
 	return b, nil
 }

+ 52 - 0
krberror/error.go

@@ -0,0 +1,52 @@
+package krberror
+
+import (
+	"fmt"
+	"strings"
+)
+
+const (
+	SEPARATOR        = " < "
+	ENCODING_ERROR   = "Encoding_Error"
+	NETWORKING_ERROR = "Networking_Error"
+	DECRYPTING_ERROR = "Decrypting_Error"
+	ENCRYPTING_ERROR = "Encrypting_Error"
+	CHKSUM_ERROR     = "Checksum_Error"
+	KRBMSG_ERROR     = "KRBMessage_Handling_Error"
+)
+
+type krberror struct {
+	RootCause string
+	EText     []string
+}
+
+func (e krberror) Error() string {
+	return fmt.Sprintf("[Root cause: %s] ", e.RootCause) + strings.Join(e.EText, SEPARATOR)
+}
+
+func (e *krberror) Add2(et string, s string) {
+	e.EText = append([]string{fmt.Sprintf("%s: %s", et, s)}, e.EText...)
+}
+
+func NewKrberror(et, s string) krberror {
+	return krberror{
+		RootCause: et,
+		EText:     []string{s},
+	}
+}
+
+func Errorf(err error, et, format string, a ...interface{}) krberror {
+	if e, ok := err.(krberror); ok {
+		e.EText = append([]string{fmt.Sprintf("%s: "+format, et, a)}, e.EText...)
+		return e
+	} else {
+		return NewErrorf(et, format+": %v", a, err)
+	}
+}
+
+func NewErrorf(et, format string, a ...interface{}) krberror {
+	return krberror{
+		RootCause: et,
+		EText:     []string{fmt.Sprintf("%s: %s", et, fmt.Sprintf(format, a))},
+	}
+}

+ 5 - 4
messages/APRep.go

@@ -5,6 +5,7 @@ import (
 	"github.com/jcmturner/asn1"
 	"github.com/jcmturner/gokrb5/iana/asnAppTag"
 	"github.com/jcmturner/gokrb5/iana/msgtype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/types"
 	"time"
 )
@@ -43,20 +44,20 @@ type EncAPRepPart struct {
 func (a *APRep) Unmarshal(b []byte) error {
 	_, err := asn1.UnmarshalWithParams(b, a, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.APREP))
 	if err != nil {
-		return processReplyError(b, err)
+		return processUnmarshalReplyError(b, err)
 	}
 	expectedMsgType := msgtype.KRB_AP_REP
 	if a.MsgType != expectedMsgType {
-		return fmt.Errorf("Message ID does not indicate a KRB_AP_REP. Expected: %v; Actual: %v", expectedMsgType, a.MsgType)
+		return krberror.NewErrorf(krberror.KRBMSG_ERROR, "Message ID does not indicate a KRB_AP_REP. Expected: %v; Actual: %v", expectedMsgType, a.MsgType)
 	}
 	return nil
 }
 
-// Unmarshal bytes b into the APRep encryoted part struct.
+// Unmarshal bytes b into the APRep encrypted part struct.
 func (a *EncAPRepPart) Unmarshal(b []byte) error {
 	_, err := asn1.UnmarshalWithParams(b, a, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncAPRepPart))
 	if err != nil {
-		return err
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "AP_REP unmarshal error")
 	}
 	return nil
 }

+ 12 - 8
messages/APReq.go

@@ -1,7 +1,6 @@
 package messages
 
 import (
-	"errors"
 	"fmt"
 	"github.com/jcmturner/asn1"
 	"github.com/jcmturner/gokrb5/asn1tools"
@@ -11,6 +10,7 @@ import (
 	"github.com/jcmturner/gokrb5/iana/keyusage"
 	"github.com/jcmturner/gokrb5/iana/msgtype"
 	"github.com/jcmturner/gokrb5/iana/nametype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/types"
 )
 
@@ -50,7 +50,7 @@ func NewAPReq(tkt Ticket, sessionKey types.EncryptionKey, auth types.Authenticat
 	var a APReq
 	ed, err := encryptAuthenticator(auth, sessionKey, tkt)
 	if err != nil {
-		return a, fmt.Errorf("Error creating authenticator for AP_REQ: %v", err)
+		return a, krberror.Errorf(err, krberror.KRBMSG_ERROR, "Error creating Authenticator for AP_REQ")
 	}
 	a = APReq{
 		PVNO:          iana.PVNO,
@@ -67,7 +67,7 @@ func encryptAuthenticator(a types.Authenticator, sessionKey types.EncryptionKey,
 	var ed types.EncryptedData
 	m, err := a.Marshal()
 	if err != nil {
-		return ed, fmt.Errorf("Error marshalling authenticator: %v", err)
+		return ed, krberror.Errorf(err, krberror.ENCODING_ERROR, "Marshaling error of EncryptedData form of Authenticator")
 	}
 	var usage int
 	switch tkt.SName.NameType {
@@ -76,7 +76,11 @@ func encryptAuthenticator(a types.Authenticator, sessionKey types.EncryptionKey,
 	case nametype.KRB_NT_SRV_INST:
 		usage = keyusage.TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR
 	}
-	return crypto.GetEncryptedData(m, sessionKey, uint32(usage), tkt.EncPart.KVNO)
+	ed, err = crypto.GetEncryptedData(m, sessionKey, uint32(usage), tkt.EncPart.KVNO)
+	if err != nil {
+		return ed, krberror.Errorf(err, krberror.ENCRYPTING_ERROR, "Error encrypting Authenticator")
+	}
+	return ed, nil
 }
 
 // Unmarshal bytes b into the APReq struct.
@@ -84,10 +88,10 @@ func (a *APReq) Unmarshal(b []byte) error {
 	var m marshalAPReq
 	_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.APREQ))
 	if err != nil {
-		return err
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Unmarshal error of AP_REQ")
 	}
 	if m.MsgType != msgtype.KRB_AP_REQ {
-		return errors.New("Message ID does not indicate a KRB_AS_REP")
+		return krberror.NewErrorf(krberror.KRBMSG_ERROR, "Message ID does not indicate an AP_REQ. Expected: %v; Actual: %v", msgtype.KRB_AP_REQ, m.MsgType)
 	}
 	a.PVNO = m.PVNO
 	a.MsgType = m.MsgType
@@ -95,7 +99,7 @@ func (a *APReq) Unmarshal(b []byte) error {
 	a.Authenticator = m.Authenticator
 	a.Ticket, err = UnmarshalTicket(m.Ticket.Bytes)
 	if err != nil {
-		return fmt.Errorf("Error unmarshalling ticket in AP_REQ; %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Unmarshaling error of Ticket within AP_REQ")
 	}
 	return nil
 }
@@ -121,7 +125,7 @@ func (a *APReq) Marshal() ([]byte, error) {
 	}
 	mk, err := asn1.Marshal(m)
 	if err != nil {
-		return mk, fmt.Errorf("Error marshalling AP_REQ: %v", err)
+		return mk, krberror.Errorf(err, krberror.ENCODING_ERROR, "Marshaling error of AP_REQ")
 	}
 	mk = asn1tools.AddASNAppTag(mk, asnAppTag.APREQ)
 	return mk, nil

+ 43 - 41
messages/KDCRep.go

@@ -4,7 +4,6 @@ package messages
 // Section: 5.4.2
 
 import (
-	"errors"
 	"fmt"
 	"github.com/jcmturner/asn1"
 	"github.com/jcmturner/gokrb5/config"
@@ -16,6 +15,7 @@ import (
 	"github.com/jcmturner/gokrb5/iana/keyusage"
 	"github.com/jcmturner/gokrb5/iana/msgtype"
 	"github.com/jcmturner/gokrb5/iana/patype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/types"
 	"time"
 )
@@ -81,15 +81,15 @@ func (k *ASRep) Unmarshal(b []byte) error {
 	var m marshalKDCRep
 	_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.ASREP))
 	if err != nil {
-		return processReplyError(b, err)
+		return processUnmarshalReplyError(b, err)
 	}
 	if m.MsgType != msgtype.KRB_AS_REP {
-		return errors.New("Message ID does not indicate a KRB_AS_REP")
+		return krberror.NewErrorf(krberror.KRBMSG_ERROR, "Message ID does not indicate an AS_REP. Expected: %v; Actual: %v", msgtype.KRB_AS_REP, m.MsgType)
 	}
 	//Process the raw ticket within
 	tkt, err := UnmarshalTicket(m.Ticket.Bytes)
 	if err != nil {
-		return err
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling Ticket within AS_REP")
 	}
 	k.KDCRepFields = KDCRepFields{
 		PVNO:    m.PVNO,
@@ -108,15 +108,15 @@ func (k *TGSRep) Unmarshal(b []byte) error {
 	var m marshalKDCRep
 	_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.TGSREP))
 	if err != nil {
-		return processReplyError(b, err)
+		return processUnmarshalReplyError(b, err)
 	}
 	if m.MsgType != msgtype.KRB_TGS_REP {
-		return errors.New("Message ID does not indicate a KRB_TGS_REP")
+		return krberror.NewErrorf(krberror.KRBMSG_ERROR, "Message ID does not indicate an TGS_REP. Expected: %v; Actual: %v", msgtype.KRB_TGS_REP, m.MsgType)
 	}
 	//Process the raw ticket within
 	tkt, err := UnmarshalTicket(m.Ticket.Bytes)
 	if err != nil {
-		return err
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling Ticket within TGS_REP")
 	}
 	k.KDCRepFields = KDCRepFields{
 		PVNO:    m.PVNO,
@@ -142,9 +142,11 @@ func (e *EncKDCRepPart) Unmarshal(b []byte) error {
 		interest of compatibility, implementors MAY relax the check on the
 		tag number of the decrypted ENC-PART.*/
 		_, err = asn1.UnmarshalWithParams(b, e, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncTGSRepPart))
-		return err
+		if err != nil {
+			return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling encrypted part within KDC_REP")
+		}
 	}
-	return err
+	return nil
 }
 
 // Decrypt the encrypted part of an AS_REP.
@@ -154,26 +156,26 @@ func (k *ASRep) DecryptEncPart(c *credentials.Credentials) (types.EncryptionKey,
 	if c.HasKeytab() {
 		key, err = c.Keytab.GetEncryptionKey(k.CName.NameString, k.CRealm, k.EncPart.KVNO, k.EncPart.EType)
 		if err != nil {
-			return key, fmt.Errorf("Could not get key from keytab: %v", err)
+			return key, krberror.Errorf(err, krberror.DECRYPTING_ERROR, "Error decrypting AS_REP encrypted part")
 		}
 	}
 	if c.HasPassword() {
 		key, _, err = crypto.GetKeyFromPassword(c.Password, k.CName, k.CRealm, k.EncPart.EType, k.PAData)
 		if err != nil {
-			return key, fmt.Errorf("Could not derive key from password: %v", err)
+			return key, krberror.Errorf(err, krberror.DECRYPTING_ERROR, "Error decrypting AS_REP encrypted part")
 		}
 	}
 	if !c.HasKeytab() && !c.HasPassword() {
-		return key, errors.New("No secret available in credentials to preform decryption")
+		return key, krberror.NewErrorf(krberror.DECRYPTING_ERROR, "No secret available in credentials to preform decryption of AS_REP encrypted part")
 	}
 	b, err := crypto.DecryptEncPart(k.EncPart, key, keyusage.AS_REP_ENCPART)
 	if err != nil {
-		return key, fmt.Errorf("Error decrypting KDC_REP EncPart: %v", err)
+		return key, krberror.Errorf(err, krberror.DECRYPTING_ERROR, "Error decrypting AS_REP encrypted part")
 	}
 	var denc EncKDCRepPart
 	err = denc.Unmarshal(b)
 	if err != nil {
-		return key, fmt.Errorf("Error unmarshalling encrypted part: %v", err)
+		return key, krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling decrypted encpart of AS_REP")
 	}
 	k.DecryptedEncPart = denc
 	return key, nil
@@ -183,62 +185,62 @@ func (k *ASRep) DecryptEncPart(c *credentials.Credentials) (types.EncryptionKey,
 func (k *ASRep) IsValid(cfg *config.Config, creds *credentials.Credentials, asReq ASReq) (bool, error) {
 	//Ref RFC 4120 Section 3.1.5
 	if k.CName.NameType != asReq.ReqBody.CName.NameType || k.CName.NameString == nil {
-		return false, fmt.Errorf("CName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.CName, k.CName)
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "CName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.CName, k.CName)
 	}
 	for i := range k.CName.NameString {
 		if k.CName.NameString[i] != asReq.ReqBody.CName.NameString[i] {
-			return false, fmt.Errorf("CName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.CName, k.CName)
+			return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "CName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.CName, k.CName)
 		}
 	}
 	if k.CRealm != asReq.ReqBody.Realm {
-		return false, fmt.Errorf("CRealm in response does not match what was requested. Requested: %s; Reply: %s", asReq.ReqBody.Realm, k.CRealm)
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "CRealm in response does not match what was requested. Requested: %s; Reply: %s", asReq.ReqBody.Realm, k.CRealm)
 	}
 	key, err := k.DecryptEncPart(creds)
 	if err != nil {
-		return false, fmt.Errorf("Error decrypting EncPart of AS_REP: %v", err)
+		return false, krberror.Errorf(err, krberror.DECRYPTING_ERROR, "Error decrypting EncPart of AS_REP")
 	}
 	if k.DecryptedEncPart.Nonce != asReq.ReqBody.Nonce {
-		return false, errors.New("Possible replay attack, nonce in response does not match that in request")
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "Possible replay attack, nonce in response does not match that in request")
 	}
 	if k.DecryptedEncPart.SName.NameType != asReq.ReqBody.SName.NameType || k.DecryptedEncPart.SName.NameString == nil {
-		return false, fmt.Errorf("SName in response does not match what was requested. Requested: %v; Reply: %v", asReq.ReqBody.SName, k.DecryptedEncPart.SName)
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "SName in response does not match what was requested. Requested: %v; Reply: %v", asReq.ReqBody.SName, k.DecryptedEncPart.SName)
 	}
 	for i := range k.CName.NameString {
 		if k.DecryptedEncPart.SName.NameString[i] != asReq.ReqBody.SName.NameString[i] {
-			return false, fmt.Errorf("SName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.SName, k.DecryptedEncPart.SName)
+			return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "SName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.SName, k.DecryptedEncPart.SName)
 		}
 	}
 	if k.DecryptedEncPart.SRealm != asReq.ReqBody.Realm {
-		return false, fmt.Errorf("SRealm in response does not match what was requested. Requested: %s; Reply: %s", asReq.ReqBody.Realm, k.DecryptedEncPart.SRealm)
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "SRealm in response does not match what was requested. Requested: %s; Reply: %s", asReq.ReqBody.Realm, k.DecryptedEncPart.SRealm)
 	}
 	if len(asReq.ReqBody.Addresses) > 0 {
 		if !types.HostAddressesEqual(k.DecryptedEncPart.CAddr, asReq.ReqBody.Addresses) {
-			return false, errors.New("Addresses listed in the AS_REP does not match those listed in the AS_REQ")
+			return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "Addresses listed in the AS_REP does not match those listed in the AS_REQ")
 		}
 	}
 	t := time.Now().UTC()
 	if t.Sub(k.DecryptedEncPart.AuthTime) > cfg.LibDefaults.Clockskew || k.DecryptedEncPart.AuthTime.Sub(t) > cfg.LibDefaults.Clockskew {
-		return false, fmt.Errorf("Clock skew with KDC too large. Greater than %v seconds", cfg.LibDefaults.Clockskew.Seconds())
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "Clock skew with KDC too large. Greater than %v seconds", cfg.LibDefaults.Clockskew.Seconds())
 	}
 	// RFC 6806 https://tools.ietf.org/html/rfc6806.html#section-11
 	if asReq.PAData.Contains(patype.PA_REQ_ENC_PA_REP) && types.IsFlagSet(&k.DecryptedEncPart.Flags, flags.EncPARep) {
 		if len(k.DecryptedEncPart.EncPAData) < 2 || !k.DecryptedEncPart.EncPAData.Contains(patype.PA_FX_FAST) {
-			return false, errors.New("KDC did not respond appropriately to FAST negotiation")
+			return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "KDC did not respond appropriately to FAST negotiation")
 		}
 		for _, pa := range k.DecryptedEncPart.EncPAData {
 			if pa.PADataType == patype.PA_REQ_ENC_PA_REP {
 				var pafast types.PAReqEncPARep
 				err := pafast.Unmarshal(pa.PADataValue)
 				if err != nil {
-					return false, fmt.Errorf("KDC FAST negotiation response error, could not unmarshal PA_REQ_ENC_PA_REP: %v", err)
+					return false, krberror.Errorf(err, krberror.ENCODING_ERROR, "KDC FAST negotiation response error, could not unmarshal PA_REQ_ENC_PA_REP")
 				}
 				etype, err := crypto.GetChksumEtype(pafast.ChksumType)
 				if err != nil {
-					return false, fmt.Errorf("KDC FAST negotiation response error, %v", err)
+					return false, krberror.Errorf(err, krberror.CHKSUM_ERROR, "KDC FAST negotiation response error")
 				}
 				ab, _ := asReq.Marshal()
 				if !engine.VerifyChecksum(key.KeyValue, pafast.Chksum, ab, keyusage.KEY_USAGE_AS_REQ, etype) {
-					return false, errors.New("KDC FAST negotiation response checksum invalid")
+					return false, krberror.Errorf(err, krberror.CHKSUM_ERROR, "KDC FAST negotiation response checksum invalid")
 				}
 			}
 		}
@@ -250,12 +252,12 @@ func (k *ASRep) IsValid(cfg *config.Config, creds *credentials.Credentials, asRe
 func (k *TGSRep) DecryptEncPart(key types.EncryptionKey) error {
 	b, err := crypto.DecryptEncPart(k.EncPart, key, keyusage.TGS_REP_ENCPART_SESSION_KEY)
 	if err != nil {
-		return fmt.Errorf("Error decrypting KDC_REP EncPart: %v", err)
+		return krberror.Errorf(err, krberror.DECRYPTING_ERROR, "Error decrypting TGS_REP EncPart")
 	}
 	var denc EncKDCRepPart
 	err = denc.Unmarshal(b)
 	if err != nil {
-		return fmt.Errorf("Error unmarshalling encrypted part: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling encrypted part")
 	}
 	k.DecryptedEncPart = denc
 	return nil
@@ -264,46 +266,46 @@ func (k *TGSRep) DecryptEncPart(key types.EncryptionKey) error {
 // Check validity of TGS_REP message.
 func (k *TGSRep) IsValid(cfg *config.Config, tgsReq TGSReq) (bool, error) {
 	if k.CName.NameType != tgsReq.ReqBody.CName.NameType || k.CName.NameString == nil {
-		return false, fmt.Errorf("CName in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.CName, k.CName)
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "CName in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.CName, k.CName)
 	}
 	for i := range k.CName.NameString {
 		if k.CName.NameString[i] != tgsReq.ReqBody.CName.NameString[i] {
-			return false, fmt.Errorf("CName in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.CName, k.CName)
+			return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "CName in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.CName, k.CName)
 		}
 	}
 	if k.CRealm != tgsReq.ReqBody.Realm {
-		return false, fmt.Errorf("CRealm in response does not match what was requested. Requested: %s; Reply: %s", tgsReq.ReqBody.Realm, k.CRealm)
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "CRealm in response does not match what was requested. Requested: %s; Reply: %s", tgsReq.ReqBody.Realm, k.CRealm)
 	}
 	if k.DecryptedEncPart.Nonce != tgsReq.ReqBody.Nonce {
-		return false, errors.New("Possible replay attack, nonce in response does not match that in request")
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "Possible replay attack, nonce in response does not match that in request")
 	}
 	if k.Ticket.SName.NameType != tgsReq.ReqBody.SName.NameType || k.Ticket.SName.NameString == nil {
-		return false, fmt.Errorf("SName in response ticket does not match what was requested. Requested: %v; Reply: %v", tgsReq.ReqBody.SName, k.Ticket.SName)
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "SName in response ticket does not match what was requested. Requested: %v; Reply: %v", tgsReq.ReqBody.SName, k.Ticket.SName)
 	}
 	for i := range k.Ticket.SName.NameString {
 		if k.Ticket.SName.NameString[i] != tgsReq.ReqBody.SName.NameString[i] {
-			return false, fmt.Errorf("SName in response ticket does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.SName, k.Ticket.SName)
+			return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "SName in response ticket does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.SName, k.Ticket.SName)
 		}
 	}
 	if k.DecryptedEncPart.SName.NameType != tgsReq.ReqBody.SName.NameType || k.DecryptedEncPart.SName.NameString == nil {
-		return false, fmt.Errorf("SName in response does not match what was requested. Requested: %v; Reply: %v", tgsReq.ReqBody.SName, k.DecryptedEncPart.SName)
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "SName in response does not match what was requested. Requested: %v; Reply: %v", tgsReq.ReqBody.SName, k.DecryptedEncPart.SName)
 	}
 	for i := range k.CName.NameString {
 		if k.DecryptedEncPart.SName.NameString[i] != tgsReq.ReqBody.SName.NameString[i] {
-			return false, fmt.Errorf("SName in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.SName, k.DecryptedEncPart.SName)
+			return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "SName in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.SName, k.DecryptedEncPart.SName)
 		}
 	}
 	if k.DecryptedEncPart.SRealm != tgsReq.ReqBody.Realm {
-		return false, fmt.Errorf("SRealm in response does not match what was requested. Requested: %s; Reply: %s", tgsReq.ReqBody.Realm, k.DecryptedEncPart.SRealm)
+		return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "SRealm in response does not match what was requested. Requested: %s; Reply: %s", tgsReq.ReqBody.Realm, k.DecryptedEncPart.SRealm)
 	}
 	if len(tgsReq.ReqBody.Addresses) > 0 {
 		if !types.HostAddressesEqual(k.DecryptedEncPart.CAddr, tgsReq.ReqBody.Addresses) {
-			return false, errors.New("Addresses listed in the TGS_REP does not match those listed in the TGS_REQ")
+			return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "Addresses listed in the TGS_REP does not match those listed in the TGS_REQ")
 		}
 	}
 	if time.Since(k.DecryptedEncPart.StartTime) > cfg.LibDefaults.Clockskew || k.DecryptedEncPart.StartTime.Sub(time.Now().UTC()) > cfg.LibDefaults.Clockskew {
 		if time.Since(k.DecryptedEncPart.AuthTime) > cfg.LibDefaults.Clockskew || k.DecryptedEncPart.AuthTime.Sub(time.Now().UTC()) > cfg.LibDefaults.Clockskew {
-			return false, fmt.Errorf("Clock skew with KDC too large. Greater than %v seconds.", cfg.LibDefaults.Clockskew.Seconds())
+			return false, krberror.NewErrorf(krberror.KRBMSG_ERROR, "Clock skew with KDC too large. Greater than %v seconds.", cfg.LibDefaults.Clockskew.Seconds())
 		}
 	}
 	return true, nil

+ 22 - 17
messages/KDCReq.go

@@ -17,6 +17,7 @@ import (
 	"github.com/jcmturner/gokrb5/iana/msgtype"
 	"github.com/jcmturner/gokrb5/iana/nametype"
 	"github.com/jcmturner/gokrb5/iana/patype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/types"
 	"math/rand"
 	"time"
@@ -165,11 +166,11 @@ func NewTGSReq(cname types.PrincipalName, c *config.Config, tkt Ticket, sessionK
 	a.ReqBody.CName = auth.CName
 	b, err := a.ReqBody.Marshal()
 	if err != nil {
-		return a, fmt.Errorf("Error marshalling request body: %v", err)
+		return a, krberror.Errorf(err, krberror.ENCODING_ERROR, "Error marshaling TGS_REQ body")
 	}
 	etype, err := crypto.GetEtype(sessionKey.KeyType)
 	if err != nil {
-		return a, fmt.Errorf("Error getting etype to encrypt authenticator: %v", err)
+		return a, krberror.Errorf(err, krberror.ENCRYPTING_ERROR, "Error getting etype to encrypt authenticator")
 	}
 	cb, err := engine.GetChecksumHash(b, sessionKey.KeyValue, keyusage.TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR_CHKSUM, etype)
 	auth.Cksum = types.Checksum{
@@ -179,7 +180,7 @@ func NewTGSReq(cname types.PrincipalName, c *config.Config, tkt Ticket, sessionK
 	apReq, err := NewAPReq(tkt, sessionKey, auth)
 	apb, err := apReq.Marshal()
 	if err != nil {
-		return a, fmt.Errorf("Error marshalling AP_REQ for pre-authentication data: %v", err)
+		return a, krberror.Errorf(err, krberror.ENCODING_ERROR, "Error marshaling AP_REQ for pre-authentication data")
 	}
 	a.PAData = types.PADataSequence{
 		types.PAData{
@@ -195,16 +196,16 @@ func (k *ASReq) Unmarshal(b []byte) error {
 	var m marshalKDCReq
 	_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.ASREQ))
 	if err != nil {
-		return fmt.Errorf("Error unmarshalling KDC_REQ: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling AS_REQ")
 	}
 	expectedMsgType := msgtype.KRB_AS_REQ
 	if m.MsgType != expectedMsgType {
-		return fmt.Errorf("Message ID does not indicate a KRB_AS_REQ. Expected: %v; Actual: %v", expectedMsgType, m.MsgType)
+		return krberror.NewErrorf(krberror.KRBMSG_ERROR, "Message ID does not indicate a AS_REQ. Expected: %v; Actual: %v", expectedMsgType, m.MsgType)
 	}
 	var reqb KDCReqBody
 	err = reqb.Unmarshal(m.ReqBody.Bytes)
 	if err != nil {
-		return fmt.Errorf("Error processing KDC_REQ_BODY: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error processing AS_REQ body")
 	}
 	k.MsgType = m.MsgType
 	k.PAData = m.PAData
@@ -218,16 +219,16 @@ func (k *TGSReq) Unmarshal(b []byte) error {
 	var m marshalKDCReq
 	_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.TGSREQ))
 	if err != nil {
-		return fmt.Errorf("Error unmarshalling KDC_REQ: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling TGS_REQ")
 	}
 	expectedMsgType := msgtype.KRB_TGS_REQ
 	if m.MsgType != expectedMsgType {
-		return fmt.Errorf("Message ID does not indicate a KRB_TGS_REQ. Expected: %v; Actual: %v", expectedMsgType, m.MsgType)
+		return krberror.NewErrorf(krberror.KRBMSG_ERROR, "Message ID does not indicate a TGS_REQ. Expected: %v; Actual: %v", expectedMsgType, m.MsgType)
 	}
 	var reqb KDCReqBody
 	err = reqb.Unmarshal(m.ReqBody.Bytes)
 	if err != nil {
-		return fmt.Errorf("Error processing KDC_REQ_BODY: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error processing TGS_REQ body")
 	}
 	k.MsgType = m.MsgType
 	k.PAData = m.PAData
@@ -241,7 +242,7 @@ func (k *KDCReqBody) Unmarshal(b []byte) error {
 	var m marshalKDCReqBody
 	_, err := asn1.Unmarshal(b, &m)
 	if err != nil {
-		return fmt.Errorf("Error unmarshalling KDC_REQ_BODY: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling KDC_REQ body")
 	}
 	k.KDCOptions = m.KDCOptions
 	if len(k.KDCOptions.Bytes) < 4 {
@@ -262,7 +263,7 @@ func (k *KDCReqBody) Unmarshal(b []byte) error {
 	if len(m.AdditionalTickets.Bytes) > 0 {
 		k.AdditionalTickets, err = UnmarshalTicketsSequence(m.AdditionalTickets)
 		if err != nil {
-			return fmt.Errorf("Error unmarshalling additional tickets: %v", err)
+			return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling additional tickets")
 		}
 	}
 	return nil
@@ -288,7 +289,7 @@ func (k *ASReq) Marshal() ([]byte, error) {
 	}
 	mk, err := asn1.Marshal(m)
 	if err != nil {
-		return mk, fmt.Errorf("Error marshalling AS_REQ: %v", err)
+		return mk, krberror.Errorf(err, krberror.ENCODING_ERROR, "Error marshaling AS_REQ")
 	}
 	mk = asn1tools.AddASNAppTag(mk, asnAppTag.ASREQ)
 	return mk, nil
@@ -314,7 +315,7 @@ func (k *TGSReq) Marshal() ([]byte, error) {
 	}
 	mk, err := asn1.Marshal(m)
 	if err != nil {
-		return mk, fmt.Errorf("Error marshalling AS_REQ: %v", err)
+		return mk, krberror.Errorf(err, krberror.ENCODING_ERROR, "Error marshaling AS_REQ")
 	}
 	mk = asn1tools.AddASNAppTag(mk, asnAppTag.TGSREQ)
 	return mk, nil
@@ -337,13 +338,17 @@ func (k *KDCReqBody) Marshal() ([]byte, error) {
 		EncAuthData: k.EncAuthData,
 	}
 	rawtkts, err := MarshalTicketSequence(k.AdditionalTickets)
-	//The asn1.rawValue needs the tag setting on it for where it is in the KDCReqBody
-	rawtkts.Tag = 11
 	if err != nil {
-		return b, fmt.Errorf("Error in marshalling KDC request body additional tickets: %v", err)
+		return b, krberror.Errorf(err, krberror.ENCODING_ERROR, "Error in marshaling KDC request body additional tickets")
 	}
+	//The asn1.rawValue needs the tag setting on it for where it is in the KDCReqBody
+	rawtkts.Tag = 11
 	if len(rawtkts.Bytes) > 0 {
 		m.AdditionalTickets = rawtkts
 	}
-	return asn1.Marshal(m)
+	b, err = asn1.Marshal(m)
+	if err != nil {
+		return b, krberror.Errorf(err, krberror.ENCODING_ERROR, "Error in marshaling KDC request body")
+	}
+	return b, nil
 }

+ 7 - 6
messages/KRBCred.go

@@ -7,6 +7,7 @@ import (
 	"github.com/jcmturner/gokrb5/iana/asnAppTag"
 	"github.com/jcmturner/gokrb5/iana/keyusage"
 	"github.com/jcmturner/gokrb5/iana/msgtype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/types"
 	"time"
 )
@@ -57,11 +58,11 @@ func (k *KRBCred) Unmarshal(b []byte) error {
 	var m marshalKRBCred
 	_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.KRBCred))
 	if err != nil {
-		return fmt.Errorf("Error unmarshalling KDC_CRED: %v", processReplyError(b, err))
+		return processUnmarshalReplyError(b, err)
 	}
 	expectedMsgType := msgtype.KRB_CRED
 	if m.MsgType != expectedMsgType {
-		return fmt.Errorf("Message ID does not indicate a KRB_CRED. Expected: %v; Actual: %v", expectedMsgType, m.MsgType)
+		return krberror.NewErrorf(krberror.KRBMSG_ERROR, "Message ID does not indicate a KRB_CRED. Expected: %v; Actual: %v", expectedMsgType, m.MsgType)
 	}
 	k.PVNO = m.PVNO
 	k.MsgType = m.MsgType
@@ -69,7 +70,7 @@ func (k *KRBCred) Unmarshal(b []byte) error {
 	if len(m.Tickets.Bytes) > 0 {
 		k.Tickets, err = UnmarshalTicketsSequence(m.Tickets)
 		if err != nil {
-			return fmt.Errorf("Error unmarshalling tickets within KRB_CRED: %v", err)
+			return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling tickets within KRB_CRED")
 		}
 	}
 	return nil
@@ -79,12 +80,12 @@ func (k *KRBCred) Unmarshal(b []byte) error {
 func (k *KRBCred) DecryptEncPart(key types.EncryptionKey) error {
 	b, err := crypto.DecryptEncPart(k.EncPart, key, keyusage.KRB_CRED_ENCPART)
 	if err != nil {
-		return fmt.Errorf("Error decrypting KDC_REP EncPart: %v", err)
+		return krberror.Errorf(err, krberror.DECRYPTING_ERROR, "Error decrypting KRB_CRED EncPart")
 	}
 	var denc EncKrbCredPart
 	err = denc.Unmarshal(b)
 	if err != nil {
-		return fmt.Errorf("Error unmarshalling encrypted part: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling encrypted part of KRB_CRED")
 	}
 	k.DecryptedEncPart = denc
 	return nil
@@ -94,7 +95,7 @@ func (k *KRBCred) DecryptEncPart(key types.EncryptionKey) error {
 func (k *EncKrbCredPart) Unmarshal(b []byte) error {
 	_, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncKrbCredPart))
 	if err != nil {
-		return fmt.Errorf("Error unmarshalling EncKrbCredPart: %v", err)
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling EncKrbCredPart")
 	}
 	return nil
 }

+ 6 - 5
messages/KRBError.go

@@ -8,6 +8,7 @@ import (
 	"github.com/jcmturner/gokrb5/iana/asnAppTag"
 	"github.com/jcmturner/gokrb5/iana/errorcode"
 	"github.com/jcmturner/gokrb5/iana/msgtype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/types"
 	"time"
 )
@@ -47,11 +48,11 @@ func NewKRBError(sname types.PrincipalName, realm string, code int, etext string
 func (k *KRBError) Unmarshal(b []byte) error {
 	_, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.KRBError))
 	if err != nil {
-		return err
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "KRB_ERROR unmarshal error")
 	}
 	expectedMsgType := msgtype.KRB_ERROR
 	if k.MsgType != expectedMsgType {
-		return fmt.Errorf("Message ID does not indicate a KRB_ERROR. Expected: %v; Actual: %v", expectedMsgType, k.MsgType)
+		return krberror.NewErrorf(krberror.KRBMSG_ERROR, "Message ID does not indicate a KRB_ERROR. Expected: %v; Actual: %v", expectedMsgType, k.MsgType)
 	}
 	return nil
 }
@@ -65,16 +66,16 @@ func (k KRBError) Error() string {
 	return etxt
 }
 
-func processReplyError(b []byte, err error) error {
+func processUnmarshalReplyError(b []byte, err error) error {
 	switch err.(type) {
 	case asn1.StructuralError:
 		var krberr KRBError
 		tmperr := krberr.Unmarshal(b)
 		if tmperr != nil {
-			return err
+			return krberror.Errorf(err, krberror.ENCODING_ERROR, "Failed to unmarshal KDC's reply")
 		}
 		return krberr
 	default:
-		return err
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "Failed to unmarshal KDC's reply")
 	}
 }

+ 4 - 3
messages/KRBPriv.go

@@ -5,6 +5,7 @@ import (
 	"github.com/jcmturner/asn1"
 	"github.com/jcmturner/gokrb5/iana/asnAppTag"
 	"github.com/jcmturner/gokrb5/iana/msgtype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/types"
 	"time"
 )
@@ -30,11 +31,11 @@ type EncKrbPrivPart struct {
 func (k *KRBPriv) Unmarshal(b []byte) error {
 	_, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.KRBPriv))
 	if err != nil {
-		return processReplyError(b, err)
+		return processUnmarshalReplyError(b, err)
 	}
 	expectedMsgType := msgtype.KRB_PRIV
 	if k.MsgType != expectedMsgType {
-		return fmt.Errorf("Message ID does not indicate a KRB_PRIV. Expected: %v; Actual: %v", expectedMsgType, k.MsgType)
+		return krberror.NewErrorf(krberror.KRBMSG_ERROR, "Message ID does not indicate a KRB_PRIV. Expected: %v; Actual: %v", expectedMsgType, k.MsgType)
 	}
 	return nil
 }
@@ -43,7 +44,7 @@ func (k *KRBPriv) Unmarshal(b []byte) error {
 func (k *EncKrbPrivPart) Unmarshal(b []byte) error {
 	_, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncKrbPrivPart))
 	if err != nil {
-		return err
+		return krberror.Errorf(err, krberror.ENCODING_ERROR, "KRB_PRIV unmarshal error")
 	}
 	return nil
 }

+ 3 - 2
messages/KRBSafe.go

@@ -5,6 +5,7 @@ import (
 	"github.com/jcmturner/asn1"
 	"github.com/jcmturner/gokrb5/iana/asnAppTag"
 	"github.com/jcmturner/gokrb5/iana/msgtype"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/types"
 	"time"
 )
@@ -49,11 +50,11 @@ type KRBSafeBody struct {
 func (s *KRBSafe) Unmarshal(b []byte) error {
 	_, err := asn1.UnmarshalWithParams(b, s, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.KRBSafe))
 	if err != nil {
-		return processReplyError(b, err)
+		return processUnmarshalReplyError(b, err)
 	}
 	expectedMsgType := msgtype.KRB_SAFE
 	if s.MsgType != expectedMsgType {
-		return fmt.Errorf("Message ID does not indicate a KRB_SAFE. Expected: %v; Actual: %v", expectedMsgType, s.MsgType)
+		return krberror.NewErrorf(krberror.KRBMSG_ERROR, "Message ID does not indicate a KRB_SAFE. Expected: %v; Actual: %v", expectedMsgType, s.MsgType)
 	}
 	return nil
 }

+ 7 - 6
messages/Ticket.go

@@ -12,6 +12,7 @@ import (
 	"github.com/jcmturner/gokrb5/iana/errorcode"
 	"github.com/jcmturner/gokrb5/iana/keyusage"
 	"github.com/jcmturner/gokrb5/keytab"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/pac"
 	"github.com/jcmturner/gokrb5/types"
 	"time"
@@ -50,7 +51,7 @@ type TransitedEncoding struct {
 func NewTicket(cname types.PrincipalName, crealm string, sname types.PrincipalName, srealm string, flags asn1.BitString, sktab keytab.Keytab, eTypeID, kvno int, authTime, startTime, endTime, renewTill time.Time) (Ticket, types.EncryptionKey, error) {
 	etype, err := crypto.GetEtype(eTypeID)
 	if err != nil {
-		return Ticket{}, types.EncryptionKey{}, err
+		return Ticket{}, types.EncryptionKey{}, krberror.Errorf(err, krberror.ENCRYPTING_ERROR, "Error getting etype for new ticket")
 	}
 	ks := etype.GetKeyByteSize()
 	kv := make([]byte, ks, ks)
@@ -74,7 +75,7 @@ func NewTicket(cname types.PrincipalName, crealm string, sname types.PrincipalNa
 	b = asn1tools.AddASNAppTag(b, asnAppTag.EncTicketPart)
 	skey, err := sktab.GetEncryptionKey(sname.NameString, srealm, kvno, eTypeID)
 	if err != nil {
-		return Ticket{}, types.EncryptionKey{}, err
+		return Ticket{}, types.EncryptionKey{}, krberror.Errorf(err, krberror.ENCRYPTING_ERROR, "Error getting encryption key for new ticket")
 	}
 	ed, err := crypto.GetEncryptedData(b, skey, keyusage.KDC_REP_TICKET, kvno)
 	tkt := Ticket{
@@ -121,11 +122,11 @@ func UnmarshalTicketsSequence(in asn1.RawValue) ([]Ticket, error) {
 	for p < (len(b)) {
 		_, err := asn1.UnmarshalWithParams(b[p:], &raw, fmt.Sprintf("application,tag:%d", asnAppTag.Ticket))
 		if err != nil {
-			return nil, fmt.Errorf("Unmarshalling sequence of tickets failed geting length of ticket: %v", err)
+			return nil, fmt.Errorf("Unmarshaling sequence of tickets failed geting length of ticket: %v", err)
 		}
 		t, err := UnmarshalTicket(b[p:])
 		if err != nil {
-			return nil, fmt.Errorf("Unmarshalling sequence of tickets failed: %v", err)
+			return nil, fmt.Errorf("Unmarshaling sequence of tickets failed: %v", err)
 		}
 		p += len(raw.FullBytes)
 		tkts = append(tkts, t)
@@ -147,7 +148,7 @@ func MarshalTicketSequence(tkts []Ticket) (asn1.RawValue, error) {
 	for i, t := range tkts {
 		b, err := t.Marshal()
 		if err != nil {
-			return raw, fmt.Errorf("Error marshalling ticket number %d in seqence of tickets", i+1)
+			return raw, fmt.Errorf("Error marshaling ticket number %d in seqence of tickets", i+1)
 		}
 		btkts = append(btkts, b...)
 	}
@@ -184,7 +185,7 @@ func (t *Ticket) DecryptEncPart(keytab keytab.Keytab, sa string) error {
 	var denc EncTicketPart
 	err = denc.Unmarshal(b)
 	if err != nil {
-		return fmt.Errorf("Error unmarshalling encrypted part: %v", err)
+		return fmt.Errorf("Error unmarshaling encrypted part: %v", err)
 	}
 	t.DecryptedEncPart = denc
 	return nil

+ 5 - 3
pac/client_claims.go

@@ -24,9 +24,11 @@ func (k *PAC_ClientClaimsInfo) Unmarshal(b []byte) error {
 	k.Claims = mstypes.Read_ClaimsSetMetadata(&b, &p, e)
 
 	//Check that there is only zero padding left
-	for _, v := range b[p:] {
-		if v != 0 {
-			return ndr.NDRMalformed{EText: "Non-zero padding left over at end of data stream"}
+	if len(b) >= p {
+		for _, v := range b[p:] {
+			if v != 0 {
+				return ndr.NDRMalformed{EText: "Non-zero padding left over at end of data stream"}
+			}
 		}
 	}
 

+ 8 - 3
pac/client_info.go

@@ -20,6 +20,9 @@ func (k *PAC_ClientInfo) Unmarshal(b []byte) error {
 
 	k.ClientID = mstypes.Read_FileTime(&b, &p, &e)
 	k.NameLength = ndr.Read_uint16(&b, &p, &e)
+	if len(b[p:]) < int(k.NameLength) {
+		return ndr.NDRMalformed{EText: "PAC ClientInfo length truncated"}
+	}
 	//Length devided by 2 as each run is 16bits = 2bytes
 	s := make([]rune, k.NameLength/2, k.NameLength/2)
 	for i := 0; i < len(s); i++ {
@@ -28,9 +31,11 @@ func (k *PAC_ClientInfo) Unmarshal(b []byte) error {
 	k.Name = string(s)
 
 	//Check that there is only zero padding left
-	for _, v := range b[p:] {
-		if v != 0 {
-			return ndr.NDRMalformed{EText: "Non-zero padding left over at end of data stream"}
+	if len(b) >= p {
+		for _, v := range b[p:] {
+			if v != 0 {
+				return ndr.NDRMalformed{EText: "Non-zero padding left over at end of data stream"}
+			}
 		}
 	}
 

+ 5 - 3
pac/device_claims.go

@@ -24,9 +24,11 @@ func (k *PAC_DeviceClaimsInfo) Unmarshal(b []byte) error {
 	k.Claims = mstypes.Read_ClaimsSetMetadata(&b, &p, e)
 
 	//Check that there is only zero padding left
-	for _, v := range b[p:] {
-		if v != 0 {
-			return ndr.NDRMalformed{EText: "Non-zero padding left over at end of data stream"}
+	if len(b) >= p {
+		for _, v := range b[p:] {
+			if v != 0 {
+				return ndr.NDRMalformed{EText: "Non-zero padding left over at end of data stream"}
+			}
 		}
 	}
 

+ 5 - 3
pac/device_info.go

@@ -79,9 +79,11 @@ func (k *PAC_DeviceInfo) Unmarshal(b []byte) error {
 	}
 
 	//Check that there is only zero padding left
-	for _, v := range b[p:] {
-		if v != 0 {
-			return ndr.NDRMalformed{EText: "Non-zero padding left over at end of data stream"}
+	if len(b) >= p {
+		for _, v := range b[p:] {
+			if v != 0 {
+				return ndr.NDRMalformed{EText: "Non-zero padding left over at end of data stream"}
+			}
 		}
 	}
 

+ 5 - 3
pac/kerb_validation_info.go

@@ -209,9 +209,11 @@ func (k *KerbValidationInfo) Unmarshal(b []byte) (err error) {
 	}
 
 	//Check that there is only zero padding left
-	for _, v := range b[p:] {
-		if v != 0 {
-			return ndr.NDRMalformed{EText: "Non-zero padding left over at end of data stream"}
+	if len(b) >= p {
+		for _, v := range b[p:] {
+			if v != 0 {
+				return ndr.NDRMalformed{EText: "Non-zero padding left over at end of data stream"}
+			}
 		}
 	}
 

+ 4 - 3
service/APExchange.go

@@ -8,6 +8,7 @@ import (
 	"github.com/jcmturner/gokrb5/iana/flags"
 	"github.com/jcmturner/gokrb5/iana/keyusage"
 	"github.com/jcmturner/gokrb5/keytab"
+	"github.com/jcmturner/gokrb5/krberror"
 	"github.com/jcmturner/gokrb5/messages"
 	"github.com/jcmturner/gokrb5/types"
 	"time"
@@ -18,16 +19,16 @@ func ValidateAPREQ(APReq messages.APReq, kt keytab.Keytab, sa string, cAddr stri
 	var creds credentials.Credentials
 	err := APReq.Ticket.DecryptEncPart(kt, sa)
 	if err != nil {
-		return false, creds, fmt.Errorf("Error decrypting encpart of service ticket provided: %v", err)
+		return false, creds, krberror.Errorf(err, krberror.DECRYPTING_ERROR, "Error decrypting encpart of service ticket provided")
 	}
 	ab, err := crypto.DecryptEncPart(APReq.Authenticator, APReq.Ticket.DecryptedEncPart.Key, keyusage.AP_REQ_AUTHENTICATOR)
 	if err != nil {
-		return false, creds, fmt.Errorf("Error decrypting authenticator: %v", err)
+		return false, creds, krberror.Errorf(err, krberror.DECRYPTING_ERROR, "Error decrypting authenticator")
 	}
 	var a types.Authenticator
 	err = a.Unmarshal(ab)
 	if err != nil {
-		return false, creds, fmt.Errorf("Error unmarshaling authenticator: %v", err)
+		return false, creds, krberror.Errorf(err, krberror.ENCODING_ERROR, "Error unmarshaling authenticator")
 	}
 
 	// Check CName in Authenticator is the same as that in the ticket

+ 1 - 3
types/Cryptosystem.go

@@ -2,7 +2,6 @@ package types
 
 import (
 	"github.com/jcmturner/asn1"
-	"fmt"
 )
 
 // Reference: https://www.ietf.org/rfc/rfc4120.txt
@@ -35,7 +34,7 @@ func (a *EncryptedData) Unmarshal(b []byte) error {
 func (a *EncryptedData) Marshal() ([]byte, error) {
 	edb, err := asn1.Marshal(*a)
 	if err != nil {
-		return edb, fmt.Errorf("Error marshalling EncryptedData: %v", err)
+		return edb, err
 	}
 	return edb, nil
 }
@@ -49,4 +48,3 @@ func (a *Checksum) Unmarshal(b []byte) error {
 	_, err := asn1.Unmarshal(b, a)
 	return err
 }
-

+ 1 - 1
types/PAData.go

@@ -42,7 +42,7 @@ func GetPAEncTSEncAsnMarshalled() ([]byte, error) {
 	}
 	b, err := asn1.Marshal(p)
 	if err != nil {
-		return b, fmt.Errorf("Error mashalling PAEncTSEnc: %v", err)
+		return b, fmt.Errorf("Error mashaling PAEncTSEnc: %v", err)
 	}
 	return b, nil
 }