6 "github.com/bytom/blockchain/pseudohsm"
7 "github.com/bytom/blockchain/txbuilder"
8 "github.com/bytom/crypto/ed25519/chainkd"
9 "github.com/bytom/net/http/httperror"
10 "github.com/bytom/net/http/httpjson"
14 errorFormatter.Errors[Pseudohsm.ErrDuplicateKeyAlias] = httperror.Info{400, "BTM050", "Alias already exists"}
15 errorFormatter.Errors[Pseudohsm.ErrInvalidAfter] = httperror.Info{400, "BTM801", "Invalid `after` in query"}
16 errorFormatter.Errors[Pseudohsm.ErrTooManyAliasesToList] = httperror.Info{400, "BTM802", "Too many aliases to list"}
20 // PseudoHSM configures the Core to expose the PseudoHSM endpoints. It
21 // is only included in non-production builds.
23 func PseudoHSM(hsm *Pseudohsm.HSM) RunOption {
24 return func(api *API) {
26 h := &pseudoHSMHandler{PseudoHSM: hsm}
27 needConfig := api.needConfig()
28 api.mux.Handle("/hsm/create-key", needConfig(h.pseudohsmCreateKey))
29 api.mux.Handle("/hsm/list-keys", needConfig(h.pseudohsmListKeys))
30 api.mux.Handle("/hsm/delete-key", needConfig(h.pseudohsmDeleteKey))
31 api.mux.Handle("/hsm/sign-transaction", needConfig(h.pseudohsmSignTemplates))
32 api.mux.Handle("/hsm/reset-password", needConfig(h.pseudohsmResetPassword))
33 api.mux.Handle("/hsm/update-alias", needConfig(h.pseudohsmUpdateAlias))
38 type pseudoHSMHandler struct {
39 PseudoHSM *Pseudohsm.HSM
43 func (h *PseudoHSMHandler) pseudohsmCreateKey(ctx context.Context, password string, in struct{ Alias string }) (result *Pseudohsm.XPub, err error) {
44 return h.PseudoHSM.XCreate(password, in.Alias)
47 func (h *PseudoHSMHandler) pseudohsmListKeys(ctx context.Context, query requestQuery) (page, error) {
48 limit := query.PageSize
50 limit = defGenericPageSize // defGenericPageSize = 100
53 xpubs, after, err := h.PseudoHSM.ListKeys(query.After, limit)
58 var items []interface{}
59 for _, xpub := range xpubs {
60 items = append(items, xpub)
66 Items: httpjson.Array(items),
67 LastPage: len(xpubs) < limit,
72 func (h *PseudoHSMHandler) pseudohsmDeleteKey(ctx context.Context, xpub chainkd.XPub, password string) error {
73 return h.PseudoHSM.XDelete(xpub, password)
76 func (h *PseudoHSMHandler) pseudohsmSignTemplates(ctx context.Context, x struct {
77 Txs []*txbuilder.Template `json:"transactions"`
78 XPubs []chainkd.XPub `json:"xpubs"`
80 resp := make([]interface{}, 0, len(x.Txs))
81 for _, tx := range x.Txs {
82 err := txbuilder.Sign(ctx, tx, x.XPubs, h.pseudohsmSignTemplate)
84 info := errorFormatter.Format(err)
85 resp = append(resp, info)
87 resp = append(resp, tx)
93 func (h *PseudoHSMHandler) pseudohsmSignTemplate(ctx context.Context, xpub chainkd.XPub, path [][]byte, data [32]byte) ([]byte, error) {
94 sigBytes, err := h.PseudoHSM.XSign(ctx, xpub, path, data[:])
95 if err == Pseudohsm.ErrNoKey {
103 func RemoteHSM(hsm *remoteHSM) RunOption {
104 return func(api *API) {
105 h := &retmoteHSMHandler{RemoteHSM: hsm}
106 needConfig := api.needConfig()
107 api.mux.Handle("/hsm/sign-transaction", needConfig(h.Sign))
113 type remoteHSM struct {
117 func remoteHSMHandler struct {
121 func New(conf *config.Config) *HSM {
123 httpClient := new(http.Client)
124 httpClient.Transport = &http.Transport{
125 TLSClientConfig: tlsConfig,
126 // The following fields are default values
127 // copied from DefaultTransport.
128 // (When you change them, be sure to move them
129 // above this line so this comment stays true.)
130 DialContext: (&net.Dialer{
131 Timeout: 30 * time.Second,
132 KeepAlive: 30 * time.Second,
136 IdleConnTimeout: 90 * time.Second,
137 TLSHandshakeTimeout: 10 * time.Second,
138 ExpectContinueTimeout: 1 * time.Second,
141 return &remoteHSM{Client: &rpc.Client{
142 BaseURL: conf.HsmUrl,
143 AccessToken: conf.HsmAccessToken,
144 Username: conf.processID,
146 Version: conf.version,
147 BlockchainID: conf.BlockchainId.String(),
153 func (h *remoteHSM) Sign(ctx context.Context, pk ed25519.PublicKey, date [32]byte)([]byte, err error) {
155 Block *legacy.TxHeader `json:"txheader"`
156 Pub json.HexBytes `json:"pubkey"`
157 }{data, json.HexBytes(pk[:])}
159 err = h.Client.Call(ctx, "/sign-transaction", body, &sigBytes)