diff --git a/cmd/zerotier/cli/cert.go b/cmd/zerotier/cli/cert.go index c0d1948b4..797aed6b7 100644 --- a/cmd/zerotier/cli/cert.go +++ b/cmd/zerotier/cli/cert.go @@ -20,6 +20,13 @@ import ( "zerotier/pkg/zerotier" ) +func interactiveMakeSubject() *zerotier.CertificateSubject { + s := new(zerotier.CertificateSubject) + + + return s +} + func Cert(basePath string, authTokenGenerator func() string, args []string, jsonOutput bool) int { if len(args) < 1 { Help() diff --git a/cmd/zerotier/cli/help.go b/cmd/zerotier/cli/help.go index 1f4f305ca..e1fde61bb 100644 --- a/cmd/zerotier/cli/help.go +++ b/cmd/zerotier/cli/help.go @@ -34,80 +34,81 @@ Global Options: Common Operations: - help Show this help - version Print version - now [duration] Print current time [-]#[ms|s|m|h] + help Show this help + version Print version -· status Show node status and configuration +· status Show node status and configuration -· set [option] [value] - Get or set node configuration - port Primary P2P port - secondaryport Secondary P2P port (0 to disable) - blacklist cidr Toggle physical path blacklisting - blacklist if Toggle interface prefix blacklisting - portmap Toggle use of uPnP or NAT-PMP +· set [option] [value] List all settings (with no args) +· port Primary P2P port +· secondaryport Secondary P2P port (0 to disable) +· blacklist cidr Toggle physical path blacklisting +· blacklist if Toggle interface prefix blacklisting +· portmap Toggle use of uPnP or NAT-PMP -· peer [address] [command] [option] - Peer management commands - list List peers - listroots List root peers - show Show peer details - try [...] Try peer at explicit endpoint +· peer [address] [command] [option] Peer management commands +· list List peers +· listroots List root peers +· show Show peer details +· try [...] Try peer at explicit endpoint -· network list List VL2 networks -· network [command] [option] - Network management commands - show Show network details (default) - set [option] [value] - Get or set network options - manageips Is IP management allowed? - manageroutes Is route management allowed? - globalips Allow assignment of global IPs? - globalroutes Can global IP space routes be set? - defaultroute Can default route be overridden? +· network list List VL2 networks +· network [command] [option] +· show Show network details (default) +· set [option] [value] Get or set network options +· manageips Is IP management allowed? +· manageroutes Is route management allowed? +· globalips Allow assignment of global IPs? +· globalroutes Can global IP space routes be set? +· defaultroute Can default route be overridden? -· join [-options] Join a virtual network - -a Token to submit to controller - -c Controller identity or fingerprint -· leave Leave a virtual network +· join [-options] Join a virtual network + -a Token to submit to controller + -c Controller identity or fingerprint +· leave Leave a virtual network Advanced Operations: - service Start node (seldom used from CLI) + service Start this node (runs until stopped) + now [duration] Print current time [-]#[ms|s|m|h] -· controller [option] - Local controller management commands -· list List networks run by local controller -· new Create a new network -· set [setting] [value] Show or modify network settings -· members List members of a network -· member [setting] [value] Show or modify member level settings -· auth
Authorize a peer -· deauth
Deauthorize a peer + controller [option] +· list List networks on controller +· new Create a new network +· set [setting] [value] Show or modify network settings +· members List members of a network +· member [setting] [value] Show or modify member level settings +· auth
Authorize a peer +· deauth
Deauthorize a peer - identity [args] - Identity management - new [c25519 | p384] Create identity (default: c25519) - getpublic Extract only public part of identity - fingerprint Get an identity's fingerprint - validate Locally validate an identity - sign Sign a file with an identity's key - verify Verify a signature + identity [args] + new [c25519 | p384] Create identity (default: c25519) + getpublic Extract only public part of identity + fingerprint Get an identity's fingerprint + validate Locally validate an identity + sign Sign a file with an identity's key + verify Verify a signature - locator [args] - Locator management - new [...] Create new signed locator - verify Verify locator signature - show Show contents of a locator + locator [args] + new [...] Create new signed locator + verify Verify locator signature + show Show contents of a locator - cert [args] - Certificate management -· list List certificates in local node store -· show List or show details of a certificate - newsid Create a new subject unique ID - newcsr Create a subject CSR - sign Sign a CSR to create a certificate - verify Verify certificate (not entire chain) - dump Verify and print certificate -· import [trust,[trust]] Import certificate into this node - trust flag: rootca Certificate is a root CA - trust flag: ztrootset ZeroTier root node set -· restore Re-import default certificates -· export [path] Export a certificate from this node -· delete Delete certificate from this node + cert [args] +· list List certificates at local node +· show Show certificate details + newsubject Interactive subject creation + newsid Create a new subject unique ID + newcsr Create a subject CSR + sign Sign a CSR to create a certificate + verify Verify certificate (not chain) + dump Verify and print certificate +· import [trust,[trust]] Import certificate into this node + trust flag: rootca Certificate is a root CA + trust flag: ztrootset ZeroTier root node set +· restore Re-import default certificates +· export [path] Export a certificate from this node +· delete Delete certificate from this node · Command requires a running node and access to a local API token. diff --git a/cmd/zerotier/cli/misc.go b/cmd/zerotier/cli/misc.go index f0b03746e..0894a8548 100644 --- a/cmd/zerotier/cli/misc.go +++ b/cmd/zerotier/cli/misc.go @@ -14,11 +14,13 @@ package cli import ( + "bufio" "encoding/json" "fmt" "io/ioutil" "net/http" "os" + "strconv" "strings" "zerotier/pkg/zerotier" @@ -235,3 +237,40 @@ func isValidNetworkID(a string) bool { } return false } + +func prompt(str string, dfl string) string { + if len(dfl) > 0 { + fmt.Printf("%s [%s]: ", str, dfl) + text, _ := bufio.NewReader(os.Stdin).ReadString('\n') + text = strings.TrimSpace(text) + if len(text) == 0 { + text = dfl + } + return text + } + fmt.Print(str) + text, _ := bufio.NewReader(os.Stdin).ReadString('\n') + return strings.TrimSpace(text) +} + +func promptInt(str string, dfl int64) int64 { + s := prompt(str, "") + if len(s) > 0 { + i, err := strconv.ParseInt(s, 10, 64) + if err == nil { + return i + } + } + return dfl +} + +func promptFile(str string) []byte { + s := prompt(str, "") + if len(s) > 0 { + b, err := ioutil.ReadFile(s) + if err == nil { + return b + } + } + return nil +} diff --git a/pkg/zerotier/base32blob.go b/pkg/zerotier/base32blob.go new file mode 100644 index 000000000..534d38379 --- /dev/null +++ b/pkg/zerotier/base32blob.go @@ -0,0 +1,38 @@ +/* + * Copyright (C)2013-2020 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2025-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +package zerotier + +import ( + "encoding/json" + "strings" +) + +// Base32Blob is a byte array that JSON serializes to a Base32 string. +type Base32Blob []byte + +// MarshalJSON returns this blob marshaled as a byte array or a string. +func (b *Base32Blob) MarshalJSON() ([]byte, error) { + return []byte("\""+Base32.EncodeToString(*b)+"\""), nil +} + +// UnmarshalJSON unmarshals this blob from a JSON array or string. +func (b *Base32Blob) UnmarshalJSON(j []byte) error { + var b32 string + err := json.Unmarshal(j, &b32) + if err != nil { + return err + } + *b, err = Base32.DecodeString(strings.TrimSpace(b32)) + return err +} diff --git a/pkg/zerotier/certificate.go b/pkg/zerotier/certificate.go index b1f0b18ed..ad92a5f92 100644 --- a/pkg/zerotier/certificate.go +++ b/pkg/zerotier/certificate.go @@ -18,7 +18,6 @@ package zerotier import "C" import ( - "encoding/base64" "encoding/json" "fmt" "unsafe" @@ -69,32 +68,32 @@ type CertificateSubject struct { Timestamp int64 `json:"timestamp"` Identities []CertificateIdentity `json:"identities,omitempty"` Networks []CertificateNetwork `json:"networks,omitempty"` - Certificates [][]byte `json:"certificates,omitempty"` + Certificates []Base32Blob `json:"certificates,omitempty"` UpdateURLs []string `json:"updateURLs,omitempty"` Name CertificateName `json:"name"` - UniqueID []byte `json:"uniqueId,omitempty"` - UniqueIDProofSignature []byte `json:"uniqueIdProofSignature,omitempty"` + UniqueID Base32Blob `json:"uniqueId,omitempty"` + UniqueIDProofSignature Base32Blob `json:"uniqueIdProofSignature,omitempty"` } // Certificate is a Go reflection of the C ZT_Certificate struct. type Certificate struct { - SerialNo []byte `json:"serialNo,omitempty"` + SerialNo Base32Blob `json:"serialNo,omitempty"` Flags uint64 `json:"flags"` Timestamp int64 `json:"timestamp"` Validity [2]int64 `json:"validity"` Subject CertificateSubject `json:"subject"` Issuer *Identity `json:"issuer,omitempty"` IssuerName CertificateName `json:"issuerName"` - ExtendedAttributes []byte `json:"extendedAttributes,omitempty"` + ExtendedAttributes Base32Blob `json:"extendedAttributes,omitempty"` MaxPathLength uint `json:"maxPathLength,omitempty"` - CRL [][]byte `json:"crl,omitempty"` - Signature []byte `json:"signature,omitempty"` + CRL []Base32Blob `json:"crl,omitempty"` + Signature Base32Blob `json:"signature,omitempty"` } // CertificateSubjectUniqueIDSecret bundles a certificate subject unique ID and its secret key. type CertificateSubjectUniqueIDSecret struct { - UniqueID []byte `json:"uniqueId,omitempty"` - UniqueIDSecret []byte `json:"uniqueIdSecret,omitempty"` + UniqueID Base32Blob `json:"uniqueId,omitempty"` + UniqueIDSecret Base32Blob `json:"uniqueIdSecret,omitempty"` } // LocalCertificate combines a certificate with its local trust flags. @@ -495,11 +494,6 @@ func (c *Certificate) JSON() string { return string(j) } -// URLSerialNo returns the serial number encoded for use in /cert/### local API URLs. -func (c *Certificate) URLSerialNo() string { - return base64.URLEncoding.EncodeToString(c.SerialNo) -} - // NewCertificateSubjectUniqueId creates a new certificate subject unique ID and corresponding private key. // Right now only one type is supported: CertificateUniqueIdTypeNistP384 func NewCertificateSubjectUniqueId(uniqueIdType int) (id []byte, priv []byte, err error) { diff --git a/pkg/zerotier/fingerprint.go b/pkg/zerotier/fingerprint.go index 78e17ad1e..29f981c75 100644 --- a/pkg/zerotier/fingerprint.go +++ b/pkg/zerotier/fingerprint.go @@ -51,7 +51,7 @@ func NewFingerprintFromString(fps string) (*Fingerprint, error) { return nil, err } if len(ss) == 2 { - h, err := Base32StdLowerCase.DecodeString(ss[1]) + h, err := Base32.DecodeString(ss[1]) if err != nil { return nil, err } @@ -78,7 +78,7 @@ func newFingerprintFromCFingerprint(cfp *C.ZT_Fingerprint) *Fingerprint { // String returns an address or a full address-hash depenting on whether a hash is present. func (fp *Fingerprint) String() string { if len(fp.Hash) == FingerprintHashSize { - return fmt.Sprintf("%.10x-%s", uint64(fp.Address), Base32StdLowerCase.EncodeToString(fp.Hash)) + return fmt.Sprintf("%.10x-%s", uint64(fp.Address), Base32.EncodeToString(fp.Hash)) } return fp.Address.String() } diff --git a/pkg/zerotier/misc.go b/pkg/zerotier/misc.go index 700b947d4..ee77c3ae2 100644 --- a/pkg/zerotier/misc.go +++ b/pkg/zerotier/misc.go @@ -32,8 +32,11 @@ const LogoChar = "⏁" // pointerSize is the size of a pointer on this system const pointerSize = unsafe.Sizeof(uintptr(0)) -// Base32StdLowerCase is a base32 encoder/decoder using a lower-case standard alphabet and no padding. -var Base32StdLowerCase = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567").WithPadding(base32.NoPadding) +// Base32Alphabet is the Base32 alphabet used in ZeroTier. +const Base32Alphabet = "abcdefghijklmnopqrstuvwxyz234567" + +// Base32 is an encoder using the ZeroTier base32 encoding. +var Base32 = base32.NewEncoding(Base32Alphabet) // unassignedPrivilegedPorts are ports below 1024 that do not appear to be assigned by IANA. // The new 2.0+ ZeroTier default is 793, which we will eventually seek to have assigned. These diff --git a/pkg/zerotier/node.go b/pkg/zerotier/node.go index b70d6b04a..b846d264d 100644 --- a/pkg/zerotier/node.go +++ b/pkg/zerotier/node.go @@ -731,7 +731,7 @@ func (n *Node) makeStateObjectPath(objType int, id []uint64) (string, bool) { fp = path.Join(n.basePath, "truststore") case C.ZT_STATE_OBJECT_CERT: _ = os.Mkdir(n.certsPath, 0755) - fp = path.Join(n.certsPath, Base32StdLowerCase.EncodeToString((*[48]byte)(unsafe.Pointer(&id[0]))[:])) + fp = path.Join(n.certsPath, Base32.EncodeToString((*[48]byte)(unsafe.Pointer(&id[0]))[:])) } return fp, secret }