Ticket.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package types
  2. import (
  3. "fmt"
  4. "github.com/jcmturner/asn1"
  5. "github.com/jcmturner/gokrb5/asn1tools"
  6. "github.com/jcmturner/gokrb5/iana/asnAppTag"
  7. "time"
  8. )
  9. // Reference: https://www.ietf.org/rfc/rfc4120.txt
  10. // Section: 5.3
  11. type Ticket struct {
  12. TktVNO int `asn1:"explicit,tag:0"`
  13. Realm string `asn1:"generalstring,explicit,tag:1"`
  14. SName PrincipalName `asn1:"explicit,tag:2"`
  15. EncPart EncryptedData `asn1:"explicit,tag:3"`
  16. }
  17. type EncTicketPart struct {
  18. Flags asn1.BitString `asn1:"explicit,tag:0"`
  19. Key EncryptionKey `asn1:"explicit,tag:1"`
  20. CRealm string `asn1:"generalstring,explicit,tag:2"`
  21. CName PrincipalName `asn1:"explicit,tag:3"`
  22. Transited TransitedEncoding `asn1:"explicit,tag:4"`
  23. AuthTime time.Time `asn1:"generalized,explicit,tag:5"`
  24. StartTime time.Time `asn1:"generalized,explicit,optional,tag:6"`
  25. EndTime time.Time `asn1:"generalized,explicit,tag:7"`
  26. RenewTill time.Time `asn1:"generalized,explicit,optional,tag:8"`
  27. CAddr HostAddresses `asn1:"explicit,optional,tag:9"`
  28. AuthorizationData AuthorizationData `asn1:"explicit,optional,tag:10"`
  29. }
  30. type TransitedEncoding struct {
  31. TRType int `asn1:"explicit,tag:0"`
  32. Contents []byte `asn1:"explicit,tag:1"`
  33. }
  34. func (t *Ticket) Unmarshal(b []byte) error {
  35. _, err := asn1.UnmarshalWithParams(b, t, fmt.Sprintf("application,explicit,tag:%d", asnAppTag.Ticket))
  36. return err
  37. }
  38. func (t *Ticket) Marshal() ([]byte, error) {
  39. b, err := asn1.Marshal(*t)
  40. if err != nil {
  41. return nil, err
  42. }
  43. b = asn1tools.AddASNAppTag(b, asnAppTag.Ticket)
  44. return b, nil
  45. }
  46. func (t *EncTicketPart) Unmarshal(b []byte) error {
  47. _, err := asn1.UnmarshalWithParams(b, t, fmt.Sprintf("application,explicit,tag:%d", asnAppTag.EncTicketPart))
  48. return err
  49. }
  50. func UnmarshalTicket(b []byte) (t Ticket, err error) {
  51. _, err = asn1.UnmarshalWithParams(b, &t, fmt.Sprintf("application,explicit,tag:%d", asnAppTag.Ticket))
  52. return
  53. }
  54. func UnmarshalTicketsSequence(in asn1.RawValue) ([]Ticket, error) {
  55. //This is a workaround to a asn1 decoding issue in golang - https://github.com/golang/go/issues/17321. It's not pretty I'm afraid
  56. //We pull out raw values from the larger raw value (that is actually the data of the sequence of raw values) and track our position moving along the data.
  57. b := in.Bytes
  58. // Ignore the head of the asn1 stream (3bytes) as this is what tells us its a sequence but we're handling it ourselves
  59. p := 3
  60. var tkts []Ticket
  61. var raw asn1.RawValue
  62. for p < (len(b)) {
  63. _, err := asn1.UnmarshalWithParams(b[p:], &raw, fmt.Sprintf("application,tag:%d", asnAppTag.Ticket))
  64. if err != nil {
  65. return nil, fmt.Errorf("Unmarshalling sequence of tickets failed geting length of ticket: %v", err)
  66. }
  67. t, err := UnmarshalTicket(b[p:])
  68. if err != nil {
  69. return nil, fmt.Errorf("Unmarshalling sequence of tickets failed: %v", err)
  70. }
  71. p += len(raw.FullBytes)
  72. tkts = append(tkts, t)
  73. }
  74. MarshalTicketSequence(tkts)
  75. return tkts, nil
  76. }
  77. func MarshalTicketSequence(tkts []Ticket) (asn1.RawValue, error) {
  78. raw := asn1.RawValue{
  79. Class: 2,
  80. IsCompound: true,
  81. }
  82. if len(tkts) < 1 {
  83. // There are no tickets to marshal
  84. return raw, nil
  85. }
  86. var btkts []byte
  87. for i, t := range tkts {
  88. b, err := t.Marshal()
  89. if err != nil {
  90. return raw, fmt.Errorf("Error marshalling ticket number %d in seqence of tickets", i+1)
  91. }
  92. btkts = append(btkts, b...)
  93. }
  94. // The ASN1 wrapping consists of 2 bytes:
  95. // 1st byte -> Identifier Octet - In this case an OCTET STRING (ASN TAG
  96. // 2nd byte -> The length (this will be the size indicated in the input bytes + 2 for the additional bytes we add here.
  97. // Application Tag:
  98. //| Byte: | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
  99. //| Value: | 0 | 1 | 1 | From the RFC spec 4120 |
  100. //| Explanation | Defined by the ASN1 encoding rules for an application tag | A value of 1 indicates a constructed type | The ASN Application tag value |
  101. btkts = append(asn1tools.MarshalLengthBytes(len(btkts)), btkts...)
  102. btkts = append([]byte{byte(32 + asn1.TagSequence)}, btkts...)
  103. raw.Bytes = btkts
  104. // If we need to create teh full bytes then identifier octect is "context-specific" = 128 + "constructed" + 32 + the wrapping explicit tag (11)
  105. //fmt.Fprintf(os.Stderr, "mRaw fb: %v\n", raw.FullBytes)
  106. return raw, nil
  107. }