blob: d2cf32d65819f4461986a8df0d3f3b58fb4830b7 [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// Package messages implements Kerberos 5 message types and methods.
2package messages
3
4import (
5 "fmt"
6 "time"
7
8 "github.com/jcmturner/gofork/encoding/asn1"
9 "github.com/jcmturner/gokrb5/v8/asn1tools"
10 "github.com/jcmturner/gokrb5/v8/iana"
11 "github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
12 "github.com/jcmturner/gokrb5/v8/iana/errorcode"
13 "github.com/jcmturner/gokrb5/v8/iana/msgtype"
14 "github.com/jcmturner/gokrb5/v8/krberror"
15 "github.com/jcmturner/gokrb5/v8/types"
16)
17
18// KRBError implements RFC 4120 KRB_ERROR: https://tools.ietf.org/html/rfc4120#section-5.9.1.
19type KRBError struct {
20 PVNO int `asn1:"explicit,tag:0"`
21 MsgType int `asn1:"explicit,tag:1"`
22 CTime time.Time `asn1:"generalized,optional,explicit,tag:2"`
23 Cusec int `asn1:"optional,explicit,tag:3"`
24 STime time.Time `asn1:"generalized,explicit,tag:4"`
25 Susec int `asn1:"explicit,tag:5"`
26 ErrorCode int32 `asn1:"explicit,tag:6"`
27 CRealm string `asn1:"generalstring,optional,explicit,tag:7"`
28 CName types.PrincipalName `asn1:"optional,explicit,tag:8"`
29 Realm string `asn1:"generalstring,explicit,tag:9"`
30 SName types.PrincipalName `asn1:"explicit,tag:10"`
31 EText string `asn1:"generalstring,optional,explicit,tag:11"`
32 EData []byte `asn1:"optional,explicit,tag:12"`
33}
34
35// NewKRBError creates a new KRBError.
36func NewKRBError(sname types.PrincipalName, realm string, code int32, etext string) KRBError {
37 t := time.Now().UTC()
38 return KRBError{
39 PVNO: iana.PVNO,
40 MsgType: msgtype.KRB_ERROR,
41 STime: t,
42 Susec: int((t.UnixNano() / int64(time.Microsecond)) - (t.Unix() * 1e6)),
43 ErrorCode: code,
44 SName: sname,
45 Realm: realm,
46 EText: etext,
47 }
48}
49
50// Unmarshal bytes b into the KRBError struct.
51func (k *KRBError) Unmarshal(b []byte) error {
52 _, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.KRBError))
53 if err != nil {
54 return krberror.Errorf(err, krberror.EncodingError, "KRB_ERROR unmarshal error")
55 }
56 expectedMsgType := msgtype.KRB_ERROR
57 if k.MsgType != expectedMsgType {
58 return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate a KRB_ERROR. Expected: %v; Actual: %v", expectedMsgType, k.MsgType)
59 }
60 return nil
61}
62
63// Marshal a KRBError into bytes.
64func (k *KRBError) Marshal() ([]byte, error) {
65 b, err := asn1.Marshal(*k)
66 if err != nil {
67 return b, krberror.Errorf(err, krberror.EncodingError, "error marshaling KRBError")
68 }
69 b = asn1tools.AddASNAppTag(b, asnAppTag.KRBError)
70 return b, nil
71}
72
73// Error method implementing error interface on KRBError struct.
74func (k KRBError) Error() string {
75 etxt := fmt.Sprintf("KRB Error: %s", errorcode.Lookup(k.ErrorCode))
76 if k.EText != "" {
77 etxt = fmt.Sprintf("%s - %s", etxt, k.EText)
78 }
79 return etxt
80}
81
82func processUnmarshalReplyError(b []byte, err error) error {
83 switch err.(type) {
84 case asn1.StructuralError:
85 var krberr KRBError
86 tmperr := krberr.Unmarshal(b)
87 if tmperr != nil {
88 return krberror.Errorf(err, krberror.EncodingError, "failed to unmarshal KDC's reply")
89 }
90 return krberr
91 default:
92 return krberror.Errorf(err, krberror.EncodingError, "failed to unmarshal KDC's reply")
93 }
94}