URI: 
       tRename lib to damlib and separate functions into more files - tordam - A library for peer discovery inside the Tor network
  HTML git clone https://git.parazyd.org/tordam
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 0ebc557267e12c3544b0833c6c98a2ea335a58fb
   DIR parent 2e02e951df8b4bb89560d1fdc0116d9231290d63
  HTML Author: parazyd <parazyd@dyne.org>
       Date:   Sun, 10 Dec 2017 17:02:45 +0100
       
       Rename lib to damlib and separate functions into more files
       
       Diffstat:
         M cmd/dam-client/main.go              |       2 +-
         M cmd/dam-dir/main.go                 |       2 +-
         A pkg/damlib/crypto.go                |     218 +++++++++++++++++++++++++++++++
         A pkg/damlib/helpers.go               |      15 +++++++++++++++
         A pkg/damlib/net.go                   |      55 +++++++++++++++++++++++++++++++
         A pkg/damlib/tor.go                   |      32 +++++++++++++++++++++++++++++++
         A pkg/damlib/validate.go              |      73 +++++++++++++++++++++++++++++++
         D pkg/lib/crypto.go                   |     197 -------------------------------
         D pkg/lib/helpers.go                  |     172 ------------------------------
       
       9 files changed, 395 insertions(+), 371 deletions(-)
       ---
   DIR diff --git a/cmd/dam-client/main.go b/cmd/dam-client/main.go
       t@@ -13,7 +13,7 @@ import (
                "sync"
                "time"
        
       -        "github.com/parazyd/tor-dam/pkg/lib"
       +        lib "github.com/parazyd/tor-dam/pkg/damlib"
        )
        
        // Cwd holds the path to the directory where we will Chdir on startup.
   DIR diff --git a/cmd/dam-dir/main.go b/cmd/dam-dir/main.go
       t@@ -13,7 +13,7 @@ import (
                "time"
        
                "github.com/go-redis/redis"
       -        "github.com/parazyd/tor-dam/pkg/lib"
       +        lib "github.com/parazyd/tor-dam/pkg/damlib"
        )
        
        // Cwd holds the path to the directory where we will Chdir on startup.
   DIR diff --git a/pkg/damlib/crypto.go b/pkg/damlib/crypto.go
       t@@ -0,0 +1,218 @@
       +package damlib
       +
       +// See LICENSE file for copyright and license details.
       +
       +import (
       +        "crypto"
       +        "crypto/rand"
       +        "crypto/rsa"
       +        "crypto/sha1"
       +        "crypto/sha512"
       +        "crypto/x509"
       +        "encoding/asn1"
       +        "encoding/base32"
       +        "encoding/pem"
       +        "errors"
       +        "io/ioutil"
       +        "log"
       +        "math/big"
       +        "os"
       +        "strings"
       +)
       +
       +// GenRsa generates a private RSA keypair of a given bitSize int and returns it
       +// as rsa.PrivateKey.
       +func GenRsa(bitSize int) (*rsa.PrivateKey, error) {
       +        log.Printf("Generating %d-bit RSA keypair...\n", bitSize)
       +        rng := rand.Reader
       +        key, err := rsa.GenerateKey(rng, bitSize)
       +        if err != nil {
       +                return nil, err
       +        }
       +        return key, nil
       +}
       +
       +// SavePubRsa saves a given RSA public key to a given filename.
       +// SavePubRsa takes the filename to write as a string, and the key as
       +// rsa.PublicKey. It returns a boolean value and an error, depending on whether
       +// it has failed or not.
       +func SavePubRsa(filename string, pubkey rsa.PublicKey) (bool, error) {
       +        log.Printf("Writing pubkey to %s\n", filename)
       +        // FIXME: worry or not about creating the path if it doesn't exist?
       +        outfile, err := os.Create(filename)
       +        defer outfile.Close()
       +        if err != nil {
       +                return false, err
       +        }
       +        asn1Bytes, err := asn1.Marshal(pubkey)
       +        if err != nil {
       +                return false, err
       +        }
       +        var pemkey = &pem.Block{
       +                Type:  "RSA PUBLIC KEY",
       +                Bytes: asn1Bytes,
       +        }
       +        err = pem.Encode(outfile, pemkey)
       +        if err != nil {
       +                return false, err
       +        }
       +        err = outfile.Chmod(0400)
       +        if err != nil {
       +                return false, err
       +        }
       +        return true, nil
       +}
       +
       +// SavePrivRsa saves a given RSA private key to a given filename.
       +// SavePrivRsa takes the filename to write as a string, and the key as
       +// *rsa.PrivateKey. It returns a boolean value and an error, depending on whether
       +// it has failed or not.
       +func SavePrivRsa(filename string, privkey *rsa.PrivateKey) (bool, error) {
       +        log.Printf("Writing private key to %s\n", filename)
       +        // FIXME: worry or not about creating the path if it doesn't exist?
       +        outfile, err := os.Create(filename)
       +        defer outfile.Close()
       +        if err != nil {
       +                return false, err
       +        }
       +        var pemkey = &pem.Block{
       +                Type:  "RSA PRIVATE KEY",
       +                Bytes: x509.MarshalPKCS1PrivateKey(privkey),
       +        }
       +        err = pem.Encode(outfile, pemkey)
       +        if err != nil {
       +                return false, err
       +        }
       +        err = outfile.Chmod(0400)
       +        if err != nil {
       +                return false, err
       +        }
       +        return true, nil
       +}
       +
       +// LoadRsaKeyFromFile loads a RSA private key from a given filename.
       +// LoadRsaKeyFromFile takes a string filename and tries to read from it, parsing
       +// the private RSA key. It will return a *rsa.PrivateKey on success, and error
       +// on fail.
       +func LoadRsaKeyFromFile(filename string) (*rsa.PrivateKey, error) {
       +        log.Println("Loading RSA private key from", filename)
       +        dat, err := ioutil.ReadFile(filename)
       +        if err != nil {
       +                return nil, err
       +        }
       +        block, _ := pem.Decode(dat)
       +        if block == nil {
       +                return nil, errors.New("failed to parse PEM block containing the key")
       +        }
       +        priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
       +        if err != nil {
       +                return nil, err
       +        }
       +        return priv, nil
       +}
       +
       +// SignMsgRsa signs a given []byte message using a given RSA private key.
       +// It will return the signature as a slice of bytes on success, and error on
       +// failure.
       +func SignMsgRsa(message []byte, privkey *rsa.PrivateKey) ([]byte, error) {
       +        log.Println("Signing message...")
       +        rng := rand.Reader
       +        hashed := sha512.Sum512(message)
       +        sig, err := rsa.SignPKCS1v15(rng, privkey, crypto.SHA512, hashed[:])
       +        if err != nil {
       +                return nil, err
       +        }
       +        return sig, nil
       +}
       +
       +// EncryptMsgRsa encrypts a given []byte message using a given RSA public key.
       +// Returns the encrypted message as a slice of bytes on success, and error on
       +// failure.
       +func EncryptMsgRsa(message []byte, pubkey *rsa.PublicKey) ([]byte, error) {
       +        log.Println("Encrypting message...")
       +        rng := rand.Reader
       +        msg, err := rsa.EncryptPKCS1v15(rng, pubkey, message)
       +        if err != nil {
       +                return nil, err
       +        }
       +        return msg, nil
       +}
       +
       +// DecryptMsgRsa decrypts a given []byte message using a given RSA private key.
       +// Returns the decrypted message as a slice of bytes on success, and error on
       +// failure.
       +func DecryptMsgRsa(message []byte, privkey *rsa.PrivateKey) ([]byte, error) {
       +        log.Println("Decrypting message...")
       +        rng := rand.Reader
       +        msg, err := rsa.DecryptPKCS1v15(rng, privkey, message)
       +        if err != nil {
       +                return nil, err
       +        }
       +        return msg, nil
       +}
       +
       +// VerifyMsgRsa verifies a message and signature against a given RSA pubkey.
       +// Returns a boolean value and error depending on whether it has failed or not.
       +func VerifyMsgRsa(message []byte, signature []byte, pubkey *rsa.PublicKey) (bool, error) {
       +        log.Println("Verifying message signature")
       +        hashed := sha512.Sum512(message)
       +        err := rsa.VerifyPKCS1v15(pubkey, crypto.SHA512, hashed[:], signature)
       +        if err != nil {
       +                return false, err
       +        }
       +        log.Println("Signature valid")
       +        return true, nil
       +}
       +
       +// OnionFromPubkeyRsa generates a valid onion address from a given RSA pubkey.
       +// Returns the onion address as a slice of bytes on success and error on
       +// failure.
       +func OnionFromPubkeyRsa(pubkey rsa.PublicKey) ([]byte, error) {
       +        asn1Bytes, err := asn1.Marshal(pubkey)
       +        if err != nil {
       +                return nil, err
       +        }
       +        hashed := sha1.New()
       +        _, err = hashed.Write(asn1Bytes)
       +        if err != nil {
       +                return nil, err
       +        }
       +        encoded := strings.ToLower(base32.StdEncoding.EncodeToString(hashed.Sum(nil)))[:16]
       +        encoded += ".onion"
       +
       +        return []byte(encoded), nil
       +}
       +
       +// ParsePubkeyRsa parses a []byte form of a RSA public key and returns it as
       +// *rsa.PublicKey on success. Otherwise, error.
       +func ParsePubkeyRsa(pubkey []byte) (*rsa.PublicKey, error) {
       +        var pub rsa.PublicKey
       +        var ret *rsa.PublicKey
       +        block, _ := pem.Decode(pubkey)
       +        _, err := asn1.Unmarshal(block.Bytes, &pub)
       +        if err != nil {
       +                return nil, err
       +        }
       +        ret = &pub
       +        return ret, nil
       +}
       +
       +// GenRandomASCII generates a random ASCII string of a given length.
       +// Takes length int as argument, and returns a string of that length on success
       +// and error on failure.
       +func GenRandomASCII(length int) (string, error) {
       +        var res string
       +        for {
       +                if len(res) >= length {
       +                        return res, nil
       +                }
       +                num, err := rand.Int(rand.Reader, big.NewInt(int64(127)))
       +                if err != nil {
       +                        return "", err
       +                }
       +                n := num.Int64()
       +                if n > 32 && n < 127 {
       +                        res += string(n)
       +                }
       +        }
       +}
   DIR diff --git a/pkg/damlib/helpers.go b/pkg/damlib/helpers.go
       t@@ -0,0 +1,15 @@
       +package damlib
       +
       +// See LICENSE file for copyright and license details.
       +
       +import (
       +        "log"
       +)
       +
       +// CheckError is a handler for errors. It takes an error type as an argument,
       +// and issues a log.Fatalln, printing the error and exiting with os.Exit(1).
       +func CheckError(err error) {
       +        if err != nil {
       +                log.Fatalln(err)
       +        }
       +}
   DIR diff --git a/pkg/damlib/net.go b/pkg/damlib/net.go
       t@@ -0,0 +1,55 @@
       +package damlib
       +
       +// See LICENSE file for copyright and license details.
       +
       +import (
       +        "bytes"
       +        "log"
       +        "net/http"
       +        "net/url"
       +        "strings"
       +
       +        "golang.org/x/net/proxy"
       +)
       +
       +// ProxyAddr is the address of our Tor SOCKS port.
       +const ProxyAddr = "127.0.0.1:9050"
       +
       +// HTTPPost sends an HTTP POST request to the given host.
       +// Takes the host to request and the data to post as arguments.
       +// If the host ends with ".onion", it will enable the request to be performed
       +// over a SOCKS proxy, defined in ProxyAddr.
       +// On success, it will return the http.Response. Otherwise, it returns an error.
       +func HTTPPost(host string, data []byte) (*http.Response, error) {
       +        socksify := false
       +        parsedHost, err := url.Parse(host)
       +        if err != nil {
       +                return nil, err
       +        }
       +        hostname := parsedHost.Hostname()
       +        if strings.HasSuffix(hostname, ".onion") {
       +                socksify = true
       +        }
       +        httpTransp := &http.Transport{}
       +        httpClient := &http.Client{Transport: httpTransp}
       +        if socksify {
       +                log.Println("Detected a .onion request. Using SOCKS proxy.")
       +                dialer, err := proxy.SOCKS5("tcp", ProxyAddr, nil, proxy.Direct)
       +                if err != nil {
       +                        return nil, err
       +                }
       +                httpTransp.Dial = dialer.Dial
       +        }
       +        request, err := http.NewRequest("POST", host, bytes.NewBuffer(data))
       +        if err != nil {
       +                return nil, err
       +        }
       +        request.Header.Set("Content-Type", "application/json")
       +
       +        resp, err := httpClient.Do(request)
       +        if err != nil {
       +                return nil, err
       +        }
       +
       +        return resp, nil
       +}
   DIR diff --git a/pkg/damlib/tor.go b/pkg/damlib/tor.go
       t@@ -0,0 +1,32 @@
       +package damlib
       +
       +// See LICENSE file for copyright and license details.
       +
       +import (
       +        "bytes"
       +        "log"
       +        "os/exec"
       +)
       +
       +// FetchHSPubkey fetches a hidden service's RSA pubkey by running an external
       +// program, giving it an onion address. It returns the retrieved public key as a
       +// string.
       +func FetchHSPubkey(addr string) string {
       +        var outb, errb bytes.Buffer
       +
       +        log.Println("Fetching pubkey for:", addr)
       +
       +        cmd := exec.Command("damauth.py", addr)
       +        cmd.Stdout = &outb
       +        cmd.Stderr = &errb
       +        err := cmd.Start()
       +        CheckError(err)
       +
       +        err = cmd.Wait()
       +        if err != nil {
       +                log.Println("Could not fetch descriptor:", err)
       +                return ""
       +        }
       +
       +        return outb.String()
       +}
   DIR diff --git a/pkg/damlib/validate.go b/pkg/damlib/validate.go
       t@@ -0,0 +1,73 @@
       +package damlib
       +
       +// See LICENSE file for copyright and license details.
       +
       +import (
       +        "log"
       +        "regexp"
       +        "strings"
       +        "time"
       +)
       +
       +// ValidateReq validates our given request against the logic we are checking.
       +// The function takes a request data map, and a public key in the form of a
       +// string. If the public key is an empty string, the function will run an
       +// external program to fetch the node's public key from a Tor HSDir.
       +//
       +// ValidateReq  will first validate "nodetype", looking whether the announcer
       +// is a node or a directory.
       +// Then, it will validate the onion address using a regular expression.
       +// Now, if pubkey is empty, it will run the external program to fetch it. If a
       +// descriptor can't be retrieved, it will retry for 10 times, and fail if those
       +// are not successful.
       +//
       +// Continuing, ValidateReq will verify the RSA signature posted by the
       +// announcer.
       +// If any of the above are invalid, the function will return nil and false.
       +// Otherwise, it will return the pubkey as a slice of bytes, and true.
       +func ValidateReq(req map[string]string, pubkey string) ([]byte, bool) {
       +        // Validate nodetype.
       +        if req["nodetype"] != "node" {
       +                return nil, false
       +        }
       +        // Validate address.
       +        re, err := regexp.Compile("^[a-z2-7]{16}\\.onion$")
       +        CheckError(err)
       +        if len(re.FindString(req["address"])) != 22 {
       +                return nil, false
       +        }
       +        log.Println(req["address"], "seems valid")
       +
       +        if len(pubkey) == 0 {
       +                // Address is valid, we try to fetch its pubkey from a HSDir
       +                cnt := 0
       +                for { // We try until we have it.
       +                        cnt++
       +                        if cnt > 10 {
       +                                // We probably can't get a good HSDir. The client shall retry
       +                                // later on.
       +                                return []byte("Couldn't get a descriptor. Try later."), false
       +                        }
       +                        pubkey = FetchHSPubkey(req["address"])
       +                        if strings.HasPrefix(pubkey, "-----BEGIN RSA PUBLIC KEY-----") &&
       +                                strings.HasSuffix(pubkey, "-----END RSA PUBLIC KEY-----") {
       +                                log.Println("Got descriptor!")
       +                                break
       +                        }
       +                        time.Sleep(2000 * time.Millisecond)
       +                }
       +        }
       +        // Validate signature.
       +        msg := []byte(req["message"])
       +        sig := []byte(req["signature"])
       +        pub, err := ParsePubkeyRsa([]byte(pubkey))
       +        CheckError(err)
       +
       +        val, err := VerifyMsgRsa(msg, sig, pub)
       +        CheckError(err)
       +        if val != true {
       +                return nil, false
       +        }
       +
       +        return []byte(pubkey), true
       +}
   DIR diff --git a/pkg/lib/crypto.go b/pkg/lib/crypto.go
       t@@ -1,197 +0,0 @@
       -package lib
       -
       -// See LICENSE file for copyright and license details.
       -
       -import (
       -        "crypto"
       -        "crypto/rand"
       -        "crypto/rsa"
       -        "crypto/sha1"
       -        "crypto/sha512"
       -        "crypto/x509"
       -        "encoding/asn1"
       -        "encoding/base32"
       -        "encoding/pem"
       -        "errors"
       -        "io/ioutil"
       -        "log"
       -        "os"
       -        "strings"
       -)
       -
       -// GenRsa generates a private RSA keypair of a given bitSize int and returns it
       -// as rsa.PrivateKey.
       -func GenRsa(bitSize int) (*rsa.PrivateKey, error) {
       -        log.Printf("Generating %d-bit RSA keypair...\n", bitSize)
       -        rng := rand.Reader
       -        key, err := rsa.GenerateKey(rng, bitSize)
       -        if err != nil {
       -                return nil, err
       -        }
       -        return key, nil
       -}
       -
       -// SavePubRsa saves a given RSA public key to a given filename.
       -// SavePubRsa takes the filename to write as a string, and the key as
       -// rsa.PublicKey. It returns a boolean value and an error, depending on whether
       -// it has failed or not.
       -func SavePubRsa(filename string, pubkey rsa.PublicKey) (bool, error) {
       -        log.Printf("Writing pubkey to %s\n", filename)
       -        // FIXME: worry or not about creating the path if it doesn't exist?
       -        outfile, err := os.Create(filename)
       -        defer outfile.Close()
       -        if err != nil {
       -                return false, err
       -        }
       -        asn1Bytes, err := asn1.Marshal(pubkey)
       -        if err != nil {
       -                return false, err
       -        }
       -        var pemkey = &pem.Block{
       -                Type:  "RSA PUBLIC KEY",
       -                Bytes: asn1Bytes,
       -        }
       -        err = pem.Encode(outfile, pemkey)
       -        if err != nil {
       -                return false, err
       -        }
       -        err = outfile.Chmod(0400)
       -        if err != nil {
       -                return false, err
       -        }
       -        return true, nil
       -}
       -
       -// SavePrivRsa saves a given RSA private key to a given filename.
       -// SavePrivRsa takes the filename to write as a string, and the key as
       -// *rsa.PrivateKey. It returns a boolean value and an error, depending on whether
       -// it has failed or not.
       -func SavePrivRsa(filename string, privkey *rsa.PrivateKey) (bool, error) {
       -        log.Printf("Writing private key to %s\n", filename)
       -        // FIXME: worry or not about creating the path if it doesn't exist?
       -        outfile, err := os.Create(filename)
       -        defer outfile.Close()
       -        if err != nil {
       -                return false, err
       -        }
       -        var pemkey = &pem.Block{
       -                Type:  "RSA PRIVATE KEY",
       -                Bytes: x509.MarshalPKCS1PrivateKey(privkey),
       -        }
       -        err = pem.Encode(outfile, pemkey)
       -        if err != nil {
       -                return false, err
       -        }
       -        err = outfile.Chmod(0400)
       -        if err != nil {
       -                return false, err
       -        }
       -        return true, nil
       -}
       -
       -// LoadRsaKeyFromFile loads a RSA private key from a given filename.
       -// LoadRsaKeyFromFile takes a string filename and tries to read from it, parsing
       -// the private RSA key. It will return a *rsa.PrivateKey on success, and error
       -// on fail.
       -func LoadRsaKeyFromFile(filename string) (*rsa.PrivateKey, error) {
       -        log.Println("Loading RSA private key from", filename)
       -        dat, err := ioutil.ReadFile(filename)
       -        if err != nil {
       -                return nil, err
       -        }
       -        block, _ := pem.Decode(dat)
       -        if block == nil {
       -                return nil, errors.New("failed to parse PEM block containing the key")
       -        }
       -        priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
       -        if err != nil {
       -                return nil, err
       -        }
       -        return priv, nil
       -}
       -
       -// SignMsgRsa signs a given []byte message using a given RSA private key.
       -// It will return the signature as a slice of bytes on success, and error on
       -// failure.
       -func SignMsgRsa(message []byte, privkey *rsa.PrivateKey) ([]byte, error) {
       -        log.Println("Signing message...")
       -        rng := rand.Reader
       -        hashed := sha512.Sum512(message)
       -        sig, err := rsa.SignPKCS1v15(rng, privkey, crypto.SHA512, hashed[:])
       -        if err != nil {
       -                return nil, err
       -        }
       -        return sig, nil
       -}
       -
       -// EncryptMsgRsa encrypts a given []byte message using a given RSA public key.
       -// Returns the encrypted message as a slice of bytes on success, and error on
       -// failure.
       -func EncryptMsgRsa(message []byte, pubkey *rsa.PublicKey) ([]byte, error) {
       -        log.Println("Encrypting message...")
       -        rng := rand.Reader
       -        msg, err := rsa.EncryptPKCS1v15(rng, pubkey, message)
       -        if err != nil {
       -                return nil, err
       -        }
       -        return msg, nil
       -}
       -
       -// DecryptMsgRsa decrypts a given []byte message using a given RSA private key.
       -// Returns the decrypted message as a slice of bytes on success, and error on
       -// failure.
       -func DecryptMsgRsa(message []byte, privkey *rsa.PrivateKey) ([]byte, error) {
       -        log.Println("Decrypting message...")
       -        rng := rand.Reader
       -        msg, err := rsa.DecryptPKCS1v15(rng, privkey, message)
       -        if err != nil {
       -                return nil, err
       -        }
       -        return msg, nil
       -}
       -
       -// VerifyMsgRsa verifies a message and signature against a given RSA pubkey.
       -// Returns a boolean value and error depending on whether it has failed or not.
       -func VerifyMsgRsa(message []byte, signature []byte, pubkey *rsa.PublicKey) (bool, error) {
       -        log.Println("Verifying message signature")
       -        hashed := sha512.Sum512(message)
       -        err := rsa.VerifyPKCS1v15(pubkey, crypto.SHA512, hashed[:], signature)
       -        if err != nil {
       -                return false, err
       -        }
       -        log.Println("Signature valid")
       -        return true, nil
       -}
       -
       -// OnionFromPubkeyRsa generates a valid onion address from a given RSA pubkey.
       -// Returns the onion address as a slice of bytes on success and error on
       -// failure.
       -func OnionFromPubkeyRsa(pubkey rsa.PublicKey) ([]byte, error) {
       -        asn1Bytes, err := asn1.Marshal(pubkey)
       -        if err != nil {
       -                return nil, err
       -        }
       -        hashed := sha1.New()
       -        _, err = hashed.Write(asn1Bytes)
       -        if err != nil {
       -                return nil, err
       -        }
       -        encoded := strings.ToLower(base32.StdEncoding.EncodeToString(hashed.Sum(nil)))[:16]
       -        encoded += ".onion"
       -
       -        return []byte(encoded), nil
       -}
       -
       -// ParsePubkeyRsa parses a []byte form of a RSA public key and returns it as
       -// *rsa.PublicKey on success. Otherwise, error.
       -func ParsePubkeyRsa(pubkey []byte) (*rsa.PublicKey, error) {
       -        var pub rsa.PublicKey
       -        var ret *rsa.PublicKey
       -        block, _ := pem.Decode(pubkey)
       -        _, err := asn1.Unmarshal(block.Bytes, &pub)
       -        if err != nil {
       -                return nil, err
       -        }
       -        ret = &pub
       -        return ret, nil
       -}
   DIR diff --git a/pkg/lib/helpers.go b/pkg/lib/helpers.go
       t@@ -1,172 +0,0 @@
       -package lib
       -
       -// See LICENSE file for copyright and license details.
       -
       -import (
       -        "bytes"
       -        "crypto/rand"
       -        "log"
       -        "math/big"
       -        "net/http"
       -        "net/url"
       -        "os/exec"
       -        "regexp"
       -        "strings"
       -        "time"
       -
       -        "golang.org/x/net/proxy"
       -)
       -
       -// ProxyAddr is the address of our Tor SOCKS port.
       -const ProxyAddr = "127.0.0.1:9050"
       -
       -// CheckError is a handler for errors. It takes an error type as an argument,
       -// and issues a log.Fatalln, printing the error and exiting with os.Exit(1).
       -func CheckError(err error) {
       -        if err != nil {
       -                log.Fatalln(err)
       -        }
       -}
       -
       -// FetchHSPubkey fetches a hidden service's RSA pubkey by running an external
       -// program, giving it an onion address. It returns the retrieved public key as a
       -// string.
       -func FetchHSPubkey(addr string) string {
       -        var outb, errb bytes.Buffer
       -
       -        log.Println("Fetching pubkey for:", addr)
       -
       -        cmd := exec.Command("damauth.py", addr)
       -        cmd.Stdout = &outb
       -        cmd.Stderr = &errb
       -        err := cmd.Start()
       -        CheckError(err)
       -
       -        err = cmd.Wait()
       -        if err != nil {
       -                log.Println("Could not fetch descriptor:", err)
       -                return ""
       -        }
       -
       -        return outb.String()
       -}
       -
       -// ValidateReq validates our given request against the logic we are checking.
       -// The function takes a request data map, and a public key in the form of a
       -// string. If the public key is an empty string, the function will run an
       -// external program to fetch the node's public key from a Tor HSDir.
       -//
       -// ValidateReq  will first validate "nodetype", looking whether the announcer
       -// is a node or a directory.
       -// Then, it will validate the onion address using a regular expression.
       -// Now, if pubkey is empty, it will run the external program to fetch it. If a
       -// descriptor can't be retrieved, it will retry for 10 times, and fail if those
       -// are not successful.
       -//
       -// Continuing, ValidateReq will verify the RSA signature posted by the
       -// announcer.
       -// If any of the above are invalid, the function will return nil and false.
       -// Otherwise, it will return the pubkey as a slice of bytes, and true.
       -func ValidateReq(req map[string]string, pubkey string) ([]byte, bool) {
       -        // Validate nodetype.
       -        if req["nodetype"] != "node" {
       -                return nil, false
       -        }
       -        // Validate address.
       -        re, err := regexp.Compile("^[a-z2-7]{16}\\.onion$")
       -        CheckError(err)
       -        if len(re.FindString(req["address"])) != 22 {
       -                return nil, false
       -        }
       -        log.Println(req["address"], "seems valid")
       -
       -        if len(pubkey) == 0 {
       -                // Address is valid, we try to fetch its pubkey from a HSDir
       -                cnt := 0
       -                for { // We try until we have it.
       -                        cnt++
       -                        if cnt > 10 {
       -                                // We probably can't get a good HSDir. The client shall retry
       -                                // later on.
       -                                return []byte("Couldn't get a descriptor. Try later."), false
       -                        }
       -                        pubkey = FetchHSPubkey(req["address"])
       -                        if strings.HasPrefix(pubkey, "-----BEGIN RSA PUBLIC KEY-----") &&
       -                                strings.HasSuffix(pubkey, "-----END RSA PUBLIC KEY-----") {
       -                                log.Println("Got descriptor!")
       -                                break
       -                        }
       -                        time.Sleep(2000 * time.Millisecond)
       -                }
       -        }
       -        // Validate signature.
       -        msg := []byte(req["message"])
       -        sig := []byte(req["signature"])
       -        pub, err := ParsePubkeyRsa([]byte(pubkey))
       -        CheckError(err)
       -
       -        val, err := VerifyMsgRsa(msg, sig, pub)
       -        CheckError(err)
       -        if val != true {
       -                return nil, false
       -        }
       -
       -        return []byte(pubkey), true
       -}
       -
       -// HTTPPost sends an HTTP POST request to the given host.
       -// Takes the host to request and the data to post as arguments.
       -// If the host ends with ".onion", it will enable the request to be performed
       -// over a SOCKS proxy, defined in ProxyAddr.
       -// On success, it will return the http.Response. Otherwise, it returns an error.
       -func HTTPPost(host string, data []byte) (*http.Response, error) {
       -        socksify := false
       -        parsedHost, err := url.Parse(host)
       -        if err != nil {
       -                return nil, err
       -        }
       -        hostname := parsedHost.Hostname()
       -        if strings.HasSuffix(hostname, ".onion") {
       -                socksify = true
       -        }
       -        httpTransp := &http.Transport{}
       -        httpClient := &http.Client{Transport: httpTransp}
       -        if socksify {
       -                log.Println("Detected a .onion request. Using SOCKS proxy.")
       -                dialer, err := proxy.SOCKS5("tcp", ProxyAddr, nil, proxy.Direct)
       -                if err != nil {
       -                        return nil, err
       -                }
       -                httpTransp.Dial = dialer.Dial
       -        }
       -        request, err := http.NewRequest("POST", host, bytes.NewBuffer(data))
       -        if err != nil {
       -                return nil, err
       -        }
       -        request.Header.Set("Content-Type", "application/json")
       -
       -        resp, err := httpClient.Do(request)
       -        if err != nil {
       -                return nil, err
       -        }
       -
       -        return resp, nil
       -}
       -
       -// GenRandomASCII returns a random ASCII string of a given length.
       -func GenRandomASCII(length int) (string, error) {
       -        var res string
       -        for {
       -                if len(res) >= length {
       -                        return res, nil
       -                }
       -                num, err := rand.Int(rand.Reader, big.NewInt(int64(127)))
       -                if err != nil {
       -                        return "", err
       -                }
       -                n := num.Int64()
       -                if n > 32 && n < 127 {
       -                        res += string(n)
       -                }
       -        }
       -}