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