in client/client.go [382:502]
func (c *StetClient) unwrapAndValidateShares(ctx context.Context, wrappedShares []*configpb.WrappedShare, opts sharesOpts) ([]shares.UnwrappedShare, error) {
if len(wrappedShares) != len(opts.kekInfos) {
return nil, fmt.Errorf("number of shares to unwrap (%d) does not match number of KEKs (%d)", len(wrappedShares), len(opts.kekInfos))
}
var kmsClients *cloudkms.ClientFactory
if c.testKMSClients != nil {
kmsClients = c.testKMSClients
} else {
kmsClients = cloudkms.NewClientFactory(c.Version)
}
defer kmsClients.Close()
// In order to support k-of-n decryption, don't exit early if share
// share unwrapping fails. Attempt to unwrap all shares and just
// return the subset of ones that succeeded, and let the Shamir's
// implementation handle the subset of shares.
var unwrappedShares []shares.UnwrappedShare
for i, wrapped := range wrappedShares {
unwrapped := shares.UnwrappedShare{}
kek := opts.kekInfos[i]
glog.Infof("Attempting to unwrap share #%v, URI %v", i+1, kek.GetKekUri())
switch x := kek.KekType.(type) {
case *configpb.KekInfo_RsaFingerprint:
key, err := PrivateKeyForRSAFingerprint(kek, opts.asymmetricKeys)
if err != nil {
glog.Errorf("Failed to find private key for RSA fingerprint: %v", err)
continue
}
unwrapped.Share, err = rsa.DecryptOAEP(sha256.New(), rand.Reader, key, wrapped.GetShare(), nil)
if err != nil {
glog.Errorf("Error unwrapping key share for %v: %v", kek.GetKekUri(), err)
continue
}
case *configpb.KekInfo_KekUri:
// Configure CloudKMS Client, with Confidential Space credentials if applicable.
creds := ""
if opts.confSpaceConfig != nil {
creds = opts.confSpaceConfig.FindMatchingCredentials(kek.GetKekUri(), configpb.CredentialMode_DECRYPT_ONLY_MODE)
}
kmsClient, err := kmsClients.Client(ctx, creds)
if err != nil {
glog.Errorf("Error initializing Cloud KMS Client with credentials \"%v\" for %v: %v", creds, kek.GetKekUri(), err)
continue
}
cryptoKey, err := getKekCryptoKey(ctx, kmsClient, kek)
if err != nil {
glog.Errorf("Error retrieving KEK Metadata for %v: %v", kek.GetKekUri(), err)
continue
}
var uri string
// Unwrap share via KMS.
switch pl := cryptoKey.GetPrimary().ProtectionLevel; pl {
case rpb.ProtectionLevel_SOFTWARE, rpb.ProtectionLevel_HSM:
unwrapOpts := cloudkms.UnwrapOpts{
Share: wrapped.GetShare(),
KeyName: strings.TrimPrefix(kek.GetKekUri(), gcpKeyPrefix),
}
unwrapped.Share, err = cloudkms.UnwrapShare(ctx, kmsClient, unwrapOpts)
if err != nil {
glog.Errorf("Error unwrapping key sharefor %v: %v", kek.GetKekUri(), err)
continue
}
uri = kek.GetKekUri()
case rpb.ProtectionLevel_EXTERNAL:
kmd, err := externalKEKMetadata(cryptoKey)
if err != nil {
return nil, fmt.Errorf("error creating KEK Metadata: %v", err)
}
unwrapped.Share, err = c.ekmSecureSessionUnwrap(ctx, wrapped.GetShare(), *kmd, nil)
if err != nil {
glog.Warningf("Error unwrapping with external EKM for %v: %v", kmd.uri, err)
continue
}
uri = kmd.uri
case rpb.ProtectionLevel_EXTERNAL_VPC:
kmd, ekmCerts, err := c.getExternalVPCKeyInfo(ctx, cryptoKey, creds)
if err != nil {
return nil, fmt.Errorf("error getting external VPC key info: %v", err)
}
unwrapped.Share, err = c.ekmSecureSessionUnwrap(ctx, wrapped.GetShare(), *kmd, ekmCerts)
if err != nil {
glog.Errorf("Error unwrapping with external EKM for %v: %v", kmd.uri, err)
continue
}
uri = kmd.uri
default:
glog.Errorf("Unsupported protection level for %v: %v", kek.GetKekUri(), pl)
continue
}
// Return the URI used: the Cloud KMS one in the case of a software
// or HSM key, and the external key URI for an external key.
unwrapped.URI = uri
default:
glog.Errorf("Unsupported KekInfo type for %v: %v", kek.GetKekUri(), x)
continue
}
if !shares.ValidateShare(unwrapped.Share, wrapped.GetHash()) {
glog.Errorf("Unwrapped share %v does not have the expected hash", i)
continue
}
glog.Infof("Successfully unwrapped share %v", unwrapped.URI)
unwrappedShares = append(unwrappedShares, unwrapped)
}
return unwrappedShares, nil
}