dnssec_keyscan.go raw

   1  package dns
   2  
   3  import (
   4  	"bufio"
   5  	"crypto"
   6  	"crypto/ecdsa"
   7  	"crypto/ed25519"
   8  	"crypto/rsa"
   9  	"io"
  10  	"math/big"
  11  	"strconv"
  12  	"strings"
  13  )
  14  
  15  // NewPrivateKey returns a PrivateKey by parsing the string s.
  16  // s should be in the same form of the BIND private key files.
  17  func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
  18  	if s == "" || s[len(s)-1] != '\n' { // We need a closing newline
  19  		return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
  20  	}
  21  	return k.ReadPrivateKey(strings.NewReader(s), "")
  22  }
  23  
  24  // ReadPrivateKey reads a private key from the io.Reader q. The string file is
  25  // only used in error reporting.
  26  // The public key must be known, because some cryptographic algorithms embed
  27  // the public inside the privatekey.
  28  func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error) {
  29  	m, err := parseKey(q, file)
  30  	if m == nil {
  31  		return nil, err
  32  	}
  33  	if _, ok := m["private-key-format"]; !ok {
  34  		return nil, ErrPrivKey
  35  	}
  36  	if m["private-key-format"] != "v1.2" && m["private-key-format"] != "v1.3" {
  37  		return nil, ErrPrivKey
  38  	}
  39  	// TODO(mg): check if the pubkey matches the private key
  40  	algoStr, _, _ := strings.Cut(m["algorithm"], " ")
  41  	algo, err := strconv.ParseUint(algoStr, 10, 8)
  42  	if err != nil {
  43  		return nil, ErrPrivKey
  44  	}
  45  	switch uint8(algo) {
  46  	case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
  47  		priv, err := readPrivateKeyRSA(m)
  48  		if err != nil {
  49  			return nil, err
  50  		}
  51  		pub := k.publicKeyRSA()
  52  		if pub == nil {
  53  			return nil, ErrKey
  54  		}
  55  		priv.PublicKey = *pub
  56  		return priv, nil
  57  	case ECDSAP256SHA256, ECDSAP384SHA384:
  58  		priv, err := readPrivateKeyECDSA(m)
  59  		if err != nil {
  60  			return nil, err
  61  		}
  62  		pub := k.publicKeyECDSA()
  63  		if pub == nil {
  64  			return nil, ErrKey
  65  		}
  66  		priv.PublicKey = *pub
  67  		return priv, nil
  68  	case ED25519:
  69  		return readPrivateKeyED25519(m)
  70  	default:
  71  		return nil, ErrAlg
  72  	}
  73  }
  74  
  75  // Read a private key (file) string and create a public key. Return the private key.
  76  func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
  77  	p := new(rsa.PrivateKey)
  78  	p.Primes = []*big.Int{nil, nil}
  79  	for k, v := range m {
  80  		switch k {
  81  		case "modulus", "publicexponent", "privateexponent", "prime1", "prime2":
  82  			v1, err := fromBase64([]byte(v))
  83  			if err != nil {
  84  				return nil, err
  85  			}
  86  			switch k {
  87  			case "modulus":
  88  				p.PublicKey.N = new(big.Int).SetBytes(v1)
  89  			case "publicexponent":
  90  				i := new(big.Int).SetBytes(v1)
  91  				p.PublicKey.E = int(i.Int64()) // int64 should be large enough
  92  			case "privateexponent":
  93  				p.D = new(big.Int).SetBytes(v1)
  94  			case "prime1":
  95  				p.Primes[0] = new(big.Int).SetBytes(v1)
  96  			case "prime2":
  97  				p.Primes[1] = new(big.Int).SetBytes(v1)
  98  			}
  99  		case "exponent1", "exponent2", "coefficient":
 100  			// not used in Go (yet)
 101  		case "created", "publish", "activate":
 102  			// not used in Go (yet)
 103  		}
 104  	}
 105  	return p, nil
 106  }
 107  
 108  func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) {
 109  	p := new(ecdsa.PrivateKey)
 110  	p.D = new(big.Int)
 111  	// TODO: validate that the required flags are present
 112  	for k, v := range m {
 113  		switch k {
 114  		case "privatekey":
 115  			v1, err := fromBase64([]byte(v))
 116  			if err != nil {
 117  				return nil, err
 118  			}
 119  			p.D.SetBytes(v1)
 120  		case "created", "publish", "activate":
 121  			/* not used in Go (yet) */
 122  		}
 123  	}
 124  	return p, nil
 125  }
 126  
 127  func readPrivateKeyED25519(m map[string]string) (ed25519.PrivateKey, error) {
 128  	var p ed25519.PrivateKey
 129  	// TODO: validate that the required flags are present
 130  	for k, v := range m {
 131  		switch k {
 132  		case "privatekey":
 133  			p1, err := fromBase64([]byte(v))
 134  			if err != nil {
 135  				return nil, err
 136  			}
 137  			if len(p1) != ed25519.SeedSize {
 138  				return nil, ErrPrivKey
 139  			}
 140  			p = ed25519.NewKeyFromSeed(p1)
 141  		case "created", "publish", "activate":
 142  			/* not used in Go (yet) */
 143  		}
 144  	}
 145  	return p, nil
 146  }
 147  
 148  // parseKey reads a private key from r. It returns a map[string]string,
 149  // with the key-value pairs, or an error when the file is not correct.
 150  func parseKey(r io.Reader, file string) (map[string]string, error) {
 151  	m := make(map[string]string)
 152  	var k string
 153  
 154  	c := newKLexer(r)
 155  
 156  	for l, ok := c.Next(); ok; l, ok = c.Next() {
 157  		// It should alternate
 158  		switch l.value {
 159  		case zKey:
 160  			k = l.token
 161  		case zValue:
 162  			if k == "" {
 163  				return nil, &ParseError{file: file, err: "no private key seen", lex: l}
 164  			}
 165  
 166  			m[strings.ToLower(k)] = l.token
 167  			k = ""
 168  		}
 169  	}
 170  
 171  	// Surface any read errors from r.
 172  	if err := c.Err(); err != nil {
 173  		return nil, &ParseError{file: file, err: err.Error()}
 174  	}
 175  
 176  	return m, nil
 177  }
 178  
 179  type klexer struct {
 180  	br io.ByteReader
 181  
 182  	readErr error
 183  
 184  	line   int
 185  	column int
 186  
 187  	key bool
 188  
 189  	eol bool // end-of-line
 190  }
 191  
 192  func newKLexer(r io.Reader) *klexer {
 193  	br, ok := r.(io.ByteReader)
 194  	if !ok {
 195  		br = bufio.NewReaderSize(r, 1024)
 196  	}
 197  
 198  	return &klexer{
 199  		br: br,
 200  
 201  		line: 1,
 202  
 203  		key: true,
 204  	}
 205  }
 206  
 207  func (kl *klexer) Err() error {
 208  	if kl.readErr == io.EOF {
 209  		return nil
 210  	}
 211  
 212  	return kl.readErr
 213  }
 214  
 215  // readByte returns the next byte from the input
 216  func (kl *klexer) readByte() (byte, bool) {
 217  	if kl.readErr != nil {
 218  		return 0, false
 219  	}
 220  
 221  	c, err := kl.br.ReadByte()
 222  	if err != nil {
 223  		kl.readErr = err
 224  		return 0, false
 225  	}
 226  
 227  	// delay the newline handling until the next token is delivered,
 228  	// fixes off-by-one errors when reporting a parse error.
 229  	if kl.eol {
 230  		kl.line++
 231  		kl.column = 0
 232  		kl.eol = false
 233  	}
 234  
 235  	if c == '\n' {
 236  		kl.eol = true
 237  	} else {
 238  		kl.column++
 239  	}
 240  
 241  	return c, true
 242  }
 243  
 244  func (kl *klexer) Next() (lex, bool) {
 245  	var (
 246  		l lex
 247  
 248  		str strings.Builder
 249  
 250  		commt bool
 251  	)
 252  
 253  	for x, ok := kl.readByte(); ok; x, ok = kl.readByte() {
 254  		l.line, l.column = kl.line, kl.column
 255  
 256  		switch x {
 257  		case ':':
 258  			if commt || !kl.key {
 259  				break
 260  			}
 261  
 262  			kl.key = false
 263  
 264  			// Next token is a space, eat it
 265  			kl.readByte()
 266  
 267  			l.value = zKey
 268  			l.token = str.String()
 269  			return l, true
 270  		case ';':
 271  			commt = true
 272  		case '\n':
 273  			if commt {
 274  				// Reset a comment
 275  				commt = false
 276  			}
 277  
 278  			if kl.key && str.Len() == 0 {
 279  				// ignore empty lines
 280  				break
 281  			}
 282  
 283  			kl.key = true
 284  
 285  			l.value = zValue
 286  			l.token = str.String()
 287  			return l, true
 288  		default:
 289  			if commt {
 290  				break
 291  			}
 292  
 293  			str.WriteByte(x)
 294  		}
 295  	}
 296  
 297  	if kl.readErr != nil && kl.readErr != io.EOF {
 298  		// Don't return any tokens after a read error occurs.
 299  		return lex{value: zEOF}, false
 300  	}
 301  
 302  	if str.Len() > 0 {
 303  		// Send remainder
 304  		l.value = zValue
 305  		l.token = str.String()
 306  		return l, true
 307  	}
 308  
 309  	return lex{value: zEOF}, false
 310  }
 311