package dns

import (
	
	
	
	
	
	
	
	
	
)

// NewPrivateKey returns a PrivateKey by parsing the string s.
// s should be in the same form of the BIND private key files.
func ( *DNSKEY) ( string) (crypto.PrivateKey, error) {
	if  == "" || [len()-1] != '\n' { // We need a closing newline
		return .ReadPrivateKey(strings.NewReader(+"\n"), "")
	}
	return .ReadPrivateKey(strings.NewReader(), "")
}

// ReadPrivateKey reads a private key from the io.Reader q. The string file is
// only used in error reporting.
// The public key must be known, because some cryptographic algorithms embed
// the public inside the privatekey.
func ( *DNSKEY) ( io.Reader,  string) (crypto.PrivateKey, error) {
	,  := parseKey(, )
	if  == nil {
		return nil, 
	}
	if ,  := ["private-key-format"]; ! {
		return nil, ErrPrivKey
	}
	if ["private-key-format"] != "v1.2" && ["private-key-format"] != "v1.3" {
		return nil, ErrPrivKey
	}
	// TODO(mg): check if the pubkey matches the private key
	, ,  := strings.Cut(["algorithm"], " ")
	,  := strconv.ParseUint(, 10, 8)
	if  != nil {
		return nil, ErrPrivKey
	}
	switch uint8() {
	case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
		,  := readPrivateKeyRSA()
		if  != nil {
			return nil, 
		}
		 := .publicKeyRSA()
		if  == nil {
			return nil, ErrKey
		}
		.PublicKey = *
		return , nil
	case ECDSAP256SHA256, ECDSAP384SHA384:
		,  := readPrivateKeyECDSA()
		if  != nil {
			return nil, 
		}
		 := .publicKeyECDSA()
		if  == nil {
			return nil, ErrKey
		}
		.PublicKey = *
		return , nil
	case ED25519:
		return readPrivateKeyED25519()
	default:
		return nil, ErrAlg
	}
}

// Read a private key (file) string and create a public key. Return the private key.
func readPrivateKeyRSA( map[string]string) (*rsa.PrivateKey, error) {
	 := new(rsa.PrivateKey)
	.Primes = []*big.Int{nil, nil}
	for ,  := range  {
		switch  {
		case "modulus", "publicexponent", "privateexponent", "prime1", "prime2":
			,  := fromBase64([]byte())
			if  != nil {
				return nil, 
			}
			switch  {
			case "modulus":
				.PublicKey.N = new(big.Int).SetBytes()
			case "publicexponent":
				 := new(big.Int).SetBytes()
				.PublicKey.E = int(.Int64()) // int64 should be large enough
			case "privateexponent":
				.D = new(big.Int).SetBytes()
			case "prime1":
				.Primes[0] = new(big.Int).SetBytes()
			case "prime2":
				.Primes[1] = new(big.Int).SetBytes()
			}
		case "exponent1", "exponent2", "coefficient":
			// not used in Go (yet)
		case "created", "publish", "activate":
			// not used in Go (yet)
		}
	}
	return , nil
}

func readPrivateKeyECDSA( map[string]string) (*ecdsa.PrivateKey, error) {
	 := new(ecdsa.PrivateKey)
	.D = new(big.Int)
	// TODO: validate that the required flags are present
	for ,  := range  {
		switch  {
		case "privatekey":
			,  := fromBase64([]byte())
			if  != nil {
				return nil, 
			}
			.D.SetBytes()
		case "created", "publish", "activate":
			/* not used in Go (yet) */
		}
	}
	return , nil
}

func readPrivateKeyED25519( map[string]string) (ed25519.PrivateKey, error) {
	var  ed25519.PrivateKey
	// TODO: validate that the required flags are present
	for ,  := range  {
		switch  {
		case "privatekey":
			,  := fromBase64([]byte())
			if  != nil {
				return nil, 
			}
			if len() != ed25519.SeedSize {
				return nil, ErrPrivKey
			}
			 = ed25519.NewKeyFromSeed()
		case "created", "publish", "activate":
			/* not used in Go (yet) */
		}
	}
	return , 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.
func parseKey( io.Reader,  string) (map[string]string, error) {
	 := make(map[string]string)
	var  string

	 := newKLexer()

	for ,  := .Next(); ; ,  = .Next() {
		// It should alternate
		switch .value {
		case zKey:
			 = .token
		case zValue:
			if  == "" {
				return nil, &ParseError{file: , err: "no private key seen", lex: }
			}

			[strings.ToLower()] = .token
			 = ""
		}
	}

	// Surface any read errors from r.
	if  := .Err();  != nil {
		return nil, &ParseError{file: , err: .Error()}
	}

	return , nil
}

type klexer struct {
	br io.ByteReader

	readErr error

	line   int
	column int

	key bool

	eol bool // end-of-line
}

func newKLexer( io.Reader) *klexer {
	,  := .(io.ByteReader)
	if ! {
		 = bufio.NewReaderSize(, 1024)
	}

	return &klexer{
		br: ,

		line: 1,

		key: true,
	}
}

func ( *klexer) () error {
	if .readErr == io.EOF {
		return nil
	}

	return .readErr
}

// readByte returns the next byte from the input
func ( *klexer) () (byte, bool) {
	if .readErr != nil {
		return 0, false
	}

	,  := .br.ReadByte()
	if  != nil {
		.readErr = 
		return 0, false
	}

	// delay the newline handling until the next token is delivered,
	// fixes off-by-one errors when reporting a parse error.
	if .eol {
		.line++
		.column = 0
		.eol = false
	}

	if  == '\n' {
		.eol = true
	} else {
		.column++
	}

	return , true
}

func ( *klexer) () (lex, bool) {
	var (
		 lex

		 strings.Builder

		 bool
	)

	for ,  := .readByte(); ; ,  = .readByte() {
		.line, .column = .line, .column

		switch  {
		case ':':
			if  || !.key {
				break
			}

			.key = false

			// Next token is a space, eat it
			.readByte()

			.value = zKey
			.token = .String()
			return , true
		case ';':
			 = true
		case '\n':
			if  {
				// Reset a comment
				 = false
			}

			if .key && .Len() == 0 {
				// ignore empty lines
				break
			}

			.key = true

			.value = zValue
			.token = .String()
			return , true
		default:
			if  {
				break
			}

			.WriteByte()
		}
	}

	if .readErr != nil && .readErr != io.EOF {
		// Don't return any tokens after a read error occurs.
		return lex{value: zEOF}, false
	}

	if .Len() > 0 {
		// Send remainder
		.value = zValue
		.token = .String()
		return , true
	}

	return lex{value: zEOF}, false
}