mirror of
				https://github.com/miekg/dns.git
				synced 2025-11-03 20:21:24 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			211 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package dns
 | 
						|
 | 
						|
import (
 | 
						|
	"os"
 | 
						|
	"io"
 | 
						|
	"big"
 | 
						|
	"strconv"
 | 
						|
	"crypto/rsa"
 | 
						|
	"crypto/ecdsa"
 | 
						|
	"crypto/elliptic"
 | 
						|
	"crypto/rand"
 | 
						|
)
 | 
						|
 | 
						|
// Empty interface that is used as a wrapper around all possible
 | 
						|
// private key implementations from the crypto package.
 | 
						|
type PrivateKey interface{}
 | 
						|
 | 
						|
// Generate generates a DNSKEY of the given bit size.
 | 
						|
// The public part is put inside the DNSKEY record. 
 | 
						|
// The Algorithm in the key must be set as this will define
 | 
						|
// what kind of DNSKEY will be generated.
 | 
						|
// The ECDSA algorithms imply a fixed keysize, in that case
 | 
						|
// bits should be set to the size of the algorithm.
 | 
						|
func (r *RR_DNSKEY) Generate(bits int) (PrivateKey, os.Error) {
 | 
						|
	switch r.Algorithm {
 | 
						|
        case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
 | 
						|
		if bits < 512 || bits > 4096 {
 | 
						|
			return nil, ErrKeySize
 | 
						|
		}
 | 
						|
	case RSASHA512:
 | 
						|
		if bits < 1024 || bits > 4096 {
 | 
						|
			return nil, ErrKeySize
 | 
						|
		}
 | 
						|
	case ECDSAP256SHA256:
 | 
						|
		if bits != 256 {
 | 
						|
			return nil, ErrKeySize
 | 
						|
		}
 | 
						|
	case ECDSAP384SHA384:
 | 
						|
		if bits != 384 {
 | 
						|
			return nil, ErrKeySize
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	switch r.Algorithm {
 | 
						|
        case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
 | 
						|
		priv, err := rsa.GenerateKey(rand.Reader, bits)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		r.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
 | 
						|
		return priv, nil
 | 
						|
	case ECDSAP256SHA256, ECDSAP384SHA384:
 | 
						|
		var c *elliptic.Curve
 | 
						|
		switch r.Algorithm {
 | 
						|
		case ECDSAP256SHA256:
 | 
						|
			c = elliptic.P256()
 | 
						|
		case ECDSAP384SHA384:
 | 
						|
			c = elliptic.P384()
 | 
						|
		}
 | 
						|
		priv, err := ecdsa.GenerateKey(c, rand.Reader)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		r.setPublicKeyCurve(priv.PublicKey.X, priv.PublicKey.Y)
 | 
						|
		return priv, nil
 | 
						|
	default:
 | 
						|
		return nil, ErrAlg
 | 
						|
	}
 | 
						|
	return nil, nil // Dummy return
 | 
						|
}
 | 
						|
 | 
						|
// Convert a PrivateKey to a string. This
 | 
						|
// string has the same format as the private-key-file of BIND9 (Private-key-format: v1.3). 
 | 
						|
// It needs some info from the key (hashing, keytag), so its a method of the RR_DNSKEY.
 | 
						|
func (r *RR_DNSKEY) PrivateKeyString(p PrivateKey) (s string) {
 | 
						|
	switch t := p.(type) {
 | 
						|
	case *rsa.PrivateKey:
 | 
						|
		algorithm := strconv.Itoa(int(r.Algorithm)) + " (" + alg_str[r.Algorithm] + ")"
 | 
						|
		modulus := unpackBase64(t.PublicKey.N.Bytes())
 | 
						|
		e := big.NewInt(int64(t.PublicKey.E))
 | 
						|
		publicExponent := unpackBase64(e.Bytes())
 | 
						|
		privateExponent := unpackBase64(t.D.Bytes())
 | 
						|
		prime1 := unpackBase64(t.Primes[0].Bytes())
 | 
						|
		prime2 := unpackBase64(t.Primes[1].Bytes())
 | 
						|
		// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
 | 
						|
		// and from: http://code.google.com/p/go/issues/detail?id=987
 | 
						|
		one := big.NewInt(1)
 | 
						|
		minusone := big.NewInt(-1)
 | 
						|
		p_1 := big.NewInt(0).Sub(t.Primes[0], one)
 | 
						|
		q_1 := big.NewInt(0).Sub(t.Primes[1], one)
 | 
						|
		exp1 := big.NewInt(0).Mod(t.D, p_1)
 | 
						|
		exp2 := big.NewInt(0).Mod(t.D, q_1)
 | 
						|
		coeff := big.NewInt(0).Exp(t.Primes[1], minusone, t.Primes[0])
 | 
						|
 | 
						|
		exponent1 := unpackBase64(exp1.Bytes())
 | 
						|
		exponent2 := unpackBase64(exp2.Bytes())
 | 
						|
		coefficient := unpackBase64(coeff.Bytes())
 | 
						|
 | 
						|
		s = "Private-key-format: v1.3\n" +
 | 
						|
			"Algorithm: " + algorithm + "\n" +
 | 
						|
			"Modules: " + modulus + "\n" +
 | 
						|
			"PublicExponent: " + publicExponent + "\n" +
 | 
						|
			"PrivateExponent: " + privateExponent + "\n" +
 | 
						|
			"Prime1: " + prime1 + "\n" +
 | 
						|
			"Prime2: " + prime2 + "\n" +
 | 
						|
			"Exponent1: " + exponent1 + "\n" +
 | 
						|
			"Exponent2: " + exponent2 + "\n" +
 | 
						|
			"Coefficient: " + coefficient + "\n"
 | 
						|
	case *ecdsa.PrivateKey:
 | 
						|
		//
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Read reads a DNSKEY from the io.Reader q.
 | 
						|
func (k *RR_DNSKEY) Read(q io.Reader) os.Error {
 | 
						|
	p := NewParser(q)
 | 
						|
	r, err := p.First()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if _, ok := r.(*RR_DNSKEY); !ok {
 | 
						|
		return ErrKey
 | 
						|
	}
 | 
						|
	k.Hdr = r.(*RR_DNSKEY).Hdr
 | 
						|
	k.Flags = r.(*RR_DNSKEY).Flags
 | 
						|
	k.Protocol = r.(*RR_DNSKEY).Protocol
 | 
						|
	k.Algorithm = r.(*RR_DNSKEY).Algorithm
 | 
						|
	k.PublicKey = r.(*RR_DNSKEY).PublicKey
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// ReadPrivateKey reads a private key from the io.Reader q.
 | 
						|
func (k *RR_DNSKEY) ReadPrivateKey(q io.Reader) (PrivateKey, os.Error) {
 | 
						|
	p := NewParser(q)
 | 
						|
	kv, _ := p.PrivateKey()
 | 
						|
        if kv == nil {
 | 
						|
                return nil, ErrPrivKey
 | 
						|
        }
 | 
						|
	if _, ok := kv["private-key-format"]; !ok {
 | 
						|
		return nil, ErrPrivKey
 | 
						|
	}
 | 
						|
	if kv["private-key-format"] != "v1.2" && kv["private-key-format"] != "v1.3" {
 | 
						|
		return nil, ErrPrivKey
 | 
						|
	}
 | 
						|
	switch kv["algorithm"] {
 | 
						|
	case "RSAMD5", "RSASHA1", "RSASHA256", "RSASHA512":
 | 
						|
		return k.readPrivateKeyRSA(kv)
 | 
						|
	case "ECDSAP256SHA256", "ECDSAP384SHA384":
 | 
						|
		return k.readPrivateKeyECDSA(kv)
 | 
						|
	}
 | 
						|
	return nil, ErrPrivKey
 | 
						|
}
 | 
						|
 | 
						|
// Read a private key (file) string and create a public key. Return the private key.
 | 
						|
func (k *RR_DNSKEY) readPrivateKeyRSA(kv map[string]string) (PrivateKey, os.Error) {
 | 
						|
	p := new(rsa.PrivateKey)
 | 
						|
	p.Primes = []*big.Int{nil, nil}
 | 
						|
	for k, v := range kv {
 | 
						|
		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 (k *RR_DNSKEY) readPrivateKeyECDSA(kv map[string]string) (PrivateKey, os.Error) {
 | 
						|
	p := new(ecdsa.PrivateKey)
 | 
						|
	p.D = big.NewInt(0)
 | 
						|
	// Need to check if we have everything
 | 
						|
	for k, v := range kv {
 | 
						|
		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
 | 
						|
}
 |