gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

dnssec_keyscan.go (6312B)


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