summaryrefslogtreecommitdiff
path: root/vendor/github.com/cretz/bine/control/cmd_onion.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/cretz/bine/control/cmd_onion.go')
-rw-r--r--vendor/github.com/cretz/bine/control/cmd_onion.go201
1 files changed, 201 insertions, 0 deletions
diff --git a/vendor/github.com/cretz/bine/control/cmd_onion.go b/vendor/github.com/cretz/bine/control/cmd_onion.go
new file mode 100644
index 0000000..b298d36
--- /dev/null
+++ b/vendor/github.com/cretz/bine/control/cmd_onion.go
@@ -0,0 +1,201 @@
+package control
+
+import (
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/cretz/bine/torutil"
+ "github.com/cretz/bine/torutil/ed25519"
+)
+
+// KeyType is a key type for Key in AddOnion.
+type KeyType string
+
+const (
+ // KeyTypeNew is NEW.
+ KeyTypeNew KeyType = "NEW"
+ // KeyTypeRSA1024 is RSA1024.
+ KeyTypeRSA1024 KeyType = "RSA1024"
+ // KeyTypeED25519V3 is ED25519-V3.
+ KeyTypeED25519V3 KeyType = "ED25519-V3"
+)
+
+// KeyAlgo is a key algorithm for GenKey on AddOnion.
+type KeyAlgo string
+
+const (
+ // KeyAlgoBest is BEST.
+ KeyAlgoBest KeyAlgo = "BEST"
+ // KeyAlgoRSA1024 is RSA1024.
+ KeyAlgoRSA1024 KeyAlgo = "RSA1024"
+ // KeyAlgoED25519V3 is ED25519-V3.
+ KeyAlgoED25519V3 KeyAlgo = "ED25519-V3"
+)
+
+// Key is a type of key to use for AddOnion. Implementations include GenKey,
+// RSAKey, and ED25519Key.
+type Key interface {
+ // Type is the KeyType for AddOnion.
+ Type() KeyType
+ // Blob is the serialized key for AddOnion.
+ Blob() string
+}
+
+// KeyFromString creates a Key for AddOnion based on a response string.
+func KeyFromString(str string) (Key, error) {
+ typ, blob, _ := torutil.PartitionString(str, ':')
+ switch KeyType(typ) {
+ case KeyTypeNew:
+ return GenKeyFromBlob(blob), nil
+ case KeyTypeRSA1024:
+ return RSA1024KeyFromBlob(blob)
+ case KeyTypeED25519V3:
+ return ED25519KeyFromBlob(blob)
+ default:
+ return nil, fmt.Errorf("Unrecognized key type: %v", typ)
+ }
+}
+
+// GenKey is a Key for AddOnion that asks Tor to generate a key for the given
+// algorithm.
+type GenKey KeyAlgo
+
+// GenKeyFromBlob creates a GenKey for the given response blob which is a
+// KeyAlgo.
+func GenKeyFromBlob(blob string) GenKey { return GenKey(KeyAlgo(blob)) }
+
+// Type implements Key.Type.
+func (GenKey) Type() KeyType { return KeyTypeNew }
+
+// Blob implements Key.Blob.
+func (g GenKey) Blob() string { return string(g) }
+
+// RSAKey is a Key for AddOnion that is a RSA-1024 key (i.e. v2).
+type RSAKey struct{ *rsa.PrivateKey }
+
+// RSA1024KeyFromBlob creates a RSAKey for the given response blob.
+func RSA1024KeyFromBlob(blob string) (*RSAKey, error) {
+ byts, err := base64.StdEncoding.DecodeString(blob)
+ if err != nil {
+ return nil, err
+ }
+ rsaKey, err := x509.ParsePKCS1PrivateKey(byts)
+ if err != nil {
+ return nil, err
+ }
+ return &RSAKey{rsaKey}, nil
+}
+
+// Type implements Key.Type.
+func (*RSAKey) Type() KeyType { return KeyTypeRSA1024 }
+
+// Blob implements Key.Blob.
+func (r *RSAKey) Blob() string {
+ return base64.StdEncoding.EncodeToString(x509.MarshalPKCS1PrivateKey(r.PrivateKey))
+}
+
+// ED25519Key is a Key for AddOnion that is a ed25519 key (i.e. v3).
+type ED25519Key struct{ ed25519.KeyPair }
+
+// ED25519KeyFromBlob creates a ED25519Key for the given response blob.
+func ED25519KeyFromBlob(blob string) (*ED25519Key, error) {
+ byts, err := base64.StdEncoding.DecodeString(blob)
+ if err != nil {
+ return nil, err
+ }
+ return &ED25519Key{ed25519.PrivateKey(byts).KeyPair()}, nil
+}
+
+// Type implements Key.Type.
+func (*ED25519Key) Type() KeyType { return KeyTypeED25519V3 }
+
+// Blob implements Key.Blob.
+func (e *ED25519Key) Blob() string { return base64.StdEncoding.EncodeToString(e.PrivateKey()) }
+
+// AddOnionRequest is a set of request params for AddOnion.
+type AddOnionRequest struct {
+ // Key is the key to use or GenKey if Tor should generate it.
+ Key Key
+ // Flags are ADD_ONION flags.
+ Flags []string
+ // MaxStreams is ADD_ONION MaxStreams.
+ MaxStreams int
+ // Ports are ADD_ONION Port values. Key is virtual port, Val is target
+ // port (or can be empty to use virtual port).
+ Ports []*KeyVal
+ // ClientAuths are ADD_ONION ClientAuth values. If value is empty string,
+ // Tor will generate the password.
+ ClientAuths map[string]string
+}
+
+// AddOnionResponse is the response for AddOnion.
+type AddOnionResponse struct {
+ // ServiceID is the ADD_ONION response ServiceID value.
+ ServiceID string
+ // Key is the ADD_ONION response PrivateKey value.
+ Key Key
+ // ClientAuths are the ADD_ONION response ClientAuth values.
+ ClientAuths map[string]string
+ // RawResponse is the raw ADD_ONION response.
+ RawResponse *Response
+}
+
+// AddOnion invokes ADD_ONION and returns its response.
+func (c *Conn) AddOnion(req *AddOnionRequest) (*AddOnionResponse, error) {
+ // Build command
+ if req.Key == nil {
+ return nil, c.protoErr("Key required")
+ }
+ cmd := "ADD_ONION " + string(req.Key.Type()) + ":" + req.Key.Blob()
+ if len(req.Flags) > 0 {
+ cmd += " Flags=" + strings.Join(req.Flags, ",")
+ }
+ if req.MaxStreams > 0 {
+ cmd += " MaxStreams=" + strconv.Itoa(req.MaxStreams)
+ }
+ for _, port := range req.Ports {
+ cmd += " Port=" + port.Key
+ if port.Val != "" {
+ cmd += "," + port.Val
+ }
+ }
+ for name, blob := range req.ClientAuths {
+ cmd += " ClientAuth=" + name
+ if blob != "" {
+ cmd += ":" + blob
+ }
+ }
+ // Invoke and read response
+ resp, err := c.SendRequest(cmd)
+ if err != nil {
+ return nil, err
+ }
+ ret := &AddOnionResponse{RawResponse: resp}
+ for _, data := range resp.Data {
+ key, val, _ := torutil.PartitionString(data, '=')
+ switch key {
+ case "ServiceID":
+ ret.ServiceID = val
+ case "PrivateKey":
+ if ret.Key, err = KeyFromString(val); err != nil {
+ return nil, err
+ }
+ case "ClientAuth":
+ name, pass, _ := torutil.PartitionString(val, ':')
+ if ret.ClientAuths == nil {
+ ret.ClientAuths = map[string]string{}
+ }
+ ret.ClientAuths[name] = pass
+ }
+ }
+ return ret, nil
+}
+
+// DelOnion invokes DELONION.
+func (c *Conn) DelOnion(serviceID string) error {
+ return c.sendRequestIgnoreResponse("DEL_ONION %v", serviceID)
+}