/
kmssigner.go
81 lines (70 loc) · 2.35 KB
/
kmssigner.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/*
Copyright 2020 Skyscanner Limited.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package signer
import (
"crypto"
"crypto/x509"
"io"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/aws/aws-sdk-go/service/kms/kmsiface"
)
// KMSSigner implements the crypto/Signer interface that can be used for signing operations
// using an AWS KMS key. see https://golang.org/pkg/crypto/#Signer
type KMSSigner struct {
// client is and instance of the aws kms client
client kmsiface.KMSAPI
// keyID is the KMS Key Id used for signing
keyID string
// public key
publicKey crypto.PublicKey
}
// New returns a KMSSigner instance given and AWS client and a KMS key used for signing.
// TODO: explain what are the pre-requisits for the KMS key.
// TODO: implement PublicKey caching with periodical refresh
func New(client kmsiface.KMSAPI, keyID string) (*KMSSigner, error) {
response, err := client.GetPublicKey(&kms.GetPublicKeyInput{
KeyId: &keyID,
})
if err != nil {
return nil, err
}
key, err := x509.ParsePKIXPublicKey(response.PublicKey)
if err != nil {
return nil, err
}
return &KMSSigner{
client: client,
keyID: keyID,
publicKey: key,
}, nil
}
// Public returns the public key corresponding to the opaque, private key.
func (s *KMSSigner) Public() crypto.PublicKey {
return s.publicKey
}
// Sign signs digest with the KMS key.
// TODO: currently use SigningAlgorithmSpecRsassaPkcs1V15Sha256. Is that ok?
// TODO: should use the opts provided.
func (s *KMSSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
resp, err := s.client.Sign(&kms.SignInput{
KeyId: &s.keyID,
Message: digest,
MessageType: aws.String(kms.MessageTypeDigest),
SigningAlgorithm: aws.String(kms.SigningAlgorithmSpecRsassaPkcs1V15Sha256),
})
if err != nil {
return nil, err
}
return resp.Signature, nil
}