密钥管理系统KMS

密钥管理系统KMS(Key Management Service,KMS)是一款密钥管理和数据加密服务平台,功能类似硬件加密机,可以让您轻松创建和安全管理密钥, 符合监管和合规要求。 长安链支持KMS的接入,能够提供更加安全的节点私钥、用户端私钥保护能力。

整体设计

为了保证不强制绑定特定厂商KMS,设计上采用KMS插件方式来接入不同厂商的KMS,对上层提供加密、签名以及私钥保护的能力。

长安链支持KMS整体设计

  • KMS提供商:厂商提供,一般通过http协议对外提供密码服务。

  • 适配层:提供KMS适配层,用来屏蔽不同厂商KMS实现上的差异,方便接入

  • 工具层:为了上层应用方便调用底层密码接口,工具层对KMS密钥结构进行了封装,并提供了封装/解析功能;同时提供了生成数字证书的功能。

  • 应用层:长安链在证书生成工具、节点共识投票、交易签名等应用组件上都对KMS进行了支持。

适配层

为了支持不同厂商KMS系统,长安链根据上层应用需要的密码功能,设计了一套适配器接口IKMSAdapter, 不同厂商KMS实现差异 通过适配器插件的方式封装在适配层,供上层统一调用, 包括KMS连接初始化、密码服务调用等。

IKMSAdapter接口定义如下:

type IKMSAdapter interface {
	NewPrivateKey(keyId string, keyType string, keyAlias string) (bccrypto.PrivateKey, error)
	NewPublicKey(keyId string) (bccrypto.PublicKey, error)
}

长安链默认支持了腾讯云KMS, 不需要单独实现适配器插件,如果要支持其他厂商KMS需要提供适配器插件,并实现IKMSAdapter接口, 实现方式可参考长安链gitlab托管的common仓库,默认实现在common/crypto/kms/default.go.

实现以上接口后,通过go工具打包成golang插件,如下:

go build -buildmode=plugin -o kms_adapter.so kms_adapter.go

然后通过环境变量指定该适配器插件,如下:

export KMS_ADAPTER_LIB= ./kms_adapter.go #路径根据实际情况指定

工具层

工具层主要用来生成和解析KMS私钥,并生成测试证书等。

KMS私钥结构
长安链共识节点私钥、客户端私钥可以通过KMS控制台生成,在长安链使用过程中,使用json形式表示私钥,结构如下:

$ cat crypto-config/wx-org1.chainmaker.org/node/consensus1/consensus1.sign.key | jq
{
  "key_id": "4ad75e10-5ead-11eb-a04f-5254009cd9d4",
  "key_type": "SM2DSA",
  "key_alias": ""
}

其中,key_id表示密钥唯一id,key_type表示密钥类型(如在腾讯云KMS平台上,国密sm2的密钥类型为SM2DSA),key_alias为 密钥别名(可选)。

KMS私钥生成和解析

// CreateKMSKey - create kms private key
func CreateKMSKey(keyType, keyId, keyAlias string, extParams map[string]string) ([]byte, crypto.PrivateKey, error) {
	privKey, err = kms.GetKMSAdapter().NewPrivateKey(keyId, keyType, keyAlias)
	if err != nil {
		return nil, nil, errors.WithMessagef(err, "failed to get kms private key, "+
			"keyId = %s, keyType = %s, keyAlias = %s", keyId, keyType, keyAlias)
	}

	keySpec := &kmsKeySpec{
		KeyType:  keyType,
		KeyId:    keyId,
		KeyAlias: keyAlias,
	}
	keySpecJson, _ := json.Marshal(keySpec)

	return keySpecJson, privKey, nil
}

// ParseKMSPrivKey parse a kms private key
func ParseKMSPrivKey(keySpecJson []byte) (crypto.PrivateKey, error) {
	var keySpec kmsKeySpec
	if err := json.Unmarshal(keySpecJson, &keySpec); err != nil {
		return nil, errors.WithMessage(err, "failed to parse kms keySpec")
	}
	return kms.GetKMSAdapter().NewPrivateKey(keySpec.KeyId, keySpec.KeyType, keySpec.KeyAlias)
}

应用层

//签名
keySpec, _ := ioutil.ReadFile(userKeyPath)
sk, _ := ParseKMSPrivKey(keySpec)
sig, _ := sk.SignWithOpts([]byte(msg), nil)

//验签, cert为解析x509证书文件得到
ok, _ := cert.PublicKey.VerifyWithOpts(msg, sig, nil)

长安链KMS配置

长安链配置

kms:
	enabled: true            # kms enable flag, set true if use kms
	is_public: true           # private cloud kms or public cloud kms, set true if use public kms
	secret_id: ""             # cloud kms SecretId
	secret_key: ""            # cloud kms SecretKey
	address: "kms.tencentcloudapi.com" # kms server address, ip or dns
	region: "ap-guangzhou"    # kms server region
	sdk_scheme: "https"       # kms sdk scheme, http or https
	ext_params: ""            # optional,this is a map string, like "".

以上配置涉及chainmaker-cryptogen、chainmaker-go以及sdk-go的配置文件。其中chainmaker-cryptogen需要在 config/test_keys.yml内配置KMS测试密钥,如下:

$ cat chainmaker-cryptogen/config/test_keys.yml

test_keys:
  - wx-org1.chainmaker.org:
      ca:
        - e2920cd5-5a02-11eb-840b-525400e8e6ea,SM2DSA,
      node:
        consensus:
          - 4ad75e10-5ead-11eb-a04f-5254009cd9d4,SM2DSA,
        common:
          - 4ad75e10-5ead-11eb-a04f-5254009cd9d4,SM2DSA,
      user:
        admin:
          - 4a296f1a-5ead-11eb-8768-525400ce83fb,SM2DSA,
        client:
          - 4a5ebd1d-5ead-11eb-840b-525400e8e6ea,SM2DSA,
        light:
          - 4a5ebd1d-5ead-11eb-840b-525400e8e6ea,SM2DSA,
  - wx-org2.chainmaker.org:
      ca:
        - c4c263c2-5d9c-11eb-8768-525400ce83fb,SM2DSA,
      node:
        consensus:
          - c4e8faa1-5d9c-11eb-b9b1-525400d9da05,SM2DSA,
        common:
          - c4e8faa1-5d9c-11eb-b9b1-525400d9da05,SM2DSA,
      user:
        admin:
          - c50e9d19-5d9c-11eb-840b-525400e8e6ea,SM2DSA,
        client:
          - c5330fdf-5d9c-11eb-8787-52540018dc09,SM2DSA,
        light:
          - c5330fdf-5d9c-11eb-8787-52540018dc09,SM2DSA,
  - wx-org3.chainmaker.org:
      ca:
        - d71bbbf9-5d98-11eb-8768-525400ce83fb,SM2DSA,
      node:
        consensus:
          - d770a3e9-5d98-11eb-a04f-5254009cd9d4,SM2DSA,
        common:
          - d770a3e9-5d98-11eb-a04f-5254009cd9d4,SM2DSA,
      user:
        admin:
          - d6f5c969-5d98-11eb-840b-525400e8e6ea,SM2DSA,
        client:
          - 3fd1cfad-5d68-11eb-8787-52540018dc09,SM2DSA,
        light:
          - 3fd1cfad-5d68-11eb-8787-52540018dc09,SM2DSA,
  - wx-org4.chainmaker.org:
      ca:
        - e9570909-5d65-11eb-840b-525400e8e6ea,SM2DSA,
      node:
        consensus:
          - e971f0e9-5d65-11eb-840b-525400e8e6ea,SM2DSA,
        common:
          - e9570909-5d65-11eb-840b-525400e8e6ea,SM2DSA,
      user:
        admin:
          - 2efc1a70-5d64-11eb-8768-525400ce83fb,SM2DSA,
        client:
          - dd1bfef9-5d62-11eb-b9b1-525400d9da05,SM2DSA,
        light:
          - 2efc1a70-5d64-11eb-8768-525400ce83fb,SM2DSA,

适配器插件配置
参考- ChainMaker - KMS适配层
注:如果使用腾讯云KMS,则无需配置kms适配器。