David K. Bainbridge | bd6b288 | 2021-08-26 13:31:02 +0000 | [diff] [blame] | 1 | // Package messages implements Kerberos 5 message types and methods. |
| 2 | package messages |
| 3 | |
| 4 | import ( |
| 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. |
| 19 | type 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. |
| 36 | func 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. |
| 51 | func (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. |
| 64 | func (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. |
| 74 | func (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 | |
| 82 | func 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 | } |