Last active
February 25, 2019 14:03
-
-
Save sykesm/fa60726c23ab5891f59f1f99faf3d5df to your computer and use it in GitHub Desktop.
Possible use of reflection to address interface compatibility issues with vending of bccsp plugin.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Copyright IBM Corp. All Rights Reserved. | |
SPDX-License-Identifier: Apache-2.0 | |
*/ | |
package factory | |
import ( | |
"errors" | |
"fmt" | |
"hash" | |
"os" | |
"plugin" | |
"reflect" | |
"github.com/hyperledger/fabric/bccsp" | |
) | |
const ( | |
// PluginFactoryName is the factory name for BCCSP plugins | |
PluginFactoryName = "PLUGIN" | |
) | |
// PluginOpts contains the options for the PluginFactory | |
type PluginOpts struct { | |
// Path to plugin library | |
Library string | |
// Config map for the plugin library | |
Config map[string]interface{} | |
} | |
// PluginFactory is the factory for BCCSP plugins | |
type PluginFactory struct{} | |
// Name returns the name of this factory | |
func (f *PluginFactory) Name() string { | |
return PluginFactoryName | |
} | |
// Get returns an instance of BCCSP using Opts. | |
func (f *PluginFactory) Get(config *FactoryOpts) (bccsp.BCCSP, error) { | |
// check for valid config | |
if config == nil || config.PluginOpts == nil { | |
return nil, errors.New("Invalid config. It must not be nil.") | |
} | |
// Library is required property | |
if config.PluginOpts.Library == "" { | |
return nil, errors.New("Invalid config: missing property 'Library'") | |
} | |
// make sure the library exists | |
if _, err := os.Stat(config.PluginOpts.Library); err != nil { | |
return nil, fmt.Errorf("Could not find library '%s' [%s]", config.PluginOpts.Library, err) | |
} | |
// attempt to load the library as a plugin | |
plug, err := plugin.Open(config.PluginOpts.Library) | |
if err != nil { | |
return nil, fmt.Errorf("Failed to load plugin '%s' [%s]", config.PluginOpts.Library, err) | |
} | |
// lookup the required symbol 'New' | |
sym, err := plug.Lookup("New") | |
if err != nil { | |
return nil, fmt.Errorf("could not find required symbol 'New': %s", err) | |
} | |
if reflect.TypeOf(sym).Kind() != reflect.Func { | |
panic(fmt.Sprintf("%v is not a function", sym)) | |
} | |
out := newMethod(reflect.ValueOf(sym)).call(config.PluginOpts.Config) | |
if !out[1].IsNil() { | |
return nil, out[1].Interface().(error) | |
} | |
return &pluginProxy{out[0]}, nil | |
} | |
type method struct { | |
m reflect.Value | |
} | |
func newMethod(v reflect.Value) *method { | |
return &method{m: v} | |
} | |
func (m *method) call(args ...interface{}) []reflect.Value { | |
var in []reflect.Value | |
for i, a := range args { | |
if a == nil { | |
zv := reflect.Zero(m.m.Type().In(i)) | |
in = append(in, zv) | |
} else { | |
in = append(in, reflect.ValueOf(a)) | |
} | |
} | |
return m.m.Call(in) | |
} | |
type pluginProxy struct { | |
delegate reflect.Value | |
} | |
func (p *pluginProxy) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { | |
m := newMethod(p.delegate.MethodByName("KeyGen")) | |
out := m.call(opts) | |
if !out[0].IsNil() { | |
k = &keyProxy{delegate: out[0]} | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
func (p *pluginProxy) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk bccsp.Key, err error) { | |
m := newMethod(p.delegate.MethodByName("KeyDeriv")) | |
out := m.call(k, opts) | |
if !out[0].IsNil() { | |
k = &keyProxy{delegate: out[0]} | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
func (p *pluginProxy) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { | |
m := newMethod(p.delegate.MethodByName("KeyImport")) | |
out := m.call(raw, opts) | |
if !out[0].IsNil() { | |
k = &keyProxy{delegate: out[0]} | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
func (p *pluginProxy) GetKey(ski []byte) (k bccsp.Key, err error) { | |
m := newMethod(p.delegate.MethodByName("GetKey")) | |
out := m.call(ski) | |
if !out[0].IsNil() { | |
k = &keyProxy{delegate: out[0]} | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
func (p *pluginProxy) Hash(msg []byte, opts bccsp.HashOpts) (hash []byte, err error) { | |
m := newMethod(p.delegate.MethodByName("Hash")) | |
out := m.call(msg, opts) | |
if !out[0].IsNil() { | |
hash = out[0].Bytes() | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
func (p *pluginProxy) GetHash(opts bccsp.HashOpts) (h hash.Hash, err error) { | |
m := newMethod(p.delegate.MethodByName("GetHash")) | |
out := m.call(opts) | |
if !out[0].IsNil() { | |
h = out[0].Interface().(hash.Hash) | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
func (p *pluginProxy) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { | |
m := newMethod(p.delegate.MethodByName("Sign")) | |
out := m.call(k, digest, opts) | |
if !out[0].IsNil() { | |
signature = out[0].Bytes() | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
func (p *pluginProxy) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { | |
m := newMethod(p.delegate.MethodByName("Verify")) | |
out := m.call(k, signature, digest, opts) | |
if !out[0].IsNil() { | |
valid = out[0].Bool() | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
func (p *pluginProxy) Encrypt(k bccsp.Key, plaintext []byte, opts bccsp.EncrypterOpts) (ciphertext []byte, err error) { | |
m := newMethod(p.delegate.MethodByName("Encrypt")) | |
out := m.call(k, plaintext, opts) | |
if !out[0].IsNil() { | |
ciphertext = out[0].Bytes() | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
func (p *pluginProxy) Decrypt(k bccsp.Key, ciphertext []byte, opts bccsp.DecrypterOpts) (plaintext []byte, err error) { | |
m := newMethod(p.delegate.MethodByName("Decrypt")) | |
out := m.call(k, ciphertext, opts) | |
if !out[0].IsNil() { | |
plaintext = out[0].Bytes() | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
type keyProxy struct { | |
delegate reflect.Value | |
} | |
func (k *keyProxy) Bytes() (b []byte, err error) { | |
m := newMethod(k.delegate.MethodByName("Bytes")) | |
out := m.call() | |
if !out[0].IsNil() { | |
b = out[0].Bytes() | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} | |
func (k *keyProxy) SKI() (b []byte) { | |
m := newMethod(k.delegate.MethodByName("SKI")) | |
out := m.call() | |
if !out[0].IsNil() { | |
b = out[0].Bytes() | |
} | |
return | |
} | |
func (k *keyProxy) Symmetric() bool { | |
m := newMethod(k.delegate.MethodByName("Symmetric")) | |
out := m.call() | |
return out[0].Bool() | |
} | |
func (k *keyProxy) Private() bool { | |
m := newMethod(k.delegate.MethodByName("Private")) | |
out := m.call() | |
return out[0].Bool() | |
} | |
func (k *keyProxy) PublicKey() (key bccsp.Key, err error) { | |
m := newMethod(k.delegate.MethodByName("PublicKey")) | |
out := m.call() | |
if !out[0].IsNil() { | |
key = &keyProxy{delegate: out[0]} | |
} | |
if !out[1].IsNil() { | |
err = out[1].Interface().(error) | |
} | |
return | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This may be workable but will probably need a way to unwrap the original key from the proxy when presenting it to a plugin.