tsigkey.go raw

   1  package internal
   2  
   3  import (
   4  	"bufio"
   5  	"fmt"
   6  	"os"
   7  	"strings"
   8  )
   9  
  10  type Key struct {
  11  	Name      string
  12  	Algorithm string
  13  	Secret    string
  14  }
  15  
  16  // ReadTSIGFile reads TSIG key file generated with `tsig-keygen`.
  17  func ReadTSIGFile(filename string) (*Key, error) {
  18  	file, err := os.Open(filename)
  19  	if err != nil {
  20  		return nil, fmt.Errorf("open file: %w", err)
  21  	}
  22  
  23  	defer func() { _ = file.Close() }()
  24  
  25  	key := &Key{}
  26  
  27  	var read bool
  28  
  29  	scanner := bufio.NewScanner(file)
  30  	for scanner.Scan() {
  31  		line := strings.TrimSpace(strings.TrimSuffix(scanner.Text(), ";"))
  32  
  33  		if line == "" {
  34  			continue
  35  		}
  36  
  37  		if read && line == "}" {
  38  			break
  39  		}
  40  
  41  		fields := strings.Fields(line)
  42  
  43  		switch {
  44  		case fields[0] == "key":
  45  			read = true
  46  
  47  			if len(fields) != 3 {
  48  				return nil, fmt.Errorf("invalid key line: %s", line)
  49  			}
  50  
  51  			key.Name = safeUnquote(fields[1])
  52  
  53  		case !read:
  54  			continue
  55  
  56  		default:
  57  			if len(fields) != 2 {
  58  				continue
  59  			}
  60  
  61  			v := safeUnquote(fields[1])
  62  
  63  			switch safeUnquote(fields[0]) {
  64  			case "algorithm":
  65  				key.Algorithm = v
  66  			case "secret":
  67  				key.Secret = v
  68  			default:
  69  				continue
  70  			}
  71  		}
  72  	}
  73  
  74  	return key, nil
  75  }
  76  
  77  func safeUnquote(v string) string {
  78  	if len(v) < 2 {
  79  		// empty or single character string
  80  		return v
  81  	}
  82  
  83  	if v[0] == '"' && v[len(v)-1] == '"' {
  84  		// string wrapped in quotes
  85  		return v[1 : len(v)-1]
  86  	}
  87  
  88  	return v
  89  }
  90