2020-07-14 00:46:05 +00:00
|
|
|
package model
|
|
|
|
|
2020-10-01 17:13:45 +00:00
|
|
|
import (
|
|
|
|
"crypto/ed25519"
|
|
|
|
"cwtch.im/tapir/primitives"
|
|
|
|
"encoding/base32"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"strings"
|
|
|
|
)
|
2020-07-14 00:46:05 +00:00
|
|
|
|
2020-07-22 17:14:32 +00:00
|
|
|
// KeyType provides a wrapper for a generic public key type identifier (could be an onion address, a zcash address etc.)
|
|
|
|
type KeyType string
|
|
|
|
|
2020-07-14 00:46:05 +00:00
|
|
|
const (
|
2020-07-22 17:14:32 +00:00
|
|
|
// KeyTypeServerOnion - a cwtch address
|
|
|
|
KeyTypeServerOnion = KeyType("bulletin_board_onion") // bulletin board
|
2020-07-14 00:46:05 +00:00
|
|
|
|
|
|
|
// KeyTypeTokenOnion - a cwtch peer with a PoW based token protocol
|
2020-07-22 17:14:32 +00:00
|
|
|
KeyTypeTokenOnion = KeyType("token_service_onion")
|
2020-07-14 00:46:05 +00:00
|
|
|
|
|
|
|
//KeyTypePrivacyPass - a privacy pass based token server
|
2020-07-22 17:14:32 +00:00
|
|
|
KeyTypePrivacyPass = KeyType("privacy_pass_public_key")
|
2020-07-14 00:46:05 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Key provides a wrapper for a generic public key identifier (could be an onion address, a zcash address etc.)
|
|
|
|
type Key string
|
|
|
|
|
|
|
|
// KeyBundle manages a collection of related keys for various different services.
|
|
|
|
type KeyBundle struct {
|
2020-10-01 17:13:45 +00:00
|
|
|
Keys map[KeyType]Key
|
|
|
|
Signature []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewKeyBundle creates a new KeyBundle initialized with no keys.
|
|
|
|
func NewKeyBundle() *KeyBundle {
|
|
|
|
keyBundle := new(KeyBundle)
|
|
|
|
keyBundle.Keys = make(map[KeyType]Key)
|
|
|
|
return keyBundle
|
2020-07-14 00:46:05 +00:00
|
|
|
}
|
|
|
|
|
2020-07-22 17:14:32 +00:00
|
|
|
// HasKeyType returns true if the bundle has a public key of a given type.
|
|
|
|
func (kb *KeyBundle) HasKeyType(keytype KeyType) bool {
|
|
|
|
_, exists := kb.Keys[keytype]
|
2020-07-14 00:46:05 +00:00
|
|
|
return exists
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetKey retrieves a key with a given type from the bundle
|
2020-07-22 17:14:32 +00:00
|
|
|
func (kb *KeyBundle) GetKey(keytype KeyType) (Key, error) {
|
|
|
|
key, exists := kb.Keys[keytype]
|
2020-07-14 00:46:05 +00:00
|
|
|
if exists {
|
|
|
|
return key, nil
|
|
|
|
}
|
|
|
|
return "", errors.New("no such key")
|
|
|
|
}
|
|
|
|
|
2020-10-01 17:13:45 +00:00
|
|
|
// Serialize produces a json encoded byte array.
|
|
|
|
func (kb KeyBundle) Serialize() []byte {
|
|
|
|
// json.Marshal sorts map keys
|
|
|
|
bundle, _ := json.Marshal(kb)
|
|
|
|
return bundle
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sign allows a server to authenticate a key bundle by signing it (this uses the tapir identity interface)
|
|
|
|
func (kb *KeyBundle) Sign(identity primitives.Identity) {
|
|
|
|
kb.Signature = identity.Sign(kb.Serialize())
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeserializeAndVerify takes in a json formatted bundle and only returns a valid key bundle
|
|
|
|
// if it has been signed by the server.
|
|
|
|
func DeserializeAndVerify(bundle []byte) (*KeyBundle, error) {
|
|
|
|
keyBundle := new(KeyBundle)
|
|
|
|
err := json.Unmarshal(bundle, &keyBundle)
|
|
|
|
if err == nil {
|
|
|
|
signature := keyBundle.Signature
|
|
|
|
keyBundle.Signature = nil
|
|
|
|
serverKey, _ := keyBundle.GetKey(KeyTypeServerOnion)
|
|
|
|
|
|
|
|
// We have to do convert the encoded key to a format that can be used to verify the signature
|
|
|
|
var decodedPub []byte
|
|
|
|
decodedPub, err = base32.StdEncoding.DecodeString(strings.ToUpper(string(serverKey)))
|
|
|
|
if err == nil && len(decodedPub) == 35 {
|
|
|
|
if ed25519.Verify(decodedPub[:32], keyBundle.Serialize(), signature) == true {
|
|
|
|
return keyBundle, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err = InvalidEd25519PublicKey
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-07-14 00:46:05 +00:00
|
|
|
// AttributeBundle returns a map that can be used as part of a peer attribute bundle
|
|
|
|
func (kb *KeyBundle) AttributeBundle() map[string]string {
|
|
|
|
ab := make(map[string]string)
|
|
|
|
for k, v := range kb.Keys {
|
2020-07-22 17:14:32 +00:00
|
|
|
ab[string(k)] = string(v)
|
2020-07-14 00:46:05 +00:00
|
|
|
}
|
|
|
|
return ab
|
|
|
|
}
|