Sfoglia il codice sorgente

refactor re encryptionkey

Jonathan Turner 9 anni fa
parent
commit
0fdb91d2c6

+ 4 - 2
client/ASExchange.go

@@ -47,13 +47,15 @@ func (cl *Client) ASExchange() error {
 			if err != nil {
 				return fmt.Errorf("Error creating etype: %v", err)
 			}
-			paEncTS, err := crypto.GetEncryptedData(paTSb, etype, cl.Config.LibDefaults.Default_realm, cl.Credentials.Username, cl.Credentials.Keytab, 1)
+			//paEncTS, err := crypto.GetEncryptedData(paTSb, etype, cl.Config.LibDefaults.Default_realm, cl.Credentials.Username, cl.Credentials.Keytab, 1)
+			key, err := cl.Credentials.Keytab.GetEncryptionKey(cl.Credentials.Username, cl.Config.LibDefaults.Default_realm, 1, etype.GetETypeID())
+			paEncTS, err := crypto.GetEncryptedData(paTSb, key, 0, 1)
 			if err != nil {
 				return fmt.Errorf("Error encrypting pre-authentication timestamp: %v", err)
 			}
 			pa := types.PAData{
 				PADataType:  patype.PA_ENC_TIMESTAMP,
-				PADataValue: paEncTS,
+				PADataValue: paEncTS.Cipher,
 			}
 			a.PAData = append(a.PAData, pa)
 			b, err := a.Marshal()

+ 28 - 13
crypto/EncryptionEngine.go

@@ -8,7 +8,6 @@ import (
 	"errors"
 	"fmt"
 	"github.com/jcmturner/gokrb5/iana/patype"
-	"github.com/jcmturner/gokrb5/keytab"
 	"github.com/jcmturner/gokrb5/types"
 	"hash"
 )
@@ -153,8 +152,8 @@ func DecryptEncPart(key []byte, pe types.EncryptedData, etype EType, usage uint3
 	return b, nil
 }
 
-func GetKeyFromPassword(passwd string, cn types.PrincipalName, realm string, etypeId int, pas types.PADataSequence) ([]byte, EType, error) {
-	var key []byte
+func GetKeyFromPassword(passwd string, cn types.PrincipalName, realm string, etypeId int, pas types.PADataSequence) (types.EncryptionKey, EType, error) {
+	var key types.EncryptionKey
 	etype, err := GetEtype(etypeId)
 	if err != nil {
 		return key, etype, fmt.Errorf("Error getting encryption type: %v", err)
@@ -209,10 +208,14 @@ func GetKeyFromPassword(passwd string, cn types.PrincipalName, realm string, ety
 	if salt == "" {
 		salt = cn.GetSalt(realm)
 	}
-	key, err = etype.StringToKey(passwd, salt, sk2p)
+	k, err := etype.StringToKey(passwd, salt, sk2p)
 	if err != nil {
 		return key, etype, fmt.Errorf("Error deriving key from string: %+v", err)
 	}
+	key = types.EncryptionKey{
+		KeyType: etypeId,
+		KeyValue: k,
+	}
 	return key, etype, nil
 }
 
@@ -276,16 +279,28 @@ func getUsage(un uint32, o byte) []byte {
 	return append(buf.Bytes(), o)
 }
 
-func GetEncryptedData(b []byte, etype EType, crealm, username string, kt keytab.Keytab, kvno int) ([]byte, error) {
-	key, err := kt.GetKey(username, crealm, kvno, etype.GetETypeID())
-	_, cb, err := etype.Encrypt(key, b)
+// Pass a usage value of zero to use the key provided directly rather than deriving one
+func GetEncryptedData(pt []byte, key types.EncryptionKey, usage int, kvno int) (types.EncryptedData, error) {
+	var ed types.EncryptedData
+	etype, err := GetEtype(key.KeyType)
+	if err != nil {
+		return ed, fmt.Errorf("Error getting etype to encrypt authenticator: %v", err)
+	}
+	k := key.KeyValue
+	if usage != 0 {
+		k, err = etype.DeriveKey(key.KeyValue, GetUsageKe(uint32(usage)))
+	}
+	if err != nil {
+		return ed, fmt.Errorf("Error deriving key for authenticator: %v", err)
+	}
+	_, b, err := etype.Encrypt(k, pt)
 	if err != nil {
-		return b, fmt.Errorf("Error encrypting data to form EncryptedData: %v", err)
+		return ed, fmt.Errorf("Error encrypting authenticator: %v", err)
 	}
-	ed := types.EncryptedData{
-		KVNO:   kvno,
-		EType:  etype.GetETypeID(),
-		Cipher: cb,
+	ed = types.EncryptedData{
+		EType: key.KeyType,
+		Cipher: b,
+		KVNO: kvno,
 	}
-	return ed.Marshal()
+	return ed, nil
 }

+ 31 - 20
keytab/keytab.go

@@ -9,6 +9,7 @@ import (
 	"io/ioutil"
 	"time"
 	"unsafe"
+	"github.com/jcmturner/gokrb5/types"
 )
 
 type Keytab struct {
@@ -20,7 +21,7 @@ type KeytabEntry struct {
 	Principal Principal
 	Timestamp time.Time
 	KVNO8     uint8
-	Key       KeyBlock
+	Key       types.EncryptionKey
 	KVNO      uint32
 }
 
@@ -31,11 +32,6 @@ type Principal struct {
 	NameType      int32
 }
 
-type KeyBlock struct {
-	EType       uint16
-	KeyMaterial []byte
-}
-
 //Create new, empty Keytab type
 func NewKeytab() Keytab {
 	var e []KeytabEntry
@@ -46,14 +42,14 @@ func NewKeytab() Keytab {
 }
 
 // Get the key material from the keytab for the newest entry with the required kvno, etype and matching principal
-func (kt *Keytab) GetKey(username, realm string, kvno, etype int) ([]byte, error) {
+/*func (kt *Keytab) GetKey(username, realm string, kvno, etype int) ([]byte, error) {
 	var key []byte
 	var t time.Time
 	for _, k := range kt.Entries {
-		if k.Principal.Realm == realm && int(k.Key.EType) == etype && (int(k.KVNO) == kvno || kvno == 0) && k.Timestamp.After(t) {
+		if k.Principal.Realm == realm && int(k.Key.KeyType) == etype && (int(k.KVNO) == kvno || kvno == 0) && k.Timestamp.After(t) {
 			for _, n := range k.Principal.Components {
 				if n == username {
-					key = k.Key.KeyMaterial
+					key = k.Key.KeyValue
 				}
 			}
 		}
@@ -62,14 +58,37 @@ func (kt *Keytab) GetKey(username, realm string, kvno, etype int) ([]byte, error
 		return key, errors.New("Matching key not found in keytab")
 	}
 	return key, nil
+}*/
+
+// Get the EncryptionKey from the keytab for the newest entry with the required kvno, etype and matching principal
+func (kt *Keytab) GetEncryptionKey(username, realm string, kvno, etype int) (types.EncryptionKey, error) {
+	var key types.EncryptionKey
+	var t time.Time
+	for _, k := range kt.Entries {
+		if k.Principal.Realm == realm && int(k.Key.KeyType) == etype && (int(k.KVNO) == kvno || kvno == 0) && k.Timestamp.After(t) {
+			for _, n := range k.Principal.Components {
+				if n == username {
+					key = k.Key
+				}
+			}
+		}
+	}
+	if len(key.KeyValue) < 1 {
+		return key, errors.New("Matching key not found in keytab")
+	}
+	return key, nil
 }
 
 func newKeytabEntry() KeytabEntry {
+	var b []byte
 	return KeytabEntry{
 		Principal: newPrincipal(),
 		Timestamp: time.Time{},
 		KVNO8:     0,
-		Key:       newKeyBlock(),
+		Key:       types.EncryptionKey{
+			KeyType: 0,
+			KeyValue: b,
+		},
 		KVNO:      0,
 	}
 }
@@ -84,14 +103,6 @@ func newPrincipal() Principal {
 	}
 }
 
-func newKeyBlock() KeyBlock {
-	var b []byte
-	return KeyBlock{
-		EType:       0,
-		KeyMaterial: b,
-	}
-}
-
 //Load a keytab file into Keytab type
 func Load(ktPath string) (kt Keytab, err error) {
 	k, err := ioutil.ReadFile(ktPath)
@@ -146,9 +157,9 @@ func Parse(b []byte) (kt Keytab, err error) {
 			parse_principal(eb, &p, &kt, &ke, &endian)
 			ke.Timestamp = read_timestamp(eb, &p, &endian)
 			ke.KVNO8 = uint8(read_int8(eb, &p, &endian))
-			ke.Key.EType = uint16(read_int16(eb, &p, &endian))
+			ke.Key.KeyType = int(read_int16(eb, &p, &endian))
 			key_len := int(read_int16(eb, &p, &endian))
-			ke.Key.KeyMaterial = read_Bytes(eb, &p, key_len, &endian)
+			ke.Key.KeyValue = read_Bytes(eb, &p, key_len, &endian)
 			//The 32-bit key version overrides the 8-bit key version.
 			// To determine if it is present, the implementation must check that at least 4 bytes remain in the record after the other fields are read,
 			// and that the value of the 32-bit integer contained in those bytes is non-zero.

+ 2 - 2
keytab/keytab_test.go

@@ -20,8 +20,8 @@ func TestParse(t *testing.T) {
 	assert.Equal(t, uint32(1), kt.Entries[0].KVNO, "KVNO not as expected")
 	assert.Equal(t, uint8(1), kt.Entries[0].KVNO8, "KVNO8 not as expected")
 	assert.Equal(t, time.Unix(1483384877, 0), kt.Entries[0].Timestamp, "Timestamp not as expected")
-	assert.Equal(t, uint16(23), kt.Entries[0].Key.EType, "Key's EType not as expected")
-	assert.Equal(t, "0c61039f010b2fbb88fe449fbf262477", hex.EncodeToString(kt.Entries[0].Key.KeyMaterial), "Key material not as expected")
+	assert.Equal(t, 23, kt.Entries[0].Key.KeyType, "Key's EType not as expected")
+	assert.Equal(t, "0c61039f010b2fbb88fe449fbf262477", hex.EncodeToString(kt.Entries[0].Key.KeyValue), "Key material not as expected")
 	assert.Equal(t, int16(1), kt.Entries[0].Principal.NumComponents, "Number of components in principal not as expected")
 	assert.Equal(t, int32(1), kt.Entries[0].Principal.NameType, "Name type of principal not as expected")
 	assert.Equal(t, "EXAMPLE.COM", kt.Entries[0].Principal.Realm, "Realm of principal not as expected")

+ 5 - 5
messages/KDCRep.go

@@ -129,14 +129,14 @@ func (e *EncKDCRepPart) Unmarshal(b []byte) error {
 
 func (k *ASRep) DecryptEncPart(c *credentials.Credentials) error {
 	var etype crypto.EType
-	var key []byte
+	var key types.EncryptionKey
 	var err error
 	if c.HasKeytab() {
 		etype, err = crypto.GetEtype(k.EncPart.EType)
 		if err != nil {
 			return fmt.Errorf("Error getting encryption type: %v", err)
 		}
-		key, err = c.Keytab.GetKey(k.CName.NameString[0], k.CRealm, k.EncPart.KVNO, k.EncPart.EType)
+		key, err = c.Keytab.GetEncryptionKey(k.CName.NameString[0], k.CRealm, k.EncPart.KVNO, k.EncPart.EType)
 		if err != nil {
 			return fmt.Errorf("Could not get key from keytab: %v", err)
 		}
@@ -150,7 +150,7 @@ func (k *ASRep) DecryptEncPart(c *credentials.Credentials) error {
 	if !c.HasKeytab() && !c.HasPassword() {
 		return errors.New("No secret available in credentials to preform decryption")
 	}
-	b, err := crypto.DecryptEncPart(key, k.EncPart, etype, keyusage.AS_REP_ENCPART)
+	b, err := crypto.DecryptEncPart(key.KeyValue, k.EncPart, etype, keyusage.AS_REP_ENCPART)
 	if err != nil {
 		return fmt.Errorf("Error decrypting KDC_REP EncPart: %v", err)
 	}
@@ -209,11 +209,11 @@ func (k *TGSRep) DecryptEncPart(kt keytab.Keytab) error {
 	if err != nil {
 		return fmt.Errorf("Keytab error: %v", err)
 	}
-	key, err := kt.GetKey(k.CName.NameString[0], k.CRealm, k.EncPart.KVNO, k.EncPart.EType)
+	key, err := kt.GetEncryptionKey(k.CName.NameString[0], k.CRealm, k.EncPart.KVNO, k.EncPart.EType)
 	if err != nil {
 		return fmt.Errorf("Could not get key from keytab: %v", err)
 	}
-	b, err := crypto.DecryptEncPart(key, k.EncPart, etype, keyusage.AS_REP_ENCPART)
+	b, err := crypto.DecryptEncPart(key.KeyValue, k.EncPart, etype, keyusage.AS_REP_ENCPART)
 	if err != nil {
 		return fmt.Errorf("Error decrypting KDC_REP EncPart: %v", err)
 	}

+ 18 - 0
types/Authenticator_test.go

@@ -72,3 +72,21 @@ func TestUnmarshalAuthenticator_optionalsNULL(t *testing.T) {
 	assert.Equal(t, 123456, a.Cusec, "Client microseconds not as expected")
 	assert.Equal(t, tt, a.CTime, "Client time not as expected")
 }
+
+func TestMarshalAuthenticator(t *testing.T) {
+	var a Authenticator
+	v := "encode_krb5_authenticator"
+	b, err := hex.DecodeString(testdata.TestVectors[v])
+	if err != nil {
+		t.Fatalf("Test vector read error of %s: %v\n", v, err)
+	}
+	err = a.Unmarshal(b)
+	if err != nil {
+		t.Fatalf("Unmarshal error of %s: %v\n", v, err)
+	}
+	mb, err := a.Marshal()
+	if err != nil {
+		t.Fatalf("Marshal of ticket errored: %v", err)
+	}
+	assert.Equal(t, b, mb, "Marshal bytes of Authenticator not as expected")
+}

+ 18 - 0
types/Cryptosystem_test.go

@@ -70,3 +70,21 @@ func TestUnmarshalEncryptionKey(t *testing.T) {
 	assert.Equal(t, 1, a.KeyType, "Key type not as expected")
 	assert.Equal(t, []byte("12345678"), a.KeyValue, "Key value not as expected")
 }
+
+func TestMarshalEncryptedData(t *testing.T) {
+	var a EncryptedData
+	v := "encode_krb5_enc_data"
+	b, err := hex.DecodeString(testdata.TestVectors[v])
+	if err != nil {
+		t.Fatalf("Test vector read error of %s: %v\n", v, err)
+	}
+	err = a.Unmarshal(b)
+	if err != nil {
+		t.Fatalf("Unmarshal error of %s: %v\n", v, err)
+	}
+	mb, err := a.Marshal()
+	if err != nil {
+		t.Fatalf("Marshal of ticket errored: %v", err)
+	}
+	assert.Equal(t, b, mb, "Marshal bytes of Encrypted Data not as expected")
+}