Explorar el Código

client spnego working

Jonathan Turner hace 9 años
padre
commit
d91ab76148
Se han modificado 6 ficheros con 40 adiciones y 9 borrados
  1. 12 3
      GSSAPI/krb5Token.go
  2. 14 1
      README.md
  3. 1 1
      debug.go
  4. 11 3
      messages/APReq.go
  5. 1 1
      testdata/test_vectors.go
  6. 1 0
      testenv/krbhttp-vagrant/bootstrap.sh

+ 12 - 3
GSSAPI/krb5Token.go

@@ -7,6 +7,7 @@ import (
 	"github.com/jcmturner/asn1"
 	"github.com/jcmturner/gokrb5/asn1tools"
 	"github.com/jcmturner/gokrb5/config"
+	"github.com/jcmturner/gokrb5/crypto"
 	"github.com/jcmturner/gokrb5/iana/chksumtype"
 	"github.com/jcmturner/gokrb5/messages"
 	"github.com/jcmturner/gokrb5/types"
@@ -35,7 +36,7 @@ func NewKRB5APREQMechToken(c config.Config, cname types.PrincipalName, tkt types
 	APReq, err := messages.NewAPReq(
 		tkt,
 		sessionKey,
-		newAuthenticator(c, cname),
+		newAuthenticator(c, cname, sessionKey.KeyType),
 	)
 	tb, err = APReq.Marshal()
 	if err != nil {
@@ -45,14 +46,22 @@ func NewKRB5APREQMechToken(c config.Config, cname types.PrincipalName, tkt types
 	return asn1tools.AddASNAppTag(b, 0), nil
 }
 
-func newAuthenticator(c config.Config, username types.PrincipalName) types.Authenticator {
+func newAuthenticator(c config.Config, username types.PrincipalName, keyType int) types.Authenticator {
 	//RFC 4121 Section 4.1.1
 	auth := types.NewAuthenticator(c.LibDefaults.Default_realm, username)
 	auth.Cksum = types.Checksum{
 		CksumType: chksumtype.GSSAPI,
 		Checksum:  newAuthenticatorChksum([]int{GSS_C_INTEG_FLAG, GSS_C_CONF_FLAG}),
 	}
-	auth.SeqNumber = int(rand.Int63())
+	auth.SeqNumber = int(rand.Int31())
+	//Generate subkey value
+	etype, _ := crypto.GetEtype(keyType)
+	sk := make([]byte, etype.GetKeyByteSize())
+	rand.Read(sk)
+	auth.SubKey = types.EncryptionKey{
+		KeyType:  keyType,
+		KeyValue: sk,
+	}
 	return auth
 }
 

+ 14 - 1
README.md

@@ -1,6 +1,10 @@
 # gokrb5
 
-This is work in progress and does not yet fully work...
+This is work in progress and may have some issues.
+
+Currently the following is working/tested:
+* Works with a KDC that supports [PA FAST](https://tools.ietf.org/html/rfc6806.html#section-11)
+* Client side authentication to HTTP servers that implement SPNEGO using Kerberos 5
 
 [![GoDoc](https://godoc.org/github.com/jcmturner/gokrb5?status.svg)](https://godoc.org/github.com/jcmturner/gokrb5)
 
@@ -51,12 +55,21 @@ err := cl.Login
 ```go
 cl.EnableAutoSessionRenewal()
 ```
+#### Authenticate to a Service
+##### Native Kerberos
 Request a Serivce ticket for a Service Principal Name (SPN).
 This method will use the client's cache either returning a valid cached ticket, renewing a cached ticket with the KDC or requesting a new ticket from the KDC.
 Therefore the GetServiceTicket method can be continually used for the most efficient interaction with the KDC.
 ```go
 tkt, err := cl.GetServiceTicket("HTTP/host.test.gokrb5")
 ```
+##### HTTP SPNEGO
+Create the HTTP request object and then call the client's SetSPNEGOHeader method passing the Service Principal Name (SPN)
+```go
+r, _ := http.NewRequest("GET", "http://host.test.gokrb5/index.html", nil)
+cl.SetSPNEGOHeader(r, "HTTP/host.test.gokrb5")
+HTTPResp, err := http.DefaultClient.Do(r)
+```
 
 ## References
 ### RFCs

+ 1 - 1
debug.go

@@ -72,7 +72,7 @@ func httpRequest() {
 	if err != nil {
 		fmt.Fprintf(os.Stderr, "Error on AS_REQ: %v\n", err)
 	}
-	r, _ := http.NewRequest("GET", "http://10.80.88.90/index.html", nil)
+	r, _ := http.NewRequest("GET", "http://host.test.gokrb5/index.html", nil)
 	cl.SetSPNEGOHeader(r, "HTTP/host.test.gokrb5")
 	httpResp, err := http.DefaultClient.Do(r)
 	fmt.Fprintf(os.Stderr, "RESPONSE CODE: %v\n", httpResp.StatusCode)

+ 11 - 3
messages/APReq.go

@@ -10,6 +10,7 @@ import (
 	"github.com/jcmturner/gokrb5/iana/asnAppTag"
 	"github.com/jcmturner/gokrb5/iana/keyusage"
 	"github.com/jcmturner/gokrb5/iana/msgtype"
+	"github.com/jcmturner/gokrb5/iana/nametype"
 	"github.com/jcmturner/gokrb5/types"
 )
 
@@ -47,7 +48,7 @@ type APReq struct {
 // Generate a new KRB_AP_REQ struct.
 func NewAPReq(tkt types.Ticket, sessionKey types.EncryptionKey, auth types.Authenticator) (APReq, error) {
 	var a APReq
-	ed, err := encryptAuthenticator(auth, sessionKey)
+	ed, err := encryptAuthenticator(auth, sessionKey, tkt)
 	if err != nil {
 		return a, fmt.Errorf("Error creating authenticator for AP_REQ: %v", err)
 	}
@@ -62,13 +63,20 @@ func NewAPReq(tkt types.Ticket, sessionKey types.EncryptionKey, auth types.Authe
 }
 
 // Encrypt Authenticator
-func encryptAuthenticator(a types.Authenticator, sessionKey types.EncryptionKey) (types.EncryptedData, error) {
+func encryptAuthenticator(a types.Authenticator, sessionKey types.EncryptionKey, tkt types.Ticket) (types.EncryptedData, error) {
 	var ed types.EncryptedData
 	m, err := a.Marshal()
 	if err != nil {
 		return ed, fmt.Errorf("Error marshalling authenticator: %v", err)
 	}
-	return crypto.GetEncryptedData(m, sessionKey, keyusage.TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR, 0)
+	var usage int
+	switch tkt.SName.NameType {
+	case nametype.KRB_NT_PRINCIPAL:
+		usage = keyusage.AP_REQ_AUTHENTICATOR
+	case nametype.KRB_NT_SRV_INST:
+		usage = keyusage.TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR
+	}
+	return crypto.GetEncryptedData(m, sessionKey, uint32(usage), tkt.EncPart.KVNO)
 }
 
 // Unmarshal bytes b into the APReq struct.

+ 1 - 1
testdata/test_vectors.go

@@ -98,7 +98,7 @@ var TestVectors = map[string]string{
 }
 
 const (
-	TESTUSER1_KEYTAB = "05020000004b0001000b544553542e474f4b52423500097465737475736572310000000158e14ba20200120020ece15fc2116941977fab023c6fb784933ff1c80d3a71f5d742e169273a3585c5000000020000003b0001000b544553542e474f4b52423500097465737475736572310000000158e14ba202001100106fd4e428fdf2f54f03866c94b6d34d8900000002000000430001000b544553542e474f4b52423500097465737475736572310000000158e14ba202001000189408ef92262634badc25089ef2e0047fcb463425c18f2f20000000020000003b0001000b544553542e474f4b52423500097465737475736572310000000158e14ba202001700109d890eb35d54e48ff29e3386e858e0c0000000020000004b0001000b544553542e474f4b52423500097465737475736572310000000158e14ba202001a0020e4a7346f6e37484ec10ca0bcf14d4e340ab8bcc6b9a42851e1114540325b7e4f000000020000003b0001000b544553542e474f4b52423500097465737475736572310000000158e14ba2020019001076ed573a0bd71371eecd9c5402dace6a00000002000000330001000b544553542e474f4b52423500097465737475736572310000000158e14ba202000800087f68858f6413e54f00000002000000330001000b544553542e474f4b52423500097465737475736572310000000158e14ba202000300080283f2ea20a10efb00000002"
+	TESTUSER1_KEYTAB = "05020000004b0001000b544553542e474f4b52423500097465737475736572310000000158e543060100120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de900000001"
 	TEST_AS_REQ      = "6a81a63081a3a103020105a20302010aa30e300c300aa10402020095a2020400a48186308183a00703050040000010a1163014a003020101a10d300b1b09746573747573657231a20d1b0b544553542e474f4b524235a320301ea003020102a11730151b066b72627467741b0b544553542e474f4b524235a511180f32303137303232303134323530315aa70602040f6755a6a814301202011202011102011002011702011902011a"
 	TEST_AS_REP      = "6b8202f3308202efa003020105a10302010ba22e302c302aa103020113a2230421301f301da003020112a1161b14544553542e474f4b524235746573747573657231a30d1b0b544553542e474f4b524235a4163014a003020101a10d300b1b09746573747573657231a582015a6182015630820152a003020105a10d1b0b544553542e474f4b524235a220301ea003020102a11730151b066b72627467741b0b544553542e474f4b524235a382011830820114a003020112a103020101a28201060482010264d3fa49d89b627ed471298846ff92cd8632f657c58fe25322a61fffa32bb7966dc4c44c86a81353def2a11c36c537191406a609147f424a63266c00d02bcc56a27b0969d86ff4352634be9e2a4ac0ad5a36b0b0a3d689f128c0afa97401796e88037a35ad19efaf31d1ed4f3213769c03a58bc90ffac2051db152c0ed0809ad05ffb03aa3afaf731ed85f7a73020cb72355e0de27842dcf7eae3de9f7c14aa237edb25153b217ef3693373bc3cacbebe406910ff9ae9d00b7b08f726cb29a213cb9ad51ba80a8c24fa4b6692a445686889702cfa6ea749bac03e27e982407aca623fbd48586bcf566cfe87e1d9f17a74b1315669c16480f93e9d8782e71a8f11000a682012c30820128a003020112a282011f0482011b99b86153c0393c0e4130628f3e1e0f0a1f034e7e61a111b7fad15884e231c8fd8727e0bc945c9b35be20c57d057c8b09b0de74c53fb38cc15c9a2d483023fc369f5bde4da7324b4732b5a3d9504d92f67026aaa01df4f0138245d2ccb1c5a4014804cf295c7e7e56a867e6cf0c534f667f32da7aa5e700af1461764f1c276a8ff0fbee0e99322fe2059d2321853be09d0956c3afcfd07e3e702646a4678926a77bea20d9aaf3086b6d384821c81900af9013a3519f0e50eab6e1491d72e4ee17c2a44441b2ebc8a796cc3d876e328347dce65f61104e14d4c31532885776c9c8a70186b8b39f928972945c98bd60381ead5448e7ebe93fea308054287ac34b0583b4b9b5e43c5f8518d693ba9eb48a219c27344466b3c693a70462"
 	TEST_TGS_REQ     = "6c82038f3082038ba103020105a20302010ca382031a3082031630820245a103020101a282023c048202386e82023430820230a003020105a10302010ea20703050000000000a382015a6182015630820152a003020105a10d1b0b544553542e474f4b524235a220301ea003020102a11730151b066b72627467741b0b544553542e474f4b524235a382011830820114a003020112a103020101a28201060482010264d3fa49d89b627ed471298846ff92cd8632f657c58fe25322a61fffa32bb7966dc4c44c86a81353def2a11c36c537191406a609147f424a63266c00d02bcc56a27b0969d86ff4352634be9e2a4ac0ad5a36b0b0a3d689f128c0afa97401796e88037a35ad19efaf31d1ed4f3213769c03a58bc90ffac2051db152c0ed0809ad05ffb03aa3afaf731ed85f7a73020cb72355e0de27842dcf7eae3de9f7c14aa237edb25153b217ef3693373bc3cacbebe406910ff9ae9d00b7b08f726cb29a213cb9ad51ba80a8c24fa4b6692a445686889702cfa6ea749bac03e27e982407aca623fbd48586bcf566cfe87e1d9f17a74b1315669c16480f93e9d8782e71a8f11000a481bc3081b9a003020112a281b10481ae8ae3cb8ac47d77cfc7b0b6bf0d3c5f8fcc6dd569344256a6a40c004fc2d23ebbe6ee0b9e00eccf37e710b7c01a7d2a63bbed6d75f2b230d24d724ef90edad2c5680e7e2436ab1145ff68481673444ebd61e3aef79b9ee05809551672c6c436eb8ac732a7fe78bd8f380e68a541191e3125554e4bab63dcc19ea931c1477366a6039ff7b7e62521ebfeffd6784b6ef0c97f653ac4d8dfb304f3e2e843faab12d838c23f1105f0a281c39325987cb03081caa10402020088a281c10481bea081bb3081b8a1173015a003020110a10e040ce613d8e9d544f0e56c60d3bba2819c308199a003020112a2819104818ec4fabcb1ec2f24e04ef51f9247239b28275653fa5cbc1dc9e747530c597631050fe86a5f3cba2ff54270aa771dcefa87efc8c8604407f84e603f5c01a2d929e18103561c3ffbc3a0cf63340bdd67a0739d4d81989827fc1d3f7f13e9dd5cc2346ca08e26a2aaf6d0102fbef8f7a6ee0a1caae7880e953ea678da619038786122a0b71853e8d0b95f544f8fbd6945a461305fa00703050040810000a20d1b0b544553542e474f4b524235a3233021a003020101a11a30181b04485454501b10686f73742e746573742e676f6b726235a511180f32303137303232303032323634325aa706020458a9ab2aa8053003020112"

+ 1 - 0
testenv/krbhttp-vagrant/bootstrap.sh

@@ -22,6 +22,7 @@ net.ipv6.conf.default.disable_ipv6 = 1
 net.ipv6.conf.lo.disable_ipv6 = 1
 EOF
 
+echo "10.80.88.88 kdc.test.gokrb5" >> /etc/hosts
 echo "10.80.88.89 client.test.gokrb5" >> /etc/hosts
 echo "10.80.88.90 host.test.gokrb5" >> /etc/hosts