Jonathan Turner 8 лет назад
Родитель
Сommit
d3bdd4d8c6

+ 1 - 0
README.md

@@ -24,6 +24,7 @@
 | aes256-cts-hmac-sha1-96 | 18 | 16 | 3962 |
 | aes128-cts-hmac-sha256-128 | 19 | 19 | 8009 |
 | aes256-cts-hmac-sha384-192 | 20 | 20 | 8009 |
+| rc4-hmac | 23 | -138 | 4757 |
 
 
 Currently the following is working/tested:

+ 17 - 0
client/client_integration_test.go

@@ -106,6 +106,23 @@ func TestClient_SuccessfulLogin_ETYPE_AES256_CTS_HMAC_SHA384_192(t *testing.T) {
 	}
 }
 
+func TestClient_SuccessfulLogin_RC4HMAC(t *testing.T) {
+	b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
+	c.LibDefaults.DefaultTktEnctypes = []string{"rc4-hmac"}
+	c.LibDefaults.DefaultTktEnctypeIDs = []int{etypeID.RC4_HMAC}
+	c.LibDefaults.DefaultTGSEnctypes = []string{"rc4-hmac"}
+	c.LibDefaults.DefaultTGSEnctypeIDs = []int{etypeID.RC4_HMAC}
+	cl := NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
+	cl.WithConfig(c)
+
+	err = cl.Login()
+	if err != nil {
+		t.Fatalf("Error on login: %v\n", err)
+	}
+}
+
 func TestClient_SuccessfulLogin_AD(t *testing.T) {
 	b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
 	kt, _ := keytab.Parse(b)

+ 6 - 0
crypto/crypto.go

@@ -30,6 +30,9 @@ func GetEtype(id int) (etype.EType, error) {
 	case etypeID.DES3_CBC_SHA1_KD:
 		var et Des3CbcSha1Kd
 		return et, nil
+	case etypeID.RC4_HMAC:
+		var et RC4HMAC
+		return et, nil
 	default:
 		return nil, fmt.Errorf("Unknown or unsupported EType: %d", id)
 	}
@@ -53,6 +56,9 @@ func GetChksumEtype(id int) (etype.EType, error) {
 	case chksumtype.HMAC_SHA1_DES3_KD:
 		var et Des3CbcSha1Kd
 		return et, nil
+	case chksumtype.KERB_CHECKSUM_HMAC_MD5:
+		var et RC4HMAC
+		return et, nil
 	default:
 		return nil, fmt.Errorf("Unknown or unsupported checksum type: %d", id)
 	}

+ 137 - 0
crypto/rc4-hmac.go

@@ -0,0 +1,137 @@
+package crypto
+
+import (
+	"bytes"
+	"crypto/md5"
+	"github.com/jcmturner/gokrb5/crypto/common"
+	"github.com/jcmturner/gokrb5/crypto/rfc3961"
+	"github.com/jcmturner/gokrb5/crypto/rfc4757"
+	"github.com/jcmturner/gokrb5/iana/chksumtype"
+	"github.com/jcmturner/gokrb5/iana/etypeID"
+	"golang.org/x/crypto/md4"
+	"hash"
+	"io"
+)
+
+//http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/sun/security/krb5/internal/crypto/dk/ArcFourCrypto.java#ArcFourCrypto.encrypt%28byte%5B%5D%2Cint%2Cbyte%5B%5D%2Cbyte%5B%5D%2Cbyte%5B%5D%2Cint%2Cint%29
+
+// RC4HMAC implements Kerberos encryption type aes256-cts-hmac-sha1-96
+type RC4HMAC struct {
+}
+
+// GetETypeID returns the EType ID number.
+func (e RC4HMAC) GetETypeID() int {
+	return etypeID.RC4_HMAC
+}
+
+// GetHashID returns the checksum type ID number.
+func (e RC4HMAC) GetHashID() int {
+	return chksumtype.KERB_CHECKSUM_HMAC_MD5
+}
+
+// GetKeyByteSize returns the number of bytes for key of this etype.
+func (e RC4HMAC) GetKeyByteSize() int {
+	return 16
+}
+
+// GetKeySeedBitLength returns the number of bits for the seed for key generation.
+func (e RC4HMAC) GetKeySeedBitLength() int {
+	return e.GetKeyByteSize() * 8
+}
+
+// GetHashFunc returns the hash function for this etype.
+func (e RC4HMAC) GetHashFunc() func() hash.Hash {
+	return md5.New
+}
+
+// GetMessageBlockByteSize returns the block size for the etype's messages.
+func (e RC4HMAC) GetMessageBlockByteSize() int {
+	return 1
+}
+
+// GetDefaultStringToKeyParams returns the default key derivation parameters in string form.
+func (e RC4HMAC) GetDefaultStringToKeyParams() string {
+	return ""
+}
+
+// GetConfounderByteSize returns the byte count for confounder to be used during cryptographic operations.
+func (e RC4HMAC) GetConfounderByteSize() int {
+	return 8
+}
+
+// GetHMACBitLength returns the bit count size of the integrity hash.
+func (e RC4HMAC) GetHMACBitLength() int {
+	return md5.Size * 8
+}
+
+// GetCypherBlockBitLength returns the bit count size of the cypher block.
+func (e RC4HMAC) GetCypherBlockBitLength() int {
+	return 8 // doesn't really apply
+}
+
+// StringToKey returns a key derived from the string provided.
+func (e RC4HMAC) StringToKey(secret string, salt string, s2kparams string) ([]byte, error) {
+	return rfc4757.StringToKey(secret)
+}
+
+// RandomToKey returns a key from the bytes provided.
+func (e RC4HMAC) RandomToKey(b []byte) []byte {
+	r := bytes.NewReader(b)
+	h := md4.New()
+	io.Copy(h, r)
+	return h.Sum(nil)
+}
+
+// EncryptData encrypts the data provided.
+func (e RC4HMAC) EncryptData(key, data []byte) ([]byte, []byte, error) {
+	b, err := rfc4757.EncryptData(key, data, e)
+	return []byte{}, b, err
+}
+
+// EncryptMessage encrypts the message provided and concatenates it with the integrity hash to create an encrypted message.
+func (e RC4HMAC) EncryptMessage(key, message []byte, usage uint32) ([]byte, []byte, error) {
+	b, err := rfc4757.EncryptMessage(key, message, usage, false, e)
+	return []byte{}, b, err
+}
+
+// DecryptData decrypts the data provided.
+func (e RC4HMAC) DecryptData(key, data []byte) ([]byte, error) {
+	return rfc4757.DecryptData(key, data, e)
+}
+
+// DecryptMessage decrypts the message provided and verifies the integrity of the message.
+func (e RC4HMAC) DecryptMessage(key, ciphertext []byte, usage uint32) ([]byte, error) {
+	return rfc4757.DecryptMessage(key, ciphertext, usage, false, e)
+}
+
+// DeriveKey derives a key from the protocol key based on the usage value.
+func (e RC4HMAC) DeriveKey(protocolKey, usage []byte) ([]byte, error) {
+	return rfc4757.HMAC(protocolKey, usage), nil
+}
+
+// DeriveRandom generates data needed for key generation.
+func (e RC4HMAC) DeriveRandom(protocolKey, usage []byte) ([]byte, error) {
+	return rfc3961.DeriveRandom(protocolKey, usage, e)
+}
+
+// VerifyIntegrity checks the integrity of the plaintext message.
+func (e RC4HMAC) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool {
+	return rfc4757.VerifyIntegrity(protocolKey, pt, ct, e)
+}
+
+// GetChecksumHash returns a keyed checksum hash of the bytes provided.
+func (e RC4HMAC) GetChecksumHash(protocolKey, data []byte, usage uint32) ([]byte, error) {
+	return common.GetHash(data, protocolKey, common.GetUsageKc(usage), e)
+}
+
+// VerifyChecksum compares the checksum of the message bytes is the same as the checksum provided.
+func (e RC4HMAC) VerifyChecksum(protocolKey, data, chksum []byte, usage uint32) bool {
+	checksum, err := rfc4757.Checksum(protocolKey, usage, data)
+	if err != nil {
+		return false
+	}
+	if !bytes.Equal(checksum, chksum) {
+		return false
+	}
+	return true
+}

+ 38 - 0
crypto/rfc4757/checksum.go

@@ -0,0 +1,38 @@
+package rfc4757
+
+import (
+	"bytes"
+	"crypto/hmac"
+	"crypto/md5"
+	"io"
+)
+
+func Checksum(key []byte, T uint32, data []byte) ([]byte, error) {
+	// Create hashing key
+	s := append([]byte(`signaturekey`), byte(0x00)) //includes zero octet at end
+	mac := hmac.New(md5.New, key)
+	mac.Write(s)
+	Ksign := mac.Sum(nil)
+
+	// Format data
+	tb := MessageTypeBytes(T)
+	p := append(tb, data...)
+	h := md5.New()
+	rb := bytes.NewReader(p)
+	_, err := io.Copy(h, rb)
+	if err != nil {
+		return []byte{}, err
+	}
+	tmp := h.Sum(nil)
+
+	// Generate HMAC
+	mac = hmac.New(md5.New, Ksign)
+	mac.Write(tmp)
+	return mac.Sum(nil), nil
+}
+
+func HMAC(key []byte, data []byte) []byte {
+	mac := hmac.New(md5.New, key)
+	mac.Write(data)
+	return mac.Sum(nil)
+}

+ 81 - 0
crypto/rfc4757/encryption.go

@@ -0,0 +1,81 @@
+// Package rfc3962 provides encryption and checksum methods as specified in RFC 4757
+package rfc4757
+
+import (
+	"bytes"
+	"crypto/rand"
+	"crypto/rc4"
+	"errors"
+	"fmt"
+	"github.com/jcmturner/gokrb5/crypto/etype"
+)
+
+// EncryptData encrypts the data provided using methods specific to the etype provided as defined in RFC 4757.
+func EncryptData(key, data []byte, e etype.EType) ([]byte, error) {
+	if len(key) != e.GetKeyByteSize() {
+		return []byte{}, fmt.Errorf("Incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
+	}
+	rc4Cipher, err := rc4.NewCipher(key)
+	if err != nil {
+		return []byte{}, fmt.Errorf("Error creating RC4 cipher: %v", err)
+	}
+	ed := make([]byte, len(data))
+	copy(ed, data)
+	rc4Cipher.XORKeyStream(ed, ed)
+	rc4Cipher.Reset()
+	return ed, nil
+}
+
+// DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 4757.
+func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
+	return EncryptData(key, data, e)
+}
+
+// EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 4757.
+// The encrypted data is concatenated with its RC4 header containing integrity checksum and confounder to create an encrypted message.
+func EncryptMessage(key, data []byte, usage uint32, export bool, e etype.EType) ([]byte, error) {
+	confounder := make([]byte, e.GetConfounderByteSize()) // size = 8
+	_, err := rand.Read(confounder)
+	if err != nil {
+		return []byte{}, fmt.Errorf("Error generating confounder: %v", err)
+	}
+	k1 := key
+	k2 := HMAC(k1, MessageTypeBytes(usage))
+	toenc := append(confounder, data...)
+	chksum := HMAC(k2, toenc)
+	k3 := HMAC(k2, chksum)
+
+	ed, err := EncryptData(k3, toenc, e)
+	if err != nil {
+		return []byte{}, fmt.Errorf("Error encrypting data: %v", err)
+	}
+
+	msg := append(chksum, ed...)
+	return msg, nil
+}
+
+// DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 4757.
+// The integrity of the message is also verified.
+func DecryptMessage(key, data []byte, usage uint32, export bool, e etype.EType) ([]byte, error) {
+	checksum := data[:e.GetHMACBitLength()/8]
+	ct := data[e.GetHMACBitLength()/8:]
+	_, k2, k3 := deriveKeys(key, checksum, usage, export)
+
+	pt, err := DecryptData(k3, ct, e)
+	if err != nil {
+		return []byte{}, fmt.Errorf("Error decrypting data: %v", err)
+	}
+
+	if !VerifyIntegrity(k2, pt, data, e) {
+		return []byte{}, errors.New("Integrity checksum incorrect")
+	}
+	return pt[e.GetConfounderByteSize():], nil
+}
+
+func VerifyIntegrity(key, pt, data []byte, e etype.EType) bool {
+	chksum := HMAC(key, pt)
+	if bytes.Equal(chksum, data[:e.GetHMACBitLength()/8]) {
+		return true
+	}
+	return false
+}

+ 54 - 0
crypto/rfc4757/keyDerivation.go

@@ -0,0 +1,54 @@
+package rfc4757
+
+import (
+	"bytes"
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"golang.org/x/crypto/md4"
+	"io"
+)
+
+// StringToKey returns a key derived from the string provided according to the definition in RFC 4757.
+func StringToKey(secret string) ([]byte, error) {
+	b := make([]byte, len(secret)*2, len(secret)*2)
+	for i, r := range secret {
+		u := fmt.Sprintf("%04x", r)
+		c, err := hex.DecodeString(u)
+		if err != nil {
+			return []byte{}, errors.New("character could not be encoded")
+		}
+		// Swap round the two bytes to make little endian as we put into byte slice
+		b[2*i] = c[1]
+		b[2*i+1] = c[0]
+	}
+	r := bytes.NewReader(b)
+	h := md4.New()
+	_, err := io.Copy(h, r)
+	if err != nil {
+		return []byte{}, err
+	}
+	return h.Sum(nil), nil
+}
+
+func deriveKeys(key, checksum []byte, usage uint32, export bool) (k1, k2, k3 []byte) {
+	//if export {
+	//	L40 := make([]byte, 14, 14)
+	//	copy(L40, []byte(`fortybits`))
+	//	k1 = HMAC(key, L40)
+	//} else {
+	//	tb := MessageTypeBytes(usage)
+	//	k1 = HMAC(key, tb)
+	//}
+	//k2 = k1[:16]
+	//if export {
+	//	mask := []byte{0xAB,0xAB,0xAB,0xAB,0xAB,0xAB,0xAB,0xAB,0xAB}
+	//	copy(k1[7:16], mask)
+	//}
+	//k3 = HMAC(k1, checksum)
+	//return
+	k1 = key
+	k2 = HMAC(k1, MessageTypeBytes(usage))
+	k3 = HMAC(k2, checksum)
+	return
+}

+ 21 - 0
crypto/rfc4757/keyDerivation_test.go

@@ -0,0 +1,21 @@
+package rfc4757
+
+import (
+	"encoding/hex"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+const (
+	testPassword = "foo"
+	testKey      = "ac8e657f83df82beea5d43bdaf7800cc"
+)
+
+func TestStringToKey(t *testing.T) {
+	kb, err := StringToKey(testPassword)
+	if err != nil {
+		t.Fatalf("Error deriving key from string: %v", err)
+	}
+	k := hex.EncodeToString(kb)
+	assert.Equal(t, testKey, k, "Key not as expected")
+}

+ 19 - 0
crypto/rfc4757/msgtype.go

@@ -0,0 +1,19 @@
+package rfc4757
+
+import "encoding/binary"
+
+func MessageTypeBytes(T uint32) []byte {
+	// Translate usage numbers to the Microsoft T numbers
+	switch T {
+	case 3:
+		T = 8
+	case 9:
+		T = 8
+	case 23:
+		T = 13
+	}
+	// Now convert to bytes
+	tb := make([]byte, 4) // We force an int32 input so we can't go over 4 bytes
+	binary.PutUvarint(tb, uint64(T))
+	return tb
+}

+ 3 - 3
testdata/test_vectors.go

@@ -109,10 +109,10 @@ var TestVectors = map[string]string{
 }
 
 const (
-	TESTUSER1_KEYTAB      = "05020000003b0001000b544553542e474f4b524235000974657374757365723100000001592d16240100110010698c4df8e9f60e7eea5a21bf4526ad25000000010000004b0001000b544553542e474f4b524235000974657374757365723100000001592d16240100120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de9000000010000003b0001000b544553542e474f4b524235000974657374757365723100000001592d16240200110010698c4df8e9f60e7eea5a21bf4526ad25000000020000004b0001000b544553542e474f4b524235000974657374757365723100000001592d16240200120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de9000000020000003b0001000b544553542e474f4b524235000974657374757365723100000001592d162401001300102eb8501967a7886e1f0c63ac9be8c4a0000000010000003b0001000b544553542e474f4b524235000974657374757365723100000001592d162402001300102eb8501967a7886e1f0c63ac9be8c4a0000000020000004b0001000b544553542e474f4b524235000974657374757365723100000001592d162401001400208ad66f209bb07daa186f8a229830f5ba06a3a2a33638f4ec66e1d29324e417ee000000010000004b0001000b544553542e474f4b524235000974657374757365723100000001592d162402001400208ad66f209bb07daa186f8a229830f5ba06a3a2a33638f4ec66e1d29324e417ee00000002000000430001000b544553542e474f4b524235000974657374757365723100000001592d162401001000184580fb91760dabe6f808c22c26494f644cb35d61d32c79e300000001000000430001000b544553542e474f4b524235000974657374757365723100000001592d162402001000184580fb91760dabe6f808c22c26494f644cb35d61d32c79e300000002"
+	TESTUSER1_KEYTAB      = "05020000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80100110010698c4df8e9f60e7eea5a21bf4526ad25000000010000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80100120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de9000000010000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80200110010698c4df8e9f60e7eea5a21bf4526ad25000000020000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80200120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de9000000020000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d801001300102eb8501967a7886e1f0c63ac9be8c4a0000000010000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d802001300102eb8501967a7886e1f0c63ac9be8c4a0000000020000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d801001400208ad66f209bb07daa186f8a229830f5ba06a3a2a33638f4ec66e1d29324e417ee000000010000004b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d802001400208ad66f209bb07daa186f8a229830f5ba06a3a2a33638f4ec66e1d29324e417ee00000002000000430001000b544553542e474f4b52423500097465737475736572310000000159beb1d801001000184580fb91760dabe6f808c22c26494f644cb35d61d32c79e300000001000000430001000b544553542e474f4b52423500097465737475736572310000000159beb1d802001000184580fb91760dabe6f808c22c26494f644cb35d61d32c79e3000000020000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80100170010084768c373663b3bef1f6385883cf7ff000000010000003b0001000b544553542e474f4b52423500097465737475736572310000000159beb1d80200170010084768c373663b3bef1f6385883cf7ff00000002"
 	TESTUSER1_WRONGPASSWD = "0502000000370001000b544553542e474f4b52423500097465737475736572310000000158ef4bc5010011001039a9a382153105f8708e80f93382654e000000470001000b544553542e474f4b52423500097465737475736572310000000158ef4bc60100120020fc5bb940d6075214e0c6fc0456ce68c33306094198a927b4187d7cf3f4aea50d"
-	TESTUSER2_KEYTAB      = "05020000003b0001000b544553542e474f4b524235000974657374757365723200000001592d166f010011001086824c55ff5de30386dd83dc62b44bb7000000010000004b0001000b544553542e474f4b524235000974657374757365723200000001592d166f0100120020d8ed27f96be76fd5b281ee9f8029db93cc5fb06c7eb3be9ee753106d3488fa92000000010000003b0001000b544553542e474f4b524235000974657374757365723200000001592d166f020011001086824c55ff5de30386dd83dc62b44bb7000000020000004b0001000b544553542e474f4b524235000974657374757365723200000001592d166f0200120020d8ed27f96be76fd5b281ee9f8029db93cc5fb06c7eb3be9ee753106d3488fa92000000020000003b0001000b544553542e474f4b524235000974657374757365723200000001592d166f01001300106ccff358aaa8a4a41c444e173b1463c2000000010000003b0001000b544553542e474f4b524235000974657374757365723200000001592d166f02001300106ccff358aaa8a4a41c444e173b1463c2000000020000004b0001000b544553542e474f4b524235000974657374757365723200000001592d166f01001400205cf3773dd920be800229ac1c6f9bf59c6706c583f82c2dea66c9a29152118cd7000000010000004b0001000b544553542e474f4b524235000974657374757365723200000001592d166f02001400205cf3773dd920be800229ac1c6f9bf59c6706c583f82c2dea66c9a29152118cd700000002000000430001000b544553542e474f4b524235000974657374757365723200000001592d166f0100100018bc025746e9e66bd6b62a918f6413d529803192a28aabf79200000001000000430001000b544553542e474f4b524235000974657374757365723200000001592d166f0200100018bc025746e9e66bd6b62a918f6413d529803192a28aabf79200000002"
-	TESTUSER3_KEYTAB      = "05020000003b0001000b544553542e474f4b524235000974657374757365723300000001592d16c30100110010220789f5cf68e44a852c73b1e3729efc000000010000004b0001000b544553542e474f4b524235000974657374757365723300000001592d16c301001200205e1b7287f78f3f88c9eefe92c08ec1613f35d72bc6ee2c2e1c5cb6fb9d8b0580000000010000003b0001000b544553542e474f4b524235000974657374757365723300000001592d16c30200110010220789f5cf68e44a852c73b1e3729efc000000020000004b0001000b544553542e474f4b524235000974657374757365723300000001592d16c302001200205e1b7287f78f3f88c9eefe92c08ec1613f35d72bc6ee2c2e1c5cb6fb9d8b0580000000020000003b0001000b544553542e474f4b524235000974657374757365723300000001592d16c30100130010d2509e2bf9c08f73aafe08745c85e8fd000000010000003b0001000b544553542e474f4b524235000974657374757365723300000001592d16c30200130010d2509e2bf9c08f73aafe08745c85e8fd000000020000004b0001000b544553542e474f4b524235000974657374757365723300000001592d16c3010014002060e5e3fb9166db825eb3e4ff4bd1f4307e3f5fe85cdf7faccf8d65330557f74e000000010000004b0001000b544553542e474f4b524235000974657374757365723300000001592d16c3020014002060e5e3fb9166db825eb3e4ff4bd1f4307e3f5fe85cdf7faccf8d65330557f74e00000002000000430001000b544553542e474f4b524235000974657374757365723300000001592d16c301001000182cad768989a125fd26f24adf671976456d8097548c4c83f100000001000000430001000b544553542e474f4b524235000974657374757365723300000001592d16c302001000182cad768989a125fd26f24adf671976456d8097548c4c83f100000002"
+	TESTUSER2_KEYTAB      = "05020000003b0001000b544553542e474f4b52423500097465737475736572320000000159beb240010011001086824c55ff5de30386dd83dc62b44bb7000000010000004b0001000b544553542e474f4b52423500097465737475736572320000000159beb2400100120020d8ed27f96be76fd5b281ee9f8029db93cc5fb06c7eb3be9ee753106d3488fa92000000010000003b0001000b544553542e474f4b52423500097465737475736572320000000159beb240020011001086824c55ff5de30386dd83dc62b44bb7000000020000004b0001000b544553542e474f4b52423500097465737475736572320000000159beb2400200120020d8ed27f96be76fd5b281ee9f8029db93cc5fb06c7eb3be9ee753106d3488fa92000000020000003b0001000b544553542e474f4b52423500097465737475736572320000000159beb24001001300106ccff358aaa8a4a41c444e173b1463c2000000010000003b0001000b544553542e474f4b52423500097465737475736572320000000159beb24002001300106ccff358aaa8a4a41c444e173b1463c2000000020000004b0001000b544553542e474f4b52423500097465737475736572320000000159beb24001001400205cf3773dd920be800229ac1c6f9bf59c6706c583f82c2dea66c9a29152118cd7000000010000004b0001000b544553542e474f4b52423500097465737475736572320000000159beb24002001400205cf3773dd920be800229ac1c6f9bf59c6706c583f82c2dea66c9a29152118cd700000002000000430001000b544553542e474f4b52423500097465737475736572320000000159beb2400100100018bc025746e9e66bd6b62a918f6413d529803192a28aabf79200000001000000430001000b544553542e474f4b52423500097465737475736572320000000159beb2400200100018bc025746e9e66bd6b62a918f6413d529803192a28aabf792000000020000003b0001000b544553542e474f4b52423500097465737475736572320000000159beb2400100170010084768c373663b3bef1f6385883cf7ff000000010000003b0001000b544553542e474f4b52423500097465737475736572320000000159beb2400200170010084768c373663b3bef1f6385883cf7ff00000002"
+	TESTUSER3_KEYTAB      = "05020000003b0001000b544553542e474f4b52423500097465737475736572330000000159beb2740100110010220789f5cf68e44a852c73b1e3729efc000000010000004b0001000b544553542e474f4b52423500097465737475736572330000000159beb27401001200205e1b7287f78f3f88c9eefe92c08ec1613f35d72bc6ee2c2e1c5cb6fb9d8b0580000000010000003b0001000b544553542e474f4b52423500097465737475736572330000000159beb2740200110010220789f5cf68e44a852c73b1e3729efc000000020000004b0001000b544553542e474f4b52423500097465737475736572330000000159beb27402001200205e1b7287f78f3f88c9eefe92c08ec1613f35d72bc6ee2c2e1c5cb6fb9d8b0580000000020000003b0001000b544553542e474f4b52423500097465737475736572330000000159beb2740100130010d2509e2bf9c08f73aafe08745c85e8fd000000010000003b0001000b544553542e474f4b52423500097465737475736572330000000159beb2740200130010d2509e2bf9c08f73aafe08745c85e8fd000000020000004b0001000b544553542e474f4b52423500097465737475736572330000000159beb274010014002060e5e3fb9166db825eb3e4ff4bd1f4307e3f5fe85cdf7faccf8d65330557f74e000000010000004b0001000b544553542e474f4b52423500097465737475736572330000000159beb274020014002060e5e3fb9166db825eb3e4ff4bd1f4307e3f5fe85cdf7faccf8d65330557f74e00000002000000430001000b544553542e474f4b52423500097465737475736572330000000159beb27401001000182cad768989a125fd26f24adf671976456d8097548c4c83f100000001000000430001000b544553542e474f4b52423500097465737475736572330000000159beb27402001000182cad768989a125fd26f24adf671976456d8097548c4c83f1000000020000003b0001000b544553542e474f4b52423500097465737475736572330000000159beb2740100170010084768c373663b3bef1f6385883cf7ff000000010000003b0001000b544553542e474f4b52423500097465737475736572330000000159beb2740200170010084768c373663b3bef1f6385883cf7ff00000002"
 	HTTP_KEYTAB           = "0502000000440002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b72623500000001590dc4dc010011001057a7754c70c4d85c155c718c2f1292b0000000540002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b72623500000001590dc4dc01001200209cad00bbc72d703258e911dc18e6d5487cf737bf67fd111f0c2463ad6033bf51000000440002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b72623500000001590dc4dc020011001057a7754c70c4d85c155c718c2f1292b0000000540002000b544553542e474f4b5242350004485454500010686f73742e746573742e676f6b72623500000001590dc4dc02001200209cad00bbc72d703258e911dc18e6d5487cf737bf67fd111f0c2463ad6033bf51"
 	SYSHTTP_KEYTAB        = "0502000000450001000b544553542e474f4b52423500077379734854545000000001590dc5af020012002043763702868978d1b6d91a36704b987e27e517250055bdfc40b8a6b3848d9aae"
 	TEST_AS_REQ           = "6a81a63081a3a103020105a20302010aa30e300c300aa10402020095a2020400a48186308183a00703050040000010a1163014a003020101a10d300b1b09746573747573657231a20d1b0b544553542e474f4b524235a320301ea003020102a11730151b066b72627467741b0b544553542e474f4b524235a511180f32303137303232303134323530315aa70602040f6755a6a814301202011202011102011002011702011902011a"

BIN
testenv/testuser1.testtab


BIN
testenv/testuser2.testtab


BIN
testenv/testuser3.testtab