1
0
Fork 0
mirror of https://github.com/SamTherapy/dnscrypt.git synced 2024-07-05 06:46:07 +00:00
dnscrypt/generate.go
2020-10-19 17:20:49 +03:00

168 lines
4.6 KiB
Go

package dnscrypt
import (
"crypto/ed25519"
"crypto/rand"
"encoding/hex"
"strings"
"time"
"github.com/AdguardTeam/golibs/log"
"github.com/ameshkov/dnsstamps"
"golang.org/x/crypto/curve25519"
)
const dnsCryptV2Prefix = "2.dnscrypt-cert."
// ResolverConfig - DNSCrypt resolver configuration
type ResolverConfig struct {
// DNSCrypt provider name
ProviderName string `yaml:"provider_name"`
// PublicKey - DNSCrypt resolver public key
PublicKey string `yaml:"public_key"`
// PrivateKey - DNSCrypt resolver private key
// The main and only purpose of this key is to sign the certificate
PrivateKey string `yaml:"private_key"`
// ResolverSk - hex-encoded short-term private key.
// This key is used to encrypt/decrypt DNS queries.
// If not set, we'll generate a new random ResolverSk and ResolverPk.
ResolverSk string `yaml:"resolver_secret"`
// ResolverSk - hex-encoded short-term public key corresponding to ResolverSk.
// This key is used to encrypt/decrypt DNS queries.
ResolverPk string `yaml:"resolver_public"`
// EsVersion - crypto to use in this resolver
EsVersion CryptoConstruction `yaml:"es_version"`
// CertificateTTL - time-to-live for the certificate that is generated using this ResolverConfig.
// If not set, we'll use 1 year by default.
CertificateTTL time.Duration `yaml:"certificate_ttl"`
}
// CreateCert - generates a signed Cert to be used by Server
func (rc *ResolverConfig) CreateCert() (*Cert, error) {
log.Printf("Creating signed DNSCrypt certificate")
notAfter := time.Now()
if rc.CertificateTTL > 0 {
notAfter = notAfter.Add(rc.CertificateTTL)
} else {
// Default cert validity is 1 year
notAfter = notAfter.Add(time.Hour * 24 * 365)
}
cert := &Cert{
Serial: uint32(time.Now().Unix()),
NotAfter: uint32(notAfter.Unix()),
NotBefore: uint32(time.Now().Unix()),
EsVersion: rc.EsVersion,
}
// short-term public key
resolverPk, err := HexDecodeKey(rc.ResolverPk)
if err != nil {
return nil, err
}
// short-term private key
resolverSk, err := HexDecodeKey(rc.ResolverSk)
if err != nil {
return nil, err
}
if len(resolverPk) != keySize || len(resolverSk) != keySize {
log.Printf("Short-term keys are not set, generating random ones")
sk, pk := generateRandomKeyPair()
resolverSk = sk[:]
resolverPk = pk[:]
}
copy(cert.ResolverPk[:], resolverPk[:])
copy(cert.ResolverSk[:], resolverSk)
// private key
privateKey, err := HexDecodeKey(rc.PrivateKey)
if err != nil {
return nil, err
}
// sign the data
cert.Sign(privateKey)
log.Info("Signed cert: %s", cert.String())
// done
return cert, nil
}
// CreateStamp - generates a DNS stamp for this resolver
func (rc *ResolverConfig) CreateStamp(addr string) (dnsstamps.ServerStamp, error) {
stamp := dnsstamps.ServerStamp{
ProviderName: rc.ProviderName,
Proto: dnsstamps.StampProtoTypeDNSCrypt,
}
serverPk, err := HexDecodeKey(rc.PublicKey)
if err != nil {
return stamp, err
}
stamp.ServerPk = serverPk
stamp.ServerAddrStr = addr
return stamp, nil
}
// GenerateResolverConfig - generates resolver configuration for a given provider name.
// providerName is mandatory. If needed, "2.dnscrypt-cert." prefix is added to it.
// privateKey is optional. If not set, it will be generated automatically.
func GenerateResolverConfig(providerName string, privateKey ed25519.PrivateKey) (ResolverConfig, error) {
rc := ResolverConfig{
// Use XSalsa20Poly1305 by default
EsVersion: XSalsa20Poly1305,
}
if !strings.HasPrefix(providerName, dnsCryptV2Prefix) {
providerName = dnsCryptV2Prefix + providerName
}
rc.ProviderName = providerName
var err error
if privateKey == nil {
// privateKey = gene
_, privateKey, err = ed25519.GenerateKey(rand.Reader)
if err != nil {
return rc, err
}
}
rc.PrivateKey = HexEncodeKey(privateKey)
rc.PublicKey = HexEncodeKey(privateKey.Public().(ed25519.PublicKey))
resolverSk, resolverPk := generateRandomKeyPair()
rc.ResolverSk = HexEncodeKey(resolverSk[:])
rc.ResolverPk = HexEncodeKey(resolverPk[:])
return rc, nil
}
// HexEncodeKey - encodes a byte slice to a hex-encoded string.
func HexEncodeKey(b []byte) string {
return strings.ToUpper(hex.EncodeToString(b))
}
// HexDecodeKey - decodes a hex-encoded string with (optional) colons
// to a byte array.
func HexDecodeKey(str string) ([]byte, error) {
return hex.DecodeString(strings.ReplaceAll(str, ":", ""))
}
// generateRandomKeyPair - generates a random key-pair
func generateRandomKeyPair() (privateKey [keySize]byte, publicKey [keySize]byte) {
privateKey = [keySize]byte{}
publicKey = [keySize]byte{}
_, _ = rand.Read(privateKey[:])
curve25519.ScalarBaseMult(&publicKey, &privateKey)
return
}