mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-01-13 16:30:33 +00:00
149 lines
4.1 KiB
Go
149 lines
4.1 KiB
Go
/*
|
|
* Copyright (c)2019 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: 2023-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/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// IdentityTypeC25519 is a classic Curve25519/Ed25519 identity
|
|
const IdentityTypeC25519 = 0
|
|
|
|
// IdentityTypeP384 is an identity containing both NIST P-384 and Curve25519/Ed25519 key types and leveraging both when possible
|
|
const IdentityTypeP384 = 1
|
|
|
|
// Sizes of components of different identity types
|
|
const (
|
|
IdentityTypeC25519PublicKeySize = 64 // C25519/Ed25519 keys
|
|
IdentityTypeC25519PrivateKeySize = 64 // C25519/Ed25519 private keys
|
|
IdentityTypeP384PublicKeySize = 209 // C25519/Ed25519, P-384 point-compressed public, P-384 self-signature
|
|
IdentityTypeP384PrivateKeySize = 112 // C25519/Ed25519 and P-384 private keys
|
|
)
|
|
|
|
// Identity is precisely what it sounds like: the address and associated keys for a ZeroTier node
|
|
type Identity struct {
|
|
address Address
|
|
idtype int
|
|
publicKey []byte
|
|
privateKey []byte
|
|
}
|
|
|
|
// NewIdentityFromString generates a new identity from its string representation.
|
|
// The private key is imported as well if it is present.
|
|
func NewIdentityFromString(s string) (*Identity, error) {
|
|
ss := strings.Split(s, ":")
|
|
if len(ss) < 3 {
|
|
return nil, ErrInvalidParameter
|
|
}
|
|
|
|
var err error
|
|
var id Identity
|
|
id.address, err = NewAddressFromString(ss[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if ss[1] == "0" {
|
|
id.idtype = 0
|
|
} else if ss[1] == "1" {
|
|
id.idtype = 1
|
|
} else {
|
|
return nil, ErrUncrecognizedIdentityType
|
|
}
|
|
|
|
switch id.idtype {
|
|
|
|
case 0:
|
|
id.publicKey, err = hex.DecodeString(ss[2])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(ss) >= 4 {
|
|
id.privateKey, err = hex.DecodeString(ss[3])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
case 1:
|
|
id.publicKey, err = base32StdLowerCase.DecodeString(ss[2])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(id.publicKey) != IdentityTypeP384PublicKeySize {
|
|
return nil, ErrInvalidKey
|
|
}
|
|
if len(ss) >= 4 {
|
|
id.privateKey, err = base32StdLowerCase.DecodeString(ss[3])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(id.privateKey) != IdentityTypeP384PrivateKeySize {
|
|
return nil, ErrInvalidKey
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return &id, nil
|
|
}
|
|
|
|
// HasPrivate returns true if this identity has its own private portion.
|
|
func (id *Identity) HasPrivate() bool { return len(id.privateKey) > 0 }
|
|
|
|
// PrivateKeyString returns the full identity.secret if the private key is set, or an empty string if no private key is set.
|
|
func (id *Identity) PrivateKeyString() string {
|
|
switch id.idtype {
|
|
case IdentityTypeC25519:
|
|
if len(id.publicKey) == IdentityTypeC25519PublicKeySize && len(id.privateKey) == IdentityTypeC25519PrivateKeySize {
|
|
return fmt.Sprintf("%.10x:0:%x:%x", uint64(id.address), id.publicKey, id.privateKey)
|
|
}
|
|
case IdentityTypeP384:
|
|
if len(id.publicKey) == IdentityTypeP384PublicKeySize && len(id.privateKey) == IdentityTypeP384PrivateKeySize {
|
|
return fmt.Sprintf("%.10x:1:%s:%s", uint64(id.address), base32StdLowerCase.EncodeToString(id.publicKey), base32StdLowerCase.EncodeToString(id.privateKey))
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// PublicKeyString returns the address and public key (identity.public contents).
|
|
// An empty string is returned if this identity is invalid or not initialized.
|
|
func (id *Identity) String() string {
|
|
if len(id.publicKey) == IdentityTypeC25519PublicKeySize {
|
|
s := fmt.Sprintf("%.10x:0:%x", id.address, id.publicKey)
|
|
return s
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// MarshalJSON marshals this Identity in its string format (private key is never included)
|
|
func (id *Identity) MarshalJSON() ([]byte, error) {
|
|
return []byte("\"" + id.String() + "\""), nil
|
|
}
|
|
|
|
// UnmarshalJSON unmarshals this Identity from a string
|
|
func (id *Identity) UnmarshalJSON(j []byte) error {
|
|
var s string
|
|
err := json.Unmarshal(j, &s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nid, err := NewIdentityFromString(s)
|
|
*id = *nid
|
|
return err
|
|
}
|