1package keyservice 2 3import ( 4 "fmt" 5 6 "go.mozilla.org/sops/v3/azkv" 7 "go.mozilla.org/sops/v3/gcpkms" 8 "go.mozilla.org/sops/v3/hcvault" 9 "go.mozilla.org/sops/v3/kms" 10 "go.mozilla.org/sops/v3/pgp" 11 "golang.org/x/net/context" 12 "google.golang.org/grpc" 13 "google.golang.org/grpc/codes" 14 "google.golang.org/grpc/status" 15) 16 17// Server is a key service server that uses SOPS MasterKeys to fulfill requests 18type Server struct { 19 // Prompt indicates whether the server should prompt before decrypting or encrypting data 20 Prompt bool 21} 22 23func (ks *Server) encryptWithPgp(key *PgpKey, plaintext []byte) ([]byte, error) { 24 pgpKey := pgp.NewMasterKeyFromFingerprint(key.Fingerprint) 25 err := pgpKey.Encrypt(plaintext) 26 if err != nil { 27 return nil, err 28 } 29 return []byte(pgpKey.EncryptedKey), nil 30} 31 32func (ks *Server) encryptWithKms(key *KmsKey, plaintext []byte) ([]byte, error) { 33 kmsKey := kmsKeyToMasterKey(key) 34 err := kmsKey.Encrypt(plaintext) 35 if err != nil { 36 return nil, err 37 } 38 return []byte(kmsKey.EncryptedKey), nil 39} 40 41func (ks *Server) encryptWithGcpKms(key *GcpKmsKey, plaintext []byte) ([]byte, error) { 42 gcpKmsKey := gcpkms.MasterKey{ 43 ResourceID: key.ResourceId, 44 } 45 err := gcpKmsKey.Encrypt(plaintext) 46 if err != nil { 47 return nil, err 48 } 49 return []byte(gcpKmsKey.EncryptedKey), nil 50} 51 52func (ks *Server) encryptWithAzureKeyVault(key *AzureKeyVaultKey, plaintext []byte) ([]byte, error) { 53 azkvKey := azkv.MasterKey{ 54 VaultURL: key.VaultUrl, 55 Name: key.Name, 56 Version: key.Version, 57 } 58 err := azkvKey.Encrypt(plaintext) 59 if err != nil { 60 return nil, err 61 } 62 return []byte(azkvKey.EncryptedKey), nil 63} 64 65func (ks *Server) encryptWithVault(key *VaultKey, plaintext []byte) ([]byte, error) { 66 vaultKey := hcvault.MasterKey{ 67 VaultAddress: key.VaultAddress, 68 EnginePath: key.EnginePath, 69 KeyName: key.KeyName, 70 } 71 err := vaultKey.Encrypt(plaintext) 72 if err != nil { 73 return nil, err 74 } 75 return []byte(vaultKey.EncryptedKey), nil 76} 77 78func (ks *Server) decryptWithPgp(key *PgpKey, ciphertext []byte) ([]byte, error) { 79 pgpKey := pgp.NewMasterKeyFromFingerprint(key.Fingerprint) 80 pgpKey.EncryptedKey = string(ciphertext) 81 plaintext, err := pgpKey.Decrypt() 82 return []byte(plaintext), err 83} 84 85func (ks *Server) decryptWithKms(key *KmsKey, ciphertext []byte) ([]byte, error) { 86 kmsKey := kmsKeyToMasterKey(key) 87 kmsKey.EncryptedKey = string(ciphertext) 88 plaintext, err := kmsKey.Decrypt() 89 return []byte(plaintext), err 90} 91 92func (ks *Server) decryptWithGcpKms(key *GcpKmsKey, ciphertext []byte) ([]byte, error) { 93 gcpKmsKey := gcpkms.MasterKey{ 94 ResourceID: key.ResourceId, 95 } 96 gcpKmsKey.EncryptedKey = string(ciphertext) 97 plaintext, err := gcpKmsKey.Decrypt() 98 return []byte(plaintext), err 99} 100 101func (ks *Server) decryptWithAzureKeyVault(key *AzureKeyVaultKey, ciphertext []byte) ([]byte, error) { 102 azkvKey := azkv.MasterKey{ 103 VaultURL: key.VaultUrl, 104 Name: key.Name, 105 Version: key.Version, 106 } 107 azkvKey.EncryptedKey = string(ciphertext) 108 plaintext, err := azkvKey.Decrypt() 109 return []byte(plaintext), err 110} 111 112func (ks *Server) decryptWithVault(key *VaultKey, ciphertext []byte) ([]byte, error) { 113 vaultKey := hcvault.MasterKey{ 114 VaultAddress: key.VaultAddress, 115 EnginePath: key.EnginePath, 116 KeyName: key.KeyName, 117 } 118 vaultKey.EncryptedKey = string(ciphertext) 119 plaintext, err := vaultKey.Decrypt() 120 return []byte(plaintext), err 121} 122 123// Encrypt takes an encrypt request and encrypts the provided plaintext with the provided key, returning the encrypted 124// result 125func (ks Server) Encrypt(ctx context.Context, 126 req *EncryptRequest) (*EncryptResponse, error) { 127 key := *req.Key 128 var response *EncryptResponse 129 switch k := key.KeyType.(type) { 130 case *Key_PgpKey: 131 ciphertext, err := ks.encryptWithPgp(k.PgpKey, req.Plaintext) 132 if err != nil { 133 return nil, err 134 } 135 response = &EncryptResponse{ 136 Ciphertext: ciphertext, 137 } 138 case *Key_KmsKey: 139 ciphertext, err := ks.encryptWithKms(k.KmsKey, req.Plaintext) 140 if err != nil { 141 return nil, err 142 } 143 response = &EncryptResponse{ 144 Ciphertext: ciphertext, 145 } 146 case *Key_GcpKmsKey: 147 ciphertext, err := ks.encryptWithGcpKms(k.GcpKmsKey, req.Plaintext) 148 if err != nil { 149 return nil, err 150 } 151 response = &EncryptResponse{ 152 Ciphertext: ciphertext, 153 } 154 case *Key_AzureKeyvaultKey: 155 ciphertext, err := ks.encryptWithAzureKeyVault(k.AzureKeyvaultKey, req.Plaintext) 156 if err != nil { 157 return nil, err 158 } 159 response = &EncryptResponse{ 160 Ciphertext: ciphertext, 161 } 162 case *Key_VaultKey: 163 ciphertext, err := ks.encryptWithVault(k.VaultKey, req.Plaintext) 164 if err != nil { 165 return nil, err 166 } 167 response = &EncryptResponse{ 168 Ciphertext: ciphertext, 169 } 170 case nil: 171 return nil, status.Errorf(codes.NotFound, "Must provide a key") 172 default: 173 return nil, status.Errorf(codes.NotFound, "Unknown key type") 174 } 175 if ks.Prompt { 176 err := ks.prompt(key, "encrypt") 177 if err != nil { 178 return nil, err 179 } 180 } 181 return response, nil 182} 183 184func keyToString(key Key) string { 185 switch k := key.KeyType.(type) { 186 case *Key_PgpKey: 187 return fmt.Sprintf("PGP key with fingerprint %s", k.PgpKey.Fingerprint) 188 case *Key_KmsKey: 189 return fmt.Sprintf("AWS KMS key with ARN %s", k.KmsKey.Arn) 190 case *Key_GcpKmsKey: 191 return fmt.Sprintf("GCP KMS key with resource ID %s", k.GcpKmsKey.ResourceId) 192 case *Key_AzureKeyvaultKey: 193 return fmt.Sprintf("Azure Key Vault key with URL %s/keys/%s/%s", k.AzureKeyvaultKey.VaultUrl, k.AzureKeyvaultKey.Name, k.AzureKeyvaultKey.Version) 194 case *Key_VaultKey: 195 return fmt.Sprintf("Hashicorp Vault key with URI %s/v1/%s/keys/%s", k.VaultKey.VaultAddress, k.VaultKey.EnginePath, k.VaultKey.KeyName) 196 default: 197 return fmt.Sprintf("Unknown key type") 198 } 199} 200 201func (ks Server) prompt(key Key, requestType string) error { 202 keyString := keyToString(key) 203 var response string 204 for response != "y" && response != "n" { 205 fmt.Printf("\nReceived %s request using %s. Respond to request? (y/n): ", requestType, keyString) 206 _, err := fmt.Scanln(&response) 207 if err != nil { 208 return err 209 } 210 } 211 if response == "n" { 212 return grpc.Errorf(codes.PermissionDenied, "Request rejected by user") 213 } 214 return nil 215} 216 217// Decrypt takes a decrypt request and decrypts the provided ciphertext with the provided key, returning the decrypted 218// result 219func (ks Server) Decrypt(ctx context.Context, 220 req *DecryptRequest) (*DecryptResponse, error) { 221 key := *req.Key 222 var response *DecryptResponse 223 switch k := key.KeyType.(type) { 224 case *Key_PgpKey: 225 plaintext, err := ks.decryptWithPgp(k.PgpKey, req.Ciphertext) 226 if err != nil { 227 return nil, err 228 } 229 response = &DecryptResponse{ 230 Plaintext: plaintext, 231 } 232 case *Key_KmsKey: 233 plaintext, err := ks.decryptWithKms(k.KmsKey, req.Ciphertext) 234 if err != nil { 235 return nil, err 236 } 237 response = &DecryptResponse{ 238 Plaintext: plaintext, 239 } 240 case *Key_GcpKmsKey: 241 plaintext, err := ks.decryptWithGcpKms(k.GcpKmsKey, req.Ciphertext) 242 if err != nil { 243 return nil, err 244 } 245 response = &DecryptResponse{ 246 Plaintext: plaintext, 247 } 248 case *Key_AzureKeyvaultKey: 249 plaintext, err := ks.decryptWithAzureKeyVault(k.AzureKeyvaultKey, req.Ciphertext) 250 if err != nil { 251 return nil, err 252 } 253 response = &DecryptResponse{ 254 Plaintext: plaintext, 255 } 256 case *Key_VaultKey: 257 plaintext, err := ks.decryptWithVault(k.VaultKey, req.Ciphertext) 258 if err != nil { 259 return nil, err 260 } 261 response = &DecryptResponse{ 262 Plaintext: plaintext, 263 } 264 case nil: 265 return nil, grpc.Errorf(codes.NotFound, "Must provide a key") 266 default: 267 return nil, grpc.Errorf(codes.NotFound, "Unknown key type") 268 } 269 if ks.Prompt { 270 err := ks.prompt(key, "decrypt") 271 if err != nil { 272 return nil, err 273 } 274 } 275 return response, nil 276} 277 278func kmsKeyToMasterKey(key *KmsKey) kms.MasterKey { 279 ctx := make(map[string]*string) 280 for k, v := range key.Context { 281 value := v // Allocate a new string to prevent the pointer below from referring to only the last iteration value 282 ctx[k] = &value 283 } 284 return kms.MasterKey{ 285 Arn: key.Arn, 286 Role: key.Role, 287 EncryptionContext: ctx, 288 AwsProfile: key.AwsProfile, 289 } 290} 291