func (r *RemoteKMS) ExportPubKeyBytes(keyID string) ([]byte, error) {
	startExport := time.Now()
	keyURL := r.buildKIDURL(keyID)
	destination := keyURL + "/export"
	resp, err := r.getHTTPRequest(destination)
	if err != nil {
		return nil, fmt.Errorf("posting GET ExportPubKeyBytes key failed [%s, %w]", destination, err)
	}
	defer closeResponseBody(resp.Body, logger, "ExportPubKeyBytes")
	err = checkError(resp)
	if err != nil {
		return nil, err
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("read key response for ExportPubKeyBytes failed [%s, %w]", destination, err)
	}
	httpResp := &exportKeyResp{}
	err = r.unmarshalFunc(respBody, httpResp)
	if err != nil {
		return nil, fmt.Errorf("unmarshal key for ExportPubKeyBytes failed [%s, %w]", destination, err)
	}
	keyBytes, err := base64.URLEncoding.DecodeString(httpResp.KeyBytes)
	if err != nil {
		return nil, err
	}
	logger.Debugf("overall ExportPubKeyBytes duration: %s", time.Since(startExport))
	return keyBytes, nil
}
ExportPubKeyBytes will remotely fetch a key referenced by id then gets its public key in raw bytes and returns it.
The key must be an asymmetric key.
Returns:
- marshalled public key []byte
- error if it fails to export the public key bytes
package webkms
import (
	"bytes"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
	"github.com/hyperledger/aries-framework-go/pkg/common/log"
	"github.com/hyperledger/aries-framework-go/pkg/kms"
	spi "github.com/hyperledger/aries-framework-go/spi/log"
)
const (
	KeystoreEndpoint = "{serverEndpoint}/kms/keystores"
	ContentType = "application/json"
	LocationHeader = "Location"
	XRootCapabilityHeader = "X-ROOTCAPABILITY"
)
var logger = log.New("aries-framework/kms/webkms")
type HTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
}
type errMessage struct {
	Error string `json:"errMessage"`
}
type createKeystoreReq struct {
	Controller string `json:"controller,omitempty"`
	VaultID    string `json:"vaultID,omitempty"`
}
type createKeyReq struct {
	KeyType   string `json:"keyType,omitempty"`
	ExportKey bool   `json:"export,omitempty"`
}
type createResp struct {
	Location string `json:"location,omitempty"`
	KeyBytes string `json:"publicKey,omitempty"`
}
type exportKeyResp struct {
	KeyBytes string `json:"publicKey,omitempty"`
}
type importKeyReq struct {
	KeyBytes string `json:"keyBytes,omitempty"`
	KeyType  string `json:"keyType,omitempty"`
	KeyID    string `json:"keyID,omitempty"`
}
type importKeyResp struct {
	Location string `json:"location,omitempty"`
}
type marshalFunc func(interface{}) ([]byte, error)
type unmarshalFunc func([]byte, interface{}) error
type RemoteKMS struct {
	httpClient    HTTPClient
	keystoreURL   string
	marshalFunc   marshalFunc
	unmarshalFunc unmarshalFunc
	opts          *Opts
}
func checkError(resp *http.Response) error {
	if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices {
		return nil
	}
	var errAPI errMessage
	if err := json.NewDecoder(resp.Body).Decode(&errAPI); err != nil {
		return err
	}
	return errors.New(errAPI.Error)
}
func CreateKeyStore(httpClient HTTPClient, keyserverURL, controller, vaultID string,  
	opts ...Opt) (string, string, error) {
	createKeyStoreStart := time.Now()
	kmsOpts := NewOpt()
	for _, opt := range opts {
		opt(kmsOpts)
	}
	destination := strings.ReplaceAll(KeystoreEndpoint, "{serverEndpoint}", keyserverURL)
	httpReqJSON := &createKeystoreReq{
		Controller: controller,
	}
	if vaultID != "" {
		httpReqJSON.VaultID = vaultID
	}
	mReq, err := kmsOpts.marshal(httpReqJSON)
	if err != nil {
		return "", "", fmt.Errorf("failed to marshal Create keystore request [%s, %w]", destination, err)
	}
	httpReq, err := http.NewRequest(http.MethodPost, destination, bytes.NewBuffer(mReq))
	if err != nil {
		return "", "", fmt.Errorf("build request for Create keystore error: %w", err)
	}
	httpReq.Header.Set("Content-Type", ContentType)
	if kmsOpts.HeadersFunc != nil {
		httpHeaders, e := kmsOpts.HeadersFunc(httpReq)
		if e != nil {
			return "", "", fmt.Errorf("add optional request headers error: %w", e)
		}
		if httpHeaders != nil {
			httpReq.Header = httpHeaders.Clone()
		}
	}
	start := time.Now()
	resp, err := httpClient.Do(httpReq)
	if err != nil {
		return "", "", fmt.Errorf("posting Create keystore failed [%s, %w]", destination, err)
	}
	defer closeResponseBody(resp.Body, logger, "CreateKeyStore")
	err = checkError(resp)
	if err != nil {
		return "", "", err
	}
	logger.Debugf("call of CreateStore http request duration: %s", time.Since(start))
	keystoreURL := resp.Header.Get(LocationHeader)
	capability := resp.Header.Get(XRootCapabilityHeader)
	logger.Debugf("overall CreateStore duration: %s", time.Since(createKeyStoreStart))
	return keystoreURL, capability, nil
}
func New(keystoreURL string, client HTTPClient, opts ...Opt) *RemoteKMS {
	kmsOpts := NewOpt()
	for _, opt := range opts {
		opt(kmsOpts)
	}
	return &RemoteKMS{
		httpClient:    client,
		keystoreURL:   keystoreURL,
		marshalFunc:   json.Marshal,
		unmarshalFunc: json.Unmarshal,
		opts:          kmsOpts,
	}
}
func (r *RemoteKMS) postHTTPRequest(destination string, mReq []byte) (*http.Response, error) {
	return r.doHTTPRequest(http.MethodPost, destination, mReq)
}
func (r *RemoteKMS) getHTTPRequest(destination string) (*http.Response, error) {
	return r.doHTTPRequest(http.MethodGet, destination, nil)
}
func (r *RemoteKMS) doHTTPRequest(method, destination string, mReq []byte) (*http.Response, error) {
	start := time.Now()
	var (
		httpReq *http.Request
		err     error
	)
	if mReq != nil {
		httpReq, err = http.NewRequest(method, destination, bytes.NewBuffer(mReq))
		if err != nil {
			return nil, fmt.Errorf("build post request error: %w", err)
		}
	} else {
		httpReq, err = http.NewRequest(method, destination, nil)
		if err != nil {
			return nil, fmt.Errorf("build get request error: %w", err)
		}
	}
	if method == http.MethodPost {
		httpReq.Header.Set("Content-Type", ContentType)
	}
	if r.opts.HeadersFunc != nil {
		httpHeaders, e := r.opts.HeadersFunc(httpReq)
		if e != nil {
			return nil, fmt.Errorf("add optional request headers error: %w", e)
		}
		if httpHeaders != nil {
			httpReq.Header = httpHeaders.Clone()
		}
	}
	resp, err := r.httpClient.Do(httpReq)
	logger.Debugf("  HTTP %s %s call duration: %s", method, destination, time.Since(start))
	return resp, err
}
func (r *RemoteKMS) Create(kt kms.KeyType) (string, interface{}, error) {
	startCreate := time.Now()
	keyURL, _, err := r.createKey(kt, false)
	if err != nil {
		return "", nil, err
	}
	kid := keyURL[strings.LastIndex(keyURL, "/")+1:]
	logger.Debugf("overall Create key duration: %s", time.Since(startCreate))
	return kid, keyURL, nil
}
func (r *RemoteKMS) createKey(kt kms.KeyType, exportKey bool) (string, []byte, error) {
	destination := r.keystoreURL + "/keys"
	httpReqJSON := &createKeyReq{
		KeyType:   string(kt),
		ExportKey: exportKey,
	}
	marshaledReq, err := r.marshalFunc(httpReqJSON)
	if err != nil {
		return "", nil, fmt.Errorf("failed to marshal Create key request [%s, %w]", destination, err)
	}
	resp, err := r.postHTTPRequest(destination, marshaledReq)
	if err != nil {
		return "", nil, fmt.Errorf("posting Create key failed [%s, %w]", destination, err)
	}
	defer closeResponseBody(resp.Body, logger, "Create")
	err = checkError(resp)
	if err != nil {
		return "", nil, err
	}
	keyURL := resp.Header.Get(LocationHeader)
	if keyURL != "" && !exportKey {
		return keyURL, nil, nil
	}
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", nil, fmt.Errorf("read key response for Create failed [%s, %w]", destination, err)
	}
	var httpResp createResp
	err = r.unmarshalFunc(respBody, &httpResp)
	if err != nil {
		return "", nil, fmt.Errorf("unmarshal key for Create failed [%s, %w]", destination, err)
	}
	if keyURL == "" {
		keyURL = httpResp.Location
	}
	keyBytes, err := base64.URLEncoding.DecodeString(httpResp.KeyBytes)
	if err != nil {
		return "", nil, err
	}
	return keyURL, keyBytes, nil
}
func (r *RemoteKMS) Get(keyID string) (interface{}, error) {
	return r.buildKIDURL(keyID), nil
}
func (r *RemoteKMS) buildKIDURL(keyID string) string {
	return r.keystoreURL + "/keys/" + keyID
}
func (r *RemoteKMS) Rotate(kt kms.KeyType, keyID string) (string, interface{}, error) {
	return "", nil, errors.New("function Rotate is not implemented in remoteKMS")
}