github.com/hyperledger/aries-framework-go@v0.3.2/pkg/wallet/kmsclient.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package wallet 8 9 import ( 10 "bytes" 11 "crypto/ed25519" 12 "crypto/sha256" 13 "errors" 14 "fmt" 15 "net/http" 16 "strings" 17 "sync" 18 19 "github.com/bluele/gcache" 20 "github.com/btcsuite/btcutil/base58" 21 "github.com/google/tink/go/subtle/random" 22 23 "github.com/hyperledger/aries-framework-go/pkg/crypto" 24 "github.com/hyperledger/aries-framework-go/pkg/crypto/primitive/bbs12381g2pub" 25 "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk" 26 "github.com/hyperledger/aries-framework-go/pkg/internal/kmssigner" 27 "github.com/hyperledger/aries-framework-go/pkg/kms" 28 "github.com/hyperledger/aries-framework-go/pkg/kms/localkms" 29 "github.com/hyperledger/aries-framework-go/pkg/kms/webkms" 30 "github.com/hyperledger/aries-framework-go/pkg/secretlock" 31 "github.com/hyperledger/aries-framework-go/pkg/secretlock/local" 32 "github.com/hyperledger/aries-framework-go/pkg/secretlock/local/masterlock/hkdf" 33 ) 34 35 const ( 36 // LocalKeyURIPrefix for locally stored keys. 37 localKeyURIPrefix = "local-lock://" 38 39 // number of sections in verification method. 40 vmSectionCount = 2 41 ) 42 43 // supported key types for import key base58 (all constants defined in lower case). 44 const ( 45 Ed25519VerificationKey2018 = "ed25519verificationkey2018" 46 Bls12381G1Key2020 = "bls12381g1key2020" 47 ) 48 49 // supported JWK curves for jwk private key import. 50 // nolint: gochecknoglobals 51 var jwkCurves = map[string]kms.KeyType{ 52 "Ed25519": kms.ED25519Type, 53 "P-256": kms.ECDSAP256TypeIEEEP1363, 54 "P-384": kms.ECDSAP384TypeIEEEP1363, 55 "BLS12381G2": kms.BLS12381G2Type, 56 } 57 58 // errors. 59 var ( 60 // ErrAlreadyUnlocked error when key manager is already created for a given user. 61 ErrAlreadyUnlocked = errors.New("wallet already unlocked") 62 63 // ErrWalletLocked when key manager operation is attempted without unlocking wallet. 64 ErrWalletLocked = errors.New("wallet locked") 65 ) 66 67 // walletKMSInstance is key manager store singleton - access only via keyManager() 68 // 69 //nolint:gochecknoglobals 70 var ( 71 walletKMSInstance *walletKeyManager 72 kmsStoreOnce sync.Once 73 ) 74 75 func keyManager() *walletKeyManager { 76 kmsStoreOnce.Do(func() { 77 walletKMSInstance = &walletKeyManager{ 78 gstore: gcache.New(0).Build(), 79 } 80 }) 81 82 return walletKMSInstance 83 } 84 85 // walletKeyManager manages key manager instances in cache. 86 // underlying gcache is threasafe, no need of locks. 87 type walletKeyManager struct { 88 gstore gcache.Cache 89 } 90 91 func (k *walletKeyManager) createKeyManager(profileInfo *profile, 92 storeProvider kms.Store, opts *unlockOpts) (kms.KeyManager, error) { 93 if profileInfo.MasterLockCipher == "" && profileInfo.KeyServerURL == "" { 94 return nil, fmt.Errorf("invalid wallet profile") 95 } 96 97 var err error 98 99 var keyManager kms.KeyManager 100 101 // create key manager 102 if profileInfo.MasterLockCipher != "" { 103 // local kms 104 keyManager, err = createLocalKeyManager(profileInfo.User, opts.passphrase, 105 profileInfo.MasterLockCipher, opts.secretLockSvc, storeProvider) 106 if err != nil { 107 return nil, fmt.Errorf("failed to create local key manager: %w", err) 108 } 109 } else { 110 // remote kms 111 keyManager = createRemoteKeyManager(opts, profileInfo.KeyServerURL) 112 } 113 114 return keyManager, nil 115 } 116 117 // createMasterLock creates master lock from secret lock service provided. 118 func createMasterLock(secretLockSvc secretlock.Service) (string, error) { 119 masterKeyContent := random.GetRandomBytes(uint32(32)) //nolint: gomnd 120 121 masterLockEnc, err := secretLockSvc.Encrypt(localKeyURIPrefix, &secretlock.EncryptRequest{ 122 Plaintext: string(masterKeyContent), 123 }) 124 if err != nil { 125 return "", fmt.Errorf("failed to create master lock from secret lock service provided: %w", err) 126 } 127 128 return masterLockEnc.Ciphertext, nil 129 } 130 131 type kmsProvider struct { 132 storageProvider kms.Store 133 secretLock secretlock.Service 134 } 135 136 func (k *kmsProvider) StorageProvider() kms.Store { 137 return k.storageProvider 138 } 139 140 func (k *kmsProvider) SecretLock() secretlock.Service { 141 return k.secretLock 142 } 143 144 // createLocalKeyManager creates and returns local KMS instance. 145 func createLocalKeyManager(user, passphrase, masterLockCipher string, 146 masterLocker secretlock.Service, storeProvider kms.Store) (*localkms.LocalKMS, error) { 147 var err error 148 if passphrase != "" { 149 masterLocker, err = getDefaultSecretLock(passphrase) 150 if err != nil { 151 return nil, err 152 } 153 } 154 155 secretLockSvc, err := local.NewService(bytes.NewBufferString(masterLockCipher), masterLocker) 156 if err != nil { 157 return nil, err 158 } 159 160 return localkms.New(localKeyURIPrefix+user, &kmsProvider{ 161 storageProvider: storeProvider, 162 secretLock: secretLockSvc, 163 }) 164 } 165 166 // getDefaultSecretLock returns hkdf secret lock service from passphrase. 167 func getDefaultSecretLock(passphrase string) (secretlock.Service, error) { 168 return hkdf.NewMasterLock(passphrase, sha256.New, nil) 169 } 170 171 // createRemoteKeyManager creates and returns remote KMS instance. 172 func createRemoteKeyManager(opts *unlockOpts, keyServerURL string) *webkms.RemoteKMS { 173 kmsOpts := opts.webkmsOpts 174 175 if opts.authToken != "" { 176 kmsOpts = append(kmsOpts, webkms.WithHeaders(func(req *http.Request) (*http.Header, error) { 177 req.Header.Set("authorization", fmt.Sprintf("Bearer %s", opts.authToken)) 178 179 return &req.Header, nil 180 })) 181 } 182 183 return webkms.New(keyServerURL, http.DefaultClient, kmsOpts...) 184 } 185 186 func newKMSSigner(authToken string, c crypto.Crypto, opts *ProofOptions) (*kmssigner.KMSSigner, error) { 187 session, err := sessionManager().getSession(authToken) 188 if err != nil { 189 if errors.Is(err, ErrInvalidAuthToken) { 190 return nil, ErrWalletLocked 191 } 192 193 return nil, fmt.Errorf("failed to get session: %w", err) 194 } 195 196 keyManager := session.KeyManager 197 198 vmSplit := strings.Split(opts.VerificationMethod, "#") 199 200 if len(vmSplit) != vmSectionCount { 201 return nil, errors.New("invalid verification method format") 202 } 203 204 kid := vmSplit[vmSectionCount-1] 205 206 keyHandler, err := keyManager.Get(kid) 207 if err != nil { 208 return nil, err 209 } 210 211 _, kt, err := keyManager.ExportPubKeyBytes(kid) 212 if err != nil { 213 return nil, err 214 } 215 216 return &kmssigner.KMSSigner{ 217 KeyType: kt, 218 KeyHandle: keyHandler, 219 Crypto: c, 220 MultiMsg: opts.ProofType == BbsBlsSignature2020, 221 }, nil 222 } 223 224 // importKeyJWK imports private key jwk found in key contents, 225 // supported curve types - Ed25519, P-256, BLS12381G2. 226 func importKeyJWK(auth string, key *keyContent) error { 227 session, err := sessionManager().getSession(auth) 228 if err != nil { 229 if errors.Is(err, ErrInvalidAuthToken) { 230 return ErrWalletLocked 231 } 232 233 return fmt.Errorf("failed to get session: %w", err) 234 } 235 236 keyManager := session.KeyManager 237 238 var j jwk.JWK 239 if e := j.UnmarshalJSON(key.PrivateKeyJwk); e != nil { 240 return fmt.Errorf("failed to unmarshal jwk : %w", e) 241 } 242 243 keyType, ok := jwkCurves[j.Crv] 244 if !ok { 245 return fmt.Errorf("unsupported Key type %s", j.Crv) 246 } 247 248 _, _, err = keyManager.ImportPrivateKey(j.Key, keyType, kms.WithKeyID(getKIDFromJWK(key.ID, &j))) 249 if err != nil { 250 return fmt.Errorf("failed to import jwk key : %w", err) 251 } 252 253 return nil 254 } 255 256 // importKeyBase58 imports private key base58 found in key contents, 257 // supported types - Ed25519Signature2018, Bls12381G1Key2020. 258 func importKeyBase58(auth string, key *keyContent) error { 259 session, err := sessionManager().getSession(auth) 260 if err != nil { 261 if errors.Is(err, ErrInvalidAuthToken) { 262 return ErrWalletLocked 263 } 264 265 return fmt.Errorf("failed to get session: %w", err) 266 } 267 268 keyManager := session.KeyManager 269 270 switch strings.ToLower(key.KeyType) { 271 case Ed25519VerificationKey2018: 272 edPriv := ed25519.PrivateKey(base58.Decode(key.PrivateKeyBase58)) 273 274 _, _, err := keyManager.ImportPrivateKey(edPriv, kms.ED25519, kms.WithKeyID(getKID(key.ID))) 275 if err != nil { 276 return fmt.Errorf("failed to import Ed25519Signature2018 key : %w", err) 277 } 278 case Bls12381G1Key2020: 279 blsKey, err := bbs12381g2pub.UnmarshalPrivateKey(base58.Decode(key.PrivateKeyBase58)) 280 if err != nil { 281 return fmt.Errorf("failed to unmarshal %s private key : %w", kms.BLS12381G2Type, err) 282 } 283 284 _, _, err = keyManager.ImportPrivateKey(blsKey, kms.BLS12381G2, kms.WithKeyID(getKID(key.ID))) 285 if err != nil { 286 return fmt.Errorf("failed to import Ed25519Signature2018 key : %w", err) 287 } 288 default: 289 return errors.New("only Ed25519VerificationKey2018 & Bls12381G1Key2020 are supported in base58 format") 290 } 291 292 return nil 293 } 294 295 func getKID(id string) string { 296 cSplit := strings.Split(id, "#") 297 298 if len(cSplit) > 1 { 299 return cSplit[1] 300 } 301 302 return "" 303 } 304 305 func getKIDFromJWK(id string, j *jwk.JWK) string { 306 if j.KeyID != "" { 307 return j.KeyID 308 } 309 310 return getKID(id) 311 }