Skip to content

Commit

Permalink
add marshal methods KDC replies
Browse files Browse the repository at this point in the history
  • Loading branch information
jcmturner authored Jun 14, 2020
1 parent e4c9668 commit 9822c92
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 17 deletions.
12 changes: 4 additions & 8 deletions v8/client/network.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package client

import (
"bytes"
"encoding/binary"
"errors"
"fmt"
Expand Down Expand Up @@ -173,14 +172,11 @@ func (cl *Client) sendTCP(conn *net.TCPConn, b []byte) ([]byte, error) {
defer conn.Close()
var r []byte
// RFC 4120 7.2.2 specifies the first 4 bytes indicate the length of the message in big endian order.
var buf bytes.Buffer
err := binary.Write(&buf, binary.BigEndian, uint32(len(b)))
if err != nil {
return r, err
}
b = append(buf.Bytes(), b...)
hb := make([]byte, 4, 4)
binary.BigEndian.PutUint32(hb, uint32(len(b)))
b = append(hb, b...)

_, err = conn.Write(b)
_, err := conn.Write(b)
if err != nil {
return r, fmt.Errorf("error sending to KDC (%s): %v", conn.RemoteAddr().String(), err)
}
Expand Down
68 changes: 68 additions & 0 deletions v8/messages/KDCRep.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/jcmturner/gofork/encoding/asn1"
"github.com/jcmturner/gokrb5/v8/asn1tools"
"github.com/jcmturner/gokrb5/v8/config"
"github.com/jcmturner/gokrb5/v8/credentials"
"github.com/jcmturner/gokrb5/v8/crypto"
Expand Down Expand Up @@ -103,6 +104,34 @@ func (k *ASRep) Unmarshal(b []byte) error {
return nil
}

// Marshal ASRep struct.
func (k *ASRep) Marshal() ([]byte, error) {
m := marshalKDCRep{
PVNO: k.PVNO,
MsgType: k.MsgType,
PAData: k.PAData,
CRealm: k.CRealm,
CName: k.CName,
EncPart: k.EncPart,
}
b, err := k.Ticket.Marshal()
if err != nil {
return []byte{}, err
}
m.Ticket = asn1.RawValue{
Class: asn1.ClassContextSpecific,
IsCompound: true,
Tag: 5,
Bytes: b,
}
mk, err := asn1.Marshal(m)
if err != nil {
return mk, krberror.Errorf(err, krberror.EncodingError, "error marshaling AS_REP")
}
mk = asn1tools.AddASNAppTag(mk, asnAppTag.ASREP)
return mk, nil
}

// Unmarshal bytes b into the TGSRep struct.
func (k *TGSRep) Unmarshal(b []byte) error {
var m marshalKDCRep
Expand Down Expand Up @@ -130,6 +159,34 @@ func (k *TGSRep) Unmarshal(b []byte) error {
return nil
}

// Marshal TGSRep struct.
func (k *TGSRep) Marshal() ([]byte, error) {
m := marshalKDCRep{
PVNO: k.PVNO,
MsgType: k.MsgType,
PAData: k.PAData,
CRealm: k.CRealm,
CName: k.CName,
EncPart: k.EncPart,
}
b, err := k.Ticket.Marshal()
if err != nil {
return []byte{}, err
}
m.Ticket = asn1.RawValue{
Class: asn1.ClassContextSpecific,
IsCompound: true,
Tag: 5,
Bytes: b,
}
mk, err := asn1.Marshal(m)
if err != nil {
return mk, krberror.Errorf(err, krberror.EncodingError, "error marshaling TGS_REP")
}
mk = asn1tools.AddASNAppTag(mk, asnAppTag.TGSREP)
return mk, nil
}

// Unmarshal bytes b into encrypted part of KRB_KDC_REP.
func (e *EncKDCRepPart) Unmarshal(b []byte) error {
_, err := asn1.UnmarshalWithParams(b, e, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncASRepPart))
Expand All @@ -145,6 +202,16 @@ func (e *EncKDCRepPart) Unmarshal(b []byte) error {
return nil
}

// Marshal encrypted part of KRB_KDC_REP.
func (e *EncKDCRepPart) Marshal() ([]byte, error) {
b, err := asn1.Marshal(*e)
if err != nil {
return b, krberror.Errorf(err, krberror.EncodingError, "marshaling error of AS_REP encpart")
}
b = asn1tools.AddASNAppTag(b, asnAppTag.EncASRepPart)
return b, nil
}

// DecryptEncPart decrypts the encrypted part of an AS_REP.
func (k *ASRep) DecryptEncPart(c *credentials.Credentials) (types.EncryptionKey, error) {
var key types.EncryptionKey
Expand Down Expand Up @@ -201,6 +268,7 @@ func (k *ASRep) Verify(cfg *config.Config, creds *credentials.Credentials, asReq
if k.DecryptedEncPart.SName.NameType != asReq.ReqBody.SName.NameType || k.DecryptedEncPart.SName.NameString == nil {
return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response does not match what was requested. Requested: %v; Reply: %v", asReq.ReqBody.SName, k.DecryptedEncPart.SName)
}
//TODO is there something wrong here...>
for i := range k.CName.NameString {
if k.DecryptedEncPart.SName.NameString[i] != asReq.ReqBody.SName.NameString[i] {
return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.SName, k.DecryptedEncPart.SName)
Expand Down
36 changes: 36 additions & 0 deletions v8/messages/KDCRep_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,24 @@ func TestUnmarshalASRep_optionalsNULL(t *testing.T) {
assert.Equal(t, testdata.TEST_CIPHERTEXT, string(a.EncPart.Cipher), "Ticket encrypted part cipher not as expected")
}

func TestMarshalASRep(t *testing.T) {
t.Parallel()
var a ASRep
b, err := hex.DecodeString(testdata.MarshaledKRB5as_rep)
if err != nil {
t.Fatalf("Test vector read error: %v", err)
}
err = a.Unmarshal(b)
if err != nil {
t.Fatalf("Unmarshal error: %v", err)
}
mb, err := a.Marshal()
if err != nil {
t.Fatalf("Marshal errored: %v", err)
}
assert.Equal(t, b, mb, "Marshal bytes of ASRep not as expected")
}

func TestUnmarshalTGSRep(t *testing.T) {
t.Parallel()
var a TGSRep
Expand Down Expand Up @@ -157,6 +175,24 @@ func TestUnmarshalTGSRep_optionalsNULL(t *testing.T) {
assert.Equal(t, testdata.TEST_CIPHERTEXT, string(a.EncPart.Cipher), "Ticket encrypted part cipher not as expected")
}

func TestMarshalTGSRep(t *testing.T) {
t.Parallel()
var a TGSRep
b, err := hex.DecodeString(testdata.MarshaledKRB5tgs_rep)
if err != nil {
t.Fatalf("Test vector read error: %v", err)
}
err = a.Unmarshal(b)
if err != nil {
t.Fatalf("Unmarshal error: %v", err)
}
mb, err := a.Marshal()
if err != nil {
t.Fatalf("Marshal errored: %v", err)
}
assert.Equal(t, b, mb, "Marshal bytes of TGSRep not as expected")
}

func TestUnmarshalEncKDCRepPart(t *testing.T) {
t.Parallel()
var a EncKDCRepPart
Expand Down
11 changes: 11 additions & 0 deletions v8/messages/KRBError.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/jcmturner/gofork/encoding/asn1"
"github.com/jcmturner/gokrb5/v8/asn1tools"
"github.com/jcmturner/gokrb5/v8/iana"
"github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
"github.com/jcmturner/gokrb5/v8/iana/errorcode"
Expand Down Expand Up @@ -59,6 +60,16 @@ func (k *KRBError) Unmarshal(b []byte) error {
return nil
}

// Marshal a KRBError into bytes.
func (k *KRBError) Marshal() ([]byte, error) {
b, err := asn1.Marshal(*k)
if err != nil {
return b, krberror.Errorf(err, krberror.EncodingError, "error marshaling KRBError")
}
b = asn1tools.AddASNAppTag(b, asnAppTag.KRBError)
return b, nil
}

// Error method implementing error interface on KRBError struct.
func (k KRBError) Error() string {
etxt := fmt.Sprintf("KRB Error: %s", errorcode.Lookup(k.ErrorCode))
Expand Down
16 changes: 14 additions & 2 deletions v8/messages/KRBError_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
"github.com/stretchr/testify/assert"
)

func TestUnmarshalKRBError(t *testing.T) {
func TestUnmarshalMarshalKRBError(t *testing.T) {
t.Parallel()
var a KRBError
b, err := hex.DecodeString(testdata.MarshaledKRB5error)
Expand Down Expand Up @@ -44,9 +44,15 @@ func TestUnmarshalKRBError(t *testing.T) {
assert.Equal(t, testdata.TEST_PRINCIPALNAME_NAMESTRING, a.SName.NameString, "Ticket SName name string entries not as expected")
assert.Equal(t, "krb5data", a.EText, "EText not as expected")
assert.Equal(t, []byte("krb5data"), a.EData, "EData not as expected")

b2, err := a.Marshal()
if err != nil {
t.Errorf("error marshalling KRBError: %v", err)
}
assert.Equal(t, b, b2, "marshalled bytes not as expected")
}

func TestUnmarshalKRBError_optionalsNULL(t *testing.T) {
func TestUnmarshalMarshalKRBError_optionalsNULL(t *testing.T) {
t.Parallel()
var a KRBError
b, err := hex.DecodeString(testdata.MarshaledKRB5errorOptionalsNULL)
Expand All @@ -70,4 +76,10 @@ func TestUnmarshalKRBError_optionalsNULL(t *testing.T) {
assert.Equal(t, nametype.KRB_NT_PRINCIPAL, a.SName.NameType, "Ticket SName NameType not as expected")
assert.Equal(t, len(testdata.TEST_PRINCIPALNAME_NAMESTRING), len(a.SName.NameString), "Ticket SName does not have the expected number of NameStrings")
assert.Equal(t, testdata.TEST_PRINCIPALNAME_NAMESTRING, a.SName.NameString, "Ticket SName name string entries not as expected")

b2, err := a.Marshal()
if err != nil {
t.Errorf("error marshalling KRBError: %v", err)
}
assert.Equal(t, b, b2, "marshalled bytes not as expected")
}
11 changes: 4 additions & 7 deletions v8/messages/Ticket.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package messages

import (
"crypto/rand"
"fmt"
"log"
"time"
Expand Down Expand Up @@ -60,13 +59,11 @@ func NewTicket(cname types.PrincipalName, crealm string, sname types.PrincipalNa
if err != nil {
return Ticket{}, types.EncryptionKey{}, krberror.Errorf(err, krberror.EncryptingError, "error getting etype for new ticket")
}
ks := etype.GetKeyByteSize()
kv := make([]byte, ks, ks)
rand.Read(kv)
sessionKey := types.EncryptionKey{
KeyType: eTypeID,
KeyValue: kv,
sessionKey, err := types.GenerateEncryptionKey(etype)
if err != nil {
return Ticket{}, types.EncryptionKey{}, krberror.Errorf(err, krberror.EncryptingError, "error generating session key")
}

etp := EncTicketPart{
Flags: flags,
Key: sessionKey,
Expand Down
16 changes: 16 additions & 0 deletions v8/types/Cryptosystem.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package types

import (
"crypto/rand"

"github.com/jcmturner/gofork/encoding/asn1"
"github.com/jcmturner/gokrb5/v8/crypto/etype"
)

// Reference: https://www.ietf.org/rfc/rfc4120.txt
Expand Down Expand Up @@ -53,3 +56,16 @@ func (a *Checksum) Unmarshal(b []byte) error {
_, err := asn1.Unmarshal(b, a)
return err
}

func GenerateEncryptionKey(etype etype.EType) (EncryptionKey, error) {
k := EncryptionKey{
KeyType: etype.GetETypeID(),
}
b := make([]byte, etype.GetKeyByteSize(), etype.GetKeyByteSize())
_, err := rand.Read(b)
if err != nil {
return k, err
}
k.KeyValue = b
return k, nil
}

0 comments on commit 9822c92

Please sign in to comment.