فهرست منبع

add marshal methods KDC replies

Jonathan Turner 6 سال پیش
والد
کامیت
9822c92fbe
7فایلهای تغییر یافته به همراه153 افزوده شده و 17 حذف شده
  1. 4 8
      v8/client/network.go
  2. 68 0
      v8/messages/KDCRep.go
  3. 36 0
      v8/messages/KDCRep_test.go
  4. 11 0
      v8/messages/KRBError.go
  5. 14 2
      v8/messages/KRBError_test.go
  6. 4 7
      v8/messages/Ticket.go
  7. 16 0
      v8/types/Cryptosystem.go

+ 4 - 8
v8/client/network.go

@@ -1,7 +1,6 @@
 package client
 
 import (
-	"bytes"
 	"encoding/binary"
 	"errors"
 	"fmt"
@@ -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)
 	}

+ 68 - 0
v8/messages/KDCRep.go

@@ -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"
@@ -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
@@ -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))
@@ -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
@@ -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)

+ 36 - 0
v8/messages/KDCRep_test.go

@@ -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
@@ -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

+ 11 - 0
v8/messages/KRBError.go

@@ -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"
@@ -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))

+ 14 - 2
v8/messages/KRBError_test.go

@@ -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)
@@ -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)
@@ -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")
 }

+ 4 - 7
v8/messages/Ticket.go

@@ -1,7 +1,6 @@
 package messages
 
 import (
-	"crypto/rand"
 	"fmt"
 	"log"
 	"time"
@@ -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,

+ 16 - 0
v8/types/Cryptosystem.go

@@ -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
@@ -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
+}