Browse Source

more tests

Jonathan Turner 9 years ago
parent
commit
2fe42086da
4 changed files with 373 additions and 12 deletions
  1. 41 0
      messages/Ticket.go
  2. 331 0
      service/APExchange_test.go
  3. 0 11
      service/service_integration_test.go
  4. 1 1
      types/Authenticator.go

+ 41 - 0
messages/Ticket.go

@@ -1,10 +1,12 @@
 package messages
 
 import (
+	"crypto/rand"
 	"fmt"
 	"github.com/jcmturner/asn1"
 	"github.com/jcmturner/gokrb5/asn1tools"
 	"github.com/jcmturner/gokrb5/crypto"
+	"github.com/jcmturner/gokrb5/iana"
 	"github.com/jcmturner/gokrb5/iana/asnAppTag"
 	"github.com/jcmturner/gokrb5/iana/errorcode"
 	"github.com/jcmturner/gokrb5/iana/keyusage"
@@ -43,6 +45,45 @@ type TransitedEncoding struct {
 	Contents []byte `asn1:"explicit,tag:1"`
 }
 
+func NewTicket(cname types.PrincipalName, crealm string, sname types.PrincipalName, srealm string, flags asn1.BitString, sktab keytab.Keytab, eTypeID, kvno int, authTime, startTime, endTime, renewTill time.Time) (Ticket, types.EncryptionKey, error) {
+	etype, err := crypto.GetEtype(eTypeID)
+	if err != nil {
+		return Ticket{}, types.EncryptionKey{}, err
+	}
+	ks := etype.GetKeyByteSize()
+	kv := make([]byte, ks, ks)
+	rand.Read(kv)
+	sessionKey := types.EncryptionKey{
+		KeyType:  eTypeID,
+		KeyValue: kv,
+	}
+	etp := EncTicketPart{
+		Flags:     flags,
+		Key:       sessionKey,
+		CRealm:    crealm,
+		CName:     cname,
+		Transited: TransitedEncoding{},
+		AuthTime:  authTime,
+		StartTime: startTime,
+		EndTime:   endTime,
+		RenewTill: renewTill,
+	}
+	b, err := asn1.Marshal(etp)
+	b = asn1tools.AddASNAppTag(b, asnAppTag.EncTicketPart)
+	skey, err := sktab.GetEncryptionKey(sname.NameString, srealm, kvno, eTypeID)
+	if err != nil {
+		return Ticket{}, types.EncryptionKey{}, err
+	}
+	ed, err := crypto.GetEncryptedData(b, skey, keyusage.KDC_REP_TICKET, kvno)
+	tkt := Ticket{
+		TktVNO:  iana.PVNO,
+		Realm:   srealm,
+		SName:   sname,
+		EncPart: ed,
+	}
+	return tkt, sessionKey, nil
+}
+
 func (t *Ticket) Unmarshal(b []byte) error {
 	_, err := asn1.UnmarshalWithParams(b, t, fmt.Sprintf("application,explicit,tag:%d", asnAppTag.Ticket))
 	return err

+ 331 - 0
service/APExchange_test.go

@@ -0,0 +1,331 @@
+package service
+
+import (
+	"encoding/hex"
+	"github.com/jcmturner/gokrb5/client"
+	"github.com/jcmturner/gokrb5/config"
+	"github.com/jcmturner/gokrb5/credentials"
+	"github.com/jcmturner/gokrb5/iana/errorcode"
+	"github.com/jcmturner/gokrb5/iana/flags"
+	"github.com/jcmturner/gokrb5/iana/nametype"
+	"github.com/jcmturner/gokrb5/keytab"
+	"github.com/jcmturner/gokrb5/messages"
+	"github.com/jcmturner/gokrb5/testdata"
+	"github.com/jcmturner/gokrb5/types"
+	"github.com/stretchr/testify/assert"
+	"testing"
+	"time"
+)
+
+func TestValidateAPREQ(t *testing.T) {
+	cl := getClient()
+	sname := types.PrincipalName{
+		NameType:   nametype.KRB_NT_PRINCIPAL,
+		NameString: []string{"HTTP", "host.test.gokrb5"},
+	}
+	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	st := time.Now().UTC()
+	tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName, cl.Credentials.Realm,
+		sname, "TEST.GOKRB5",
+		types.NewKrbFlags(),
+		kt,
+		18,
+		1,
+		st,
+		st,
+		st.Add(time.Duration(24)*time.Hour),
+		st.Add(time.Duration(48)*time.Hour),
+	)
+	if err != nil {
+		t.Fatalf("Error getting test ticket: %v", err)
+	}
+	APReq, err := messages.NewAPReq(
+		tkt,
+		sessionKey,
+		newTestAuthenticator(*cl.Credentials),
+	)
+	if err != nil {
+		t.Fatalf("Error getting test AP_REQ: %v", err)
+	}
+
+	ok, _, err := ValidateAPREQ(APReq, kt, "127.0.0.1")
+	if !ok || err != nil {
+		t.Fatalf("Validation of AP_REQ failed when it should not have: %v", err)
+	}
+}
+
+func TestValidateAPREQ_KRB_AP_ERR_BADMATCH(t *testing.T) {
+	cl := getClient()
+	sname := types.PrincipalName{
+		NameType:   nametype.KRB_NT_PRINCIPAL,
+		NameString: []string{"HTTP", "host.test.gokrb5"},
+	}
+	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	st := time.Now().UTC()
+	tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName, cl.Credentials.Realm,
+		sname, "TEST.GOKRB5",
+		types.NewKrbFlags(),
+		kt,
+		18,
+		1,
+		st,
+		st,
+		st.Add(time.Duration(24)*time.Hour),
+		st.Add(time.Duration(48)*time.Hour),
+	)
+	if err != nil {
+		t.Fatalf("Error getting test ticket: %v", err)
+	}
+	a := newTestAuthenticator(*cl.Credentials)
+	a.CName = types.PrincipalName{
+		NameType:   nametype.KRB_NT_PRINCIPAL,
+		NameString: []string{"BADMATCH"},
+	}
+	APReq, err := messages.NewAPReq(
+		tkt,
+		sessionKey,
+		a,
+	)
+	if err != nil {
+		t.Fatalf("Error getting test AP_REQ: %v", err)
+	}
+
+	ok, _, err := ValidateAPREQ(APReq, kt, "127.0.0.1")
+	if ok || err == nil {
+		t.Fatal("Validation of AP_REQ passed when it should not have")
+	}
+	assert.IsType(t, messages.KRBError{}, err, "Error is not a KRBError")
+	assert.Equal(t, errorcode.KRB_AP_ERR_BADMATCH, err.(messages.KRBError).ErrorCode, "Error code not as expected")
+}
+
+func TestValidateAPREQ_LargeClockSkew(t *testing.T) {
+	cl := getClient()
+	sname := types.PrincipalName{
+		NameType:   nametype.KRB_NT_PRINCIPAL,
+		NameString: []string{"HTTP", "host.test.gokrb5"},
+	}
+	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	st := time.Now().UTC()
+	tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName, cl.Credentials.Realm,
+		sname, "TEST.GOKRB5",
+		types.NewKrbFlags(),
+		kt,
+		18,
+		1,
+		st,
+		st,
+		st.Add(time.Duration(24)*time.Hour),
+		st.Add(time.Duration(48)*time.Hour),
+	)
+	if err != nil {
+		t.Fatalf("Error getting test ticket: %v", err)
+	}
+	a := newTestAuthenticator(*cl.Credentials)
+	a.CTime = a.CTime.Add(time.Duration(-10) * time.Minute)
+	APReq, err := messages.NewAPReq(
+		tkt,
+		sessionKey,
+		a,
+	)
+	if err != nil {
+		t.Fatalf("Error getting test AP_REQ: %v", err)
+	}
+
+	ok, _, err := ValidateAPREQ(APReq, kt, "127.0.0.1")
+	if ok || err == nil {
+		t.Fatal("Validation of AP_REQ passed when it should not have")
+	}
+	assert.IsType(t, messages.KRBError{}, err, "Error is not a KRBError")
+	assert.Equal(t, errorcode.KRB_AP_ERR_SKEW, err.(messages.KRBError).ErrorCode, "Error code not as expected")
+}
+
+func TestValidateAPREQ_Replay(t *testing.T) {
+	cl := getClient()
+	sname := types.PrincipalName{
+		NameType:   nametype.KRB_NT_PRINCIPAL,
+		NameString: []string{"HTTP", "host.test.gokrb5"},
+	}
+	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	st := time.Now().UTC()
+	tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName, cl.Credentials.Realm,
+		sname, "TEST.GOKRB5",
+		types.NewKrbFlags(),
+		kt,
+		18,
+		1,
+		st,
+		st,
+		st.Add(time.Duration(24)*time.Hour),
+		st.Add(time.Duration(48)*time.Hour),
+	)
+	if err != nil {
+		t.Fatalf("Error getting test ticket: %v", err)
+	}
+	APReq, err := messages.NewAPReq(
+		tkt,
+		sessionKey,
+		newTestAuthenticator(*cl.Credentials),
+	)
+	if err != nil {
+		t.Fatalf("Error getting test AP_REQ: %v", err)
+	}
+
+	ok, _, err := ValidateAPREQ(APReq, kt, "127.0.0.1")
+	if !ok || err != nil {
+		t.Fatalf("Validation of AP_REQ failed when it should not have: %v", err)
+	}
+	// Replay
+	ok, _, err = ValidateAPREQ(APReq, kt, "127.0.0.1")
+	if ok || err == nil {
+		t.Fatal("Validation of AP_REQ passed when it should not have")
+	}
+	assert.IsType(t, messages.KRBError{}, err, "Error is not a KRBError")
+	assert.Equal(t, errorcode.KRB_AP_ERR_REPEAT, err.(messages.KRBError).ErrorCode, "Error code not as expected")
+}
+
+func TestValidateAPREQ_FutureTicket(t *testing.T) {
+	cl := getClient()
+	sname := types.PrincipalName{
+		NameType:   nametype.KRB_NT_PRINCIPAL,
+		NameString: []string{"HTTP", "host.test.gokrb5"},
+	}
+	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	st := time.Now().UTC()
+	tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName, cl.Credentials.Realm,
+		sname, "TEST.GOKRB5",
+		types.NewKrbFlags(),
+		kt,
+		18,
+		1,
+		st,
+		st.Add(time.Duration(60)*time.Minute),
+		st.Add(time.Duration(24)*time.Hour),
+		st.Add(time.Duration(48)*time.Hour),
+	)
+	if err != nil {
+		t.Fatalf("Error getting test ticket: %v", err)
+	}
+	a := newTestAuthenticator(*cl.Credentials)
+	APReq, err := messages.NewAPReq(
+		tkt,
+		sessionKey,
+		a,
+	)
+	if err != nil {
+		t.Fatalf("Error getting test AP_REQ: %v", err)
+	}
+
+	ok, _, err := ValidateAPREQ(APReq, kt, "127.0.0.1")
+	if ok || err == nil {
+		t.Fatal("Validation of AP_REQ passed when it should not have")
+	}
+	assert.IsType(t, messages.KRBError{}, err, "Error is not a KRBError")
+	assert.Equal(t, errorcode.KRB_AP_ERR_TKT_NYV, err.(messages.KRBError).ErrorCode, "Error code not as expected")
+}
+
+func TestValidateAPREQ_InvalidTicket(t *testing.T) {
+	cl := getClient()
+	sname := types.PrincipalName{
+		NameType:   nametype.KRB_NT_PRINCIPAL,
+		NameString: []string{"HTTP", "host.test.gokrb5"},
+	}
+	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	st := time.Now().UTC()
+	f := types.NewKrbFlags()
+	types.SetFlag(&f, flags.Invalid)
+	tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName, cl.Credentials.Realm,
+		sname, "TEST.GOKRB5",
+		f,
+		kt,
+		18,
+		1,
+		st,
+		st,
+		st.Add(time.Duration(24)*time.Hour),
+		st.Add(time.Duration(48)*time.Hour),
+	)
+	if err != nil {
+		t.Fatalf("Error getting test ticket: %v", err)
+	}
+	APReq, err := messages.NewAPReq(
+		tkt,
+		sessionKey,
+		newTestAuthenticator(*cl.Credentials),
+	)
+	if err != nil {
+		t.Fatalf("Error getting test AP_REQ: %v", err)
+	}
+
+	ok, _, err := ValidateAPREQ(APReq, kt, "127.0.0.1")
+	if ok || err == nil {
+		t.Fatal("Validation of AP_REQ passed when it should not have")
+	}
+	assert.IsType(t, messages.KRBError{}, err, "Error is not a KRBError")
+	assert.Equal(t, errorcode.KRB_AP_ERR_TKT_NYV, err.(messages.KRBError).ErrorCode, "Error code not as expected")
+}
+
+func TestValidateAPREQ_ExpiredTicket(t *testing.T) {
+	cl := getClient()
+	sname := types.PrincipalName{
+		NameType:   nametype.KRB_NT_PRINCIPAL,
+		NameString: []string{"HTTP", "host.test.gokrb5"},
+	}
+	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	st := time.Now().UTC()
+	tkt, sessionKey, err := messages.NewTicket(cl.Credentials.CName, cl.Credentials.Realm,
+		sname, "TEST.GOKRB5",
+		types.NewKrbFlags(),
+		kt,
+		18,
+		1,
+		st,
+		st,
+		st.Add(time.Duration(-30)*time.Minute),
+		st.Add(time.Duration(48)*time.Hour),
+	)
+	if err != nil {
+		t.Fatalf("Error getting test ticket: %v", err)
+	}
+	a := newTestAuthenticator(*cl.Credentials)
+	APReq, err := messages.NewAPReq(
+		tkt,
+		sessionKey,
+		a,
+	)
+	if err != nil {
+		t.Fatalf("Error getting test AP_REQ: %v", err)
+	}
+
+	ok, _, err := ValidateAPREQ(APReq, kt, "127.0.0.1")
+	if ok || err == nil {
+		t.Fatal("Validation of AP_REQ passed when it should not have")
+	}
+	assert.IsType(t, messages.KRBError{}, err, "Error is not a KRBError")
+	assert.Equal(t, errorcode.KRB_AP_ERR_TKT_EXPIRED, err.(messages.KRBError).ErrorCode, "Error code not as expected")
+}
+
+func newTestAuthenticator(creds credentials.Credentials) types.Authenticator {
+	auth := types.NewAuthenticator(creds.Realm, creds.CName)
+	auth.GenerateSeqNumberAndSubKey(18, 32)
+	//auth.Cksum = types.Checksum{
+	//	CksumType: chksumtype.GSSAPI,
+	//	Checksum:  newAuthenticatorChksum([]int{GSS_C_INTEG_FLAG, GSS_C_CONF_FLAG}),
+	//}
+	return auth
+}
+
+func getClient() client.Client {
+	b, _ := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
+	cl := client.NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
+	cl.WithConfig(c)
+	return cl
+}

+ 0 - 11
service/service_integration_test.go

@@ -6,8 +6,6 @@ package service
 import (
 	"encoding/hex"
 	"fmt"
-	"github.com/jcmturner/gokrb5/client"
-	"github.com/jcmturner/gokrb5/config"
 	"github.com/jcmturner/gokrb5/keytab"
 	"github.com/jcmturner/gokrb5/testdata"
 	"github.com/stretchr/testify/assert"
@@ -86,15 +84,6 @@ func TestService_SPNEGOKRB_Replay(t *testing.T) {
 	assert.Equal(t, http.StatusUnauthorized, httpResp.StatusCode, "Status code in response to client with no SPNEGO not as expected. Expected a replay to be detected.")
 }
 
-func getClient() client.Client {
-	b, _ := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
-	kt, _ := keytab.Parse(b)
-	c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
-	cl := client.NewClientWithKeytab("testuser1", "TEST.GOKRB5", kt)
-	cl.WithConfig(c)
-	return cl
-}
-
 func httpServer() *httptest.Server {
 	l := log.New(ioutil.Discard, "GOKRB5 Service Tests: ", log.Ldate|log.Ltime|log.Lshortfile)
 	b, _ := hex.DecodeString(testdata.HTTP_KEYTAB)

+ 1 - 1
types/Authenticator.go

@@ -59,7 +59,7 @@ func NewAuthenticator(realm string, cname PrincipalName) Authenticator {
 func (a *Authenticator) GenerateSeqNumberAndSubKey(keyType, keySize int) {
 	a.SeqNumber = int(rand.Int31())
 	//Generate subkey value
-	sk := make([]byte, keySize)
+	sk := make([]byte, keySize, keySize)
 	rand.Read(sk)
 	a.SubKey = EncryptionKey{
 		KeyType:  keyType,