Skip to content

Commit 9006d47

Browse files
committed
refine to support kms self generated keys
Signed-off-by: dahu.kdh <dahu.kdh@alibaba-inc.com>
1 parent 3bed917 commit 9006d47

File tree

2 files changed

+146
-31
lines changed

2 files changed

+146
-31
lines changed

cmd/notation-alibabacloud-secret-manager/plugin.go

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ func (p *AlibabaCloudSecretManagerPlugin) DescribeKey(_ context.Context, req *pl
9898
}
9999

100100
func (p *AlibabaCloudSecretManagerPlugin) GenerateSignature(_ context.Context, req *plugin.GenerateSignatureRequest) (*plugin.GenerateSignatureResponse, error) {
101-
102101
messageType := "RAW"
103102
signRequest := &dkms.SignRequest{
104103
KeyId: tea.String(req.KeyID),
@@ -108,6 +107,8 @@ func (p *AlibabaCloudSecretManagerPlugin) GenerateSignature(_ context.Context, r
108107
runtimeOptions := &dedicatedkmsopenapiutil.RuntimeOptions{
109108
IgnoreSSL: tea.Bool(true),
110109
}
110+
111+
rawCertChain := make([][]byte, 0)
111112
//set instance ca from file
112113
caFilePath := sm.GetKMSCAFile()
113114
if caFilePath != "" {
@@ -143,6 +144,7 @@ func (p *AlibabaCloudSecretManagerPlugin) GenerateSignature(_ context.Context, r
143144
log.Logger.Infof("sign response is %s", signResponse.String())
144145
var certChain []*x509.Certificate
145146
if caCertsPath, ok := req.PluginConfig[CaCerts]; ok {
147+
//for imported key
146148
caCertPEMBlock, err := os.ReadFile(caCertsPath)
147149
if err != nil {
148150
log.Logger.Errorf("Failed to read ca_certs from %s, err %v", caCertsPath, err)
@@ -153,32 +155,26 @@ func (p *AlibabaCloudSecretManagerPlugin) GenerateSignature(_ context.Context, r
153155
log.Logger.Errorf("Failed to parse ca_certs from %s, err %v", caCertsPath, err)
154156
return nil, err
155157
}
158+
// build raw cert chain
159+
for _, cert := range certChain {
160+
rawCertChain = append(rawCertChain, cert.Raw)
161+
}
156162
} else {
157-
//getPublicKeyRequest := &dkms.GetPublicKeyRequest{
158-
// KeyId: tea.String(req.KeyID),
159-
//}
160-
//publicKeyResponse, err := p.DedicatedClient.GetPublicKeyWithOptions(getPublicKeyRequest, runtimeOptions)
161-
//if err != nil {
162-
// log.Logger.Errorf("Failed to get public key from KMS service, err %v", err)
163-
// return nil, err
164-
//}
165-
//log.Logger.Infof("public key response is %s", tea.StringValue(publicKeyResponse.PublicKey))
166-
//
167-
//certChain, err := sm.ParseCertificates(tea.StringValue(publicKeyResponse.PublicKey))
168-
//if err != nil {
169-
// log.Logger.Errorf("Failed to parse public key response, err %v", err)
170-
// return nil, err
171-
//}
172-
173-
log.Logger.Errorf("Can not find ca_certs in plugin-config")
174-
return nil, errors.New("No ca_certs parameter given in plugin-config")
163+
//for kms self generated key
164+
pub, err := sm.GetPublicKey(p.DedicatedClient, req.KeyID)
165+
if err != nil {
166+
log.Logger.Errorf("Failed to get the public key from the given kms key %s, err %v", req.KeyID, err)
167+
return nil, err
168+
}
169+
//get cert data based on the given key id
170+
certData, err := sm.GetCertDataFromKey(p.DedicatedClient, pub, req.KeyID)
171+
if err != nil {
172+
log.Logger.Errorf("Failed to parse ca_certs from %s, err %v", caCertsPath, err)
173+
return nil, err
174+
}
175+
rawCertChain = append(rawCertChain, certData)
175176
}
176177

177-
// build raw cert chain
178-
rawCertChain := make([][]byte, 0, len(certChain))
179-
for _, cert := range certChain {
180-
rawCertChain = append(rawCertChain, cert.Raw)
181-
}
182178
return &plugin.GenerateSignatureResponse{
183179
KeyID: req.KeyID,
184180
Signature: signResponse.Signature,
@@ -217,10 +213,10 @@ func (p *AlibabaCloudSecretManagerPlugin) VerifySignature(_ context.Context, req
217213
func (p *AlibabaCloudSecretManagerPlugin) GetMetadata(_ context.Context, _ *plugin.GetMetadataRequest) (*plugin.GetMetadataResponse, error) {
218214
return &plugin.GetMetadataResponse{
219215
SupportedContractVersions: []string{plugin.ContractVersion},
220-
Name: "notation-alibabacloud.secretmanager.plugin",
216+
Name: "alibabacloud.secretmanager.plugin",
221217
Description: "Alibaba Cloud Secret Manager signer plugin for Notation",
222-
URL: "https://github.com/AliyunContainerService/notation-alibabacloud-secret-manager",
223-
Version: "0.1.0",
218+
URL: "https://example.com/notation/plugin",
219+
Version: "0.0.1",
224220
Capabilities: []plugin.Capability{
225221
plugin.CapabilitySignatureGenerator,
226222
plugin.CapabilityTrustedIdentityVerifier},

internal/sm/secret_manager.go

Lines changed: 123 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,150 @@
11
package sm
22

33
import (
4+
"crypto"
5+
"crypto/rand"
6+
"crypto/rsa"
47
"crypto/x509"
8+
"crypto/x509/pkix"
59
"encoding/pem"
610
"errors"
711
"fmt"
12+
"github.com/AliyunContainerService/notation-alibabacloud-secret-manager/internal/log"
813
"github.com/alibabacloud-go/tea/tea"
914
dedicatedkmsopenapi "github.com/aliyun/alibabacloud-dkms-gcs-go-sdk/openapi"
1015
dedicatedkmssdk "github.com/aliyun/alibabacloud-dkms-gcs-go-sdk/sdk"
1116
"github.com/notaryproject/notation-plugin-framework-go/plugin"
17+
"io"
18+
"math/big"
19+
"time"
1220
)
1321

1422
const (
1523
KMS_RSA_2048 = "RSA_2048"
1624
KMS_RSA_3072 = "RSA_3072"
1725
KMS_RSA_4096 = "RSA_4096"
1826
KMS_EC_P256 = "EC_P256"
27+
//sign algorithm supported by KMS
28+
KMS_ALG_RSA_PSS_SHA_256 = "RSA_PSS_SHA_256"
29+
KMS_ALG_RSA_PKCS1_SHA_256 = "RSA_PKCS1_SHA_256"
30+
31+
NOTATION_CN = "notation"
1932
)
2033

34+
type KmsPrivateKeySigner struct {
35+
client *dedicatedkmssdk.Client
36+
publicKey crypto.PublicKey
37+
keyId string
38+
algorithm string
39+
}
40+
41+
func (ks *KmsPrivateKeySigner) Public() crypto.PublicKey {
42+
return ks.publicKey
43+
}
44+
45+
func (ks *KmsPrivateKeySigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
46+
request := &dedicatedkmssdk.SignRequest{
47+
KeyId: tea.String(ks.keyId),
48+
Message: digest,
49+
MessageType: tea.String("DIGEST"),
50+
Algorithm: tea.String(ks.algorithm),
51+
}
52+
resp, err := ks.client.Sign(request)
53+
if err != nil {
54+
return nil, err
55+
}
56+
return resp.Signature, nil
57+
}
58+
59+
func genSerialNum() (*big.Int, error) {
60+
serialNumLimit := new(big.Int).Lsh(big.NewInt(1), 128)
61+
serialNum, err := rand.Int(rand.Reader, serialNumLimit)
62+
if err != nil {
63+
return nil, fmt.Errorf("serial number generation failure (%v)", err)
64+
}
65+
return serialNum, nil
66+
}
67+
68+
func GetCertDataFromKey(dkmsClient *dedicatedkmssdk.Client, pub *rsa.PublicKey, keyId string) ([]byte, error) {
69+
//init csr subject
70+
subject := pkix.Name{
71+
Country: []string{"CN"},
72+
Organization: []string{"AlibabaCloud"},
73+
OrganizationalUnit: []string{"Ack"},
74+
CommonName: NOTATION_CN,
75+
}
76+
77+
//Create kms service signer object
78+
priv := &KmsPrivateKeySigner{
79+
client: dkmsClient, //kms client
80+
keyId: keyId, //kms instance asymmetric key Id
81+
publicKey: pub, //kms instance asymmetric public key
82+
algorithm: KMS_ALG_RSA_PSS_SHA_256, //kms instance signing algorithm, RSA_PKCS1_SHA_256 is not conform with notation specification
83+
}
84+
85+
serialNum, err := genSerialNum()
86+
if err != nil {
87+
log.Logger.Errorf("Failed to generate serail number, err %v", err)
88+
return nil, err
89+
}
90+
91+
// Create a new certificate template
92+
template := x509.Certificate{
93+
SerialNumber: serialNum,
94+
Subject: subject,
95+
NotBefore: time.Now(),
96+
NotAfter: time.Now().Add(365 * 24 * time.Hour), // Valid for 1 year
97+
IsCA: false,
98+
KeyUsage: x509.KeyUsageDigitalSignature,
99+
SignatureAlgorithm: x509.SHA256WithRSAPSS, //only support RSA_PSS_SHA_256 here
100+
}
101+
102+
// Create the certificate
103+
certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, pub, priv)
104+
if err != nil {
105+
log.Logger.Errorf("Failed to generate certificate from key %s, err %v", keyId, err)
106+
return nil, err
107+
}
108+
return certBytes, nil
109+
}
110+
111+
func GetPublicKey(client *dedicatedkmssdk.Client, keyId string) (*rsa.PublicKey, error) {
112+
request := &dedicatedkmssdk.GetPublicKeyRequest{
113+
KeyId: tea.String(keyId),
114+
}
115+
response, err := client.GetPublicKey(request)
116+
if err != nil {
117+
return nil, err
118+
}
119+
block, _ := pem.Decode([]byte(*response.PublicKey))
120+
if block == nil || block.Type != "PUBLIC KEY" {
121+
return nil, errors.New("failed to decode public key")
122+
}
123+
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
124+
if err != nil {
125+
return nil, err
126+
}
127+
//return rsa public key
128+
rsaPub, ok := pub.(*rsa.PublicKey)
129+
if !ok {
130+
return nil, errors.New(fmt.Sprintf("unsupport public key type %T", pub))
131+
}
132+
133+
return rsaPub, nil
134+
}
135+
21136
func GetDkmsClientByClientKeyFile(clientKeyPath, password, endpoint string) (*dedicatedkmssdk.Client, error) {
137+
// 创建DKMS Client配置
22138
config := &dedicatedkmsopenapi.Config{
23-
Protocol: tea.String("https"),
139+
Protocol: tea.String("https"),
140+
// 请替换为您在KMS应用管理获取的ClientKey文件的路径
24141
ClientKeyFile: tea.String(clientKeyPath),
25-
Password: tea.String(password),
26-
Endpoint: tea.String(endpoint),
142+
// 请替换为您在KMS应用管理创建ClientKey时输入的加密口令
143+
Password: tea.String(password),
144+
// 请替换为您实际的专属KMS实例服务地址(不包括协议头https://)
145+
Endpoint: tea.String(endpoint),
27146
}
28-
// Init DKMS client
147+
// 创建DKMS Client对象
29148
client, err := dedicatedkmssdk.NewClient(config)
30149
if err != nil {
31150
return nil, err

0 commit comments

Comments
 (0)