dns/kscan.go

170 lines
3.6 KiB
Go
Raw Normal View History

2011-12-16 03:38:14 +11:00
package dns
import (
2011-12-17 03:32:15 +11:00
"crypto/ecdsa"
"crypto/rsa"
2011-12-16 03:38:14 +11:00
"io"
2011-12-17 03:32:15 +11:00
"math/big"
"strings"
2011-12-16 03:38:14 +11:00
"text/scanner"
)
2011-12-17 03:32:15 +11:00
// ReadPrivateKey reads a private key from the io.Reader q.
func ReadPrivateKey(q io.Reader) (PrivateKey, error) {
m, e := ParseKey(q)
if m == nil {
return nil, e
}
if _, ok := m["private-key-format"]; !ok {
return nil, ErrPrivKey
}
if m["private-key-format"] != "v1.2" && m["private-key-format"] != "v1.3" {
return nil, ErrPrivKey
}
switch m["algorithm"] {
case "1 (RSAMD5)", "5 (RSASHA1)", "8 (RSASHA256)", "10 (RSASHA512)":
2011-12-17 05:42:30 +11:00
fallthrough
case "7 (RSASHA1NSEC3SHA1)":
2011-12-17 03:32:15 +11:00
return readPrivateKeyRSA(m)
case "13 (ECDSAP256SHA256)", "14 (ECDSAP384SHA384)":
return readPrivateKeyECDSA(m)
}
return nil, ErrPrivKey
}
// Read a private key (file) string and create a public key. Return the private key.
func readPrivateKeyRSA(m map[string]string) (PrivateKey, error) {
p := new(rsa.PrivateKey)
p.Primes = []*big.Int{nil, nil}
for k, v := range m {
switch k {
case "modulus", "publicexponent", "privateexponent", "prime1", "prime2":
v1, err := packBase64([]byte(v))
if err != nil {
return nil, err
}
switch k {
case "modulus":
p.PublicKey.N = big.NewInt(0)
p.PublicKey.N.SetBytes(v1)
case "publicexponent":
i := big.NewInt(0)
i.SetBytes(v1)
p.PublicKey.E = int(i.Int64()) // int64 should be large enough
case "privateexponent":
p.D = big.NewInt(0)
p.D.SetBytes(v1)
case "prime1":
p.Primes[0] = big.NewInt(0)
p.Primes[0].SetBytes(v1)
case "prime2":
p.Primes[1] = big.NewInt(0)
p.Primes[1].SetBytes(v1)
}
case "exponent1", "exponent2", "coefficient":
// not used in Go (yet)
case "created", "publish", "activate":
// not used in Go (yet)
}
}
return p, nil
}
func readPrivateKeyECDSA(m map[string]string) (PrivateKey, error) {
p := new(ecdsa.PrivateKey)
p.D = big.NewInt(0)
// Need to check if we have everything
for k, v := range m {
switch k {
case "privatekey:":
v1, err := packBase64([]byte(v))
if err != nil {
return nil, err
}
p.D.SetBytes(v1)
case "created:", "publish:", "activate:":
/* not used in Go (yet) */
}
}
return p, nil
}
// ParseKey reads a private key from r. It returns a map[string]string,
// with the key-value pairs, or an error when the file is not correct.
2011-12-16 03:38:14 +11:00
func ParseKey(r io.Reader) (map[string]string, error) {
var s scanner.Scanner
2011-12-17 00:48:30 +11:00
m := make(map[string]string)
2011-12-17 05:34:30 +11:00
c := make(chan lex)
2011-12-17 00:48:30 +11:00
k := ""
2011-12-16 03:38:14 +11:00
s.Init(r)
s.Mode = 0
s.Whitespace = 0
// Start the lexer
go klexer(s, c)
for l := range c {
2011-12-17 00:48:30 +11:00
// It should alternate
2011-12-16 03:38:14 +11:00
switch l.value {
case _KEY:
2011-12-17 00:48:30 +11:00
k = l.token
2011-12-16 03:38:14 +11:00
case _VALUE:
2011-12-17 03:32:15 +11:00
if k == "" {
return nil, &ParseError{"No key seen", l}
}
2011-12-17 05:42:30 +11:00
//println("Setting", strings.ToLower(k), "to", l.token, "b")
2011-12-17 03:32:15 +11:00
m[strings.ToLower(k)] = l.token
k = ""
2011-12-16 03:38:14 +11:00
}
}
2011-12-17 00:48:30 +11:00
return m, nil
2011-12-16 03:38:14 +11:00
}
// klexer scans the sourcefile and returns tokens on the channel c.
2011-12-17 05:34:30 +11:00
func klexer(s scanner.Scanner, c chan lex) {
var l lex
2011-12-16 03:38:14 +11:00
str := "" // Hold the current read text
commt := false
2011-12-17 00:48:30 +11:00
key := true
2011-12-16 03:38:14 +11:00
tok := s.Scan()
defer close(c)
for tok != scanner.EOF {
l.column = s.Position.Column
l.line = s.Position.Line
switch x := s.TokenText(); x {
2011-12-17 00:48:30 +11:00
case ":":
2011-12-16 03:38:14 +11:00
if commt {
break
}
2011-12-17 05:42:30 +11:00
l.token = str
2011-12-17 00:48:30 +11:00
if key {
l.value = _KEY
c <- l
2011-12-17 05:42:30 +11:00
// Next token is a space, eat it
s.Scan()
2011-12-17 00:48:30 +11:00
key = false
2011-12-17 05:42:30 +11:00
str = ""
2011-12-17 00:48:30 +11:00
} else {
l.value = _VALUE
}
2011-12-16 03:38:14 +11:00
case ";":
commt = true
case "\n":
if commt {
// Reset a comment
commt = false
}
2011-12-17 05:42:30 +11:00
l.value = _VALUE
l.token = str
2011-12-17 00:48:30 +11:00
c <- l
2011-12-16 03:38:14 +11:00
str = ""
commt = false
2011-12-17 00:48:30 +11:00
key = true
2011-12-16 03:38:14 +11:00
default:
if commt {
break
}
str += x
}
tok = s.Scan()
}
}