[VOL-4290] Voltha go library updates for gRPC migration
Change-Id: I1aa2774beb6b7ed7419bc45aeb53fcae8a8ecda0
diff --git a/vendor/github.com/jcmturner/gokrb5/v8/keytab/keytab.go b/vendor/github.com/jcmturner/gokrb5/v8/keytab/keytab.go
new file mode 100644
index 0000000..5c2e9d7
--- /dev/null
+++ b/vendor/github.com/jcmturner/gokrb5/v8/keytab/keytab.go
@@ -0,0 +1,530 @@
+// Package keytab implements Kerberos keytabs: https://web.mit.edu/kerberos/krb5-devel/doc/formats/keytab_file_format.html.
+package keytab
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "strings"
+ "time"
+ "unsafe"
+
+ "github.com/jcmturner/gokrb5/v8/crypto"
+ "github.com/jcmturner/gokrb5/v8/types"
+)
+
+const (
+ keytabFirstByte byte = 05
+)
+
+// Keytab struct.
+type Keytab struct {
+ version uint8
+ Entries []entry
+}
+
+// Keytab entry struct.
+type entry struct {
+ Principal principal
+ Timestamp time.Time
+ KVNO8 uint8
+ Key types.EncryptionKey
+ KVNO uint32
+}
+
+func (e entry) String() string {
+ return fmt.Sprintf("% 4d %s %-56s %2d %-64x",
+ e.KVNO8,
+ e.Timestamp.Format("02/01/06 15:04:05"),
+ e.Principal.String(),
+ e.Key.KeyType,
+ e.Key.KeyValue,
+ )
+}
+
+// Keytab entry principal struct.
+type principal struct {
+ NumComponents int16 `json:"-"`
+ Realm string
+ Components []string
+ NameType int32
+}
+
+func (p principal) String() string {
+ return fmt.Sprintf("%s@%s", strings.Join(p.Components, "/"), p.Realm)
+}
+
+// New creates new, empty Keytab type.
+func New() *Keytab {
+ var e []entry
+ return &Keytab{
+ version: 2,
+ Entries: e,
+ }
+}
+
+// GetEncryptionKey returns the EncryptionKey from the Keytab for the newest entry with the required kvno, etype and matching principal.
+// If the kvno is zero then the latest kvno will be returned. The kvno is also returned for
+func (kt *Keytab) GetEncryptionKey(princName types.PrincipalName, realm string, kvno int, etype int32) (types.EncryptionKey, int, error) {
+ var key types.EncryptionKey
+ var t time.Time
+ var kv int
+ for _, k := range kt.Entries {
+ if k.Principal.Realm == realm && len(k.Principal.Components) == len(princName.NameString) &&
+ k.Key.KeyType == etype &&
+ (k.KVNO == uint32(kvno) || kvno == 0) &&
+ k.Timestamp.After(t) {
+ p := true
+ for i, n := range k.Principal.Components {
+ if princName.NameString[i] != n {
+ p = false
+ break
+ }
+ }
+ if p {
+ key = k.Key
+ kv = int(k.KVNO)
+ t = k.Timestamp
+ }
+ }
+ }
+ if len(key.KeyValue) < 1 {
+ return key, 0, fmt.Errorf("matching key not found in keytab. Looking for %v realm: %v kvno: %v etype: %v", princName.NameString, realm, kvno, etype)
+ }
+ return key, kv, nil
+}
+
+// Create a new Keytab entry.
+func newEntry() entry {
+ var b []byte
+ return entry{
+ Principal: newPrincipal(),
+ Timestamp: time.Time{},
+ KVNO8: 0,
+ Key: types.EncryptionKey{
+ KeyType: 0,
+ KeyValue: b,
+ },
+ KVNO: 0,
+ }
+}
+
+func (kt Keytab) String() string {
+ var s string
+ s = `KVNO Timestamp Principal ET Key
+---- ----------------- -------------------------------------------------------- -- ----------------------------------------------------------------
+`
+ for _, entry := range kt.Entries {
+ s += entry.String() + "\n"
+ }
+ return s
+}
+
+// AddEntry adds an entry to the keytab. The password should be provided in plain text and it will be converted using the defined enctype to be stored.
+func (kt *Keytab) AddEntry(principalName, realm, password string, ts time.Time, KVNO uint8, encType int32) error {
+ // Generate a key from the password
+ princ, _ := types.ParseSPNString(principalName)
+ key, _, err := crypto.GetKeyFromPassword(password, princ, realm, encType, types.PADataSequence{})
+ if err != nil {
+ return err
+ }
+
+ // Populate the keytab entry principal
+ ktep := newPrincipal()
+ ktep.NumComponents = int16(len(princ.NameString))
+ if kt.version == 1 {
+ ktep.NumComponents += 1
+ }
+
+ ktep.Realm = realm
+ ktep.Components = princ.NameString
+ ktep.NameType = princ.NameType
+
+ // Populate the keytab entry
+ e := newEntry()
+ e.Principal = ktep
+ e.Timestamp = ts
+ e.KVNO8 = KVNO
+ e.KVNO = uint32(KVNO)
+ e.Key = key
+
+ kt.Entries = append(kt.Entries, e)
+ return nil
+}
+
+// Create a new principal.
+func newPrincipal() principal {
+ var c []string
+ return principal{
+ NumComponents: 0,
+ Realm: "",
+ Components: c,
+ NameType: 0,
+ }
+}
+
+// Load a Keytab file into a Keytab type.
+func Load(ktPath string) (*Keytab, error) {
+ kt := new(Keytab)
+ b, err := ioutil.ReadFile(ktPath)
+ if err != nil {
+ return kt, err
+ }
+ err = kt.Unmarshal(b)
+ return kt, err
+}
+
+// Marshal keytab into byte slice
+func (kt *Keytab) Marshal() ([]byte, error) {
+ b := []byte{keytabFirstByte, kt.version}
+ for _, e := range kt.Entries {
+ eb, err := e.marshal(int(kt.version))
+ if err != nil {
+ return b, err
+ }
+ b = append(b, eb...)
+ }
+ return b, nil
+}
+
+// Write the keytab bytes to io.Writer.
+// Returns the number of bytes written
+func (kt *Keytab) Write(w io.Writer) (int, error) {
+ b, err := kt.Marshal()
+ if err != nil {
+ return 0, fmt.Errorf("error marshaling keytab: %v", err)
+ }
+ return w.Write(b)
+}
+
+// Unmarshal byte slice of Keytab data into Keytab type.
+func (kt *Keytab) Unmarshal(b []byte) error {
+ if len(b) < 2 {
+ return fmt.Errorf("byte array is less than 2 bytes: %d", len(b))
+ }
+
+ //The first byte of the file always has the value 5
+ if b[0] != keytabFirstByte {
+ return errors.New("invalid keytab data. First byte does not equal 5")
+ }
+ //Get keytab version
+ //The 2nd byte contains the version number (1 or 2)
+ kt.version = b[1]
+ if kt.version != 1 && kt.version != 2 {
+ return errors.New("invalid keytab data. Keytab version is neither 1 nor 2")
+ }
+ //Version 1 of the file format uses native byte order for integer representations. Version 2 always uses big-endian byte order
+ var endian binary.ByteOrder
+ endian = binary.BigEndian
+ if kt.version == 1 && isNativeEndianLittle() {
+ endian = binary.LittleEndian
+ }
+ // n tracks position in the byte array
+ n := 2
+ l, err := readInt32(b, &n, &endian)
+ if err != nil {
+ return err
+ }
+ for l != 0 {
+ if l < 0 {
+ //Zero padded so skip over
+ l = l * -1
+ n = n + int(l)
+ } else {
+ if n < 0 {
+ return fmt.Errorf("%d can't be less than zero", n)
+ }
+ if n+int(l) > len(b) {
+ return fmt.Errorf("%s's length is less than %d", b, n+int(l))
+ }
+ eb := b[n : n+int(l)]
+ n = n + int(l)
+ ke := newEntry()
+ // p keeps track as to where we are in the byte stream
+ var p int
+ var err error
+ parsePrincipal(eb, &p, kt, &ke, &endian)
+ ke.Timestamp, err = readTimestamp(eb, &p, &endian)
+ if err != nil {
+ return err
+ }
+ rei8, err := readInt8(eb, &p, &endian)
+ if err != nil {
+ return err
+ }
+ ke.KVNO8 = uint8(rei8)
+ rei16, err := readInt16(eb, &p, &endian)
+ if err != nil {
+ return err
+ }
+ ke.Key.KeyType = int32(rei16)
+ rei16, err = readInt16(eb, &p, &endian)
+ if err != nil {
+ return err
+ }
+ kl := int(rei16)
+ ke.Key.KeyValue, err = readBytes(eb, &p, kl, &endian)
+ if err != nil {
+ return err
+ }
+ // The 32-bit key version overrides the 8-bit key version.
+ // If at least 4 bytes are left after the other fields are read and they are non-zero
+ // this indicates the 32-bit version is present.
+ if len(eb)-p >= 4 {
+ // The 32-bit key may be present
+ ri32, err := readInt32(eb, &p, &endian)
+ if err != nil {
+ return err
+ }
+ ke.KVNO = uint32(ri32)
+ }
+ if ke.KVNO == 0 {
+ // Handles if the value from the last 4 bytes was zero and also if there are not the 4 bytes present. Makes sense to put the same value here as KVNO8
+ ke.KVNO = uint32(ke.KVNO8)
+ }
+ // Add the entry to the keytab
+ kt.Entries = append(kt.Entries, ke)
+ }
+ // Check if there are still 4 bytes left to read
+ // Also check that n is greater than zero
+ if n < 0 || n > len(b) || len(b[n:]) < 4 {
+ break
+ }
+ // Read the size of the next entry
+ l, err = readInt32(b, &n, &endian)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (e entry) marshal(v int) ([]byte, error) {
+ var b []byte
+ pb, err := e.Principal.marshal(v)
+ if err != nil {
+ return b, err
+ }
+ b = append(b, pb...)
+
+ var endian binary.ByteOrder
+ endian = binary.BigEndian
+ if v == 1 && isNativeEndianLittle() {
+ endian = binary.LittleEndian
+ }
+
+ t := make([]byte, 9)
+ endian.PutUint32(t[0:4], uint32(e.Timestamp.Unix()))
+ t[4] = e.KVNO8
+ endian.PutUint16(t[5:7], uint16(e.Key.KeyType))
+ endian.PutUint16(t[7:9], uint16(len(e.Key.KeyValue)))
+ b = append(b, t...)
+
+ buf := new(bytes.Buffer)
+ err = binary.Write(buf, endian, e.Key.KeyValue)
+ if err != nil {
+ return b, err
+ }
+ b = append(b, buf.Bytes()...)
+
+ t = make([]byte, 4)
+ endian.PutUint32(t, e.KVNO)
+ b = append(b, t...)
+
+ // Add the length header
+ t = make([]byte, 4)
+ endian.PutUint32(t, uint32(len(b)))
+ b = append(t, b...)
+ return b, nil
+}
+
+// Parse the Keytab bytes of a principal into a Keytab entry's principal.
+func parsePrincipal(b []byte, p *int, kt *Keytab, ke *entry, e *binary.ByteOrder) error {
+ var err error
+ ke.Principal.NumComponents, err = readInt16(b, p, e)
+ if err != nil {
+ return err
+ }
+ if kt.version == 1 {
+ //In version 1 the number of components includes the realm. Minus 1 to make consistent with version 2
+ ke.Principal.NumComponents--
+ }
+ lenRealm, err := readInt16(b, p, e)
+ if err != nil {
+ return err
+ }
+ realmB, err := readBytes(b, p, int(lenRealm), e)
+ if err != nil {
+ return err
+ }
+ ke.Principal.Realm = string(realmB)
+ for i := 0; i < int(ke.Principal.NumComponents); i++ {
+ l, err := readInt16(b, p, e)
+ if err != nil {
+ return err
+ }
+ compB, err := readBytes(b, p, int(l), e)
+ if err != nil {
+ return err
+ }
+ ke.Principal.Components = append(ke.Principal.Components, string(compB))
+ }
+ if kt.version != 1 {
+ //Name Type is omitted in version 1
+ ke.Principal.NameType, err = readInt32(b, p, e)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (p principal) marshal(v int) ([]byte, error) {
+ //var b []byte
+ b := make([]byte, 2)
+ var endian binary.ByteOrder
+ endian = binary.BigEndian
+ if v == 1 && isNativeEndianLittle() {
+ endian = binary.LittleEndian
+ }
+ endian.PutUint16(b[0:], uint16(p.NumComponents))
+ realm, err := marshalString(p.Realm, v)
+ if err != nil {
+ return b, err
+ }
+ b = append(b, realm...)
+ for _, c := range p.Components {
+ cb, err := marshalString(c, v)
+ if err != nil {
+ return b, err
+ }
+ b = append(b, cb...)
+ }
+ if v != 1 {
+ t := make([]byte, 4)
+ endian.PutUint32(t, uint32(p.NameType))
+ b = append(b, t...)
+ }
+ return b, nil
+}
+
+func marshalString(s string, v int) ([]byte, error) {
+ sb := []byte(s)
+ b := make([]byte, 2)
+ var endian binary.ByteOrder
+ endian = binary.BigEndian
+ if v == 1 && isNativeEndianLittle() {
+ endian = binary.LittleEndian
+ }
+ endian.PutUint16(b[0:], uint16(len(sb)))
+ buf := new(bytes.Buffer)
+ err := binary.Write(buf, endian, sb)
+ if err != nil {
+ return b, err
+ }
+ b = append(b, buf.Bytes()...)
+ return b, err
+}
+
+// Read bytes representing a timestamp.
+func readTimestamp(b []byte, p *int, e *binary.ByteOrder) (time.Time, error) {
+ i32, err := readInt32(b, p, e)
+ if err != nil {
+ return time.Time{}, err
+ }
+ return time.Unix(int64(i32), 0), nil
+}
+
+// Read bytes representing an eight bit integer.
+func readInt8(b []byte, p *int, e *binary.ByteOrder) (i int8, err error) {
+ if *p < 0 {
+ return 0, fmt.Errorf("%d cannot be less than zero", *p)
+ }
+
+ if (*p + 1) > len(b) {
+ return 0, fmt.Errorf("%s's length is less than %d", b, *p+1)
+ }
+ buf := bytes.NewBuffer(b[*p : *p+1])
+ binary.Read(buf, *e, &i)
+ *p++
+ return
+}
+
+// Read bytes representing a sixteen bit integer.
+func readInt16(b []byte, p *int, e *binary.ByteOrder) (i int16, err error) {
+ if *p < 0 {
+ return 0, fmt.Errorf("%d cannot be less than zero", *p)
+ }
+
+ if (*p + 2) > len(b) {
+ return 0, fmt.Errorf("%s's length is less than %d", b, *p+2)
+ }
+
+ buf := bytes.NewBuffer(b[*p : *p+2])
+ binary.Read(buf, *e, &i)
+ *p += 2
+ return
+}
+
+// Read bytes representing a thirty two bit integer.
+func readInt32(b []byte, p *int, e *binary.ByteOrder) (i int32, err error) {
+ if *p < 0 {
+ return 0, fmt.Errorf("%d cannot be less than zero", *p)
+ }
+
+ if (*p + 4) > len(b) {
+ return 0, fmt.Errorf("%s's length is less than %d", b, *p+4)
+ }
+
+ buf := bytes.NewBuffer(b[*p : *p+4])
+ binary.Read(buf, *e, &i)
+ *p += 4
+ return
+}
+
+func readBytes(b []byte, p *int, s int, e *binary.ByteOrder) ([]byte, error) {
+ if s < 0 {
+ return nil, fmt.Errorf("%d cannot be less than zero", s)
+ }
+ i := *p + s
+ if i > len(b) {
+ return nil, fmt.Errorf("%s's length is greater than %d", b, i)
+ }
+ buf := bytes.NewBuffer(b[*p:i])
+ r := make([]byte, s)
+ if err := binary.Read(buf, *e, &r); err != nil {
+ return nil, err
+ }
+ *p += s
+ return r, nil
+}
+
+func isNativeEndianLittle() bool {
+ var x = 0x012345678
+ var p = unsafe.Pointer(&x)
+ var bp = (*[4]byte)(p)
+
+ var endian bool
+ if 0x01 == bp[0] {
+ endian = false
+ } else if (0x78 & 0xff) == (bp[0] & 0xff) {
+ endian = true
+ } else {
+ // Default to big endian
+ endian = false
+ }
+ return endian
+}
+
+// JSON return information about the keys held in the keytab in a JSON format.
+func (kt *Keytab) JSON() (string, error) {
+ b, err := json.MarshalIndent(kt, "", " ")
+ if err != nil {
+ return "", err
+ }
+ return string(b), nil
+}