Selaa lähdekoodia

encryption work

Jonathan Turner 9 vuotta sitten
vanhempi
commit
06e8e417fb

+ 1 - 1
client/ASExchange.go

@@ -31,7 +31,7 @@ func (cl *Client) ASExchange() error {
 	var ar messages.ASRep
 	var ar messages.ASRep
 	err = ar.Unmarshal(rb)
 	err = ar.Unmarshal(rb)
 	if err != nil {
 	if err != nil {
-		//An KRBError may have been returned instead.
+		//A KRBError may have been returned instead.
 		var krberr messages.KRBError
 		var krberr messages.KRBError
 		err = krberr.Unmarshal(rb)
 		err = krberr.Unmarshal(rb)
 		if err != nil {
 		if err != nil {

+ 1 - 1
client/network.go

@@ -18,7 +18,7 @@ func (cl *Client) SendToKDC(b []byte) ([]byte, error) {
 		}
 		}
 	}
 	}
 	if len(kdcs) < 1 {
 	if len(kdcs) < 1 {
-		return rb, fmt.Errorf("No KDCs defined in configuration for realm %v", cl.Config.LibDefaults.Default_realm)
+		return rb, fmt.Errorf("No KDCs defined in configuration for realm: %v", cl.Config.LibDefaults.Default_realm)
 	}
 	}
 	var kdc string
 	var kdc string
 	if len(kdcs) > 1 {
 	if len(kdcs) > 1 {

+ 13 - 3
crypto/EncryptionEngine.go

@@ -10,6 +10,7 @@ import (
 	"github.com/jcmturner/gokrb5/iana/patype"
 	"github.com/jcmturner/gokrb5/iana/patype"
 	"github.com/jcmturner/gokrb5/types"
 	"github.com/jcmturner/gokrb5/types"
 	"hash"
 	"hash"
+	"crypto/rand"
 )
 )
 
 
 type EType interface {
 type EType interface {
@@ -284,19 +285,28 @@ func GetEncryptedData(pt []byte, key types.EncryptionKey, usage int, kvno int) (
 	var ed types.EncryptedData
 	var ed types.EncryptedData
 	etype, err := GetEtype(key.KeyType)
 	etype, err := GetEtype(key.KeyType)
 	if err != nil {
 	if err != nil {
-		return ed, fmt.Errorf("Error getting etype to encrypt authenticator: %v", err)
+		return ed, fmt.Errorf("Error getting etype: %v", err)
 	}
 	}
 	k := key.KeyValue
 	k := key.KeyValue
 	if usage != 0 {
 	if usage != 0 {
 		k, err = etype.DeriveKey(key.KeyValue, GetUsageKe(uint32(usage)))
 		k, err = etype.DeriveKey(key.KeyValue, GetUsageKe(uint32(usage)))
+		if err != nil {
+			return ed, fmt.Errorf("Error deriving key: %v", err)
+		}
 	}
 	}
+	//confounder
+	c := make([]byte, etype.GetConfounderByteSize())
+	_, err = rand.Read(c)
 	if err != nil {
 	if err != nil {
-		return ed, fmt.Errorf("Error deriving key for authenticator: %v", err)
+		return ed, fmt.Errorf("Could not generate random confounder: %v", err)
 	}
 	}
+	pt = append(c, pt...)
 	_, b, err := etype.Encrypt(k, pt)
 	_, b, err := etype.Encrypt(k, pt)
 	if err != nil {
 	if err != nil {
-		return ed, fmt.Errorf("Error encrypting authenticator: %v", err)
+		return ed, fmt.Errorf("Error encrypting data: %v", err)
 	}
 	}
+	ih, err := GetIntegrityHash(pt, key.KeyValue, uint32(usage), etype)
+	b = append(b, ih...)
 	ed = types.EncryptedData{
 	ed = types.EncryptedData{
 		EType: key.KeyType,
 		EType: key.KeyType,
 		Cipher: b,
 		Cipher: b,

+ 42 - 1
debug.go

@@ -12,6 +12,7 @@ import (
 	"github.com/jcmturner/gokrb5/keytab"
 	"github.com/jcmturner/gokrb5/keytab"
 	"github.com/jcmturner/gokrb5/messages"
 	"github.com/jcmturner/gokrb5/messages"
 	"github.com/jcmturner/gokrb5/types"
 	"github.com/jcmturner/gokrb5/types"
+	"github.com/jcmturner/gokrb5/testdata"
 	"os"
 	"os"
 	"time"
 	"time"
 )
 )
@@ -41,7 +42,7 @@ const pa149rep = "6b8202f3308202efa003020105a10302010ba22e302c302aa103020113a223
 
 
 func main() {
 func main() {
 
 
-	AS()
+	TestTGSReq()
 }
 }
 
 
 func NoPA() {
 func NoPA() {
@@ -130,3 +131,43 @@ func AS() {
 		fmt.Fprintf(os.Stderr, "ERROR: %v", err)
 		fmt.Fprintf(os.Stderr, "ERROR: %v", err)
 	}
 	}
 }
 }
+
+func TestTGSReq() {
+	b, err := hex.DecodeString(testdata.TESTUSER1_KEYTAB)
+	kt, _ := keytab.Parse(b)
+	c, _ := config.NewConfigFromString(testdata.TEST_KRB5CONF)
+	cl := client.NewClientWithKeytab("testuser1", kt)
+	cl.WithConfig(c)
+
+	err = cl.ASExchange()
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error on AS_REQ: %v", err)
+	}
+	fmt.Fprintf(os.Stderr, "Client: %+v\n", cl)
+
+/*	var a messages.TGSReq
+	b, err = hex.DecodeString(testdata.TEST_TGS_REQ)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Test vector read error: %v\n", err)
+	}
+	err = a.Unmarshal(b)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Unmarshal error: %v\n", err)
+	}
+	fmt.Fprintf(os.Stderr, "TGS_REQ: %+v\n", a)*/
+
+	tgs, err := messages.NewTGSReq("testuser1", c, cl.Session.TGT, cl.Session.SessionKey, "HTTP/host.test.gokrb5")
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error on New TGS_REQ: %v", err)
+	}
+	fmt.Fprintf(os.Stderr, "TGS_REQ gen: %+v\n", tgs)
+	b, err = tgs.Marshal()
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error marshalling TGS_REQ: %v", err)
+	}
+	_, err = cl.SendToKDC(b)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error sending TGS_REQ to KDC: %v", err)
+	}
+
+}

+ 2 - 18
messages/APReq.go

@@ -52,7 +52,7 @@ func NewAPReq(TGT types.Ticket, sessionKey types.EncryptionKey, auth types.Authe
 	a = APReq{
 	a = APReq{
 		PVNO:    iana.PVNO,
 		PVNO:    iana.PVNO,
 		MsgType: msgtype.KRB_AP_REQ,
 		MsgType: msgtype.KRB_AP_REQ,
-		APOptions: asn1.BitString{},
+		APOptions: types.NewKrbFlags(),
 		Ticket: TGT,
 		Ticket: TGT,
 		Authenticator: ed,
 		Authenticator: ed,
 	}
 	}
@@ -61,27 +61,11 @@ func NewAPReq(TGT types.Ticket, sessionKey types.EncryptionKey, auth types.Authe
 
 
 func encryptAuthenticator(a types.Authenticator, sessionKey types.EncryptionKey) (types.EncryptedData, error) {
 func encryptAuthenticator(a types.Authenticator, sessionKey types.EncryptionKey) (types.EncryptedData, error) {
 	var ed types.EncryptedData
 	var ed types.EncryptedData
-	etype, err := crypto.GetEtype(sessionKey.KeyType)
-	if err != nil {
-		return ed, fmt.Errorf("Error getting etype to encrypt authenticator: %v", err)
-	}
 	m, err := a.Marshal()
 	m, err := a.Marshal()
 	if err != nil {
 	if err != nil {
 		return ed, fmt.Errorf("Error marshalling authenticator: %v", err)
 		return ed, fmt.Errorf("Error marshalling authenticator: %v", err)
 	}
 	}
-	k, err := etype.DeriveKey(sessionKey.KeyValue, crypto.GetUsageKe(uint32(keyusage.TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR)))
-	if err != nil {
-		return ed, fmt.Errorf("Error deriving key for authenticator: %v", err)
-	}
-	_, b, err := etype.Encrypt(k, m)
-	if err != nil {
-		return ed, fmt.Errorf("Error encrypting authenticator: %v", err)
-	}
-	ed = types.EncryptedData{
-		EType: sessionKey.KeyType,
-		Cipher: b,
-	}
-	return ed, nil
+	return crypto.GetEncryptedData(m, sessionKey, keyusage.TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR, 0)
 }
 }
 
 
 func (a *APReq) Unmarshal(b []byte) error {
 func (a *APReq) Unmarshal(b []byte) error {

+ 18 - 0
messages/APReq_test.go

@@ -31,3 +31,21 @@ func TestUnmarshalAPReq(t *testing.T) {
 	assert.Equal(t, testdata.TEST_KVNO, a.Ticket.EncPart.KVNO, "Ticket encPart KVNO not as expected")
 	assert.Equal(t, testdata.TEST_KVNO, a.Ticket.EncPart.KVNO, "Ticket encPart KVNO not as expected")
 	assert.Equal(t, []byte(testdata.TEST_CIPHERTEXT), a.Ticket.EncPart.Cipher, "Ticket encPart cipher not as expected")
 	assert.Equal(t, []byte(testdata.TEST_CIPHERTEXT), a.Ticket.EncPart.Cipher, "Ticket encPart cipher not as expected")
 }
 }
+
+func TestMarshalAPReq(t *testing.T) {
+	var a APReq
+	v := "encode_krb5_ap_req"
+	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")
+}

+ 6 - 3
messages/KDCReq.go

@@ -121,7 +121,7 @@ func NewTGSReq(username string, c *config.Config, TGT types.Ticket, sessionKey t
 		PVNO:    iana.PVNO,
 		PVNO:    iana.PVNO,
 		MsgType: msgtype.KRB_TGS_REQ,
 		MsgType: msgtype.KRB_TGS_REQ,
 		ReqBody: KDCReqBody{
 		ReqBody: KDCReqBody{
-			KDCOptions: c.LibDefaults.Kdc_default_options,
+			KDCOptions: types.NewKrbFlags(),
 			Realm:      c.ResolveRealm(s[len(s)-1]),
 			Realm:      c.ResolveRealm(s[len(s)-1]),
 			SName: types.PrincipalName{
 			SName: types.PrincipalName{
 				NameType:   nametype.KRB_NT_PRINCIPAL,
 				NameType:   nametype.KRB_NT_PRINCIPAL,
@@ -132,7 +132,10 @@ func NewTGSReq(username string, c *config.Config, TGT types.Ticket, sessionKey t
 			EType: c.LibDefaults.Default_tgs_enctype_ids,
 			EType: c.LibDefaults.Default_tgs_enctype_ids,
 		},
 		},
 	}
 	}
-	if c.LibDefaults.Forwardable {
+	types.SetFlag(&a.ReqBody.KDCOptions, types.Forwardable)
+	types.SetFlag(&a.ReqBody.KDCOptions, types.Renewable)
+	types.SetFlag(&a.ReqBody.KDCOptions, types.Canonicalize)
+	/*if c.LibDefaults.Forwardable {
 		types.SetFlag(&a.ReqBody.KDCOptions, types.Forwardable)
 		types.SetFlag(&a.ReqBody.KDCOptions, types.Forwardable)
 	}
 	}
 	if c.LibDefaults.Canonicalize {
 	if c.LibDefaults.Canonicalize {
@@ -143,7 +146,7 @@ func NewTGSReq(username string, c *config.Config, TGT types.Ticket, sessionKey t
 	}
 	}
 	if c.LibDefaults.Renew_lifetime != 0 {
 	if c.LibDefaults.Renew_lifetime != 0 {
 		a.ReqBody.RTime = t.Add(c.LibDefaults.Renew_lifetime)
 		a.ReqBody.RTime = t.Add(c.LibDefaults.Renew_lifetime)
-	}
+	}*/
 	b, err := a.ReqBody.Marshal()
 	b, err := a.ReqBody.Marshal()
 	if err != nil {
 	if err != nil {
 		return a, fmt.Errorf("Error marshalling request body: %v", err)
 		return a, fmt.Errorf("Error marshalling request body: %v", err)

+ 1 - 0
messages/KDCReq_test.go

@@ -424,3 +424,4 @@ func TestMarshalTGSReq(t *testing.T) {
 	}
 	}
 	assert.Equal(t, b, mb, "Marshal bytes of TGSReq not as expected")
 	assert.Equal(t, b, mb, "Marshal bytes of TGSReq not as expected")
 }
 }
+

+ 28 - 0
testdata/test_vectors.go

@@ -95,3 +95,31 @@ var TestVectors = map[string]string{
 	//"encode_krb5_cammac":                                         "3081F2A01E301C300CA003020101A1050403616431300CA003020102A1050403616432A13D303BA01A3018A003020101A111300F1B066866747361691B056578747261A103020105A203020110A3133011A003020101A10A0408636B73756D6B6463A23D303BA01A3018A003020101A111300F1B066866747361691B056578747261A103020105A203020110A3133011A003020101A10A0408636B73756D737663A35230503013A311300FA003020101A1080406636B73756D313039A01A3018A003020101A111300F1B066866747361691B056578747261A103020105A203020110A311300FA003020101A1080406636B73756D32",
 	//"encode_krb5_cammac":                                         "3081F2A01E301C300CA003020101A1050403616431300CA003020102A1050403616432A13D303BA01A3018A003020101A111300F1B066866747361691B056578747261A103020105A203020110A3133011A003020101A10A0408636B73756D6B6463A23D303BA01A3018A003020101A111300F1B066866747361691B056578747261A103020105A203020110A3133011A003020101A10A0408636B73756D737663A35230503013A311300FA003020101A1080406636B73756D313039A01A3018A003020101A111300F1B066866747361691B056578747261A103020105A203020110A311300FA003020101A1080406636B73756D32",
 	//"encode_krb5_secure_cookie":                                  "302C02042DF8022530243010A10302010DA209040770612D646174613010A10302010DA209040770612D64617461",
 	//"encode_krb5_secure_cookie":                                  "302C02042DF8022530243010A10302010DA209040770612D646174613010A10302010DA209040770612D64617461",
 }
 }
+
+const (
+	TESTUSER1_KEYTAB = "0502000000470001000b544553542e474f4b52423500097465737475736572310000000158a869020100120020bbdc430aab7e2d4622a0b6951481453b0962e9db8e2f168942ad175cda6d9de9000000370001000b544553542e474f4b52423500097465737475736572310000000158a869020100110010698c4df8e9f60e7eea5a21bf4526ad25"
+	TEST_AS_REQ = "6a81a63081a3a103020105a20302010aa30e300c300aa10402020095a2020400a48186308183a00703050040000010a1163014a003020101a10d300b1b09746573747573657231a20d1b0b544553542e474f4b524235a320301ea003020102a11730151b066b72627467741b0b544553542e474f4b524235a511180f32303137303232303134323530315aa70602040f6755a6a814301202011202011102011002011702011902011a"
+	TEST_AS_REP = "6b8202f3308202efa003020105a10302010ba22e302c302aa103020113a2230421301f301da003020112a1161b14544553542e474f4b524235746573747573657231a30d1b0b544553542e474f4b524235a4163014a003020101a10d300b1b09746573747573657231a582015a6182015630820152a003020105a10d1b0b544553542e474f4b524235a220301ea003020102a11730151b066b72627467741b0b544553542e474f4b524235a382011830820114a003020112a103020101a28201060482010264d3fa49d89b627ed471298846ff92cd8632f657c58fe25322a61fffa32bb7966dc4c44c86a81353def2a11c36c537191406a609147f424a63266c00d02bcc56a27b0969d86ff4352634be9e2a4ac0ad5a36b0b0a3d689f128c0afa97401796e88037a35ad19efaf31d1ed4f3213769c03a58bc90ffac2051db152c0ed0809ad05ffb03aa3afaf731ed85f7a73020cb72355e0de27842dcf7eae3de9f7c14aa237edb25153b217ef3693373bc3cacbebe406910ff9ae9d00b7b08f726cb29a213cb9ad51ba80a8c24fa4b6692a445686889702cfa6ea749bac03e27e982407aca623fbd48586bcf566cfe87e1d9f17a74b1315669c16480f93e9d8782e71a8f11000a682012c30820128a003020112a282011f0482011b99b86153c0393c0e4130628f3e1e0f0a1f034e7e61a111b7fad15884e231c8fd8727e0bc945c9b35be20c57d057c8b09b0de74c53fb38cc15c9a2d483023fc369f5bde4da7324b4732b5a3d9504d92f67026aaa01df4f0138245d2ccb1c5a4014804cf295c7e7e56a867e6cf0c534f667f32da7aa5e700af1461764f1c276a8ff0fbee0e99322fe2059d2321853be09d0956c3afcfd07e3e702646a4678926a77bea20d9aaf3086b6d384821c81900af9013a3519f0e50eab6e1491d72e4ee17c2a44441b2ebc8a796cc3d876e328347dce65f61104e14d4c31532885776c9c8a70186b8b39f928972945c98bd60381ead5448e7ebe93fea308054287ac34b0583b4b9b5e43c5f8518d693ba9eb48a219c27344466b3c693a70462"
+	TEST_TGS_REQ = "6c82038f3082038ba103020105a20302010ca382031a3082031630820245a103020101a282023c048202386e82023430820230a003020105a10302010ea20703050000000000a382015a6182015630820152a003020105a10d1b0b544553542e474f4b524235a220301ea003020102a11730151b066b72627467741b0b544553542e474f4b524235a382011830820114a003020112a103020101a28201060482010264d3fa49d89b627ed471298846ff92cd8632f657c58fe25322a61fffa32bb7966dc4c44c86a81353def2a11c36c537191406a609147f424a63266c00d02bcc56a27b0969d86ff4352634be9e2a4ac0ad5a36b0b0a3d689f128c0afa97401796e88037a35ad19efaf31d1ed4f3213769c03a58bc90ffac2051db152c0ed0809ad05ffb03aa3afaf731ed85f7a73020cb72355e0de27842dcf7eae3de9f7c14aa237edb25153b217ef3693373bc3cacbebe406910ff9ae9d00b7b08f726cb29a213cb9ad51ba80a8c24fa4b6692a445686889702cfa6ea749bac03e27e982407aca623fbd48586bcf566cfe87e1d9f17a74b1315669c16480f93e9d8782e71a8f11000a481bc3081b9a003020112a281b10481ae8ae3cb8ac47d77cfc7b0b6bf0d3c5f8fcc6dd569344256a6a40c004fc2d23ebbe6ee0b9e00eccf37e710b7c01a7d2a63bbed6d75f2b230d24d724ef90edad2c5680e7e2436ab1145ff68481673444ebd61e3aef79b9ee05809551672c6c436eb8ac732a7fe78bd8f380e68a541191e3125554e4bab63dcc19ea931c1477366a6039ff7b7e62521ebfeffd6784b6ef0c97f653ac4d8dfb304f3e2e843faab12d838c23f1105f0a281c39325987cb03081caa10402020088a281c10481bea081bb3081b8a1173015a003020110a10e040ce613d8e9d544f0e56c60d3bba2819c308199a003020112a2819104818ec4fabcb1ec2f24e04ef51f9247239b28275653fa5cbc1dc9e747530c597631050fe86a5f3cba2ff54270aa771dcefa87efc8c8604407f84e603f5c01a2d929e18103561c3ffbc3a0cf63340bdd67a0739d4d81989827fc1d3f7f13e9dd5cc2346ca08e26a2aaf6d0102fbef8f7a6ee0a1caae7880e953ea678da619038786122a0b71853e8d0b95f544f8fbd6945a461305fa00703050040810000a20d1b0b544553542e474f4b524235a3233021a003020101a11a30181b04485454501b10686f73742e746573742e676f6b726235a511180f32303137303232303032323634325aa706020458a9ab2aa8053003020112"
+	TEST_TGS_REP = "6d82039d30820399a003020105a10302010da281df3081dc3081d9a10402020088a281d00481cda081ca3081c7a081c43081c1a003020112a281b90481b62e2b31bd998e2747a447175bcdbe14b7bc043c747c3289e10cde7403ee685d64f9724055c667ad2d3ce6240b5457ddfe3505a5b4d5d5e35238522ba5d86f1b691f28bbe7290487ffebf7e720ecf772cef061ac2c433cabbd0d5973fbedeb5418c8ba1bb7149dd625a4ff4cb465d9599c9d4cfb899807fa088521fa0e0ed5cfa4dd6d02b2a6854c4feb4ec382de5820134ca7c140be4b0f416ca5ebb328c8a470a55154062b8070683d0897a40277bdc752e94437920aa30d1b0b544553542e474f4b524235a4163014a003020101a10d300b1b09746573747573657231a58201706182016c30820168a003020105a10d1b0b544553542e474f4b524235a2233021a003020101a11a30181b04485454501b10686f73742e746573742e676f6b726235a382012b30820127a003020112a103020102a28201190482011524db012d81dde2cb3b7b40a35ce4fe17f7898166c7a7534ad73ca761e75316a06504415b1bc62508edb6ea58544a3ac0f98911cd55332442d30e007e0f39efa939b726a5228514984a133d1ba7d93d60fec5b2f7fbb16356c85ad1b0bb7ed6108420514086ea9959037e794b535fa052651385060da83f93acffbde0cb486b2f236f8955bb521ef90bc0a52944d2a8da82389e6861065064cc5178a5a7d302e9950761648726fc4015f8772339ef401fd8327dd335c6692c010f2c31b5ccccbcd83e68f2a1b66f16ca44e0bfb2903801c27ed8dd9a7b2dcea3c2bc91d8055c603f218494b1342490fbb805492d999491c2570b3ab392ba7e62c23659663509838e91b6f560a284889075071c348c701017a0a5e5c7a682010e3082010aa003020112a28201010481fece77ad9ebec9b094b686d4885895a2530471e9a56a93c2a463eaa988932695d77a12b6c02e69edfea6759ed49b029bdef43e446129b80a1ef95b9cea69a382d5c074868e68b676869f0990cad588c6d3589b9bba795ff0572ba648915f68a3b49df1def285645e93f4285a843ead01122c4f00bebefa33ecf6df2584e33da359d3d53e0a9b8ec0f41120a0d612d3a1e4504ce464dddec5e2aa3f0d2b6dae7b8800091760d7a590eaa6d7b33539c1700d9daf22a7c8cc1e108aee75267434997666132f52c08ea7c0c898859214ac4e71e185d3bcec1467ab6e8d91e79ba2b2041d40714da495c79d232d3c4e72a0910b9143fd648fe24bc46ec3416a3c34"
+	TEST_KRB5CONF = `[libdefaults]
+  default_realm = TEST.GOKRB5
+  dns_lookup_realm = false
+  dns_lookup_kdc = false
+  ticket_lifetime = 24h
+  forwardable = yes
+  default_tkt_enctypes = aes256-cts-hmac-sha1-96
+  default_tgs_enctypes = aes256-cts-hmac-sha1-96
+
+[realms]
+ TEST.GOKRB5 = {
+  kdc = 10.80.88.88:88
+  admin_server = 10.80.88.88:749
+  default_domain = test.gokrb5
+ }
+
+[domain_realm]
+ .test.gokrb5 = TEST.GOKRB5
+ test.gokrb5 = TEST.GOKRB5
+ `
+)

+ 7 - 0
types/KerberosFlags.go

@@ -90,6 +90,13 @@ const (
 	Validate               = 31
 	Validate               = 31
 )
 )
 
 
+func NewKrbFlags() asn1.BitString {
+	f := asn1.BitString{}
+	f.Bytes = make([]byte, 4)
+	f.BitLength = len(f.Bytes) * 8
+	return f
+}
+
 func SetFlags(f *asn1.BitString, j []int) {
 func SetFlags(f *asn1.BitString, j []int) {
 	for _, i := range j {
 	for _, i := range j {
 		SetFlag(f, i)
 		SetFlag(f, i)